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