Remove QPainter::UniteClip
[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::IntersectClip || !s->clip || s->clip->hasRectClip || s->clip->hasRegionClip) {
1166         if (s->matrix.type() <= QTransform::TxScale
1167             && ((path.shape() == QVectorPath::RectangleHint)
1168                 || (isRect(points, path.elementCount())
1169                     && (!types || (types[0] == QPainterPath::MoveToElement
1170                                    && types[1] == QPainterPath::LineToElement
1171                                    && types[2] == QPainterPath::LineToElement
1172                                    && types[3] == QPainterPath::LineToElement))))) {
1173 #ifdef QT_DEBUG_DRAW
1174             qDebug() << " --- optimizing vector clip to rect clip...";
1175 #endif
1176
1177             QRectF r(points[0], points[1], points[4]-points[0], points[5]-points[1]);
1178             if (setClipRectInDeviceCoords(s->matrix.mapRect(r).toRect(), op))
1179                 return;
1180         }
1181     }
1182
1183     if (op == Qt::NoClip) {
1184         qrasterpaintengine_state_setNoClip(s);
1185
1186     } else {
1187         QClipData *base = d->baseClip.data();
1188
1189         // Intersect with current clip when available...
1190         if (op == Qt::IntersectClip && s->clip)
1191             base = s->clip;
1192
1193         // We always intersect, except when there is nothing to
1194         // intersect with, in which case we simplify the operation to
1195         // a replace...
1196         Qt::ClipOperation isectOp = Qt::IntersectClip;
1197         if (base == 0)
1198             isectOp = Qt::ReplaceClip;
1199
1200         QClipData *newClip = new QClipData(d->rasterBuffer->height());
1201         newClip->initialize();
1202         ClipData clipData = { base, newClip, isectOp };
1203         ensureOutlineMapper();
1204         d->rasterize(d->outlineMapper->convertPath(path), qt_span_clip, &clipData, 0);
1205
1206         newClip->fixup();
1207
1208         if (s->flags.has_clip_ownership)
1209             delete s->clip;
1210
1211         s->clip = newClip;
1212         s->flags.has_clip_ownership = true;
1213     }
1214     qrasterpaintengine_dirty_clip(d, s);
1215 }
1216
1217
1218
1219 /*!
1220     \internal
1221 */
1222 void QRasterPaintEngine::clip(const QRect &rect, Qt::ClipOperation op)
1223 {
1224 #ifdef QT_DEBUG_DRAW
1225     qDebug() << "QRasterPaintEngine::clip(): " << rect << op;
1226 #endif
1227
1228     QRasterPaintEngineState *s = state();
1229
1230     if (op == Qt::NoClip) {
1231         qrasterpaintengine_state_setNoClip(s);
1232
1233     } else if (s->matrix.type() > QTransform::TxScale) {
1234         QPaintEngineEx::clip(rect, op);
1235         return;
1236
1237     } else if (!setClipRectInDeviceCoords(s->matrix.mapRect(rect), op)) {
1238         QPaintEngineEx::clip(rect, op);
1239         return;
1240     }
1241 }
1242
1243
1244 bool QRasterPaintEngine::setClipRectInDeviceCoords(const QRect &r, Qt::ClipOperation op)
1245 {
1246     Q_D(QRasterPaintEngine);
1247     QRect clipRect = r & d->deviceRect;
1248     QRasterPaintEngineState *s = state();
1249
1250     if (op == Qt::ReplaceClip || s->clip == 0) {
1251
1252         // No current clip, hence we intersect with sysclip and be
1253         // done with it...
1254         QRegion clipRegion = systemClip();
1255         QClipData *clip = new QClipData(d->rasterBuffer->height());
1256
1257         if (clipRegion.isEmpty())
1258             clip->setClipRect(clipRect);
1259         else
1260             clip->setClipRegion(clipRegion & clipRect);
1261
1262         if (s->flags.has_clip_ownership)
1263             delete s->clip;
1264
1265         s->clip = clip;
1266         s->clip->enabled = true;
1267         s->flags.has_clip_ownership = true;
1268
1269     } else if (op == Qt::IntersectClip){ // intersect clip with current clip
1270         QClipData *base = s->clip;
1271
1272         Q_ASSERT(base);
1273         if (base->hasRectClip || base->hasRegionClip) {
1274             if (!s->flags.has_clip_ownership) {
1275                 s->clip = new QClipData(d->rasterBuffer->height());
1276                 s->flags.has_clip_ownership = true;
1277             }
1278             if (base->hasRectClip)
1279                 s->clip->setClipRect(base->clipRect & clipRect);
1280             else
1281                 s->clip->setClipRegion(base->clipRegion & clipRect);
1282             s->clip->enabled = true;
1283         } else {
1284             return false;
1285         }
1286     } else {
1287         return false;
1288     }
1289
1290     qrasterpaintengine_dirty_clip(d, s);
1291     return true;
1292 }
1293
1294
1295 /*!
1296     \internal
1297 */
1298 void QRasterPaintEngine::clip(const QRegion &region, Qt::ClipOperation op)
1299 {
1300 #ifdef QT_DEBUG_DRAW
1301     qDebug() << "QRasterPaintEngine::clip(): " << region << op;
1302 #endif
1303
1304     Q_D(QRasterPaintEngine);
1305
1306     if (region.rectCount() == 1) {
1307         clip(region.boundingRect(), op);
1308         return;
1309     }
1310
1311     QRasterPaintEngineState *s = state();
1312     const QClipData *clip = d->clip();
1313     const QClipData *baseClip = d->baseClip.data();
1314
1315     if (op == Qt::NoClip) {
1316         qrasterpaintengine_state_setNoClip(s);
1317     } else if (s->matrix.type() > QTransform::TxScale
1318                || (op == Qt::IntersectClip && !clip->hasRectClip && !clip->hasRegionClip)
1319                || (op == Qt::ReplaceClip && !baseClip->hasRectClip && !baseClip->hasRegionClip)) {
1320         QPaintEngineEx::clip(region, op);
1321     } else {
1322         const QClipData *curClip;
1323         QClipData *newClip;
1324
1325         if (op == Qt::IntersectClip)
1326             curClip = clip;
1327         else
1328             curClip = baseClip;
1329
1330         if (s->flags.has_clip_ownership) {
1331             newClip = s->clip;
1332             Q_ASSERT(newClip);
1333         } else {
1334             newClip = new QClipData(d->rasterBuffer->height());
1335             s->clip = newClip;
1336             s->flags.has_clip_ownership = true;
1337         }
1338
1339         QRegion r = s->matrix.map(region);
1340         if (curClip->hasRectClip)
1341             newClip->setClipRegion(r & curClip->clipRect);
1342         else if (curClip->hasRegionClip)
1343             newClip->setClipRegion(r & curClip->clipRegion);
1344
1345         qrasterpaintengine_dirty_clip(d, s);
1346     }
1347 }
1348
1349 /*!
1350     \internal
1351 */
1352 void QRasterPaintEngine::fillPath(const QPainterPath &path, QSpanData *fillData)
1353 {
1354 #ifdef QT_DEBUG_DRAW
1355     qDebug() << " --- fillPath, bounds=" << path.boundingRect();
1356 #endif
1357
1358     if (!fillData->blend)
1359         return;
1360
1361     Q_D(QRasterPaintEngine);
1362
1363     const QRectF controlPointRect = path.controlPointRect();
1364
1365     QRasterPaintEngineState *s = state();
1366     const QRect deviceRect = s->matrix.mapRect(controlPointRect).toRect();
1367     ProcessSpans blend = d->getBrushFunc(deviceRect, fillData);
1368     const bool do_clip = (deviceRect.left() < -QT_RASTER_COORD_LIMIT
1369                           || deviceRect.right() > QT_RASTER_COORD_LIMIT
1370                           || deviceRect.top() < -QT_RASTER_COORD_LIMIT
1371                           || deviceRect.bottom() > QT_RASTER_COORD_LIMIT);
1372
1373     if (!s->flags.antialiased && !do_clip) {
1374         d->initializeRasterizer(fillData);
1375         d->rasterizer->rasterize(path * s->matrix, path.fillRule());
1376         return;
1377     }
1378
1379     ensureOutlineMapper();
1380     d->rasterize(d->outlineMapper->convertPath(path), blend, fillData, d->rasterBuffer.data());
1381 }
1382
1383 static void fillRect_normalized(const QRect &r, QSpanData *data,
1384                                 QRasterPaintEnginePrivate *pe)
1385 {
1386     int x1, x2, y1, y2;
1387
1388     bool rectClipped = true;
1389
1390     if (data->clip) {
1391         x1 = qMax(r.x(), data->clip->xmin);
1392         x2 = qMin(r.x() + r.width(), data->clip->xmax);
1393         y1 = qMax(r.y(), data->clip->ymin);
1394         y2 = qMin(r.y() + r.height(), data->clip->ymax);
1395         rectClipped = data->clip->hasRectClip;
1396
1397     } else if (pe) {
1398         x1 = qMax(r.x(), pe->deviceRect.x());
1399         x2 = qMin(r.x() + r.width(), pe->deviceRect.x() + pe->deviceRect.width());
1400         y1 = qMax(r.y(), pe->deviceRect.y());
1401         y2 = qMin(r.y() + r.height(), pe->deviceRect.y() + pe->deviceRect.height());
1402     } else {
1403         x1 = qMax(r.x(), 0);
1404         x2 = qMin(r.x() + r.width(), data->rasterBuffer->width());
1405         y1 = qMax(r.y(), 0);
1406         y2 = qMin(r.y() + r.height(), data->rasterBuffer->height());
1407     }
1408
1409     if (x2 <= x1 || y2 <= y1)
1410         return;
1411
1412     const int width = x2 - x1;
1413     const int height = y2 - y1;
1414
1415     bool isUnclipped = rectClipped
1416                        || (pe && pe->isUnclipped_normalized(QRect(x1, y1, width, height)));
1417
1418     if (pe && isUnclipped) {
1419         const QPainter::CompositionMode mode = pe->rasterBuffer->compositionMode;
1420
1421         if (data->fillRect && (mode == QPainter::CompositionMode_Source
1422                                || (mode == QPainter::CompositionMode_SourceOver
1423                                    && qAlpha(data->solid.color) == 255)))
1424         {
1425             data->fillRect(data->rasterBuffer, x1, y1, width, height,
1426                            data->solid.color);
1427             return;
1428         }
1429     }
1430
1431     ProcessSpans blend = isUnclipped ? data->unclipped_blend : data->blend;
1432
1433     const int nspans = 256;
1434     QT_FT_Span spans[nspans];
1435
1436     Q_ASSERT(data->blend);
1437     int y = y1;
1438     while (y < y2) {
1439         int n = qMin(nspans, y2 - y);
1440         int i = 0;
1441         while (i < n) {
1442             spans[i].x = x1;
1443             spans[i].len = width;
1444             spans[i].y = y + i;
1445             spans[i].coverage = 255;
1446             ++i;
1447         }
1448
1449         blend(n, spans, data);
1450         y += n;
1451     }
1452 }
1453
1454 /*!
1455     \reimp
1456 */
1457 void QRasterPaintEngine::drawRects(const QRect *rects, int rectCount)
1458 {
1459 #ifdef QT_DEBUG_DRAW
1460     qDebug(" - QRasterPaintEngine::drawRect(), rectCount=%d", rectCount);
1461 #endif
1462     Q_D(QRasterPaintEngine);
1463     ensureState();
1464     QRasterPaintEngineState *s = state();
1465
1466     // Fill
1467     ensureBrush();
1468     if (s->brushData.blend) {
1469         if (!s->flags.antialiased && s->matrix.type() <= QTransform::TxTranslate) {
1470             const QRect *r = rects;
1471             const QRect *lastRect = rects + rectCount;
1472
1473             int offset_x = int(s->matrix.dx());
1474             int offset_y = int(s->matrix.dy());
1475             while (r < lastRect) {
1476                 QRect rect = r->normalized();
1477                 QRect rr = rect.translated(offset_x, offset_y);
1478                 fillRect_normalized(rr, &s->brushData, d);
1479                 ++r;
1480             }
1481         } else {
1482             QRectVectorPath path;
1483             for (int i=0; i<rectCount; ++i) {
1484                 path.set(rects[i]);
1485                 fill(path, s->brush);
1486             }
1487         }
1488     }
1489
1490     ensurePen();
1491     if (s->penData.blend) {
1492         QRectVectorPath path;
1493         if (s->flags.fast_pen) {
1494             QCosmeticStroker stroker(s, d->deviceRect);
1495             for (int i = 0; i < rectCount; ++i) {
1496                 path.set(rects[i]);
1497                 stroker.drawPath(path);
1498             }
1499         } else {
1500             for (int i = 0; i < rectCount; ++i) {
1501                 path.set(rects[i]);
1502                 stroke(path, s->pen);
1503             }
1504         }
1505     }
1506 }
1507
1508 /*!
1509     \reimp
1510 */
1511 void QRasterPaintEngine::drawRects(const QRectF *rects, int rectCount)
1512 {
1513 #ifdef QT_DEBUG_DRAW
1514     qDebug(" - QRasterPaintEngine::drawRect(QRectF*), rectCount=%d", rectCount);
1515 #endif
1516 #ifdef QT_FAST_SPANS
1517     Q_D(QRasterPaintEngine);
1518     ensureState();
1519     QRasterPaintEngineState *s = state();
1520
1521
1522     if (s->flags.tx_noshear) {
1523         ensureBrush();
1524         if (s->brushData.blend) {
1525             d->initializeRasterizer(&s->brushData);
1526             for (int i = 0; i < rectCount; ++i) {
1527                 const QRectF &rect = rects[i].normalized();
1528                 if (rect.isEmpty())
1529                     continue;
1530                 const QPointF a = s->matrix.map((rect.topLeft() + rect.bottomLeft()) * 0.5f);
1531                 const QPointF b = s->matrix.map((rect.topRight() + rect.bottomRight()) * 0.5f);
1532                 d->rasterizer->rasterizeLine(a, b, rect.height() / rect.width());
1533             }
1534         }
1535
1536         ensurePen();
1537         if (s->penData.blend) {
1538             QRectVectorPath path;
1539             if (s->flags.fast_pen) {
1540                 QCosmeticStroker stroker(s, d->deviceRect);
1541                 for (int i = 0; i < rectCount; ++i) {
1542                     path.set(rects[i]);
1543                     stroker.drawPath(path);
1544                 }
1545             } else {
1546                 for (int i = 0; i < rectCount; ++i) {
1547                     path.set(rects[i]);
1548                     QPaintEngineEx::stroke(path, s->lastPen);
1549                 }
1550             }
1551         }
1552
1553         return;
1554     }
1555 #endif // QT_FAST_SPANS
1556     QPaintEngineEx::drawRects(rects, rectCount);
1557 }
1558
1559
1560 /*!
1561     \internal
1562 */
1563 void QRasterPaintEngine::stroke(const QVectorPath &path, const QPen &pen)
1564 {
1565     Q_D(QRasterPaintEngine);
1566     QRasterPaintEngineState *s = state();
1567
1568     ensurePen(pen);
1569     if (!s->penData.blend)
1570         return;
1571
1572     if (s->flags.fast_pen) {
1573         QCosmeticStroker stroker(s, d->deviceRect);
1574         stroker.drawPath(path);
1575     } else if (s->flags.non_complex_pen && path.shape() == QVectorPath::LinesHint) {
1576         qreal width = s->lastPen.isCosmetic()
1577                       ? (qpen_widthf(s->lastPen) == 0 ? 1 : qpen_widthf(s->lastPen))
1578                       : qpen_widthf(s->lastPen) * s->txscale;
1579         int dashIndex = 0;
1580         qreal dashOffset = s->lastPen.dashOffset();
1581         bool inDash = true;
1582         qreal patternLength = 0;
1583         const QVector<qreal> pattern = s->lastPen.dashPattern();
1584         for (int i = 0; i < pattern.size(); ++i)
1585             patternLength += pattern.at(i);
1586
1587         if (patternLength > 0) {
1588             int n = qFloor(dashOffset / patternLength);
1589             dashOffset -= n * patternLength;
1590             while (dashOffset >= pattern.at(dashIndex)) {
1591                 dashOffset -= pattern.at(dashIndex);
1592                 if (++dashIndex >= pattern.size())
1593                     dashIndex = 0;
1594                 inDash = !inDash;
1595             }
1596         }
1597
1598         Q_D(QRasterPaintEngine);
1599         d->initializeRasterizer(&s->penData);
1600         int lineCount = path.elementCount() / 2;
1601         const QLineF *lines = reinterpret_cast<const QLineF *>(path.points());
1602
1603         for (int i = 0; i < lineCount; ++i) {
1604             if (lines[i].p1() == lines[i].p2()) {
1605                 if (s->lastPen.capStyle() != Qt::FlatCap) {
1606                     QPointF p = lines[i].p1();
1607                     QLineF line = s->matrix.map(QLineF(QPointF(p.x() - width*0.5, p.y()),
1608                                                        QPointF(p.x() + width*0.5, p.y())));
1609                     d->rasterizer->rasterizeLine(line.p1(), line.p2(), 1);
1610                 }
1611                 continue;
1612             }
1613
1614             const QLineF line = s->matrix.map(lines[i]);
1615             if (qpen_style(s->lastPen) == Qt::SolidLine) {
1616                 d->rasterizer->rasterizeLine(line.p1(), line.p2(),
1617                                             width / line.length(),
1618                                             s->lastPen.capStyle() == Qt::SquareCap);
1619             } else {
1620                 d->rasterizeLine_dashed(line, width,
1621                                         &dashIndex, &dashOffset, &inDash);
1622             }
1623         }
1624     }
1625     else
1626         QPaintEngineEx::stroke(path, pen);
1627 }
1628
1629 static inline QRect toNormalizedFillRect(const QRectF &rect)
1630 {
1631     int x1 = qRound(rect.x() + aliasedCoordinateDelta);
1632     int y1 = qRound(rect.y() + aliasedCoordinateDelta);
1633     int x2 = qRound(rect.right() + aliasedCoordinateDelta);
1634     int y2 = qRound(rect.bottom() + aliasedCoordinateDelta);
1635
1636     if (x2 < x1)
1637         qSwap(x1, x2);
1638     if (y2 < y1)
1639         qSwap(y1, y2);
1640
1641     return QRect(x1, y1, x2 - x1, y2 - y1);
1642 }
1643
1644 /*!
1645     \internal
1646 */
1647 void QRasterPaintEngine::fill(const QVectorPath &path, const QBrush &brush)
1648 {
1649     if (path.isEmpty())
1650         return;
1651 #ifdef QT_DEBUG_DRAW
1652     QRectF rf = path.controlPointRect();
1653     qDebug() << "QRasterPaintEngine::fill(): "
1654              << "size=" << path.elementCount()
1655              << ", hints=" << hex << path.hints()
1656              << rf << brush;
1657 #endif
1658
1659     Q_D(QRasterPaintEngine);
1660     QRasterPaintEngineState *s = state();
1661
1662     ensureBrush(brush);
1663     if (!s->brushData.blend)
1664         return;
1665
1666     if (path.shape() == QVectorPath::RectangleHint) {
1667         if (!s->flags.antialiased && s->matrix.type() <= QTransform::TxScale) {
1668             const qreal *p = path.points();
1669             QPointF tl = QPointF(p[0], p[1]) * s->matrix;
1670             QPointF br = QPointF(p[4], p[5]) * s->matrix;
1671             fillRect_normalized(toNormalizedFillRect(QRectF(tl, br)), &s->brushData, d);
1672             return;
1673         }
1674         ensureState();
1675         if (s->flags.tx_noshear) {
1676             d->initializeRasterizer(&s->brushData);
1677             // ### Is normalizing really necessary here?
1678             const qreal *p = path.points();
1679             QRectF r = QRectF(p[0], p[1], p[2] - p[0], p[7] - p[1]).normalized();
1680             if (!r.isEmpty()) {
1681                 const QPointF a = s->matrix.map((r.topLeft() + r.bottomLeft()) * 0.5f);
1682                 const QPointF b = s->matrix.map((r.topRight() + r.bottomRight()) * 0.5f);
1683                 d->rasterizer->rasterizeLine(a, b, r.height() / r.width());
1684             }
1685             return;
1686         }
1687     }
1688
1689     // ### Optimize for non transformed ellipses and rectangles...
1690     QRectF cpRect = path.controlPointRect();
1691     const QRect deviceRect = s->matrix.mapRect(cpRect).toRect();
1692     ProcessSpans blend = d->getBrushFunc(deviceRect, &s->brushData);
1693
1694         // ### Falcon
1695 //         const bool do_clip = (deviceRect.left() < -QT_RASTER_COORD_LIMIT
1696 //                               || deviceRect.right() > QT_RASTER_COORD_LIMIT
1697 //                               || deviceRect.top() < -QT_RASTER_COORD_LIMIT
1698 //                               || deviceRect.bottom() > QT_RASTER_COORD_LIMIT);
1699
1700         // ### Falonc: implement....
1701 //         if (!s->flags.antialiased && !do_clip) {
1702 //             d->initializeRasterizer(&s->brushData);
1703 //             d->rasterizer->rasterize(path * d->matrix, path.fillRule());
1704 //             return;
1705 //         }
1706
1707     ensureOutlineMapper();
1708     d->rasterize(d->outlineMapper->convertPath(path), blend, &s->brushData, d->rasterBuffer.data());
1709 }
1710
1711 void QRasterPaintEngine::fillRect(const QRectF &r, QSpanData *data)
1712 {
1713     Q_D(QRasterPaintEngine);
1714     QRasterPaintEngineState *s = state();
1715
1716     if (!s->flags.antialiased) {
1717         uint txop = s->matrix.type();
1718         if (txop == QTransform::TxNone) {
1719             fillRect_normalized(toNormalizedFillRect(r), data, d);
1720             return;
1721         } else if (txop == QTransform::TxTranslate) {
1722             const QRect rr = toNormalizedFillRect(r.translated(s->matrix.dx(), s->matrix.dy()));
1723             fillRect_normalized(rr, data, d);
1724             return;
1725         } else if (txop == QTransform::TxScale) {
1726             const QRect rr = toNormalizedFillRect(s->matrix.mapRect(r));
1727             fillRect_normalized(rr, data, d);
1728             return;
1729         }
1730     }
1731     ensureState();
1732     if (s->flags.tx_noshear) {
1733         d->initializeRasterizer(data);
1734         QRectF nr = r.normalized();
1735         if (!nr.isEmpty()) {
1736             const QPointF a = s->matrix.map((nr.topLeft() + nr.bottomLeft()) * 0.5f);
1737             const QPointF b = s->matrix.map((nr.topRight() + nr.bottomRight()) * 0.5f);
1738             d->rasterizer->rasterizeLine(a, b, nr.height() / nr.width());
1739         }
1740         return;
1741     }
1742
1743     QPainterPath path;
1744     path.addRect(r);
1745     ensureOutlineMapper();
1746     fillPath(path, data);
1747 }
1748
1749 /*!
1750     \reimp
1751 */
1752 void QRasterPaintEngine::fillRect(const QRectF &r, const QBrush &brush)
1753 {
1754 #ifdef QT_DEBUG_DRAW
1755     qDebug() << "QRasterPaintEngine::fillRecct(): " << r << brush;
1756 #endif
1757     QRasterPaintEngineState *s = state();
1758
1759     ensureBrush(brush);
1760     if (!s->brushData.blend)
1761         return;
1762
1763     fillRect(r, &s->brushData);
1764 }
1765
1766 /*!
1767     \reimp
1768 */
1769 void QRasterPaintEngine::fillRect(const QRectF &r, const QColor &color)
1770 {
1771 #ifdef QT_DEBUG_DRAW
1772     qDebug() << "QRasterPaintEngine::fillRect(): " << r << color;
1773 #endif
1774     Q_D(QRasterPaintEngine);
1775     QRasterPaintEngineState *s = state();
1776
1777     d->solid_color_filler.solid.color = PREMUL(ARGB_COMBINE_ALPHA(color.rgba(), s->intOpacity));
1778     if ((d->solid_color_filler.solid.color & 0xff000000) == 0
1779         && s->composition_mode == QPainter::CompositionMode_SourceOver) {
1780         return;
1781     }
1782     d->solid_color_filler.clip = d->clip();
1783     d->solid_color_filler.adjustSpanMethods();
1784     fillRect(r, &d->solid_color_filler);
1785 }
1786
1787 static inline bool isAbove(const QPointF *a, const QPointF *b)
1788 {
1789     return a->y() < b->y();
1790 }
1791
1792 static bool splitPolygon(const QPointF *points, int pointCount, QVector<QPointF> *upper, QVector<QPointF> *lower)
1793 {
1794     Q_ASSERT(upper);
1795     Q_ASSERT(lower);
1796
1797     Q_ASSERT(pointCount >= 2);
1798
1799     QVector<const QPointF *> sorted;
1800     sorted.reserve(pointCount);
1801
1802     upper->reserve(pointCount * 3 / 4);
1803     lower->reserve(pointCount * 3 / 4);
1804
1805     for (int i = 0; i < pointCount; ++i)
1806         sorted << points + i;
1807
1808     qSort(sorted.begin(), sorted.end(), isAbove);
1809
1810     qreal splitY = sorted.at(sorted.size() / 2)->y();
1811
1812     const QPointF *end = points + pointCount;
1813     const QPointF *last = end - 1;
1814
1815     QVector<QPointF> *bin[2] = { upper, lower };
1816
1817     for (const QPointF *p = points; p < end; ++p) {
1818         int side = p->y() < splitY;
1819         int lastSide = last->y() < splitY;
1820
1821         if (side != lastSide) {
1822             if (qFuzzyCompare(p->y(), splitY)) {
1823                 bin[!side]->append(*p);
1824             } else if (qFuzzyCompare(last->y(), splitY)) {
1825                 bin[side]->append(*last);
1826             } else {
1827                 QPointF delta = *p - *last;
1828                 QPointF intersection(p->x() + delta.x() * (splitY - p->y()) / delta.y(), splitY);
1829
1830                 bin[0]->append(intersection);
1831                 bin[1]->append(intersection);
1832             }
1833         }
1834
1835         bin[side]->append(*p);
1836
1837         last = p;
1838     }
1839
1840     // give up if we couldn't reduce the point count
1841     return upper->size() < pointCount && lower->size() < pointCount;
1842 }
1843
1844 /*!
1845   \internal
1846  */
1847 void QRasterPaintEngine::fillPolygon(const QPointF *points, int pointCount, PolygonDrawMode mode)
1848 {
1849     Q_D(QRasterPaintEngine);
1850     QRasterPaintEngineState *s = state();
1851
1852     const int maxPoints = 0xffff;
1853
1854     // max amount of points that raster engine can reliably handle
1855     if (pointCount > maxPoints) {
1856         QVector<QPointF> upper, lower;
1857
1858         if (splitPolygon(points, pointCount, &upper, &lower)) {
1859             fillPolygon(upper.constData(), upper.size(), mode);
1860             fillPolygon(lower.constData(), lower.size(), mode);
1861         } else
1862             qWarning("Polygon too complex for filling.");
1863
1864         return;
1865     }
1866
1867     // Compose polygon fill..,
1868     QVectorPath vp((qreal *) points, pointCount, 0, QVectorPath::polygonFlags(mode));
1869     ensureOutlineMapper();
1870     QT_FT_Outline *outline = d->outlineMapper->convertPath(vp);
1871
1872     // scanconvert.
1873     ProcessSpans brushBlend = d->getBrushFunc(d->outlineMapper->controlPointRect,
1874                                               &s->brushData);
1875     d->rasterize(outline, brushBlend, &s->brushData, d->rasterBuffer.data());
1876 }
1877
1878 /*!
1879     \reimp
1880 */
1881 void QRasterPaintEngine::drawPolygon(const QPointF *points, int pointCount, PolygonDrawMode mode)
1882 {
1883     Q_D(QRasterPaintEngine);
1884     QRasterPaintEngineState *s = state();
1885
1886 #ifdef QT_DEBUG_DRAW
1887     qDebug(" - QRasterPaintEngine::drawPolygon(F), pointCount=%d", pointCount);
1888     for (int i=0; i<pointCount; ++i)
1889         qDebug() << "   - " << points[i];
1890 #endif
1891     Q_ASSERT(pointCount >= 2);
1892
1893     if (mode != PolylineMode && isRect((qreal *) points, pointCount)) {
1894         QRectF r(points[0], points[2]);
1895         drawRects(&r, 1);
1896         return;
1897     }
1898
1899     ensurePen();
1900     if (mode != PolylineMode) {
1901         // Do the fill...
1902         ensureBrush();
1903         if (s->brushData.blend) {
1904             d->outlineMapper->setCoordinateRounding(s->penData.blend && s->flags.fast_pen && s->lastPen.brush().isOpaque());
1905             fillPolygon(points, pointCount, mode);
1906             d->outlineMapper->setCoordinateRounding(false);
1907         }
1908     }
1909
1910     // Do the outline...
1911     if (s->penData.blend) {
1912         QVectorPath vp((qreal *) points, pointCount, 0, QVectorPath::polygonFlags(mode));
1913         if (s->flags.fast_pen) {
1914             QCosmeticStroker stroker(s, d->deviceRect);
1915             stroker.drawPath(vp);
1916         } else {
1917             QPaintEngineEx::stroke(vp, s->lastPen);
1918         }
1919     }
1920 }
1921
1922 /*!
1923     \reimp
1924 */
1925 void QRasterPaintEngine::drawPolygon(const QPoint *points, int pointCount, PolygonDrawMode mode)
1926 {
1927     Q_D(QRasterPaintEngine);
1928     QRasterPaintEngineState *s = state();
1929
1930 #ifdef QT_DEBUG_DRAW
1931     qDebug(" - QRasterPaintEngine::drawPolygon(I), pointCount=%d", pointCount);
1932     for (int i=0; i<pointCount; ++i)
1933         qDebug() << "   - " << points[i];
1934 #endif
1935     Q_ASSERT(pointCount >= 2);
1936     if (mode != PolylineMode && isRect((int *) points, pointCount)) {
1937         QRect r(points[0].x(),
1938                 points[0].y(),
1939                 points[2].x() - points[0].x(),
1940                 points[2].y() - points[0].y());
1941         drawRects(&r, 1);
1942         return;
1943     }
1944
1945     ensurePen();
1946
1947     // Do the fill
1948     if (mode != PolylineMode) {
1949         ensureBrush();
1950         if (s->brushData.blend) {
1951             // Compose polygon fill..,
1952             ensureOutlineMapper();
1953             d->outlineMapper->setCoordinateRounding(s->penData.blend != 0);
1954             d->outlineMapper->beginOutline(mode == WindingMode ? Qt::WindingFill : Qt::OddEvenFill);
1955             d->outlineMapper->moveTo(*points);
1956             const QPoint *p = points;
1957             const QPoint *ep = points + pointCount - 1;
1958             do {
1959                 d->outlineMapper->lineTo(*(++p));
1960             } while (p < ep);
1961             d->outlineMapper->endOutline();
1962
1963             // scanconvert.
1964             ProcessSpans brushBlend = d->getBrushFunc(d->outlineMapper->controlPointRect,
1965                                                       &s->brushData);
1966             d->rasterize(d->outlineMapper->outline(), brushBlend, &s->brushData, d->rasterBuffer.data());
1967             d->outlineMapper->setCoordinateRounding(false);
1968         }
1969     }
1970
1971     // Do the outline...
1972     if (s->penData.blend) {
1973         int count = pointCount * 2;
1974         QVarLengthArray<qreal> fpoints(count);
1975         for (int i=0; i<count; ++i)
1976             fpoints[i] = ((int *) points)[i];
1977         QVectorPath vp((qreal *) fpoints.data(), pointCount, 0, QVectorPath::polygonFlags(mode));
1978
1979         if (s->flags.fast_pen) {
1980             QCosmeticStroker stroker(s, d->deviceRect);
1981             stroker.drawPath(vp);
1982         } else {
1983             QPaintEngineEx::stroke(vp, s->lastPen);
1984         }
1985     }
1986 }
1987
1988 /*!
1989     \internal
1990 */
1991 void QRasterPaintEngine::drawPixmap(const QPointF &pos, const QPixmap &pixmap)
1992 {
1993 #ifdef QT_DEBUG_DRAW
1994     qDebug() << " - QRasterPaintEngine::drawPixmap(), pos=" << pos << " pixmap=" << pixmap.size() << "depth=" << pixmap.depth();
1995 #endif
1996
1997     QPixmapData *pd = pixmap.pixmapData();
1998     if (pd->classId() == QPixmapData::RasterClass) {
1999         const QImage &image = static_cast<QRasterPixmapData *>(pd)->image;
2000         if (image.depth() == 1) {
2001             Q_D(QRasterPaintEngine);
2002             QRasterPaintEngineState *s = state();
2003             if (s->matrix.type() <= QTransform::TxTranslate) {
2004                 ensurePen();
2005                 drawBitmap(pos + QPointF(s->matrix.dx(), s->matrix.dy()), image, &s->penData);
2006             } else {
2007                 drawImage(pos, d->rasterBuffer->colorizeBitmap(image, s->pen.color()));
2008             }
2009         } else {
2010             QRasterPaintEngine::drawImage(pos, image);
2011         }
2012     } else {
2013         const QImage image = pixmap.toImage();
2014         if (pixmap.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     }
2027 }
2028
2029 /*!
2030     \reimp
2031 */
2032 void QRasterPaintEngine::drawPixmap(const QRectF &r, const QPixmap &pixmap, const QRectF &sr)
2033 {
2034 #ifdef QT_DEBUG_DRAW
2035     qDebug() << " - QRasterPaintEngine::drawPixmap(), r=" << r << " sr=" << sr << " pixmap=" << pixmap.size() << "depth=" << pixmap.depth();
2036 #endif
2037
2038     QPixmapData* pd = pixmap.pixmapData();
2039     if (pd->classId() == QPixmapData::RasterClass) {
2040         const QImage &image = static_cast<QRasterPixmapData *>(pd)->image;
2041         if (image.depth() == 1) {
2042             Q_D(QRasterPaintEngine);
2043             QRasterPaintEngineState *s = state();
2044             if (s->matrix.type() <= QTransform::TxTranslate
2045                 && r.size() == sr.size()
2046                 && r.size() == pixmap.size()) {
2047                 ensurePen();
2048                 drawBitmap(r.topLeft() + QPointF(s->matrix.dx(), s->matrix.dy()), image, &s->penData);
2049                 return;
2050             } else {
2051                 drawImage(r, d->rasterBuffer->colorizeBitmap(image, s->pen.color()), sr);
2052             }
2053         } else {
2054             drawImage(r, image, sr);
2055         }
2056     } else {
2057         QRect clippedSource = sr.toAlignedRect().intersected(pixmap.rect());
2058         const QImage image = pd->toImage(clippedSource);
2059         QRectF translatedSource = sr.translated(-clippedSource.topLeft());
2060         if (image.depth() == 1) {
2061             Q_D(QRasterPaintEngine);
2062             QRasterPaintEngineState *s = state();
2063             if (s->matrix.type() <= QTransform::TxTranslate
2064                 && r.size() == sr.size()
2065                 && r.size() == pixmap.size()) {
2066                 ensurePen();
2067                 drawBitmap(r.topLeft() + QPointF(s->matrix.dx(), s->matrix.dy()), image, &s->penData);
2068                 return;
2069             } else {
2070                 drawImage(r, d->rasterBuffer->colorizeBitmap(image, s->pen.color()), translatedSource);
2071             }
2072         } else {
2073             drawImage(r, image, translatedSource);
2074         }
2075     }
2076 }
2077
2078 // assumes that rect has positive width and height
2079 static inline const QRect toRect_normalized(const QRectF &rect)
2080 {
2081     const int x = qRound(rect.x());
2082     const int y = qRound(rect.y());
2083     const int w = int(rect.width() + qreal(0.5));
2084     const int h = int(rect.height() + qreal(0.5));
2085
2086     return QRect(x, y, w, h);
2087 }
2088
2089 static inline int fast_ceil_positive(const qreal &v)
2090 {
2091     const int iv = int(v);
2092     if (v - iv == 0)
2093         return iv;
2094     else
2095         return iv + 1;
2096 }
2097
2098 static inline const QRect toAlignedRect_positive(const QRectF &rect)
2099 {
2100     const int xmin = int(rect.x());
2101     const int xmax = int(fast_ceil_positive(rect.right()));
2102     const int ymin = int(rect.y());
2103     const int ymax = int(fast_ceil_positive(rect.bottom()));
2104     return QRect(xmin, ymin, xmax - xmin, ymax - ymin);
2105 }
2106
2107 /*!
2108     \internal
2109 */
2110 void QRasterPaintEngine::drawImage(const QPointF &p, const QImage &img)
2111 {
2112 #ifdef QT_DEBUG_DRAW
2113     qDebug() << " - QRasterPaintEngine::drawImage(), p=" <<  p << " image=" << img.size() << "depth=" << img.depth();
2114 #endif
2115
2116     Q_D(QRasterPaintEngine);
2117     QRasterPaintEngineState *s = state();
2118
2119     if (s->matrix.type() > QTransform::TxTranslate) {
2120         drawImage(QRectF(p.x(), p.y(), img.width(), img.height()),
2121                   img,
2122                   QRectF(0, 0, img.width(), img.height()));
2123     } else {
2124
2125         const QClipData *clip = d->clip();
2126         QPointF pt(p.x() + s->matrix.dx(), p.y() + s->matrix.dy());
2127
2128         if (d->canUseFastImageBlending(d->rasterBuffer->compositionMode, img)) {
2129             SrcOverBlendFunc func = qBlendFunctions[d->rasterBuffer->format][img.format()];
2130             if (func) {
2131                 if (!clip) {
2132                     d->drawImage(pt, img, func, d->deviceRect, s->intOpacity);
2133                     return;
2134                 } else if (clip->hasRectClip) {
2135                     d->drawImage(pt, img, func, clip->clipRect, s->intOpacity);
2136                     return;
2137                 }
2138             }
2139         }
2140
2141
2142
2143         d->image_filler.clip = clip;
2144         d->image_filler.initTexture(&img, s->intOpacity, QTextureData::Plain, img.rect());
2145         if (!d->image_filler.blend)
2146             return;
2147         d->image_filler.dx = -pt.x();
2148         d->image_filler.dy = -pt.y();
2149         QRect rr = img.rect().translated(qRound(pt.x()), qRound(pt.y()));
2150
2151         fillRect_normalized(rr, &d->image_filler, d);
2152     }
2153
2154 }
2155
2156 QRectF qt_mapRect_non_normalizing(const QRectF &r, const QTransform &t)
2157 {
2158     return QRectF(r.topLeft() * t, r.bottomRight() * t);
2159 }
2160
2161 namespace {
2162     enum RotationType {
2163         Rotation90,
2164         Rotation180,
2165         Rotation270,
2166         NoRotation
2167     };
2168
2169     inline RotationType qRotationType(const QTransform &transform)
2170     {
2171         QTransform::TransformationType type = transform.type();
2172
2173         if (type > QTransform::TxRotate)
2174             return NoRotation;
2175
2176         if (type == QTransform::TxRotate && qFuzzyIsNull(transform.m11()) && qFuzzyCompare(transform.m12(), qreal(-1))
2177             && qFuzzyCompare(transform.m21(), qreal(1)) && qFuzzyIsNull(transform.m22()))
2178             return Rotation90;
2179
2180         if (type == QTransform::TxScale && qFuzzyCompare(transform.m11(), qreal(-1)) && qFuzzyIsNull(transform.m12())
2181             && qFuzzyIsNull(transform.m21()) && qFuzzyCompare(transform.m22(), qreal(-1)))
2182             return Rotation180;
2183
2184         if (type == QTransform::TxRotate && qFuzzyIsNull(transform.m11()) && qFuzzyCompare(transform.m12(), qreal(1))
2185             && qFuzzyCompare(transform.m21(), qreal(-1)) && qFuzzyIsNull(transform.m22()))
2186             return Rotation270;
2187
2188         return NoRotation;
2189     }
2190
2191     inline bool isPixelAligned(const QRectF &rect) {
2192         return QRectF(rect.toRect()) == rect;
2193     }
2194 }
2195
2196 /*!
2197     \reimp
2198 */
2199 void QRasterPaintEngine::drawImage(const QRectF &r, const QImage &img, const QRectF &sr,
2200                                    Qt::ImageConversionFlags)
2201 {
2202 #ifdef QT_DEBUG_DRAW
2203     qDebug() << " - QRasterPaintEngine::drawImage(), r=" << r << " sr=" << sr << " image=" << img.size() << "depth=" << img.depth();
2204 #endif
2205
2206     if (r.isEmpty())
2207         return;
2208
2209     Q_D(QRasterPaintEngine);
2210     QRasterPaintEngineState *s = state();
2211     int sr_l = qFloor(sr.left());
2212     int sr_r = qCeil(sr.right()) - 1;
2213     int sr_t = qFloor(sr.top());
2214     int sr_b = qCeil(sr.bottom()) - 1;
2215
2216     if (s->matrix.type() <= QTransform::TxScale && !s->flags.antialiased && sr_l == sr_r && sr_t == sr_b) {
2217         // as fillRect will apply the aliased coordinate delta we need to
2218         // subtract it here as we don't use it for image drawing
2219         QTransform old = s->matrix;
2220         s->matrix = s->matrix * QTransform::fromTranslate(-aliasedCoordinateDelta, -aliasedCoordinateDelta);
2221
2222         // Do whatever fillRect() does, but without premultiplying the color if it's already premultiplied.
2223         QRgb color = img.pixel(sr_l, sr_t);
2224         switch (img.format()) {
2225         case QImage::Format_ARGB32_Premultiplied:
2226         case QImage::Format_ARGB8565_Premultiplied:
2227         case QImage::Format_ARGB6666_Premultiplied:
2228         case QImage::Format_ARGB8555_Premultiplied:
2229         case QImage::Format_ARGB4444_Premultiplied:
2230             // Combine premultiplied color with the opacity set on the painter.
2231             d->solid_color_filler.solid.color =
2232                 ((((color & 0x00ff00ff) * s->intOpacity) >> 8) & 0x00ff00ff)
2233                 | ((((color & 0xff00ff00) >> 8) * s->intOpacity) & 0xff00ff00);
2234             break;
2235         default:
2236             d->solid_color_filler.solid.color = PREMUL(ARGB_COMBINE_ALPHA(color, s->intOpacity));
2237             break;
2238         }
2239
2240         if ((d->solid_color_filler.solid.color & 0xff000000) == 0
2241             && s->composition_mode == QPainter::CompositionMode_SourceOver) {
2242             return;
2243         }
2244
2245         d->solid_color_filler.clip = d->clip();
2246         d->solid_color_filler.adjustSpanMethods();
2247         fillRect(r, &d->solid_color_filler);
2248
2249         s->matrix = old;
2250         return;
2251     }
2252
2253     bool stretch_sr = r.width() != sr.width() || r.height() != sr.height();
2254
2255     const QClipData *clip = d->clip();
2256
2257     if (s->matrix.type() > QTransform::TxTranslate
2258         && !stretch_sr
2259         && (!clip || clip->hasRectClip)
2260         && s->intOpacity == 256
2261         && (d->rasterBuffer->compositionMode == QPainter::CompositionMode_SourceOver
2262             || d->rasterBuffer->compositionMode == QPainter::CompositionMode_Source)
2263         && d->rasterBuffer->format == img.format()
2264         && (d->rasterBuffer->format == QImage::Format_RGB16
2265             || d->rasterBuffer->format == QImage::Format_RGB32
2266             || (d->rasterBuffer->format == QImage::Format_ARGB32_Premultiplied
2267                 && d->rasterBuffer->compositionMode == QPainter::CompositionMode_Source)))
2268     {
2269         RotationType rotationType = qRotationType(s->matrix);
2270
2271         if (rotationType != NoRotation && qMemRotateFunctions[d->rasterBuffer->format][rotationType] && img.rect().contains(sr.toAlignedRect())) {
2272             QRectF transformedTargetRect = s->matrix.mapRect(r);
2273
2274             if ((!(s->renderHints & QPainter::SmoothPixmapTransform) && !(s->renderHints & QPainter::Antialiasing))
2275                 || (isPixelAligned(transformedTargetRect) && isPixelAligned(sr)))
2276             {
2277                 QRect clippedTransformedTargetRect = transformedTargetRect.toRect().intersected(clip ? clip->clipRect : d->deviceRect);
2278                 if (clippedTransformedTargetRect.isNull())
2279                     return;
2280
2281                 QRectF clippedTargetRect = s->matrix.inverted().mapRect(QRectF(clippedTransformedTargetRect));
2282
2283                 QRect clippedSourceRect
2284                     = QRectF(sr.x() + clippedTargetRect.x() - r.x(), sr.y() + clippedTargetRect.y() - r.y(),
2285                             clippedTargetRect.width(), clippedTargetRect.height()).toRect();
2286
2287                 uint dbpl = d->rasterBuffer->bytesPerLine();
2288                 uint sbpl = img.bytesPerLine();
2289
2290                 uchar *dst = d->rasterBuffer->buffer();
2291                 uint bpp = img.depth() >> 3;
2292
2293                 const uchar *srcBase = img.bits() + clippedSourceRect.y() * sbpl + clippedSourceRect.x() * bpp;
2294                 uchar *dstBase = dst + clippedTransformedTargetRect.y() * dbpl + clippedTransformedTargetRect.x() * bpp;
2295
2296                 uint cw = clippedSourceRect.width();
2297                 uint ch = clippedSourceRect.height();
2298
2299                 qMemRotateFunctions[d->rasterBuffer->format][rotationType](srcBase, cw, ch, sbpl, dstBase, dbpl);
2300
2301                 return;
2302             }
2303         }
2304     }
2305
2306     if (s->matrix.type() > QTransform::TxTranslate || stretch_sr) {
2307
2308         QRectF targetBounds = s->matrix.mapRect(r);
2309         bool exceedsPrecision = targetBounds.width() > 0xffff
2310                                 || targetBounds.height() > 0xffff;
2311
2312         if (!exceedsPrecision && d->canUseFastImageBlending(d->rasterBuffer->compositionMode, img)) {
2313             if (s->matrix.type() > QTransform::TxScale) {
2314                 SrcOverTransformFunc func = qTransformFunctions[d->rasterBuffer->format][img.format()];
2315                 if (func && (!clip || clip->hasRectClip)) {
2316                     func(d->rasterBuffer->buffer(), d->rasterBuffer->bytesPerLine(), img.bits(),
2317                          img.bytesPerLine(), r, sr, !clip ? d->deviceRect : clip->clipRect,
2318                          s->matrix, s->intOpacity);
2319                     return;
2320                 }
2321             } else {
2322                 SrcOverScaleFunc func = qScaleFunctions[d->rasterBuffer->format][img.format()];
2323                 if (func && (!clip || clip->hasRectClip)) {
2324                     func(d->rasterBuffer->buffer(), d->rasterBuffer->bytesPerLine(),
2325                          img.bits(), img.bytesPerLine(),
2326                          qt_mapRect_non_normalizing(r, s->matrix), sr,
2327                          !clip ? d->deviceRect : clip->clipRect,
2328                          s->intOpacity);
2329                     return;
2330                 }
2331             }
2332         }
2333
2334         QTransform copy = s->matrix;
2335         copy.translate(r.x(), r.y());
2336         if (stretch_sr)
2337             copy.scale(r.width() / sr.width(), r.height() / sr.height());
2338         copy.translate(-sr.x(), -sr.y());
2339
2340         d->image_filler_xform.clip = clip;
2341         d->image_filler_xform.initTexture(&img, s->intOpacity, QTextureData::Plain, toAlignedRect_positive(sr));
2342         if (!d->image_filler_xform.blend)
2343             return;
2344         d->image_filler_xform.setupMatrix(copy, s->flags.bilinear);
2345
2346         if (!s->flags.antialiased && s->matrix.type() == QTransform::TxScale) {
2347             QRectF rr = s->matrix.mapRect(r);
2348
2349             const int x1 = qRound(rr.x());
2350             const int y1 = qRound(rr.y());
2351             const int x2 = qRound(rr.right());
2352             const int y2 = qRound(rr.bottom());
2353
2354             fillRect_normalized(QRect(x1, y1, x2-x1, y2-y1), &d->image_filler_xform, d);
2355             return;
2356         }
2357
2358 #ifdef QT_FAST_SPANS
2359         ensureState();
2360         if (s->flags.tx_noshear || s->matrix.type() == QTransform::TxScale) {
2361             d->initializeRasterizer(&d->image_filler_xform);
2362             d->rasterizer->setAntialiased(s->flags.antialiased);
2363
2364             const QPointF offs = s->flags.antialiased ? QPointF() : QPointF(aliasedCoordinateDelta, aliasedCoordinateDelta);
2365
2366             const QRectF &rect = r.normalized();
2367             const QPointF a = s->matrix.map((rect.topLeft() + rect.bottomLeft()) * 0.5f) - offs;
2368             const QPointF b = s->matrix.map((rect.topRight() + rect.bottomRight()) * 0.5f) - offs;
2369
2370             if (s->flags.tx_noshear)
2371                 d->rasterizer->rasterizeLine(a, b, rect.height() / rect.width());
2372             else
2373                 d->rasterizer->rasterizeLine(a, b, qAbs((s->matrix.m22() * rect.height()) / (s->matrix.m11() * rect.width())));
2374             return;
2375         }
2376 #endif
2377         const qreal offs = s->flags.antialiased ? qreal(0) : aliasedCoordinateDelta;
2378         QPainterPath path;
2379         path.addRect(r);
2380         QTransform m = s->matrix;
2381         s->matrix = QTransform(m.m11(), m.m12(), m.m13(),
2382                                m.m21(), m.m22(), m.m23(),
2383                                m.m31() - offs, m.m32() - offs, m.m33());
2384         fillPath(path, &d->image_filler_xform);
2385         s->matrix = m;
2386     } else {
2387         if (d->canUseFastImageBlending(d->rasterBuffer->compositionMode, img)) {
2388             SrcOverBlendFunc func = qBlendFunctions[d->rasterBuffer->format][img.format()];
2389             if (func) {
2390                 QPointF pt(r.x() + s->matrix.dx(), r.y() + s->matrix.dy());
2391                 if (!clip) {
2392                     d->drawImage(pt, img, func, d->deviceRect, s->intOpacity, sr.toRect());
2393                     return;
2394                 } else if (clip->hasRectClip) {
2395                     d->drawImage(pt, img, func, clip->clipRect, s->intOpacity, sr.toRect());
2396                     return;
2397                 }
2398             }
2399         }
2400
2401         d->image_filler.clip = clip;
2402         d->image_filler.initTexture(&img, s->intOpacity, QTextureData::Plain, toAlignedRect_positive(sr));
2403         if (!d->image_filler.blend)
2404             return;
2405         d->image_filler.dx = -(r.x() + s->matrix.dx()) + sr.x();
2406         d->image_filler.dy = -(r.y() + s->matrix.dy()) + sr.y();
2407
2408         QRectF rr = r;
2409         rr.translate(s->matrix.dx(), s->matrix.dy());
2410
2411         const int x1 = qRound(rr.x());
2412         const int y1 = qRound(rr.y());
2413         const int x2 = qRound(rr.right());
2414         const int y2 = qRound(rr.bottom());
2415
2416         fillRect_normalized(QRect(x1, y1, x2-x1, y2-y1), &d->image_filler, d);
2417     }
2418 }
2419
2420 /*!
2421     \reimp
2422 */
2423 void QRasterPaintEngine::drawTiledPixmap(const QRectF &r, const QPixmap &pixmap, const QPointF &sr)
2424 {
2425 #ifdef QT_DEBUG_DRAW
2426     qDebug() << " - QRasterPaintEngine::drawTiledPixmap(), r=" << r << "pixmap=" << pixmap.size();
2427 #endif
2428     Q_D(QRasterPaintEngine);
2429     QRasterPaintEngineState *s = state();
2430
2431     QImage image;
2432
2433     QPixmapData *pd = pixmap.pixmapData();
2434     if (pd->classId() == QPixmapData::RasterClass) {
2435         image = static_cast<QRasterPixmapData *>(pd)->image;
2436     } else {
2437         image = pixmap.toImage();
2438     }
2439
2440     if (image.depth() == 1)
2441         image = d->rasterBuffer->colorizeBitmap(image, s->pen.color());
2442
2443     if (s->matrix.type() > QTransform::TxTranslate) {
2444         QTransform copy = s->matrix;
2445         copy.translate(r.x(), r.y());
2446         copy.translate(-sr.x(), -sr.y());
2447         d->image_filler_xform.clip = d->clip();
2448         d->image_filler_xform.initTexture(&image, s->intOpacity, QTextureData::Tiled);
2449         if (!d->image_filler_xform.blend)
2450             return;
2451         d->image_filler_xform.setupMatrix(copy, s->flags.bilinear);
2452
2453 #ifdef QT_FAST_SPANS
2454         ensureState();
2455         if (s->flags.tx_noshear || s->matrix.type() == QTransform::TxScale) {
2456             d->initializeRasterizer(&d->image_filler_xform);
2457             d->rasterizer->setAntialiased(s->flags.antialiased);
2458
2459             const QRectF &rect = r.normalized();
2460             const QPointF a = s->matrix.map((rect.topLeft() + rect.bottomLeft()) * 0.5f);
2461             const QPointF b = s->matrix.map((rect.topRight() + rect.bottomRight()) * 0.5f);
2462             if (s->flags.tx_noshear)
2463                 d->rasterizer->rasterizeLine(a, b, rect.height() / rect.width());
2464             else
2465                 d->rasterizer->rasterizeLine(a, b, qAbs((s->matrix.m22() * rect.height()) / (s->matrix.m11() * rect.width())));
2466             return;
2467         }
2468 #endif
2469         QPainterPath path;
2470         path.addRect(r);
2471         fillPath(path, &d->image_filler_xform);
2472     } else {
2473         d->image_filler.clip = d->clip();
2474
2475         d->image_filler.initTexture(&image, s->intOpacity, QTextureData::Tiled);
2476         if (!d->image_filler.blend)
2477             return;
2478         d->image_filler.dx = -(r.x() + s->matrix.dx()) + sr.x();
2479         d->image_filler.dy = -(r.y() + s->matrix.dy()) + sr.y();
2480
2481         QRectF rr = r;
2482         rr.translate(s->matrix.dx(), s->matrix.dy());
2483         fillRect_normalized(rr.toRect().normalized(), &d->image_filler, d);
2484     }
2485 }
2486
2487
2488 //QWS hack
2489 static inline bool monoVal(const uchar* s, int x)
2490 {
2491     return  (s[x>>3] << (x&7)) & 0x80;
2492 }
2493
2494 /*!
2495     \internal
2496 */
2497 void QRasterPaintEngine::alphaPenBlt(const void* src, int bpl, int depth, int rx,int ry,int w,int h)
2498 {
2499     Q_D(QRasterPaintEngine);
2500     QRasterPaintEngineState *s = state();
2501
2502     if (!s->penData.blend)
2503         return;
2504
2505     QRasterBuffer *rb = d->rasterBuffer.data();
2506
2507     const QRect rect(rx, ry, w, h);
2508     const QClipData *clip = d->clip();
2509     bool unclipped = false;
2510     if (clip) {
2511         // inlined QRect::intersects
2512         const bool intersects = qMax(clip->xmin, rect.left()) <= qMin(clip->xmax - 1, rect.right())
2513                                 && qMax(clip->ymin, rect.top()) <= qMin(clip->ymax - 1, rect.bottom());
2514
2515         if (clip->hasRectClip) {
2516             unclipped = rx > clip->xmin
2517                         && rx + w < clip->xmax
2518                         && ry > clip->ymin
2519                         && ry + h < clip->ymax;
2520         }
2521
2522         if (!intersects)
2523             return;
2524     } else {
2525         // inlined QRect::intersects
2526         const bool intersects = qMax(0, rect.left()) <= qMin(rb->width() - 1, rect.right())
2527                                 && qMax(0, rect.top()) <= qMin(rb->height() - 1, rect.bottom());
2528         if (!intersects)
2529             return;
2530
2531         // inlined QRect::contains
2532         const bool contains = rect.left() >= 0 && rect.right() < rb->width()
2533                               && rect.top() >= 0 && rect.bottom() < rb->height();
2534
2535         unclipped = contains && d->isUnclipped_normalized(rect);
2536     }
2537
2538     ProcessSpans blend = unclipped ? s->penData.unclipped_blend : s->penData.blend;
2539     const uchar * scanline = static_cast<const uchar *>(src);
2540
2541     if (s->flags.fast_text) {
2542         if (unclipped) {
2543             if (depth == 1) {
2544                 if (s->penData.bitmapBlit) {
2545                     s->penData.bitmapBlit(rb, rx, ry, s->penData.solid.color,
2546                                           scanline, w, h, bpl);
2547                     return;
2548                 }
2549             } else if (depth == 8) {
2550                 if (s->penData.alphamapBlit) {
2551                     s->penData.alphamapBlit(rb, rx, ry, s->penData.solid.color,
2552                                             scanline, w, h, bpl, 0);
2553                     return;
2554                 }
2555             } else if (depth == 32) {
2556                 // (A)RGB Alpha mask where the alpha component is not used.
2557                 if (s->penData.alphaRGBBlit) {
2558                     s->penData.alphaRGBBlit(rb, rx, ry, s->penData.solid.color,
2559                                             (const uint *) scanline, w, h, bpl / 4, 0);
2560                     return;
2561                 }
2562             }
2563         } else if (d->deviceDepth == 32 && (depth == 8 || depth == 32)) {
2564             // (A)RGB Alpha mask where the alpha component is not used.
2565             if (!clip) {
2566                 int nx = qMax(0, rx);
2567                 int ny = qMax(0, ry);
2568
2569                 // Move scanline pointer to compensate for moved x and y
2570                 int xdiff = nx - rx;
2571                 int ydiff = ny - ry;
2572                 scanline += ydiff * bpl;
2573                 scanline += xdiff * (depth == 32 ? 4 : 1);
2574
2575                 w -= xdiff;
2576                 h -= ydiff;
2577
2578                 if (nx + w > d->rasterBuffer->width())
2579                     w = d->rasterBuffer->width() - nx;
2580                 if (ny + h > d->rasterBuffer->height())
2581                     h = d->rasterBuffer->height() - ny;
2582
2583                 rx = nx;
2584                 ry = ny;
2585             }
2586             if (depth == 8 && s->penData.alphamapBlit) {
2587                 s->penData.alphamapBlit(rb, rx, ry, s->penData.solid.color,
2588                                         scanline, w, h, bpl, clip);
2589             } else if (depth == 32 && s->penData.alphaRGBBlit) {
2590                 s->penData.alphaRGBBlit(rb, rx, ry, s->penData.solid.color,
2591                                         (const uint *) scanline, w, h, bpl / 4, clip);
2592             }
2593             return;
2594         }
2595     }
2596
2597     int x0 = 0;
2598     if (rx < 0) {
2599         x0 = -rx;
2600         w -= x0;
2601     }
2602
2603     int y0 = 0;
2604     if (ry < 0) {
2605         y0 = -ry;
2606         scanline += bpl * y0;
2607         h -= y0;
2608     }
2609
2610     w = qMin(w, rb->width() - qMax(0, rx));
2611     h = qMin(h, rb->height() - qMax(0, ry));
2612
2613     if (w <= 0 || h <= 0)
2614         return;
2615
2616     const int NSPANS = 256;
2617     QSpan spans[NSPANS];
2618     int current = 0;
2619
2620     const int x1 = x0 + w;
2621     const int y1 = y0 + h;
2622
2623     if (depth == 1) {
2624         for (int y = y0; y < y1; ++y) {
2625             for (int x = x0; x < x1; ) {
2626                 if (!monoVal(scanline, x)) {
2627                     ++x;
2628                     continue;
2629                 }
2630
2631                 if (current == NSPANS) {
2632                     blend(current, spans, &s->penData);
2633                     current = 0;
2634                 }
2635                 spans[current].x = x + rx;
2636                 spans[current].y = y + ry;
2637                 spans[current].coverage = 255;
2638                 int len = 1;
2639                 ++x;
2640                 // extend span until we find a different one.
2641                 while (x < x1 && monoVal(scanline, x)) {
2642                     ++x;
2643                     ++len;
2644                 }
2645                 spans[current].len = len;
2646                 ++current;
2647             }
2648             scanline += bpl;
2649         }
2650     } else if (depth == 8) {
2651         for (int y = y0; y < y1; ++y) {
2652             for (int x = x0; x < x1; ) {
2653                 // Skip those with 0 coverage
2654                 if (scanline[x] == 0) {
2655                     ++x;
2656                     continue;
2657                 }
2658
2659                 if (current == NSPANS) {
2660                     blend(current, spans, &s->penData);
2661                     current = 0;
2662                 }
2663                 int coverage = scanline[x];
2664                 spans[current].x = x + rx;
2665                 spans[current].y = y + ry;
2666                 spans[current].coverage = coverage;
2667                 int len = 1;
2668                 ++x;
2669
2670                 // extend span until we find a different one.
2671                 while (x < x1 && scanline[x] == coverage) {
2672                     ++x;
2673                     ++len;
2674                 }
2675                 spans[current].len = len;
2676                 ++current;
2677             }
2678             scanline += bpl;
2679         }
2680     } else { // 32-bit alpha...
2681         uint *sl = (uint *) src;
2682         for (int y = y0; y < y1; ++y) {
2683             for (int x = x0; x < x1; ) {
2684                 // Skip those with 0 coverage
2685                 if ((sl[x] & 0x00ffffff) == 0) {
2686                     ++x;
2687                     continue;
2688                 }
2689
2690                 if (current == NSPANS) {
2691                     blend(current, spans, &s->penData);
2692                     current = 0;
2693                 }
2694                 uint rgbCoverage = sl[x];
2695                 int coverage = qGreen(rgbCoverage);
2696                 spans[current].x = x + rx;
2697                 spans[current].y = y + ry;
2698                 spans[current].coverage = coverage;
2699                 int len = 1;
2700                 ++x;
2701
2702                 // extend span until we find a different one.
2703                 while (x < x1 && sl[x] == rgbCoverage) {
2704                     ++x;
2705                     ++len;
2706                 }
2707                 spans[current].len = len;
2708                 ++current;
2709             }
2710             sl += bpl / sizeof(uint);
2711         }
2712     }
2713 //     qDebug() << "alphaPenBlt: num spans=" << current
2714 //              << "span:" << spans->x << spans->y << spans->len << spans->coverage;
2715         // Call span func for current set of spans.
2716     if (current != 0)
2717         blend(current, spans, &s->penData);
2718 }
2719
2720 bool QRasterPaintEngine::drawCachedGlyphs(int numGlyphs, const glyph_t *glyphs,
2721                                           const QFixedPoint *positions, QFontEngine *fontEngine)
2722 {
2723     Q_D(QRasterPaintEngine);
2724     QRasterPaintEngineState *s = state();
2725
2726 #if !defined(QT_NO_FREETYPE)
2727     if (fontEngine->type() == QFontEngine::Freetype) {
2728         QFontEngineFT *fe = static_cast<QFontEngineFT *>(fontEngine);
2729         QFontEngineFT::GlyphFormat neededFormat =
2730             painter()->device()->devType() == QInternal::Widget
2731             ? fe->defaultGlyphFormat()
2732             : QFontEngineFT::Format_A8;
2733
2734         if (d_func()->mono_surface
2735             || fe->isBitmapFont() // alphaPenBlt can handle mono, too
2736             )
2737             neededFormat = QFontEngineFT::Format_Mono;
2738
2739         if (neededFormat == QFontEngineFT::Format_None)
2740             neededFormat = QFontEngineFT::Format_A8;
2741
2742         QFontEngineFT::QGlyphSet *gset = fe->defaultGlyphs();
2743         if (s->matrix.type() >= QTransform::TxScale) {
2744             if (s->matrix.isAffine())
2745                 gset = fe->loadTransformedGlyphSet(s->matrix);
2746             else
2747                 gset = 0;
2748         }
2749
2750         if (!gset || gset->outline_drawing
2751             || !fe->loadGlyphs(gset, glyphs, numGlyphs, positions, neededFormat))
2752             return false;
2753
2754         FT_Face lockedFace = 0;
2755
2756         int depth;
2757         switch (neededFormat) {
2758         case QFontEngineFT::Format_Mono:
2759             depth = 1;
2760             break;
2761         case QFontEngineFT::Format_A8:
2762             depth = 8;
2763             break;
2764         case QFontEngineFT::Format_A32:
2765             depth = 32;
2766             break;
2767         default:
2768             Q_ASSERT(false);
2769             depth = 0;
2770         };
2771
2772         for (int i = 0; i < numGlyphs; i++) {
2773             QFixed spp = fe->subPixelPositionForX(positions[i].x);
2774             QFontEngineFT::Glyph *glyph = gset->getGlyph(glyphs[i], spp);
2775
2776             if (!glyph || glyph->format != neededFormat) {
2777                 if (!lockedFace)
2778                     lockedFace = fe->lockFace();
2779                 glyph = fe->loadGlyph(gset, glyphs[i], spp, neededFormat);
2780             }
2781
2782             if (!glyph || !glyph->data)
2783                 continue;
2784
2785             int pitch;
2786             switch (neededFormat) {
2787             case QFontEngineFT::Format_Mono:
2788                 pitch = ((glyph->width + 31) & ~31) >> 3;
2789                 break;
2790             case QFontEngineFT::Format_A8:
2791                 pitch = (glyph->width + 3) & ~3;
2792                 break;
2793             case QFontEngineFT::Format_A32:
2794                 pitch = glyph->width * 4;
2795                 break;
2796             default:
2797                 Q_ASSERT(false);
2798                 pitch = 0;
2799             };
2800
2801             alphaPenBlt(glyph->data, pitch, depth,
2802                         qFloor(positions[i].x) + glyph->x,
2803                         qFloor(positions[i].y) - glyph->y,
2804                         glyph->width, glyph->height);
2805         }
2806         if (lockedFace)
2807             fe->unlockFace();
2808     } else
2809 #endif
2810     {
2811         QFontEngineGlyphCache::Type glyphType = fontEngine->glyphFormat >= 0 ? QFontEngineGlyphCache::Type(fontEngine->glyphFormat) : d->glyphCacheType;
2812
2813         QImageTextureGlyphCache *cache =
2814             static_cast<QImageTextureGlyphCache *>(fontEngine->glyphCache(0, glyphType, s->matrix));
2815         if (!cache) {
2816             cache = new QImageTextureGlyphCache(glyphType, s->matrix);
2817             fontEngine->setGlyphCache(0, cache);
2818         }
2819
2820         cache->populate(fontEngine, numGlyphs, glyphs, positions);
2821         cache->fillInPendingGlyphs();
2822
2823         const QImage &image = cache->image();
2824         int bpl = image.bytesPerLine();
2825
2826         int depth = image.depth();
2827         int rightShift = 0;
2828         int leftShift = 0;
2829         if (depth == 32)
2830             leftShift = 2; // multiply by 4
2831         else if (depth == 1)
2832             rightShift = 3; // divide by 8
2833
2834         int margin = cache->glyphMargin();
2835         const QFixed offs = QFixed::fromReal(aliasedCoordinateDelta);
2836         const uchar *bits = image.bits();
2837         for (int i=0; i<numGlyphs; ++i) {
2838
2839             QFixed subPixelPosition = cache->subPixelPositionForX(positions[i].x);
2840             QTextureGlyphCache::GlyphAndSubPixelPosition glyph(glyphs[i], subPixelPosition);
2841             const QTextureGlyphCache::Coord &c = cache->coords[glyph];
2842             if (c.isNull())
2843                 continue;
2844
2845             int x = qFloor(positions[i].x + offs) + c.baseLineX - margin;
2846             int y = qFloor(positions[i].y + offs) - c.baseLineY - margin;
2847
2848             // printf("drawing [%d %d %d %d] baseline [%d %d], glyph: %d, to: %d %d, pos: %d %d\n",
2849             //        c.x, c.y,
2850             //        c.w, c.h,
2851             //        c.baseLineX, c.baseLineY,
2852             //        glyphs[i],
2853             //        x, y,
2854             //        positions[i].x.toInt(), positions[i].y.toInt());
2855
2856             alphaPenBlt(bits + ((c.x << leftShift) >> rightShift) + c.y * bpl, bpl, depth, x, y, c.w, c.h);
2857         }
2858     }
2859     return true;
2860 }
2861
2862 #if defined(Q_OS_SYMBIAN) && defined(QT_NO_FREETYPE)
2863 void QRasterPaintEngine::drawGlyphsS60(const QPointF &p, const QTextItemInt &ti)
2864 {
2865     Q_D(QRasterPaintEngine);
2866     QRasterPaintEngineState *s = state();
2867
2868     QFontEngine *fontEngine = ti.fontEngine;
2869     if (fontEngine->type() != QFontEngine::S60FontEngine) {
2870         QPaintEngineEx::drawTextItem(p, ti);
2871         return;
2872     }
2873
2874     QFontEngineS60 *fe = static_cast<QFontEngineS60 *>(fontEngine);
2875
2876     QVarLengthArray<QFixedPoint> positions;
2877     QVarLengthArray<glyph_t> glyphs;
2878     QTransform matrix = s->matrix;
2879     matrix.translate(p.x(), p.y());
2880     if (matrix.type() == QTransform::TxScale)
2881         fe->setFontScale(matrix.m11());
2882     ti.fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions);
2883
2884     const QFixed aliasDelta = QFixed::fromReal(aliasedCoordinateDelta);
2885
2886     for (int i=0; i<glyphs.size(); ++i) {
2887         TOpenFontCharMetrics tmetrics;
2888         const TUint8 *glyphBitmapBytes;
2889         TSize glyphBitmapSize;
2890         fe->getCharacterData(glyphs[i], tmetrics, glyphBitmapBytes, glyphBitmapSize);
2891         const int x = qFloor(positions[i].x + tmetrics.HorizBearingX() + aliasDelta);
2892         const int y = qFloor(positions[i].y - tmetrics.HorizBearingY() + aliasDelta);
2893         alphaPenBlt(glyphBitmapBytes, glyphBitmapSize.iWidth, 8, x, y, glyphBitmapSize.iWidth, glyphBitmapSize.iHeight);
2894     }
2895
2896     if (matrix.type() == QTransform::TxScale)
2897         fe->setFontScale(1.0);
2898
2899     return;
2900 }
2901 #endif // Q_OS_SYMBIAN && QT_NO_FREETYPE
2902
2903 /*!
2904  * Returns true if the rectangle is completely within the current clip
2905  * state of the paint engine.
2906  */
2907 bool QRasterPaintEnginePrivate::isUnclipped_normalized(const QRect &r) const
2908 {
2909     const QClipData *cl = clip();
2910     if (!cl) {
2911         // inline contains() for performance (we know the rects are normalized)
2912         const QRect &r1 = deviceRect;
2913         return (r.left() >= r1.left() && r.right() <= r1.right()
2914                 && r.top() >= r1.top() && r.bottom() <= r1.bottom());
2915     }
2916
2917
2918     if (cl->hasRectClip) {
2919         // currently all painting functions clips to deviceRect internally
2920         if (cl->clipRect == deviceRect)
2921             return true;
2922
2923         // inline contains() for performance (we know the rects are normalized)
2924         const QRect &r1 = cl->clipRect;
2925         return (r.left() >= r1.left() && r.right() <= r1.right()
2926                 && r.top() >= r1.top() && r.bottom() <= r1.bottom());
2927     } else {
2928         return qt_region_strictContains(cl->clipRegion, r);
2929     }
2930 }
2931
2932 bool QRasterPaintEnginePrivate::isUnclipped(const QRect &rect,
2933                                             int penWidth) const
2934 {
2935     Q_Q(const QRasterPaintEngine);
2936     const QRasterPaintEngineState *s = q->state();
2937     const QClipData *cl = clip();
2938     if (!cl) {
2939         QRect r = rect.normalized();
2940         // inline contains() for performance (we know the rects are normalized)
2941         const QRect &r1 = deviceRect;
2942         return (r.left() >= r1.left() && r.right() <= r1.right()
2943                 && r.top() >= r1.top() && r.bottom() <= r1.bottom());
2944     }
2945
2946
2947     // currently all painting functions that call this function clip to deviceRect internally
2948     if (cl->hasRectClip && cl->clipRect == deviceRect)
2949         return true;
2950
2951     if (s->flags.antialiased)
2952         ++penWidth;
2953
2954     QRect r = rect.normalized();
2955     if (penWidth > 0) {
2956         r.setX(r.x() - penWidth);
2957         r.setY(r.y() - penWidth);
2958         r.setWidth(r.width() + 2 * penWidth);
2959         r.setHeight(r.height() + 2 * penWidth);
2960     }
2961
2962     if (cl->hasRectClip) {
2963         // inline contains() for performance (we know the rects are normalized)
2964         const QRect &r1 = cl->clipRect;
2965         return (r.left() >= r1.left() && r.right() <= r1.right()
2966                 && r.top() >= r1.top() && r.bottom() <= r1.bottom());
2967     } else {
2968         return qt_region_strictContains(cl->clipRegion, r);
2969     }
2970 }
2971
2972 inline bool QRasterPaintEnginePrivate::isUnclipped(const QRectF &rect,
2973                                                    int penWidth) const
2974 {
2975     return isUnclipped(rect.normalized().toAlignedRect(), penWidth);
2976 }
2977
2978 inline ProcessSpans
2979 QRasterPaintEnginePrivate::getBrushFunc(const QRect &rect,
2980                                         const QSpanData *data) const
2981 {
2982     return isUnclipped(rect, 0) ? data->unclipped_blend : data->blend;
2983 }
2984
2985 inline ProcessSpans
2986 QRasterPaintEnginePrivate::getBrushFunc(const QRectF &rect,
2987                                         const QSpanData *data) const
2988 {
2989     return isUnclipped(rect, 0) ? data->unclipped_blend : data->blend;
2990 }
2991
2992 inline ProcessSpans
2993 QRasterPaintEnginePrivate::getPenFunc(const QRectF &rect,
2994                                       const QSpanData *data) const
2995 {
2996     Q_Q(const QRasterPaintEngine);
2997     const QRasterPaintEngineState *s = q->state();
2998
2999     if (!s->flags.fast_pen && s->matrix.type() > QTransform::TxTranslate)
3000         return data->blend;
3001     const int penWidth = s->flags.fast_pen ? 1 : qCeil(s->lastPen.widthF());
3002     return isUnclipped(rect, penWidth) ? data->unclipped_blend : data->blend;
3003 }
3004
3005 /*!
3006    \reimp
3007 */
3008 void QRasterPaintEngine::drawStaticTextItem(QStaticTextItem *textItem)
3009 {
3010     ensurePen();
3011     ensureState();
3012
3013     QFontEngine *fontEngine = textItem->fontEngine();
3014     if (!supportsTransformations(fontEngine)) {
3015         drawCachedGlyphs(textItem->numGlyphs, textItem->glyphs, textItem->glyphPositions,
3016                          fontEngine);
3017     } else {
3018         QPaintEngineEx::drawStaticTextItem(textItem);
3019     }
3020 }
3021
3022 /*!
3023     \reimp
3024 */
3025 void QRasterPaintEngine::drawTextItem(const QPointF &p, const QTextItem &textItem)
3026 {
3027     const QTextItemInt &ti = static_cast<const QTextItemInt &>(textItem);
3028     QRasterPaintEngineState *s = state();
3029
3030 #ifdef QT_DEBUG_DRAW
3031     Q_D(QRasterPaintEngine);
3032     fprintf(stderr," - QRasterPaintEngine::drawTextItem(), (%.2f,%.2f), string=%s ct=%d\n",
3033            p.x(), p.y(), QString::fromRawData(ti.chars, ti.num_chars).toLatin1().data(),
3034            d->glyphCacheType);
3035 #endif
3036
3037     ensurePen();
3038     ensureState();
3039
3040 #if defined (Q_WS_WIN) || defined(Q_WS_MAC)
3041
3042     if (!supportsTransformations(ti.fontEngine)) {
3043         QVarLengthArray<QFixedPoint> positions;
3044         QVarLengthArray<glyph_t> glyphs;
3045
3046         QTransform matrix = s->matrix;
3047         matrix.translate(p.x(), p.y());
3048
3049         ti.fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions);
3050
3051         drawCachedGlyphs(glyphs.size(), glyphs.constData(), positions.constData(), ti.fontEngine);
3052         return;
3053     }
3054
3055 #elif defined (Q_OS_SYMBIAN) && defined(QT_NO_FREETYPE) // Q_WS_WIN || Q_WS_MAC
3056     if (s->matrix.type() <= QTransform::TxTranslate
3057         || (s->matrix.type() == QTransform::TxScale
3058                 && (qFuzzyCompare(s->matrix.m11(), s->matrix.m22())))) {
3059         drawGlyphsS60(p, ti);
3060         return;
3061     }
3062 #else // Q_WS_WIN || Q_WS_MAC
3063
3064     QFontEngine *fontEngine = ti.fontEngine;
3065
3066 #if defined(Q_WS_QWS)
3067     if (fontEngine->type() == QFontEngine::Box) {
3068         fontEngine->draw(this, qFloor(p.x()), qFloor(p.y()), ti);
3069         return;
3070     }
3071
3072     if (s->matrix.type() < QTransform::TxScale
3073         && (fontEngine->type() == QFontEngine::QPF1 || fontEngine->type() == QFontEngine::QPF2
3074             || (fontEngine->type() == QFontEngine::Proxy
3075                 && !(static_cast<QProxyFontEngine *>(fontEngine)->drawAsOutline()))
3076             )) {
3077         fontEngine->draw(this, qFloor(p.x() + aliasedCoordinateDelta), qFloor(p.y() + aliasedCoordinateDelta), ti);
3078         return;
3079     }
3080 #endif // Q_WS_QWS
3081
3082 #ifdef Q_WS_QPA
3083     if (s->matrix.type() < QTransform::TxScale) {
3084
3085         QVarLengthArray<QFixedPoint> positions;
3086         QVarLengthArray<glyph_t> glyphs;
3087         QTransform matrix = state()->transform();
3088
3089         qreal _x = qFloor(p.x());
3090         qreal _y = qFloor(p.y());
3091         matrix.translate(_x, _y);
3092
3093         fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions);
3094         if (glyphs.size() == 0)
3095             return;
3096
3097         for(int i = 0; i < glyphs.size(); i++) {
3098             QImage img = fontEngine->alphaMapForGlyph(glyphs[i]);
3099             glyph_metrics_t metrics = fontEngine->boundingBox(glyphs[i]);
3100             // ### hm, perhaps an QFixed offs = QFixed::fromReal(aliasedCoordinateDelta) is needed here?
3101             alphaPenBlt(img.bits(), img.bytesPerLine(), img.depth(),
3102                                          qRound(positions[i].x + metrics.x),
3103                                          qRound(positions[i].y + metrics.y),
3104                                          img.width(), img.height());
3105         }
3106         return;
3107     }
3108 #endif //Q_WS_QPA
3109
3110 #if (defined(Q_WS_X11) || defined(Q_WS_QWS) || defined(Q_OS_SYMBIAN)) && !defined(QT_NO_FREETYPE)
3111
3112 #if defined(Q_WS_QWS) && !defined(QT_NO_QWS_QPF2)
3113     if (fontEngine->type() == QFontEngine::QPF2) {
3114         QFontEngine *renderingEngine = static_cast<QFontEngineQPF *>(fontEngine)->renderingEngine();
3115         if (renderingEngine)
3116             fontEngine = renderingEngine;
3117     }
3118 #endif
3119
3120     if (fontEngine->type() != QFontEngine::Freetype) {
3121         QPaintEngineEx::drawTextItem(p, ti);
3122         return;
3123     }
3124
3125     QFontEngineFT *fe = static_cast<QFontEngineFT *>(fontEngine);
3126
3127     QTransform matrix = s->matrix;
3128     matrix.translate(p.x(), p.y());
3129
3130     QVarLengthArray<QFixedPoint> positions;
3131     QVarLengthArray<glyph_t> glyphs;
3132     fe->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions);
3133     if (glyphs.size() == 0)
3134         return;
3135
3136     if (!drawCachedGlyphs(glyphs.size(), glyphs.constData(), positions.constData(), fontEngine))
3137         QPaintEngine::drawTextItem(p, ti);
3138
3139     return;
3140 #endif
3141 #endif
3142
3143     QPaintEngineEx::drawTextItem(p, ti);
3144 }
3145
3146 /*!
3147     \reimp
3148 */
3149 void QRasterPaintEngine::drawPoints(const QPointF *points, int pointCount)
3150 {
3151     Q_D(QRasterPaintEngine);
3152     QRasterPaintEngineState *s = state();
3153
3154     ensurePen();
3155     if (!s->penData.blend)
3156         return;
3157
3158     if (!s->flags.fast_pen) {
3159         QPaintEngineEx::drawPoints(points, pointCount);
3160         return;
3161     }
3162
3163     QCosmeticStroker stroker(s, d->deviceRect);
3164     stroker.drawPoints(points, pointCount);
3165 }
3166
3167
3168 void QRasterPaintEngine::drawPoints(const QPoint *points, int pointCount)
3169 {
3170     Q_D(QRasterPaintEngine);
3171     QRasterPaintEngineState *s = state();
3172
3173     ensurePen();
3174     if (!s->penData.blend)
3175         return;
3176
3177     if (!s->flags.fast_pen) {
3178         QPaintEngineEx::drawPoints(points, pointCount);
3179         return;
3180     }
3181
3182     QCosmeticStroker stroker(s, d->deviceRect);
3183     stroker.drawPoints(points, pointCount);
3184 }
3185
3186 /*!
3187     \reimp
3188 */
3189 void QRasterPaintEngine::drawLines(const QLine *lines, int lineCount)
3190 {
3191 #ifdef QT_DEBUG_DRAW
3192     qDebug() << " - QRasterPaintEngine::drawLines(QLine*)" << lineCount;
3193 #endif
3194     Q_D(QRasterPaintEngine);
3195     QRasterPaintEngineState *s = state();
3196
3197     ensurePen();
3198     if (!s->penData.blend)
3199         return;
3200
3201     if (s->flags.fast_pen) {
3202         QCosmeticStroker stroker(s, d->deviceRect);
3203         for (int i=0; i<lineCount; ++i) {
3204             const QLine &l = lines[i];
3205             stroker.drawLine(l.p1(), l.p2());
3206         }
3207     } else {
3208         QPaintEngineEx::drawLines(lines, lineCount);
3209     }
3210 }
3211
3212 void QRasterPaintEnginePrivate::rasterizeLine_dashed(QLineF line,
3213                                                      qreal width,
3214                                                      int *dashIndex,
3215                                                      qreal *dashOffset,
3216                                                      bool *inDash)
3217 {
3218     Q_Q(QRasterPaintEngine);
3219     QRasterPaintEngineState *s = q->state();
3220
3221     const QPen &pen = s->lastPen;
3222     const bool squareCap = (pen.capStyle() == Qt::SquareCap);
3223     const QVector<qreal> pattern = pen.dashPattern();
3224
3225     qreal patternLength = 0;
3226     for (int i = 0; i < pattern.size(); ++i)
3227         patternLength += pattern.at(i);
3228
3229     if (patternLength <= 0)
3230         return;
3231
3232     qreal length = line.length();
3233     Q_ASSERT(length > 0);
3234     while (length > 0) {
3235         const bool rasterize = *inDash;
3236         qreal dash = (pattern.at(*dashIndex) - *dashOffset) * width;
3237         QLineF l = line;
3238
3239         if (dash >= length) {
3240             dash = length;
3241             *dashOffset += dash / width;
3242             length = 0;
3243         } else {
3244             *dashOffset = 0;
3245             *inDash = !(*inDash);
3246             if (++*dashIndex >= pattern.size())
3247                 *dashIndex = 0;
3248             length -= dash;
3249             l.setLength(dash);
3250             line.setP1(l.p2());
3251         }
3252
3253         if (rasterize && dash > 0)
3254             rasterizer->rasterizeLine(l.p1(), l.p2(), width / dash, squareCap);
3255     }
3256 }
3257
3258 /*!
3259     \reimp
3260 */
3261 void QRasterPaintEngine::drawLines(const QLineF *lines, int lineCount)
3262 {
3263 #ifdef QT_DEBUG_DRAW
3264     qDebug() << " - QRasterPaintEngine::drawLines(QLineF *)" << lineCount;
3265 #endif
3266     Q_D(QRasterPaintEngine);
3267     QRasterPaintEngineState *s = state();
3268
3269     ensurePen();
3270     if (!s->penData.blend)
3271         return;
3272     if (s->flags.fast_pen) {
3273         QCosmeticStroker stroker(s, d->deviceRect);
3274         for (int i=0; i<lineCount; ++i) {
3275             QLineF line = lines[i];
3276             stroker.drawLine(line.p1(), line.p2());
3277         }
3278     } else {
3279         QPaintEngineEx::drawLines(lines, lineCount);
3280     }
3281 }
3282
3283
3284 /*!
3285     \reimp
3286 */
3287 void QRasterPaintEngine::drawEllipse(const QRectF &rect)
3288 {
3289     Q_D(QRasterPaintEngine);
3290     QRasterPaintEngineState *s = state();
3291
3292     ensurePen();
3293     if (((qpen_style(s->lastPen) == Qt::SolidLine && s->flags.fast_pen)
3294            || (qpen_style(s->lastPen) == Qt::NoPen))
3295         && !s->flags.antialiased
3296         && qMax(rect.width(), rect.height()) < QT_RASTER_COORD_LIMIT
3297         && !rect.isEmpty()
3298         && s->matrix.type() <= QTransform::TxScale) // no shear
3299     {
3300         ensureBrush();
3301         const QRectF r = s->matrix.mapRect(rect);
3302         ProcessSpans penBlend = d->getPenFunc(r, &s->penData);
3303         ProcessSpans brushBlend = d->getBrushFunc(r, &s->brushData);
3304         const QRect brect = QRect(int(r.x()), int(r.y()),
3305                                   int_dim(r.x(), r.width()),
3306                                   int_dim(r.y(), r.height()));
3307         if (brect == r) {
3308             drawEllipse_midpoint_i(brect, d->deviceRect, penBlend, brushBlend,
3309                                    &s->penData, &s->brushData);
3310             return;
3311         }
3312     }
3313     QPaintEngineEx::drawEllipse(rect);
3314 }
3315
3316 /*!
3317     \internal
3318 */
3319 #ifdef Q_WS_MAC
3320 void QRasterPaintEngine::setCGContext(CGContextRef ctx)
3321 {
3322     Q_D(QRasterPaintEngine);
3323     d->cgContext = ctx;
3324 }
3325
3326 /*!
3327     \internal
3328 */
3329 CGContextRef QRasterPaintEngine::getCGContext() const
3330 {
3331     Q_D(const QRasterPaintEngine);
3332     return d->cgContext;
3333 }
3334 #endif
3335
3336 #ifdef Q_WS_WIN
3337 /*!
3338     \internal
3339 */
3340 void QRasterPaintEngine::setDC(HDC hdc) {
3341     Q_D(QRasterPaintEngine);
3342     d->hdc = hdc;
3343 }
3344
3345 /*!
3346     \internal
3347 */
3348 HDC QRasterPaintEngine::getDC() const
3349 {
3350     Q_D(const QRasterPaintEngine);
3351     return d->hdc;
3352 }
3353
3354 /*!
3355     \internal
3356 */
3357 void QRasterPaintEngine::releaseDC(HDC) const
3358 {
3359 }
3360
3361 #endif
3362
3363 bool QRasterPaintEngine::supportsTransformations(const QFontEngine *fontEngine) const
3364 {
3365     const QTransform &m = state()->matrix;
3366 #if defined(Q_WS_WIN) && !defined(Q_WS_WINCE)
3367     QFontEngine::Type fontEngineType = fontEngine->type();
3368     if ((fontEngineType == QFontEngine::Win && !((QFontEngineWin *) fontEngine)->ttf && m.type() > QTransform::TxTranslate)
3369         || (m.type() <= QTransform::TxTranslate
3370             && (fontEngineType == QFontEngine::TestFontEngine
3371                 || fontEngineType == QFontEngine::Box))) {
3372             return true;
3373     }
3374 #endif
3375     return supportsTransformations(fontEngine->fontDef.pixelSize, m);
3376 }
3377
3378 bool QRasterPaintEngine::supportsTransformations(qreal pixelSize, const QTransform &m) const
3379 {
3380 #if defined(Q_WS_MAC)
3381     // Mac font engines don't support scaling and rotation
3382     if (m.type() > QTransform::TxTranslate)
3383 #else
3384     if (m.type() >= QTransform::TxProject)
3385 #endif
3386         return true;
3387
3388     if (pixelSize * pixelSize * qAbs(m.determinant()) >= 64 * 64)
3389         return true;
3390
3391     return false;
3392 }
3393
3394 /*!
3395     \internal
3396 */
3397 QPoint QRasterPaintEngine::coordinateOffset() const
3398 {
3399     return QPoint(0, 0);
3400 }
3401
3402 /*!
3403     Draws the given color \a spans with the specified \a color. The \a
3404     count parameter specifies the number of spans.
3405
3406     The default implementation does nothing; reimplement this function
3407     to draw the given color \a spans with the specified \a color. Note
3408     that this function \e must be reimplemented if the framebuffer is
3409     not memory-mapped.
3410
3411     \sa drawBufferSpan()
3412 */
3413 #if defined(Q_WS_QWS) && !defined(QT_NO_RASTERCALLBACKS)
3414 void QRasterPaintEngine::drawColorSpans(const QSpan *spans, int count, uint color)
3415 {
3416     Q_UNUSED(spans);
3417     Q_UNUSED(count);
3418     Q_UNUSED(color);
3419     qFatal("QRasterPaintEngine::drawColorSpans must be reimplemented on "
3420            "a non memory-mapped device");
3421 }
3422
3423 /*!
3424     \fn void QRasterPaintEngine::drawBufferSpan(const uint *buffer, int size, int x, int y, int length, uint alpha)
3425
3426     Draws the given \a buffer.
3427
3428     The default implementation does nothing; reimplement this function
3429     to draw a buffer that contains more than one color. Note that this
3430     function \e must be reimplemented if the framebuffer is not
3431     memory-mapped.
3432
3433     The \a size parameter specifies the total size of the given \a
3434     buffer, while the \a length parameter specifies the number of
3435     pixels to draw. The buffer's position is given by (\a x, \a
3436     y). The provided \a alpha value is added to each pixel in the
3437     buffer when drawing.
3438
3439     \sa drawColorSpans()
3440 */
3441 void QRasterPaintEngine::drawBufferSpan(const uint *buffer, int bufsize,
3442                                         int x, int y, int length, uint const_alpha)
3443 {
3444     Q_UNUSED(buffer);
3445     Q_UNUSED(bufsize);
3446     Q_UNUSED(x);
3447     Q_UNUSED(y);
3448     Q_UNUSED(length);
3449     Q_UNUSED(const_alpha);
3450     qFatal("QRasterPaintEngine::drawBufferSpan must be reimplemented on "
3451            "a non memory-mapped device");
3452 }
3453 #endif // Q_WS_QWS
3454
3455 void QRasterPaintEngine::drawBitmap(const QPointF &pos, const QImage &image, QSpanData *fg)
3456 {
3457     Q_ASSERT(fg);
3458     if (!fg->blend)
3459         return;
3460     Q_D(QRasterPaintEngine);
3461
3462     Q_ASSERT(image.depth() == 1);
3463
3464     const int spanCount = 256;
3465     QT_FT_Span spans[spanCount];
3466     int n = 0;
3467
3468     // Boundaries
3469     int w = image.width();
3470     int h = image.height();
3471     int ymax = qMin(qRound(pos.y() + h), d->rasterBuffer->height());
3472     int ymin = qMax(qRound(pos.y()), 0);
3473     int xmax = qMin(qRound(pos.x() + w), d->rasterBuffer->width());
3474     int xmin = qMax(qRound(pos.x()), 0);
3475
3476     int x_offset = xmin - qRound(pos.x());
3477
3478     QImage::Format format = image.format();
3479     for (int y = ymin; y < ymax; ++y) {
3480         const uchar *src = image.scanLine(y - qRound(pos.y()));
3481         if (format == QImage::Format_MonoLSB) {
3482             for (int x = 0; x < xmax - xmin; ++x) {
3483                 int src_x = x + x_offset;
3484                 uchar pixel = src[src_x >> 3];
3485                 if (!pixel) {
3486                     x += 7 - (src_x%8);
3487                     continue;
3488                 }
3489                 if (pixel & (0x1 << (src_x & 7))) {
3490                     spans[n].x = xmin + x;
3491                     spans[n].y = y;
3492                     spans[n].coverage = 255;
3493                     int len = 1;
3494                     while (src_x < w-1 && src[(src_x+1) >> 3] & (0x1 << ((src_x+1) & 7))) {
3495                         ++src_x;
3496                         ++len;
3497                     }
3498                     spans[n].len = ((len + spans[n].x) > xmax) ? (xmax - spans[n].x) : len;
3499                     x += len;
3500                     ++n;
3501                     if (n == spanCount) {
3502                         fg->blend(n, spans, fg);
3503                         n = 0;
3504                     }
3505                 }
3506             }
3507         } else {
3508             for (int x = 0; x < xmax - xmin; ++x) {
3509                 int src_x = x + x_offset;
3510                 uchar pixel = src[src_x >> 3];
3511                 if (!pixel) {
3512                     x += 7 - (src_x%8);
3513                     continue;
3514                 }
3515                 if (pixel & (0x80 >> (x & 7))) {
3516                     spans[n].x = xmin + x;
3517                     spans[n].y = y;
3518                     spans[n].coverage = 255;
3519                     int len = 1;
3520                     while (src_x < w-1 && src[(src_x+1) >> 3] & (0x80 >> ((src_x+1) & 7))) {
3521                         ++src_x;
3522                         ++len;
3523                     }
3524                     spans[n].len = ((len + spans[n].x) > xmax) ? (xmax - spans[n].x) : len;
3525                     x += len;
3526                     ++n;
3527                     if (n == spanCount) {
3528                         fg->blend(n, spans, fg);
3529                         n = 0;
3530                     }
3531                 }
3532             }
3533         }
3534     }
3535     if (n) {
3536         fg->blend(n, spans, fg);
3537         n = 0;
3538     }
3539 }
3540
3541 /*!
3542     \enum QRasterPaintEngine::ClipType
3543     \internal
3544
3545     \value RectClip Indicates that the currently set clip is a single rectangle.
3546     \value ComplexClip Indicates that the currently set clip is a combination of several shapes.
3547 */
3548
3549 /*!
3550     \internal
3551     Returns the type of the clip currently set.
3552 */
3553 QRasterPaintEngine::ClipType QRasterPaintEngine::clipType() const
3554 {
3555     Q_D(const QRasterPaintEngine);
3556
3557     const QClipData *clip = d->clip();
3558     if (!clip || clip->hasRectClip)
3559         return RectClip;
3560     else
3561         return ComplexClip;
3562 }
3563
3564 /*!
3565     \internal
3566     Returns the bounding rect of the currently set clip.
3567 */
3568 QRect QRasterPaintEngine::clipBoundingRect() const
3569 {
3570     Q_D(const QRasterPaintEngine);
3571
3572     const QClipData *clip = d->clip();
3573
3574     if (!clip)
3575         return d->deviceRect;
3576
3577     if (clip->hasRectClip)
3578         return clip->clipRect;
3579
3580     return QRect(clip->xmin, clip->ymin, clip->xmax - clip->xmin, clip->ymax - clip->ymin);
3581 }
3582
3583 static void qt_merge_clip(const QClipData *c1, const QClipData *c2, QClipData *result)
3584 {
3585     Q_ASSERT(c1->clipSpanHeight == c2->clipSpanHeight && c1->clipSpanHeight == result->clipSpanHeight);
3586
3587     QVarLengthArray<short, 4096> buffer;
3588
3589     QClipData::ClipLine *c1ClipLines = const_cast<QClipData *>(c1)->clipLines();
3590     QClipData::ClipLine *c2ClipLines = const_cast<QClipData *>(c2)->clipLines();
3591     result->initialize();
3592
3593     for (int y = 0; y < c1->clipSpanHeight; ++y) {
3594         const QSpan *c1_spans = c1ClipLines[y].spans;
3595         int c1_count = c1ClipLines[y].count;
3596         const QSpan *c2_spans = c2ClipLines[y].spans;
3597         int c2_count = c2ClipLines[y].count;
3598
3599         if (c1_count == 0 && c2_count == 0)
3600             continue;
3601         if (c1_count == 0) {
3602             result->appendSpans(c2_spans, c2_count);
3603             continue;
3604         } else if (c2_count == 0) {
3605             result->appendSpans(c1_spans, c1_count);
3606             continue;
3607         }
3608
3609         // we need to merge the two
3610
3611         // find required length
3612         int max = qMax(c1_spans[c1_count - 1].x + c1_spans[c1_count - 1].len,
3613                 c2_spans[c2_count - 1].x + c2_spans[c2_count - 1].len);
3614         buffer.resize(max);
3615         memset(buffer.data(), 0, buffer.size() * sizeof(short));
3616
3617         // Fill with old spans.
3618         for (int i = 0; i < c1_count; ++i) {
3619             const QSpan *cs = c1_spans + i;
3620             for (int j=cs->x; j<cs->x + cs->len; ++j)
3621                 buffer[j] = cs->coverage;
3622         }
3623
3624         // Fill with new spans
3625         for (int i = 0; i < c2_count; ++i) {
3626             const QSpan *cs = c2_spans + i;
3627             for (int j = cs->x; j < cs->x + cs->len; ++j) {
3628                 buffer[j] += cs->coverage;
3629                 if (buffer[j] > 255)
3630                     buffer[j] = 255;
3631             }
3632         }
3633
3634         int x = 0;
3635         while (x<max) {
3636
3637             // Skip to next span
3638             while (x < max && buffer[x] == 0) ++x;
3639             if (x >= max) break;
3640
3641             int sx = x;
3642             int coverage = buffer[x];
3643
3644             // Find length of span
3645             while (x < max && buffer[x] == coverage)
3646                 ++x;
3647
3648             result->appendSpan(sx, x - sx, y, coverage);
3649         }
3650     }
3651 }
3652
3653 void QRasterPaintEnginePrivate::initializeRasterizer(QSpanData *data)
3654 {
3655     Q_Q(QRasterPaintEngine);
3656     QRasterPaintEngineState *s = q->state();
3657
3658     rasterizer->setAntialiased(s->flags.antialiased);
3659
3660     QRect clipRect(deviceRect);
3661     ProcessSpans blend;
3662     // ### get from optimized rectbased QClipData
3663
3664     const QClipData *c = clip();
3665     if (c) {
3666         const QRect r(QPoint(c->xmin, c->ymin),
3667                       QSize(c->xmax - c->xmin, c->ymax - c->ymin));
3668         clipRect = clipRect.intersected(r);
3669         blend = data->blend;
3670     } else {
3671         blend = data->unclipped_blend;
3672     }
3673
3674     rasterizer->setClipRect(clipRect);
3675     rasterizer->initialize(blend, data);
3676 }
3677
3678 void QRasterPaintEnginePrivate::rasterize(QT_FT_Outline *outline,
3679                                           ProcessSpans callback,
3680                                           QSpanData *spanData, QRasterBuffer *rasterBuffer)
3681 {
3682     if (!callback || !outline)
3683         return;
3684
3685     Q_Q(QRasterPaintEngine);
3686     QRasterPaintEngineState *s = q->state();
3687
3688     if (!s->flags.antialiased) {
3689         initializeRasterizer(spanData);
3690
3691         const Qt::FillRule fillRule = outline->flags == QT_FT_OUTLINE_NONE
3692                                       ? Qt::WindingFill
3693                                       : Qt::OddEvenFill;
3694
3695         rasterizer->rasterize(outline, fillRule);
3696         return;
3697     }
3698
3699     rasterize(outline, callback, (void *)spanData, rasterBuffer);
3700 }
3701
3702 extern "C" {
3703     int q_gray_rendered_spans(QT_FT_Raster raster);
3704 }
3705
3706 void QRasterPaintEnginePrivate::rasterize(QT_FT_Outline *outline,
3707                                           ProcessSpans callback,
3708                                           void *userData, QRasterBuffer *)
3709 {
3710     if (!callback || !outline)
3711         return;
3712
3713     Q_Q(QRasterPaintEngine);
3714     QRasterPaintEngineState *s = q->state();
3715
3716     if (!s->flags.antialiased) {
3717         rasterizer->setAntialiased(s->flags.antialiased);
3718         rasterizer->setClipRect(deviceRect);
3719         rasterizer->initialize(callback, userData);
3720
3721         const Qt::FillRule fillRule = outline->flags == QT_FT_OUTLINE_NONE
3722                                       ? Qt::WindingFill
3723                                       : Qt::OddEvenFill;
3724
3725         rasterizer->rasterize(outline, fillRule);
3726         return;
3727     }
3728
3729     // Initial size for raster pool is MINIMUM_POOL_SIZE so as to
3730     // minimize memory reallocations. However if initial size for
3731     // raster pool is changed for lower value, reallocations will
3732     // occur normally.
3733     const int rasterPoolInitialSize = MINIMUM_POOL_SIZE;
3734     int rasterPoolSize = rasterPoolInitialSize;
3735     unsigned char *rasterPoolBase;
3736 #if defined(Q_WS_WIN64)
3737     rasterPoolBase =
3738         // We make use of setjmp and longjmp in qgrayraster.c which requires
3739         // 16-byte alignment, hence we hardcode this requirement here..
3740         (unsigned char *) _aligned_malloc(rasterPoolSize, sizeof(void*) * 2);
3741 #else
3742     unsigned char rasterPoolOnStack[rasterPoolInitialSize];
3743     rasterPoolBase = rasterPoolOnStack;
3744 #endif
3745     Q_CHECK_PTR(rasterPoolBase);
3746
3747     qt_ft_grays_raster.raster_reset(*grayRaster.data(), rasterPoolBase, rasterPoolSize);
3748
3749     void *data = userData;
3750
3751     QT_FT_BBox clip_box = { deviceRect.x(),
3752                             deviceRect.y(),
3753                             deviceRect.x() + deviceRect.width(),
3754                             deviceRect.y() + deviceRect.height() };
3755
3756     QT_FT_Raster_Params rasterParams;
3757     rasterParams.target = 0;
3758     rasterParams.source = outline;
3759     rasterParams.flags = QT_FT_RASTER_FLAG_CLIP;
3760     rasterParams.gray_spans = 0;
3761     rasterParams.black_spans = 0;
3762     rasterParams.bit_test = 0;
3763     rasterParams.bit_set = 0;
3764     rasterParams.user = data;
3765     rasterParams.clip_box = clip_box;
3766
3767     bool done = false;
3768     int error;
3769
3770     int rendered_spans = 0;
3771
3772     while (!done) {
3773
3774         rasterParams.flags |= (QT_FT_RASTER_FLAG_AA | QT_FT_RASTER_FLAG_DIRECT);
3775         rasterParams.gray_spans = callback;
3776         rasterParams.skip_spans = rendered_spans;
3777         error = qt_ft_grays_raster.raster_render(*grayRaster.data(), &rasterParams);
3778
3779         // Out of memory, reallocate some more and try again...
3780         if (error == -6) { // ErrRaster_OutOfMemory from qgrayraster.c
3781             int new_size = rasterPoolSize * 2;
3782             if (new_size > 1024 * 1024) {
3783                 qWarning("QPainter: Rasterization of primitive failed");
3784                 break;
3785             }
3786
3787             rendered_spans += q_gray_rendered_spans(*grayRaster.data());
3788
3789 #if defined(Q_WS_WIN64)
3790             _aligned_free(rasterPoolBase);
3791 #else
3792             if (rasterPoolBase != rasterPoolOnStack) // initially on the stack
3793                 free(rasterPoolBase);
3794 #endif
3795
3796             rasterPoolSize = new_size;
3797             rasterPoolBase =
3798 #if defined(Q_WS_WIN64)
3799                 // We make use of setjmp and longjmp in qgrayraster.c which requires
3800                 // 16-byte alignment, hence we hardcode this requirement here..
3801                 (unsigned char *) _aligned_malloc(rasterPoolSize, sizeof(void*) * 2);
3802 #else
3803                 (unsigned char *) malloc(rasterPoolSize);
3804 #endif
3805             Q_CHECK_PTR(rasterPoolBase); // note: we just freed the old rasterPoolBase. I hope it's not fatal.
3806
3807             qt_ft_grays_raster.raster_done(*grayRaster.data());
3808             qt_ft_grays_raster.raster_new(grayRaster.data());
3809             qt_ft_grays_raster.raster_reset(*grayRaster.data(), rasterPoolBase, rasterPoolSize);
3810         } else {
3811             done = true;
3812         }
3813     }
3814
3815 #if defined(Q_WS_WIN64)
3816     _aligned_free(rasterPoolBase);
3817 #else
3818     if (rasterPoolBase != rasterPoolOnStack) // initially on the stack
3819         free(rasterPoolBase);
3820 #endif
3821 }
3822
3823 void QRasterPaintEnginePrivate::recalculateFastImages()
3824 {
3825     Q_Q(QRasterPaintEngine);
3826     QRasterPaintEngineState *s = q->state();
3827
3828     s->flags.fast_images = !(s->renderHints & QPainter::SmoothPixmapTransform)
3829                            && s->matrix.type() <= QTransform::TxShear;
3830 }
3831
3832 bool QRasterPaintEnginePrivate::canUseFastImageBlending(QPainter::CompositionMode mode, const QImage &image) const
3833 {
3834     Q_Q(const QRasterPaintEngine);
3835     const QRasterPaintEngineState *s = q->state();
3836
3837     return s->flags.fast_images
3838            && (mode == QPainter::CompositionMode_SourceOver
3839                || (mode == QPainter::CompositionMode_Source
3840                    && !image.hasAlphaChannel()));
3841 }
3842
3843 QImage QRasterBuffer::colorizeBitmap(const QImage &image, const QColor &color)
3844 {
3845     Q_ASSERT(image.depth() == 1);
3846
3847     QImage sourceImage = image.convertToFormat(QImage::Format_MonoLSB);
3848     QImage dest = QImage(sourceImage.size(), QImage::Format_ARGB32_Premultiplied);
3849
3850     QRgb fg = PREMUL(color.rgba());
3851     QRgb bg = 0;
3852
3853     int height = sourceImage.height();
3854     int width = sourceImage.width();
3855     for (int y=0; y<height; ++y) {
3856         uchar *source = sourceImage.scanLine(y);
3857         QRgb *target = reinterpret_cast<QRgb *>(dest.scanLine(y));
3858         if (!source || !target)
3859             QT_THROW(std::bad_alloc()); // we must have run out of memory
3860         for (int x=0; x < width; ++x)
3861             target[x] = (source[x>>3] >> (x&7)) & 1 ? fg : bg;
3862     }
3863     return dest;
3864 }
3865
3866 QRasterBuffer::~QRasterBuffer()
3867 {
3868 }
3869
3870 void QRasterBuffer::init()
3871 {
3872     compositionMode = QPainter::CompositionMode_SourceOver;
3873     monoDestinationWithClut = false;
3874     destColor0 = 0;
3875     destColor1 = 0;
3876 }
3877
3878 QImage::Format QRasterBuffer::prepare(QImage *image)
3879 {
3880     m_buffer = (uchar *)image->bits();
3881     m_width = qMin(QT_RASTER_COORD_LIMIT, image->width());
3882     m_height = qMin(QT_RASTER_COORD_LIMIT, image->height());
3883     bytes_per_pixel = image->depth()/8;
3884     bytes_per_line = image->bytesPerLine();
3885
3886     format = image->format();
3887     drawHelper = qDrawHelper + format;
3888     if (image->depth() == 1 && image->colorTable().size() == 2) {
3889         monoDestinationWithClut = true;
3890         destColor0 = PREMUL(image->colorTable()[0]);
3891         destColor1 = PREMUL(image->colorTable()[1]);
3892     }
3893
3894     return format;
3895 }
3896
3897 void QRasterBuffer::resetBuffer(int val)
3898 {
3899     memset(m_buffer, val, m_height*bytes_per_line);
3900 }
3901
3902
3903 #if defined(Q_WS_QWS)
3904 void QRasterBuffer::prepare(QCustomRasterPaintDevice *device)
3905 {
3906     m_buffer = reinterpret_cast<uchar*>(device->memory());
3907     m_width = qMin(QT_RASTER_COORD_LIMIT, device->width());
3908     m_height = qMin(QT_RASTER_COORD_LIMIT, device->height());
3909     bytes_per_pixel = device->depth() / 8;
3910     bytes_per_line = device->bytesPerLine();
3911     format = device->format();
3912 #ifndef QT_NO_RASTERCALLBACKS
3913     if (!m_buffer)
3914         drawHelper = qDrawHelperCallback + format;
3915     else
3916 #endif
3917         drawHelper = qDrawHelper + format;
3918 }
3919
3920 int QCustomRasterPaintDevice::metric(PaintDeviceMetric m) const
3921 {
3922     switch (m) {
3923     case PdmWidth:
3924         return widget->frameGeometry().width();
3925     case PdmHeight:
3926         return widget->frameGeometry().height();
3927     default:
3928         break;
3929     }
3930
3931     return qt_paint_device_metric(widget, m);
3932 }
3933
3934 int QCustomRasterPaintDevice::bytesPerLine() const
3935 {
3936     return (width() * depth() + 7) / 8;
3937 }
3938
3939 #elif defined(Q_OS_SYMBIAN)
3940
3941 void QRasterBuffer::prepareBuffer(int /* width */, int /* height */)
3942 {
3943 }
3944
3945 #endif // Q_OS_SYMBIAN
3946
3947 /*!
3948     \class QCustomRasterPaintDevice
3949     \preliminary
3950     \ingroup qws
3951     \since 4.2
3952
3953     \brief The QCustomRasterPaintDevice class is provided to activate
3954     hardware accelerated paint engines in Qt for Embedded Linux.
3955
3956     Note that this class is only available in \l{Qt for Embedded Linux}.
3957
3958     In \l{Qt for Embedded Linux}, painting is a pure software
3959     implementation. But starting with Qt 4.2, it is
3960     possible to add an accelerated graphics driver to take advantage
3961     of available hardware resources.
3962
3963     Hardware acceleration is accomplished by creating a custom screen
3964     driver, accelerating the copying from memory to the screen, and
3965     implementing a custom paint engine accelerating the various
3966     painting operations. Then a custom paint device (derived from the
3967     QCustomRasterPaintDevice class) and a custom window surface
3968     (derived from QWSWindowSurface) must be implemented to make
3969     \l{Qt for Embedded Linux} aware of the accelerated driver.
3970
3971     See the \l {Adding an Accelerated Graphics Driver to Qt for Embedded Linux}
3972     documentation for details.
3973
3974     \sa QRasterPaintEngine, QPaintDevice
3975 */
3976
3977 /*!
3978     \fn QCustomRasterPaintDevice::QCustomRasterPaintDevice(QWidget *widget)
3979
3980     Constructs a custom raster based paint device for the given
3981     top-level \a widget.
3982 */
3983
3984 /*!
3985     \fn int QCustomRasterPaintDevice::bytesPerLine() const
3986
3987     Returns the number of bytes per line in the framebuffer. Note that
3988     this number might be larger than the framebuffer width.
3989 */
3990
3991 /*!
3992     \fn int QCustomRasterPaintDevice::devType() const
3993     \internal
3994 */
3995
3996 /*!
3997     \fn QImage::Format QCustomRasterPaintDevice::format() const
3998
3999     Returns the format of the device's memory buffet.
4000
4001     The default format is QImage::Format_ARGB32_Premultiplied. The
4002     only other valid format is QImage::Format_RGB16.
4003 */
4004
4005 /*!
4006     \fn void * QCustomRasterPaintDevice::memory () const
4007
4008     Returns a pointer to the paint device's memory buffer, or 0 if no
4009     such buffer exists.
4010 */
4011
4012 /*!
4013     \fn int QCustomRasterPaintDevice::metric ( PaintDeviceMetric m ) const
4014     \reimp
4015 */
4016
4017 /*!
4018     \fn QSize QCustomRasterPaintDevice::size () const
4019     \internal
4020 */
4021
4022
4023 QClipData::QClipData(int height)
4024 {
4025     clipSpanHeight = height;
4026     m_clipLines = 0;
4027
4028     allocated = 0;
4029     m_spans = 0;
4030     xmin = xmax = ymin = ymax = 0;
4031     count = 0;
4032
4033     enabled = true;
4034     hasRectClip = hasRegionClip = false;
4035 }
4036
4037 QClipData::~QClipData()
4038 {
4039     if (m_clipLines)
4040         free(m_clipLines);
4041     if (m_spans)
4042         free(m_spans);
4043 }
4044
4045 void QClipData::initialize()
4046 {
4047     if (m_spans)
4048         return;
4049
4050     if (!m_clipLines)
4051         m_clipLines = (ClipLine *)calloc(sizeof(ClipLine), clipSpanHeight);
4052
4053     Q_CHECK_PTR(m_clipLines);
4054     QT_TRY {
4055         m_spans = (QSpan *)malloc(clipSpanHeight*sizeof(QSpan));
4056         allocated = clipSpanHeight;
4057         Q_CHECK_PTR(m_spans);
4058
4059         QT_TRY {
4060             if (hasRectClip) {
4061                 int y = 0;
4062                 while (y < ymin) {
4063                     m_clipLines[y].spans = 0;
4064                     m_clipLines[y].count = 0;
4065                     ++y;
4066                 }
4067
4068                 const int len = clipRect.width();
4069                 count = 0;
4070                 while (y < ymax) {
4071                     QSpan *span = m_spans + count;
4072                     span->x = xmin;
4073                     span->len = len;
4074                     span->y = y;
4075                     span->coverage = 255;
4076                     ++count;
4077
4078                     m_clipLines[y].spans = span;
4079                     m_clipLines[y].count = 1;
4080                     ++y;
4081                 }
4082
4083                 while (y < clipSpanHeight) {
4084                     m_clipLines[y].spans = 0;
4085                     m_clipLines[y].count = 0;
4086                     ++y;
4087                 }
4088             } else if (hasRegionClip) {
4089
4090                 const QVector<QRect> rects = clipRegion.rects();
4091                 const int numRects = rects.size();
4092
4093                 { // resize
4094                     const int maxSpans = (ymax - ymin) * numRects;
4095                     if (maxSpans > allocated) {
4096                         m_spans = q_check_ptr((QSpan *)realloc(m_spans, maxSpans * sizeof(QSpan)));
4097                         allocated = maxSpans;
4098                     }
4099                 }
4100
4101                 int y = 0;
4102                 int firstInBand = 0;
4103                 count = 0;
4104                 while (firstInBand < numRects) {
4105                     const int currMinY = rects.at(firstInBand).y();
4106                     const int currMaxY = currMinY + rects.at(firstInBand).height();
4107
4108                     while (y < currMinY) {
4109                         m_clipLines[y].spans = 0;
4110                         m_clipLines[y].count = 0;
4111                         ++y;
4112                     }
4113
4114                     int lastInBand = firstInBand;
4115                     while (lastInBand + 1 < numRects && rects.at(lastInBand+1).top() == y)
4116                         ++lastInBand;
4117
4118                     while (y < currMaxY) {
4119
4120                         m_clipLines[y].spans = m_spans + count;
4121                         m_clipLines[y].count = lastInBand - firstInBand + 1;
4122
4123                         for (int r = firstInBand; r <= lastInBand; ++r) {
4124                             const QRect &currRect = rects.at(r);
4125                             QSpan *span = m_spans + count;
4126                             span->x = currRect.x();
4127                             span->len = currRect.width();
4128                             span->y = y;
4129                             span->coverage = 255;
4130                             ++count;
4131                         }
4132                         ++y;
4133                     }
4134
4135                     firstInBand = lastInBand + 1;
4136                 }
4137
4138                 Q_ASSERT(count <= allocated);
4139
4140                 while (y < clipSpanHeight) {
4141                     m_clipLines[y].spans = 0;
4142                     m_clipLines[y].count = 0;
4143                     ++y;
4144                 }
4145
4146             }
4147         } QT_CATCH(...) {
4148             free(m_spans); // have to free m_spans again or someone might think that we were successfully initialized.
4149             m_spans = 0;
4150             QT_RETHROW;
4151         }
4152     } QT_CATCH(...) {
4153         free(m_clipLines); // same for clipLines
4154         m_clipLines = 0;
4155         QT_RETHROW;
4156     }
4157 }
4158
4159 void QClipData::fixup()
4160 {
4161     Q_ASSERT(m_spans);
4162
4163     if (count == 0) {
4164         ymin = ymax = xmin = xmax = 0;
4165         return;
4166     }
4167
4168     int y = -1;
4169     ymin = m_spans[0].y;
4170     ymax = m_spans[count-1].y + 1;
4171     xmin = INT_MAX;
4172     xmax = 0;
4173
4174     const int firstLeft = m_spans[0].x;
4175     const int firstRight = m_spans[0].x + m_spans[0].len;
4176     bool isRect = true;
4177
4178     for (int i = 0; i < count; ++i) {
4179         QT_FT_Span_& span = m_spans[i];
4180
4181         if (span.y != y) {
4182             if (span.y != y + 1 && y != -1)
4183                 isRect = false;
4184             y = span.y;
4185             m_clipLines[y].spans = &span;
4186             m_clipLines[y].count = 1;
4187         } else
4188             ++m_clipLines[y].count;
4189
4190         const int spanLeft = span.x;
4191         const int spanRight = spanLeft + span.len;
4192
4193         if (spanLeft < xmin)
4194             xmin = spanLeft;
4195
4196         if (spanRight > xmax)
4197             xmax = spanRight;
4198
4199         if (spanLeft != firstLeft || spanRight != firstRight)
4200             isRect = false;
4201     }
4202
4203     if (isRect) {
4204         hasRectClip = true;
4205         clipRect.setRect(xmin, ymin, xmax - xmin, ymax - ymin);
4206     }
4207 }
4208
4209 /*
4210     Convert \a rect to clip spans.
4211  */
4212 void QClipData::setClipRect(const QRect &rect)
4213 {
4214     if (hasRectClip && rect == clipRect)
4215         return;
4216
4217 //    qDebug() << "setClipRect" << clipSpanHeight << count << allocated << rect;
4218     hasRectClip = true;
4219     hasRegionClip = false;
4220     clipRect = rect;
4221
4222     xmin = rect.x();
4223     xmax = rect.x() + rect.width();
4224     ymin = qMin(rect.y(), clipSpanHeight);
4225     ymax = qMin(rect.y() + rect.height(), clipSpanHeight);
4226
4227     if (m_spans) {
4228         free(m_spans);
4229         m_spans = 0;
4230     }
4231
4232 //    qDebug() << xmin << xmax << ymin << ymax;
4233 }
4234
4235 /*
4236     Convert \a region to clip spans.
4237  */
4238 void QClipData::setClipRegion(const QRegion &region)
4239 {
4240     if (region.rectCount() == 1) {
4241         setClipRect(region.rects().at(0));
4242         return;
4243     }
4244
4245     hasRegionClip = true;
4246     hasRectClip = false;
4247     clipRegion = region;
4248
4249     { // set bounding rect
4250         const QRect rect = region.boundingRect();
4251         xmin = rect.x();
4252         xmax = rect.x() + rect.width();
4253         ymin = rect.y();
4254         ymax = rect.y() + rect.height();
4255     }
4256
4257     if (m_spans) {
4258         free(m_spans);
4259         m_spans = 0;
4260     }
4261
4262 }
4263
4264 /*!
4265     \internal
4266     spans must be sorted on y
4267 */
4268 static const QSpan *qt_intersect_spans(const QClipData *clip, int *currentClip,
4269                                        const QSpan *spans, const QSpan *end,
4270                                        QSpan **outSpans, int available)
4271 {
4272     const_cast<QClipData *>(clip)->initialize();
4273
4274     QSpan *out = *outSpans;
4275
4276     const QSpan *clipSpans = clip->m_spans + *currentClip;
4277     const QSpan *clipEnd = clip->m_spans + clip->count;
4278
4279     while (available && spans < end ) {
4280         if (clipSpans >= clipEnd) {
4281             spans = end;
4282             break;
4283         }
4284         if (clipSpans->y > spans->y) {
4285             ++spans;
4286             continue;
4287         }
4288         if (spans->y != clipSpans->y) {
4289             if (spans->y < clip->count && clip->m_clipLines[spans->y].spans)
4290                 clipSpans = clip->m_clipLines[spans->y].spans;
4291             else
4292                 ++clipSpans;
4293             continue;
4294         }
4295         Q_ASSERT(spans->y == clipSpans->y);
4296
4297         int sx1 = spans->x;
4298         int sx2 = sx1 + spans->len;
4299         int cx1 = clipSpans->x;
4300         int cx2 = cx1 + clipSpans->len;
4301
4302         if (cx1 < sx1 && cx2 < sx1) {
4303             ++clipSpans;
4304             continue;
4305         } else if (sx1 < cx1 && sx2 < cx1) {
4306             ++spans;
4307             continue;
4308         }
4309         int x = qMax(sx1, cx1);
4310         int len = qMin(sx2, cx2) - x;
4311         if (len) {
4312             out->x = qMax(sx1, cx1);
4313             out->len = qMin(sx2, cx2) - out->x;
4314             out->y = spans->y;
4315             out->coverage = qt_div_255(spans->coverage * clipSpans->coverage);
4316             ++out;
4317             --available;
4318         }
4319         if (sx2 < cx2) {
4320             ++spans;
4321         } else {
4322             ++clipSpans;
4323         }
4324     }
4325
4326     *outSpans = out;
4327     *currentClip = clipSpans - clip->m_spans;
4328     return spans;
4329 }
4330
4331 static void qt_span_fill_clipped(int spanCount, const QSpan *spans, void *userData)
4332 {
4333 //     qDebug() << "qt_span_fill_clipped" << spanCount;
4334     QSpanData *fillData = reinterpret_cast<QSpanData *>(userData);
4335
4336     Q_ASSERT(fillData->blend && fillData->unclipped_blend);
4337
4338     const int NSPANS = 256;
4339     QSpan cspans[NSPANS];
4340     int currentClip = 0;
4341     const QSpan *end = spans + spanCount;
4342     while (spans < end) {
4343         QSpan *clipped = cspans;
4344         spans = qt_intersect_spans(fillData->clip, &currentClip, spans, end, &clipped, NSPANS);
4345 //         qDebug() << "processed " << spanCount - (end - spans) << "clipped" << clipped-cspans
4346 //                  << "span:" << cspans->x << cspans->y << cspans->len << spans->coverage;
4347
4348         if (clipped - cspans)
4349             fillData->unclipped_blend(clipped - cspans, cspans, fillData);
4350     }
4351 }
4352
4353 /*
4354     \internal
4355     Clip spans to \a{clip}-rectangle.
4356     Returns number of unclipped spans
4357 */
4358 static int qt_intersect_spans(QT_FT_Span *spans, int numSpans,
4359                               const QRect &clip)
4360 {
4361     const short minx = clip.left();
4362     const short miny = clip.top();
4363     const short maxx = clip.right();
4364     const short maxy = clip.bottom();
4365
4366     int n = 0;
4367     for (int i = 0; i < numSpans; ++i) {
4368         if (spans[i].y > maxy)
4369             break;
4370         if (spans[i].y < miny
4371             || spans[i].x > maxx
4372             || spans[i].x + spans[i].len <= minx) {
4373             continue;
4374         }
4375         if (spans[i].x < minx) {
4376             spans[n].len = qMin(spans[i].len - (minx - spans[i].x), maxx - minx + 1);
4377             spans[n].x = minx;
4378         } else {
4379             spans[n].x = spans[i].x;
4380             spans[n].len = qMin(spans[i].len, ushort(maxx - spans[n].x + 1));
4381         }
4382         if (spans[n].len == 0)
4383             continue;
4384         spans[n].y = spans[i].y;
4385         spans[n].coverage = spans[i].coverage;
4386         ++n;
4387     }
4388     return n;
4389 }
4390
4391
4392 static void qt_span_fill_clipRect(int count, const QSpan *spans,
4393                                   void *userData)
4394 {
4395     QSpanData *fillData = reinterpret_cast<QSpanData *>(userData);
4396     Q_ASSERT(fillData->blend && fillData->unclipped_blend);
4397
4398     Q_ASSERT(fillData->clip);
4399     Q_ASSERT(!fillData->clip->clipRect.isEmpty());
4400
4401     // hw: check if this const_cast<> is safe!!!
4402     count = qt_intersect_spans(const_cast<QSpan*>(spans), count,
4403                                fillData->clip->clipRect);
4404     if (count > 0)
4405         fillData->unclipped_blend(count, spans, fillData);
4406 }
4407
4408 static void qt_span_clip(int count, const QSpan *spans, void *userData)
4409 {
4410     ClipData *clipData = reinterpret_cast<ClipData *>(userData);
4411
4412 //     qDebug() << " qt_span_clip: " << count << clipData->operation;
4413 //     for (int i = 0; i < qMin(count, 10); ++i) {
4414 //         qDebug() << "    " << spans[i].x << spans[i].y << spans[i].len << spans[i].coverage;
4415 //     }
4416
4417     switch (clipData->operation) {
4418
4419     case Qt::IntersectClip:
4420         {
4421             QClipData *newClip = clipData->newClip;
4422             newClip->initialize();
4423
4424             int currentClip = 0;
4425             const QSpan *end = spans + count;
4426             while (spans < end) {
4427                 QSpan *newspans = newClip->m_spans + newClip->count;
4428                 spans = qt_intersect_spans(clipData->oldClip, &currentClip, spans, end,
4429                                            &newspans, newClip->allocated - newClip->count);
4430                 newClip->count = newspans - newClip->m_spans;
4431                 if (spans < end) {
4432                     newClip->m_spans = q_check_ptr((QSpan *)realloc(newClip->m_spans, newClip->allocated*2*sizeof(QSpan)));
4433                     newClip->allocated *= 2;
4434                 }
4435             }
4436         }
4437         break;
4438
4439     case Qt::ReplaceClip:
4440         clipData->newClip->appendSpans(spans, count);
4441         break;
4442     case Qt::NoClip:
4443         break;
4444     }
4445 }
4446
4447 #ifndef QT_NO_DEBUG
4448 QImage QRasterBuffer::bufferImage() const
4449 {
4450     QImage image(m_width, m_height, QImage::Format_ARGB32_Premultiplied);
4451
4452     for (int y = 0; y < m_height; ++y) {
4453         uint *span = (uint *)const_cast<QRasterBuffer *>(this)->scanLine(y);
4454
4455         for (int x=0; x<m_width; ++x) {
4456             uint argb = span[x];
4457             image.setPixel(x, y, argb);
4458         }
4459     }
4460     return image;
4461 }
4462 #endif
4463
4464
4465 void QRasterBuffer::flushToARGBImage(QImage *target) const
4466 {
4467     int w = qMin(m_width, target->width());
4468     int h = qMin(m_height, target->height());
4469
4470     for (int y=0; y<h; ++y) {
4471         uint *sourceLine = (uint *)const_cast<QRasterBuffer *>(this)->scanLine(y);
4472         QRgb *dest = (QRgb *) target->scanLine(y);
4473         for (int x=0; x<w; ++x) {
4474             QRgb pixel = sourceLine[x];
4475             int alpha = qAlpha(pixel);
4476             if (!alpha) {
4477                 dest[x] = 0;
4478             } else {
4479                 dest[x] = (alpha << 24)
4480                         | ((255*qRed(pixel)/alpha) << 16)
4481                         | ((255*qGreen(pixel)/alpha) << 8)
4482                         | ((255*qBlue(pixel)/alpha) << 0);
4483             }
4484         }
4485     }
4486 }
4487
4488
4489 class QGradientCache
4490 {
4491     struct CacheInfo
4492     {
4493         inline CacheInfo(QGradientStops s, int op, QGradient::InterpolationMode mode) :
4494             stops(s), opacity(op), interpolationMode(mode) {}
4495         uint buffer[GRADIENT_STOPTABLE_SIZE];
4496         QGradientStops stops;
4497         int opacity;
4498         QGradient::InterpolationMode interpolationMode;
4499     };
4500
4501     typedef QMultiHash<quint64, CacheInfo> QGradientColorTableHash;
4502
4503 public:
4504     inline const uint *getBuffer(const QGradient &gradient, int opacity) {
4505         quint64 hash_val = 0;
4506
4507         QGradientStops stops = gradient.stops();
4508         for (int i = 0; i < stops.size() && i <= 2; i++)
4509             hash_val += stops[i].second.rgba();
4510
4511         QMutexLocker lock(&mutex);
4512         QGradientColorTableHash::const_iterator it = cache.constFind(hash_val);
4513
4514         if (it == cache.constEnd())
4515             return addCacheElement(hash_val, gradient, opacity);
4516         else {
4517             do {
4518                 const CacheInfo &cache_info = it.value();
4519                 if (cache_info.stops == stops && cache_info.opacity == opacity && cache_info.interpolationMode == gradient.interpolationMode())
4520                     return cache_info.buffer;
4521                 ++it;
4522             } while (it != cache.constEnd() && it.key() == hash_val);
4523             // an exact match for these stops and opacity was not found, create new cache
4524             return addCacheElement(hash_val, gradient, opacity);
4525         }
4526     }
4527
4528     inline int paletteSize() const { return GRADIENT_STOPTABLE_SIZE; }
4529 protected:
4530     inline int maxCacheSize() const { return 60; }
4531     inline void generateGradientColorTable(const QGradient& g,
4532                                            uint *colorTable,
4533                                            int size, int opacity) const;
4534     uint *addCacheElement(quint64 hash_val, const QGradient &gradient, int opacity) {
4535         if (cache.size() == maxCacheSize()) {
4536             // may remove more than 1, but OK
4537             cache.erase(cache.begin() + (qrand() % maxCacheSize()));
4538         }
4539         CacheInfo cache_entry(gradient.stops(), opacity, gradient.interpolationMode());
4540         generateGradientColorTable(gradient, cache_entry.buffer, paletteSize(), opacity);
4541         return cache.insert(hash_val, cache_entry).value().buffer;
4542     }
4543
4544     QGradientColorTableHash cache;
4545     QMutex mutex;
4546 };
4547
4548 void QGradientCache::generateGradientColorTable(const QGradient& gradient, uint *colorTable, int size, int opacity) const
4549 {
4550     QGradientStops stops = gradient.stops();
4551     int stopCount = stops.count();
4552     Q_ASSERT(stopCount > 0);
4553
4554     bool colorInterpolation = (gradient.interpolationMode() == QGradient::ColorInterpolation);
4555
4556     if (stopCount == 2) {
4557         uint first_color = ARGB_COMBINE_ALPHA(stops[0].second.rgba(), opacity);
4558         uint second_color = ARGB_COMBINE_ALPHA(stops[1].second.rgba(), opacity);
4559
4560         qreal first_stop = stops[0].first;
4561         qreal second_stop = stops[1].first;
4562
4563         if (second_stop < first_stop) {
4564             qSwap(first_color, second_color);
4565             qSwap(first_stop, second_stop);
4566         }
4567
4568         if (colorInterpolation) {
4569             first_color = PREMUL(first_color);
4570             second_color = PREMUL(second_color);
4571         }
4572
4573         int first_index = qRound(first_stop * (GRADIENT_STOPTABLE_SIZE-1));
4574         int second_index = qRound(second_stop * (GRADIENT_STOPTABLE_SIZE-1));
4575
4576         uint red_first = qRed(first_color) << 16;
4577         uint green_first = qGreen(first_color) << 16;
4578         uint blue_first = qBlue(first_color) << 16;
4579         uint alpha_first = qAlpha(first_color) << 16;
4580
4581         uint red_second = qRed(second_color) << 16;
4582         uint green_second = qGreen(second_color) << 16;
4583         uint blue_second = qBlue(second_color) << 16;
4584         uint alpha_second = qAlpha(second_color) << 16;
4585
4586         int i = 0;
4587         for (; i <= qMin(GRADIENT_STOPTABLE_SIZE, first_index); ++i) {
4588             if (colorInterpolation)
4589                 colorTable[i] = first_color;
4590             else
4591                 colorTable[i] = PREMUL(first_color);
4592         }
4593
4594         if (i < second_index) {
4595             qreal reciprocal = qreal(1) / (second_index - first_index);
4596
4597             int red_delta = qRound(int(red_second - red_first) * reciprocal);
4598             int green_delta = qRound(int(green_second - green_first) * reciprocal);
4599             int blue_delta = qRound(int(blue_second - blue_first) * reciprocal);
4600             int alpha_delta = qRound(int(alpha_second - alpha_first) * reciprocal);
4601
4602             // rounding
4603             red_first += 1 << 15;
4604             green_first += 1 << 15;
4605             blue_first += 1 << 15;
4606             alpha_first += 1 << 15;
4607
4608             for (; i < qMin(GRADIENT_STOPTABLE_SIZE, second_index); ++i) {
4609                 red_first += red_delta;
4610                 green_first += green_delta;
4611                 blue_first += blue_delta;
4612                 alpha_first += alpha_delta;
4613
4614                 const uint color = ((alpha_first << 8) & 0xff000000) | (red_first & 0xff0000)
4615                                  | ((green_first >> 8) & 0xff00) | (blue_first >> 16);
4616
4617                 if (colorInterpolation)
4618                     colorTable[i] = color;
4619                 else
4620                     colorTable[i] = PREMUL(color);
4621             }
4622         }
4623
4624         for (; i < GRADIENT_STOPTABLE_SIZE; ++i) {
4625             if (colorInterpolation)
4626                 colorTable[i] = second_color;
4627             else
4628                 colorTable[i] = PREMUL(second_color);
4629         }
4630
4631         return;
4632     }
4633
4634     uint current_color = ARGB_COMBINE_ALPHA(stops[0].second.rgba(), opacity);
4635     if (stopCount == 1) {
4636         current_color = PREMUL(current_color);
4637         for (int i = 0; i < size; ++i)
4638             colorTable[i] = current_color;
4639         return;
4640     }
4641
4642     // The position where the gradient begins and ends
4643     qreal begin_pos = stops[0].first;
4644     qreal end_pos = stops[stopCount-1].first;
4645
4646     int pos = 0; // The position in the color table.
4647     uint next_color;
4648
4649     qreal incr = 1 / qreal(size); // the double increment.
4650     qreal dpos = 1.5 * incr; // current position in gradient stop list (0 to 1)
4651
4652      // Up to first point
4653     colorTable[pos++] = PREMUL(current_color);
4654     while (dpos <= begin_pos) {
4655         colorTable[pos] = colorTable[pos - 1];
4656         ++pos;
4657         dpos += incr;
4658     }
4659
4660     int current_stop = 0; // We always interpolate between current and current + 1.
4661
4662     qreal t; // position between current left and right stops
4663     qreal t_delta; // the t increment per entry in the color table
4664
4665     if (dpos < end_pos) {
4666         // Gradient area
4667         while (dpos > stops[current_stop+1].first)
4668             ++current_stop;
4669
4670         if (current_stop != 0)
4671             current_color = ARGB_COMBINE_ALPHA(stops[current_stop].second.rgba(), opacity);
4672         next_color = ARGB_COMBINE_ALPHA(stops[current_stop+1].second.rgba(), opacity);
4673
4674         if (colorInterpolation) {
4675             current_color = PREMUL(current_color);
4676             next_color = PREMUL(next_color);
4677         }
4678
4679         qreal diff = stops[current_stop+1].first - stops[current_stop].first;
4680         qreal c = (diff == 0) ? qreal(0) : 256 / diff;
4681         t = (dpos - stops[current_stop].first) * c;
4682         t_delta = incr * c;
4683
4684         while (true) {
4685             Q_ASSERT(current_stop < stopCount);
4686
4687             int dist = qRound(t);
4688             int idist = 256 - dist;
4689
4690             if (colorInterpolation)
4691                 colorTable[pos] = INTERPOLATE_PIXEL_256(current_color, idist, next_color, dist);
4692             else
4693                 colorTable[pos] = PREMUL(INTERPOLATE_PIXEL_256(current_color, idist, next_color, dist));
4694
4695             ++pos;
4696             dpos += incr;
4697
4698             if (dpos >= end_pos)
4699                 break;
4700
4701             t += t_delta;
4702
4703             int skip = 0;
4704             while (dpos > stops[current_stop+skip+1].first)
4705                 ++skip;
4706
4707             if (skip != 0) {
4708                 current_stop += skip;
4709                 if (skip == 1)
4710                     current_color = next_color;
4711                 else
4712                     current_color = ARGB_COMBINE_ALPHA(stops[current_stop].second.rgba(), opacity);
4713                 next_color = ARGB_COMBINE_ALPHA(stops[current_stop+1].second.rgba(), opacity);
4714
4715                 if (colorInterpolation) {
4716                     if (skip != 1)
4717                         current_color = PREMUL(current_color);
4718                     next_color = PREMUL(next_color);
4719                 }
4720
4721                 qreal diff = stops[current_stop+1].first - stops[current_stop].first;
4722                 qreal c = (diff == 0) ? qreal(0) : 256 / diff;
4723                 t = (dpos - stops[current_stop].first) * c;
4724                 t_delta = incr * c;
4725             }
4726         }
4727     }
4728
4729     // After last point
4730     current_color = PREMUL(ARGB_COMBINE_ALPHA(stops[stopCount - 1].second.rgba(), opacity));
4731     while (pos < size - 1) {
4732         colorTable[pos] = current_color;
4733         ++pos;
4734     }
4735
4736     // Make sure the last color stop is represented at the end of the table
4737     colorTable[size - 1] = current_color;
4738 }
4739
4740 Q_GLOBAL_STATIC(QGradientCache, qt_gradient_cache)
4741
4742
4743 void QSpanData::init(QRasterBuffer *rb, const QRasterPaintEngine *pe)
4744 {
4745     rasterBuffer = rb;
4746 #ifdef Q_WS_QWS
4747     rasterEngine = const_cast<QRasterPaintEngine *>(pe);
4748 #endif
4749     type = None;
4750     txop = 0;
4751     bilinear = false;
4752     m11 = m22 = m33 = 1.;
4753     m12 = m13 = m21 = m23 = dx = dy = 0.0;
4754     clip = pe ? pe->d_func()->clip() : 0;
4755 }
4756
4757 Q_GUI_EXPORT extern QImage qt_imageForBrush(int brushStyle, bool invert);
4758
4759 void QSpanData::setup(const QBrush &brush, int alpha, QPainter::CompositionMode compositionMode)
4760 {
4761     Qt::BrushStyle brushStyle = qbrush_style(brush);
4762     switch (brushStyle) {
4763     case Qt::SolidPattern: {
4764         type = Solid;
4765         QColor c = qbrush_color(brush);
4766         QRgb rgba = c.rgba();
4767         solid.color = PREMUL(ARGB_COMBINE_ALPHA(rgba, alpha));
4768         if ((solid.color & 0xff000000) == 0
4769             && compositionMode == QPainter::CompositionMode_SourceOver) {
4770             type = None;
4771         }
4772         break;
4773     }
4774
4775     case Qt::LinearGradientPattern:
4776         {
4777             type = LinearGradient;
4778             const QLinearGradient *g = static_cast<const QLinearGradient *>(brush.gradient());
4779             gradient.alphaColor = !brush.isOpaque() || alpha != 256;
4780             gradient.colorTable = const_cast<uint*>(qt_gradient_cache()->getBuffer(*g, alpha));
4781             gradient.spread = g->spread();
4782
4783             QLinearGradientData &linearData = gradient.linear;
4784
4785             linearData.origin.x = g->start().x();
4786             linearData.origin.y = g->start().y();
4787             linearData.end.x = g->finalStop().x();
4788             linearData.end.y = g->finalStop().y();
4789             break;
4790         }
4791
4792     case Qt::RadialGradientPattern:
4793         {
4794             type = RadialGradient;
4795             const QRadialGradient *g = static_cast<const QRadialGradient *>(brush.gradient());
4796             gradient.alphaColor = !brush.isOpaque() || alpha != 256;
4797             gradient.colorTable = const_cast<uint*>(qt_gradient_cache()->getBuffer(*g, alpha));
4798             gradient.spread = g->spread();
4799
4800             QRadialGradientData &radialData = gradient.radial;
4801
4802             QPointF center = g->center();
4803             radialData.center.x = center.x();
4804             radialData.center.y = center.y();
4805             radialData.center.radius = g->centerRadius();
4806             QPointF focal = g->focalPoint();
4807             radialData.focal.x = focal.x();
4808             radialData.focal.y = focal.y();
4809             radialData.focal.radius = g->focalRadius();
4810         }
4811         break;
4812
4813     case Qt::ConicalGradientPattern:
4814         {
4815             type = ConicalGradient;
4816             const QConicalGradient *g = static_cast<const QConicalGradient *>(brush.gradient());
4817             gradient.alphaColor = !brush.isOpaque() || alpha != 256;
4818             gradient.colorTable = const_cast<uint*>(qt_gradient_cache()->getBuffer(*g, alpha));
4819             gradient.spread = QGradient::RepeatSpread;
4820
4821             QConicalGradientData &conicalData = gradient.conical;
4822
4823             QPointF center = g->center();
4824             conicalData.center.x = center.x();
4825             conicalData.center.y = center.y();
4826             conicalData.angle = g->angle() * 2 * Q_PI / 360.0;
4827         }
4828         break;
4829
4830     case Qt::Dense1Pattern:
4831     case Qt::Dense2Pattern:
4832     case Qt::Dense3Pattern:
4833     case Qt::Dense4Pattern:
4834     case Qt::Dense5Pattern:
4835     case Qt::Dense6Pattern:
4836     case Qt::Dense7Pattern:
4837     case Qt::HorPattern:
4838     case Qt::VerPattern:
4839     case Qt::CrossPattern:
4840     case Qt::BDiagPattern:
4841     case Qt::FDiagPattern:
4842     case Qt::DiagCrossPattern:
4843         type = Texture;
4844         if (!tempImage)
4845             tempImage = new QImage();
4846         *tempImage = rasterBuffer->colorizeBitmap(qt_imageForBrush(brushStyle, true), brush.color());
4847         initTexture(tempImage, alpha, QTextureData::Tiled);
4848         break;
4849     case Qt::TexturePattern:
4850         type = Texture;
4851         if (!tempImage)
4852             tempImage = new QImage();
4853
4854         if (qHasPixmapTexture(brush) && brush.texture().isQBitmap())
4855             *tempImage = rasterBuffer->colorizeBitmap(brush.textureImage(), brush.color());
4856         else
4857             *tempImage = brush.textureImage();
4858         initTexture(tempImage, alpha, QTextureData::Tiled, tempImage->rect());
4859         break;
4860
4861     case Qt::NoBrush:
4862     default:
4863         type = None;
4864         break;
4865     }
4866     adjustSpanMethods();
4867 }
4868
4869 void QSpanData::adjustSpanMethods()
4870 {
4871     bitmapBlit = 0;
4872     alphamapBlit = 0;
4873     alphaRGBBlit = 0;
4874
4875     fillRect = 0;
4876
4877     switch(type) {
4878     case None:
4879         unclipped_blend = 0;
4880         break;
4881     case Solid:
4882         unclipped_blend = rasterBuffer->drawHelper->blendColor;
4883         bitmapBlit = rasterBuffer->drawHelper->bitmapBlit;
4884         alphamapBlit = rasterBuffer->drawHelper->alphamapBlit;
4885         alphaRGBBlit = rasterBuffer->drawHelper->alphaRGBBlit;
4886         fillRect = rasterBuffer->drawHelper->fillRect;
4887         break;
4888     case LinearGradient:
4889     case RadialGradient:
4890     case ConicalGradient:
4891         unclipped_blend = rasterBuffer->drawHelper->blendGradient;
4892         break;
4893     case Texture:
4894 #ifdef Q_WS_QWS
4895 #ifndef QT_NO_RASTERCALLBACKS
4896         if (!rasterBuffer->buffer())
4897             unclipped_blend = qBlendTextureCallback;
4898         else
4899 #endif
4900             unclipped_blend = qBlendTexture;
4901 #else
4902         unclipped_blend = qBlendTexture;
4903 #endif
4904         if (!texture.imageData)
4905             unclipped_blend = 0;
4906
4907         break;
4908     }
4909     // setup clipping
4910     if (!unclipped_blend) {
4911         blend = 0;
4912     } else if (!clip) {
4913         blend = unclipped_blend;
4914     } else if (clip->hasRectClip) {
4915         blend = clip->clipRect.isEmpty() ? 0 : qt_span_fill_clipRect;
4916     } else {
4917         blend = qt_span_fill_clipped;
4918     }
4919 }
4920
4921 void QSpanData::setupMatrix(const QTransform &matrix, int bilin)
4922 {
4923     QTransform delta;
4924     // make sure we round off correctly in qdrawhelper.cpp
4925     delta.translate(1.0 / 65536, 1.0 / 65536);
4926
4927     QTransform inv = (delta * matrix).inverted();
4928     m11 = inv.m11();
4929     m12 = inv.m12();
4930     m13 = inv.m13();
4931     m21 = inv.m21();
4932     m22 = inv.m22();
4933     m23 = inv.m23();
4934     m33 = inv.m33();
4935     dx = inv.dx();
4936     dy = inv.dy();
4937     txop = inv.type();
4938     bilinear = bilin;
4939
4940     const bool affine = !m13 && !m23;
4941     fast_matrix = affine
4942         && m11 * m11 + m21 * m21 < 1e4
4943         && m12 * m12 + m22 * m22 < 1e4
4944         && qAbs(dx) < 1e4
4945         && qAbs(dy) < 1e4;
4946
4947     adjustSpanMethods();
4948 }
4949
4950 extern const QVector<QRgb> *qt_image_colortable(const QImage &image);
4951
4952 void QSpanData::initTexture(const QImage *image, int alpha, QTextureData::Type _type, const QRect &sourceRect)
4953 {
4954     const QImageData *d = const_cast<QImage *>(image)->data_ptr();
4955     if (!d || d->height == 0) {
4956         texture.imageData = 0;
4957         texture.width = 0;
4958         texture.height = 0;
4959         texture.x1 = 0;
4960         texture.y1 = 0;
4961         texture.x2 = 0;
4962         texture.y2 = 0;
4963         texture.bytesPerLine = 0;
4964         texture.format = QImage::Format_Invalid;
4965         texture.colorTable = 0;
4966         texture.hasAlpha = alpha != 256;
4967     } else {
4968         texture.imageData = d->data;
4969         texture.width = d->width;
4970         texture.height = d->height;
4971
4972         if (sourceRect.isNull()) {
4973             texture.x1 = 0;
4974             texture.y1 = 0;
4975             texture.x2 = texture.width;
4976             texture.y2 = texture.height;
4977         } else {
4978             texture.x1 = sourceRect.x();
4979             texture.y1 = sourceRect.y();
4980             texture.x2 = qMin(texture.x1 + sourceRect.width(), d->width);
4981             texture.y2 = qMin(texture.y1 + sourceRect.height(), d->height);
4982         }
4983
4984         texture.bytesPerLine = d->bytes_per_line;
4985
4986         texture.format = d->format;
4987         texture.colorTable = (d->format <= QImage::Format_Indexed8 && !d->colortable.isEmpty()) ? &d->colortable : 0;
4988         texture.hasAlpha = image->hasAlphaChannel() || alpha != 256;
4989     }
4990     texture.const_alpha = alpha;
4991     texture.type = _type;
4992
4993     adjustSpanMethods();
4994 }
4995
4996 /*!
4997     \internal
4998     \a x and \a y is relative to the midpoint of \a rect.
4999 */
5000 static inline void drawEllipsePoints(int x, int y, int length,
5001                                      const QRect &rect,
5002                                      const QRect &clip,
5003                                      ProcessSpans pen_func, ProcessSpans brush_func,
5004                                      QSpanData *pen_data, QSpanData *brush_data)
5005 {
5006     if (length == 0)
5007         return;
5008
5009     QT_FT_Span outline[4];
5010     const int midx = rect.x() + (rect.width() + 1) / 2;
5011     const int midy = rect.y() + (rect.height() + 1) / 2;
5012
5013     x = x + midx;
5014     y = midy - y;
5015
5016     // topleft
5017     outline[0].x = midx + (midx - x) - (length - 1) - (rect.width() & 0x1);
5018     outline[0].len = qMin(length, x - outline[0].x);
5019     outline[0].y = y;
5020     outline[0].coverage = 255;
5021
5022     // topright
5023     outline[1].x = x;
5024     outline[1].len = length;
5025     outline[1].y = y;
5026     outline[1].coverage = 255;
5027
5028     // bottomleft
5029     outline[2].x = outline[0].x;
5030     outline[2].len = outline[0].len;
5031     outline[2].y = midy + (midy - y) - (rect.height() & 0x1);
5032     outline[2].coverage = 255;
5033
5034     // bottomright
5035     outline[3].x = x;
5036     outline[3].len = length;
5037     outline[3].y = outline[2].y;
5038     outline[3].coverage = 255;
5039
5040     if (brush_func && outline[0].x + outline[0].len < outline[1].x) {
5041         QT_FT_Span fill[2];
5042
5043         // top fill
5044         fill[0].x = outline[0].x + outline[0].len - 1;
5045         fill[0].len = qMax(0, outline[1].x - fill[0].x);
5046         fill[0].y = outline[1].y;
5047         fill[0].coverage = 255;
5048
5049         // bottom fill
5050         fill[1].x = outline[2].x + outline[2].len - 1;
5051         fill[1].len = qMax(0, outline[3].x - fill[1].x);
5052         fill[1].y = outline[3].y;
5053         fill[1].coverage = 255;
5054
5055         int n = (fill[0].y >= fill[1].y ? 1 : 2);
5056         n = qt_intersect_spans(fill, n, clip);
5057         if (n > 0)
5058             brush_func(n, fill, brush_data);
5059     }
5060     if (pen_func) {
5061         int n = (outline[1].y >= outline[2].y ? 2 : 4);
5062         n = qt_intersect_spans(outline, n, clip);
5063         if (n > 0)
5064             pen_func(n, outline, pen_data);
5065     }
5066 }
5067
5068 /*!
5069     \internal
5070     Draws an ellipse using the integer point midpoint algorithm.
5071 */
5072 static void drawEllipse_midpoint_i(const QRect &rect, const QRect &clip,
5073                                    ProcessSpans pen_func, ProcessSpans brush_func,
5074                                    QSpanData *pen_data, QSpanData *brush_data)
5075 {
5076     const qreal a = qreal(rect.width()) / 2;
5077     const qreal b = qreal(rect.height()) / 2;
5078     qreal d = b*b - (a*a*b) + 0.25*a*a;
5079
5080     int x = 0;
5081     int y = (rect.height() + 1) / 2;
5082     int startx = x;
5083
5084     // region 1
5085     while (a*a*(2*y - 1) > 2*b*b*(x + 1)) {
5086         if (d < 0) { // select E
5087             d += b*b*(2*x + 3);
5088             ++x;
5089         } else {     // select SE
5090             d += b*b*(2*x + 3) + a*a*(-2*y + 2);
5091             drawEllipsePoints(startx, y, x - startx + 1, rect, clip,
5092                               pen_func, brush_func, pen_data, brush_data);
5093             startx = ++x;
5094             --y;
5095         }
5096     }
5097     drawEllipsePoints(startx, y, x - startx + 1, rect, clip,
5098                       pen_func, brush_func, pen_data, brush_data);
5099
5100     // region 2
5101     d = b*b*(x + 0.5)*(x + 0.5) + a*a*((y - 1)*(y - 1) - b*b);
5102     const int miny = rect.height() & 0x1;
5103     while (y > miny) {
5104         if (d < 0) { // select SE
5105             d += b*b*(2*x + 2) + a*a*(-2*y + 3);
5106             ++x;
5107         } else {     // select S
5108             d += a*a*(-2*y + 3);
5109         }
5110         --y;
5111         drawEllipsePoints(x, y, 1, rect, clip,
5112                           pen_func, brush_func, pen_data, brush_data);
5113     }
5114 }
5115
5116 /*!
5117     \fn void QRasterPaintEngine::drawPoints(const QPoint *points, int pointCount)
5118     \overload
5119
5120     Draws the first \a pointCount points in the buffer \a points
5121
5122     The default implementation converts the first \a pointCount QPoints in \a points
5123     to QPointFs and calls the floating point version of drawPoints.
5124 */
5125
5126 /*!
5127     \fn void QRasterPaintEngine::drawEllipse(const QRect &rect)
5128     \overload
5129
5130     Reimplement this function to draw the largest ellipse that can be
5131     contained within rectangle \a rect.
5132 */
5133
5134 #ifdef QT_DEBUG_DRAW
5135 void dumpClip(int width, int height, const QClipData *clip)
5136 {
5137     QImage clipImg(width, height, QImage::Format_ARGB32_Premultiplied);
5138     clipImg.fill(0xffff0000);
5139
5140     int x0 = width;
5141     int x1 = 0;
5142     int y0 = height;
5143     int y1 = 0;
5144
5145     ((QClipData *) clip)->spans(); // Force allocation of the spans structure...
5146
5147     for (int i = 0; i < clip->count; ++i) {
5148         const QSpan *span = ((QClipData *) clip)->spans() + i;
5149         for (int j = 0; j < span->len; ++j)
5150             clipImg.setPixel(span->x + j, span->y, 0xffffff00);
5151         x0 = qMin(x0, int(span->x));
5152         x1 = qMax(x1, int(span->x + span->len - 1));
5153
5154         y0 = qMin(y0, int(span->y));
5155         y1 = qMax(y1, int(span->y));
5156     }
5157
5158     static int counter = 0;
5159
5160     Q_ASSERT(y0 >= 0);
5161     Q_ASSERT(x0 >= 0);
5162     Q_ASSERT(y1 >= 0);
5163     Q_ASSERT(x1 >= 0);
5164
5165     fprintf(stderr,"clip %d: %d %d - %d %d\n", counter, x0, y0, x1, y1);
5166     clipImg.save(QString::fromLatin1("clip-%0.png").arg(counter++));
5167 }
5168 #endif
5169
5170
5171 QT_END_NAMESPACE