Revert "Fix how subpixel positions are intepreted in an aliased grid."
[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     const QFixed aliasDelta = QFixed::fromReal(aliasedCoordinateDelta);
2925
2926     for (int i=0; i<glyphs.size(); ++i) {
2927         TOpenFontCharMetrics tmetrics;
2928         const TUint8 *glyphBitmapBytes;
2929         TSize glyphBitmapSize;
2930         fe->getCharacterData(glyphs[i], tmetrics, glyphBitmapBytes, glyphBitmapSize);
2931         const int x = qFloor(positions[i].x + metrics.x + aliasDelta);
2932         const int y = qFloor(positions[i].y + metrics.y + aliasDelta);
2933         alphaPenBlt(glyphBitmapBytes, glyphBitmapSize.iWidth, 8, x, y, glyphBitmapSize.iWidth, glyphBitmapSize.iHeight);
2934     }
2935
2936     if (matrix.type() == QTransform::TxScale)
2937         fe->setFontScale(1.0);
2938
2939     return;
2940 }
2941 #endif // Q_OS_SYMBIAN && QT_NO_FREETYPE
2942
2943 /*!
2944  * Returns true if the rectangle is completely within the current clip
2945  * state of the paint engine.
2946  */
2947 bool QRasterPaintEnginePrivate::isUnclipped_normalized(const QRect &r) const
2948 {
2949     const QClipData *cl = clip();
2950     if (!cl) {
2951         // inline contains() for performance (we know the rects are normalized)
2952         const QRect &r1 = deviceRect;
2953         return (r.left() >= r1.left() && r.right() <= r1.right()
2954                 && r.top() >= r1.top() && r.bottom() <= r1.bottom());
2955     }
2956
2957
2958     if (cl->hasRectClip) {
2959         // currently all painting functions clips to deviceRect internally
2960         if (cl->clipRect == deviceRect)
2961             return true;
2962
2963         // inline contains() for performance (we know the rects are normalized)
2964         const QRect &r1 = cl->clipRect;
2965         return (r.left() >= r1.left() && r.right() <= r1.right()
2966                 && r.top() >= r1.top() && r.bottom() <= r1.bottom());
2967     } else {
2968         return qt_region_strictContains(cl->clipRegion, r);
2969     }
2970 }
2971
2972 bool QRasterPaintEnginePrivate::isUnclipped(const QRect &rect,
2973                                             int penWidth) const
2974 {
2975     Q_Q(const QRasterPaintEngine);
2976     const QRasterPaintEngineState *s = q->state();
2977     const QClipData *cl = clip();
2978     if (!cl) {
2979         QRect r = rect.normalized();
2980         // inline contains() for performance (we know the rects are normalized)
2981         const QRect &r1 = deviceRect;
2982         return (r.left() >= r1.left() && r.right() <= r1.right()
2983                 && r.top() >= r1.top() && r.bottom() <= r1.bottom());
2984     }
2985
2986
2987     // currently all painting functions that call this function clip to deviceRect internally
2988     if (cl->hasRectClip && cl->clipRect == deviceRect)
2989         return true;
2990
2991     if (s->flags.antialiased)
2992         ++penWidth;
2993
2994     QRect r = rect.normalized();
2995     if (penWidth > 0) {
2996         r.setX(r.x() - penWidth);
2997         r.setY(r.y() - penWidth);
2998         r.setWidth(r.width() + 2 * penWidth);
2999         r.setHeight(r.height() + 2 * penWidth);
3000     }
3001
3002     if (cl->hasRectClip) {
3003         // inline contains() for performance (we know the rects are normalized)
3004         const QRect &r1 = cl->clipRect;
3005         return (r.left() >= r1.left() && r.right() <= r1.right()
3006                 && r.top() >= r1.top() && r.bottom() <= r1.bottom());
3007     } else {
3008         return qt_region_strictContains(cl->clipRegion, r);
3009     }
3010 }
3011
3012 inline bool QRasterPaintEnginePrivate::isUnclipped(const QRectF &rect,
3013                                                    int penWidth) const
3014 {
3015     return isUnclipped(rect.normalized().toAlignedRect(), penWidth);
3016 }
3017
3018 inline ProcessSpans
3019 QRasterPaintEnginePrivate::getBrushFunc(const QRect &rect,
3020                                         const QSpanData *data) const
3021 {
3022     return isUnclipped(rect, 0) ? data->unclipped_blend : data->blend;
3023 }
3024
3025 inline ProcessSpans
3026 QRasterPaintEnginePrivate::getBrushFunc(const QRectF &rect,
3027                                         const QSpanData *data) const
3028 {
3029     return isUnclipped(rect, 0) ? data->unclipped_blend : data->blend;
3030 }
3031
3032 /*!
3033    \reimp
3034 */
3035 void QRasterPaintEngine::drawStaticTextItem(QStaticTextItem *textItem)
3036 {
3037     ensurePen();
3038     ensureState();
3039
3040     QFontEngine *fontEngine = textItem->fontEngine();
3041     if (!supportsTransformations(fontEngine)) {
3042         drawCachedGlyphs(textItem->numGlyphs, textItem->glyphs, textItem->glyphPositions,
3043                          fontEngine);
3044     } else {
3045         QPaintEngineEx::drawStaticTextItem(textItem);
3046     }
3047 }
3048
3049 /*!
3050     \reimp
3051 */
3052 void QRasterPaintEngine::drawTextItem(const QPointF &p, const QTextItem &textItem)
3053 {
3054     const QTextItemInt &ti = static_cast<const QTextItemInt &>(textItem);
3055     QRasterPaintEngineState *s = state();
3056
3057 #ifdef QT_DEBUG_DRAW
3058     Q_D(QRasterPaintEngine);
3059     fprintf(stderr," - QRasterPaintEngine::drawTextItem(), (%.2f,%.2f), string=%s ct=%d\n",
3060            p.x(), p.y(), QString::fromRawData(ti.chars, ti.num_chars).toLatin1().data(),
3061            d->glyphCacheType);
3062 #endif
3063
3064     ensurePen();
3065     ensureState();
3066
3067 #if defined (Q_WS_WIN) || defined(Q_WS_MAC)
3068
3069     if (!supportsTransformations(ti.fontEngine)) {
3070         QVarLengthArray<QFixedPoint> positions;
3071         QVarLengthArray<glyph_t> glyphs;
3072
3073         QTransform matrix = s->matrix;
3074         matrix.translate(p.x(), p.y());
3075
3076         ti.fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions);
3077
3078         drawCachedGlyphs(glyphs.size(), glyphs.constData(), positions.constData(), ti.fontEngine);
3079         return;
3080     }
3081
3082 #elif defined (Q_OS_SYMBIAN) && defined(QT_NO_FREETYPE) // Q_WS_WIN || Q_WS_MAC
3083     if (s->matrix.type() <= QTransform::TxTranslate
3084         || (s->matrix.type() == QTransform::TxScale
3085                 && (qFuzzyCompare(s->matrix.m11(), s->matrix.m22())))) {
3086         drawGlyphsS60(p, ti);
3087         return;
3088     }
3089 #else // Q_WS_WIN || Q_WS_MAC
3090
3091     QFontEngine *fontEngine = ti.fontEngine;
3092
3093 #if defined(Q_WS_QWS)
3094     if (fontEngine->type() == QFontEngine::Box) {
3095         fontEngine->draw(this, qFloor(p.x()), qFloor(p.y()), ti);
3096         return;
3097     }
3098
3099     if (s->matrix.type() < QTransform::TxScale
3100         && (fontEngine->type() == QFontEngine::QPF1 || fontEngine->type() == QFontEngine::QPF2
3101             || (fontEngine->type() == QFontEngine::Proxy
3102                 && !(static_cast<QProxyFontEngine *>(fontEngine)->drawAsOutline()))
3103             )) {
3104         fontEngine->draw(this, qFloor(p.x() + aliasedCoordinateDelta), qFloor(p.y() + aliasedCoordinateDelta), ti);
3105         return;
3106     }
3107 #endif // Q_WS_QWS
3108
3109 #ifdef Q_WS_QPA
3110     if (s->matrix.type() < QTransform::TxScale) {
3111
3112         QVarLengthArray<QFixedPoint> positions;
3113         QVarLengthArray<glyph_t> glyphs;
3114         QTransform matrix = state()->transform();
3115
3116         qreal _x = qFloor(p.x());
3117         qreal _y = qFloor(p.y());
3118         matrix.translate(_x, _y);
3119
3120         fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions);
3121         if (glyphs.size() == 0)
3122             return;
3123
3124         for(int i = 0; i < glyphs.size(); i++) {
3125             QImage img = fontEngine->alphaMapForGlyph(glyphs[i]);
3126             glyph_metrics_t metrics = fontEngine->boundingBox(glyphs[i]);
3127             // ### hm, perhaps an QFixed offs = QFixed::fromReal(aliasedCoordinateDelta) is needed here?
3128             alphaPenBlt(img.bits(), img.bytesPerLine(), img.depth(),
3129                                          qRound(positions[i].x + metrics.x),
3130                                          qRound(positions[i].y + metrics.y),
3131                                          img.width(), img.height());
3132         }
3133         return;
3134     }
3135 #endif //Q_WS_QPA
3136
3137 #if (defined(Q_WS_X11) || defined(Q_WS_QWS) || defined(Q_OS_SYMBIAN)) && !defined(QT_NO_FREETYPE)
3138
3139 #if defined(Q_WS_QWS) && !defined(QT_NO_QWS_QPF2)
3140     if (fontEngine->type() == QFontEngine::QPF2) {
3141         QFontEngine *renderingEngine = static_cast<QFontEngineQPF *>(fontEngine)->renderingEngine();
3142         if (renderingEngine)
3143             fontEngine = renderingEngine;
3144     }
3145 #endif
3146
3147     if (fontEngine->type() != QFontEngine::Freetype) {
3148         QPaintEngineEx::drawTextItem(p, ti);
3149         return;
3150     }
3151
3152     QFontEngineFT *fe = static_cast<QFontEngineFT *>(fontEngine);
3153
3154     QTransform matrix = s->matrix;
3155     matrix.translate(p.x(), p.y());
3156
3157     QVarLengthArray<QFixedPoint> positions;
3158     QVarLengthArray<glyph_t> glyphs;
3159     fe->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions);
3160     if (glyphs.size() == 0)
3161         return;
3162
3163     if (!drawCachedGlyphs(glyphs.size(), glyphs.constData(), positions.constData(), fontEngine))
3164         QPaintEngine::drawTextItem(p, ti);
3165
3166     return;
3167 #endif
3168 #endif
3169
3170     QPaintEngineEx::drawTextItem(p, ti);
3171 }
3172
3173 /*!
3174     \reimp
3175 */
3176 void QRasterPaintEngine::drawPoints(const QPointF *points, int pointCount)
3177 {
3178     Q_D(QRasterPaintEngine);
3179     QRasterPaintEngineState *s = state();
3180
3181     ensurePen();
3182     if (!s->penData.blend)
3183         return;
3184
3185     if (!s->flags.fast_pen) {
3186         QPaintEngineEx::drawPoints(points, pointCount);
3187         return;
3188     }
3189
3190     QCosmeticStroker stroker(s, d->deviceRect);
3191     stroker.drawPoints(points, pointCount);
3192 }
3193
3194
3195 void QRasterPaintEngine::drawPoints(const QPoint *points, int pointCount)
3196 {
3197     Q_D(QRasterPaintEngine);
3198     QRasterPaintEngineState *s = state();
3199
3200     ensurePen();
3201     if (!s->penData.blend)
3202         return;
3203
3204     if (!s->flags.fast_pen) {
3205         QPaintEngineEx::drawPoints(points, pointCount);
3206         return;
3207     }
3208
3209     QCosmeticStroker stroker(s, d->deviceRect);
3210     stroker.drawPoints(points, pointCount);
3211 }
3212
3213 /*!
3214     \reimp
3215 */
3216 void QRasterPaintEngine::drawLines(const QLine *lines, int lineCount)
3217 {
3218 #ifdef QT_DEBUG_DRAW
3219     qDebug() << " - QRasterPaintEngine::drawLines(QLine*)" << lineCount;
3220 #endif
3221     Q_D(QRasterPaintEngine);
3222     QRasterPaintEngineState *s = state();
3223
3224     ensurePen();
3225     if (!s->penData.blend)
3226         return;
3227
3228     if (s->flags.fast_pen) {
3229         QCosmeticStroker stroker(s, d->deviceRect);
3230         for (int i=0; i<lineCount; ++i) {
3231             const QLine &l = lines[i];
3232             stroker.drawLine(l.p1(), l.p2());
3233         }
3234     } else {
3235         QPaintEngineEx::drawLines(lines, lineCount);
3236     }
3237 }
3238
3239 void QRasterPaintEnginePrivate::rasterizeLine_dashed(QLineF line,
3240                                                      qreal width,
3241                                                      int *dashIndex,
3242                                                      qreal *dashOffset,
3243                                                      bool *inDash)
3244 {
3245     Q_Q(QRasterPaintEngine);
3246     QRasterPaintEngineState *s = q->state();
3247
3248     const QPen &pen = s->lastPen;
3249     const bool squareCap = (pen.capStyle() == Qt::SquareCap);
3250     const QVector<qreal> pattern = pen.dashPattern();
3251
3252     qreal patternLength = 0;
3253     for (int i = 0; i < pattern.size(); ++i)
3254         patternLength += pattern.at(i);
3255
3256     if (patternLength <= 0)
3257         return;
3258
3259     qreal length = line.length();
3260     Q_ASSERT(length > 0);
3261     while (length > 0) {
3262         const bool rasterize = *inDash;
3263         qreal dash = (pattern.at(*dashIndex) - *dashOffset) * width;
3264         QLineF l = line;
3265
3266         if (dash >= length) {
3267             dash = length;
3268             *dashOffset += dash / width;
3269             length = 0;
3270         } else {
3271             *dashOffset = 0;
3272             *inDash = !(*inDash);
3273             if (++*dashIndex >= pattern.size())
3274                 *dashIndex = 0;
3275             length -= dash;
3276             l.setLength(dash);
3277             line.setP1(l.p2());
3278         }
3279
3280         if (rasterize && dash > 0)
3281             rasterizer->rasterizeLine(l.p1(), l.p2(), width / dash, squareCap);
3282     }
3283 }
3284
3285 /*!
3286     \reimp
3287 */
3288 void QRasterPaintEngine::drawLines(const QLineF *lines, int lineCount)
3289 {
3290 #ifdef QT_DEBUG_DRAW
3291     qDebug() << " - QRasterPaintEngine::drawLines(QLineF *)" << lineCount;
3292 #endif
3293     Q_D(QRasterPaintEngine);
3294     QRasterPaintEngineState *s = state();
3295
3296     ensurePen();
3297     if (!s->penData.blend)
3298         return;
3299     if (s->flags.fast_pen) {
3300         QCosmeticStroker stroker(s, d->deviceRect);
3301         for (int i=0; i<lineCount; ++i) {
3302             QLineF line = lines[i];
3303             stroker.drawLine(line.p1(), line.p2());
3304         }
3305     } else {
3306         QPaintEngineEx::drawLines(lines, lineCount);
3307     }
3308 }
3309
3310
3311 /*!
3312     \reimp
3313 */
3314 void QRasterPaintEngine::drawEllipse(const QRectF &rect)
3315 {
3316     QPaintEngineEx::drawEllipse(rect);
3317 }
3318
3319 /*!
3320     \internal
3321 */
3322 #ifdef Q_WS_MAC
3323 void QRasterPaintEngine::setCGContext(CGContextRef ctx)
3324 {
3325     Q_D(QRasterPaintEngine);
3326     d->cgContext = ctx;
3327 }
3328
3329 /*!
3330     \internal
3331 */
3332 CGContextRef QRasterPaintEngine::getCGContext() const
3333 {
3334     Q_D(const QRasterPaintEngine);
3335     return d->cgContext;
3336 }
3337 #endif
3338
3339 #ifdef Q_WS_WIN
3340 /*!
3341     \internal
3342 */
3343 void QRasterPaintEngine::setDC(HDC hdc) {
3344     Q_D(QRasterPaintEngine);
3345     d->hdc = hdc;
3346 }
3347
3348 /*!
3349     \internal
3350 */
3351 HDC QRasterPaintEngine::getDC() const
3352 {
3353     Q_D(const QRasterPaintEngine);
3354     return d->hdc;
3355 }
3356
3357 /*!
3358     \internal
3359 */
3360 void QRasterPaintEngine::releaseDC(HDC) const
3361 {
3362 }
3363
3364 #endif
3365
3366 bool QRasterPaintEngine::supportsTransformations(const QFontEngine *fontEngine) const
3367 {
3368     const QTransform &m = state()->matrix;
3369 #if defined(Q_WS_WIN) && !defined(Q_WS_WINCE)
3370     QFontEngine::Type fontEngineType = fontEngine->type();
3371     if ((fontEngineType == QFontEngine::Win && !((QFontEngineWin *) fontEngine)->ttf && m.type() > QTransform::TxTranslate)
3372         || (m.type() <= QTransform::TxTranslate
3373             && (fontEngineType == QFontEngine::TestFontEngine
3374                 || fontEngineType == QFontEngine::Box))) {
3375             return true;
3376     }
3377 #endif
3378     return supportsTransformations(fontEngine->fontDef.pixelSize, m);
3379 }
3380
3381 bool QRasterPaintEngine::supportsTransformations(qreal pixelSize, const QTransform &m) const
3382 {
3383 #if defined(Q_WS_MAC)
3384     // Mac font engines don't support scaling and rotation
3385     if (m.type() > QTransform::TxTranslate)
3386 #else
3387     if (m.type() >= QTransform::TxProject)
3388 #endif
3389         return true;
3390
3391     if (pixelSize * pixelSize * qAbs(m.determinant()) >= 64 * 64)
3392         return true;
3393
3394     return false;
3395 }
3396
3397 /*!
3398     \internal
3399 */
3400 QPoint QRasterPaintEngine::coordinateOffset() const
3401 {
3402     return QPoint(0, 0);
3403 }
3404
3405 /*!
3406     Draws the given color \a spans with the specified \a color. The \a
3407     count parameter specifies the number of spans.
3408
3409     The default implementation does nothing; reimplement this function
3410     to draw the given color \a spans with the specified \a color. Note
3411     that this function \e must be reimplemented if the framebuffer is
3412     not memory-mapped.
3413
3414     \sa drawBufferSpan()
3415 */
3416 #if defined(Q_WS_QWS) && !defined(QT_NO_RASTERCALLBACKS)
3417 void QRasterPaintEngine::drawColorSpans(const QSpan *spans, int count, uint color)
3418 {
3419     Q_UNUSED(spans);
3420     Q_UNUSED(count);
3421     Q_UNUSED(color);
3422     qFatal("QRasterPaintEngine::drawColorSpans must be reimplemented on "
3423            "a non memory-mapped device");
3424 }
3425
3426 /*!
3427     \fn void QRasterPaintEngine::drawBufferSpan(const uint *buffer, int size, int x, int y, int length, uint alpha)
3428
3429     Draws the given \a buffer.
3430
3431     The default implementation does nothing; reimplement this function
3432     to draw a buffer that contains more than one color. Note that this
3433     function \e must be reimplemented if the framebuffer is not
3434     memory-mapped.
3435
3436     The \a size parameter specifies the total size of the given \a
3437     buffer, while the \a length parameter specifies the number of
3438     pixels to draw. The buffer's position is given by (\a x, \a
3439     y). The provided \a alpha value is added to each pixel in the
3440     buffer when drawing.
3441
3442     \sa drawColorSpans()
3443 */
3444 void QRasterPaintEngine::drawBufferSpan(const uint *buffer, int bufsize,
3445                                         int x, int y, int length, uint const_alpha)
3446 {
3447     Q_UNUSED(buffer);
3448     Q_UNUSED(bufsize);
3449     Q_UNUSED(x);
3450     Q_UNUSED(y);
3451     Q_UNUSED(length);
3452     Q_UNUSED(const_alpha);
3453     qFatal("QRasterPaintEngine::drawBufferSpan must be reimplemented on "
3454            "a non memory-mapped device");
3455 }
3456 #endif // Q_WS_QWS
3457
3458 void QRasterPaintEngine::drawBitmap(const QPointF &pos, const QImage &image, QSpanData *fg)
3459 {
3460     Q_ASSERT(fg);
3461     if (!fg->blend)
3462         return;
3463     Q_D(QRasterPaintEngine);
3464
3465     Q_ASSERT(image.depth() == 1);
3466
3467     const int spanCount = 256;
3468     QT_FT_Span spans[spanCount];
3469     int n = 0;
3470
3471     // Boundaries
3472     int w = image.width();
3473     int h = image.height();
3474     int ymax = qMin(qRound(pos.y() + h), d->rasterBuffer->height());
3475     int ymin = qMax(qRound(pos.y()), 0);
3476     int xmax = qMin(qRound(pos.x() + w), d->rasterBuffer->width());
3477     int xmin = qMax(qRound(pos.x()), 0);
3478
3479     int x_offset = xmin - qRound(pos.x());
3480
3481     QImage::Format format = image.format();
3482     for (int y = ymin; y < ymax; ++y) {
3483         const uchar *src = image.scanLine(y - qRound(pos.y()));
3484         if (format == QImage::Format_MonoLSB) {
3485             for (int x = 0; x < xmax - xmin; ++x) {
3486                 int src_x = x + x_offset;
3487                 uchar pixel = src[src_x >> 3];
3488                 if (!pixel) {
3489                     x += 7 - (src_x%8);
3490                     continue;
3491                 }
3492                 if (pixel & (0x1 << (src_x & 7))) {
3493                     spans[n].x = xmin + x;
3494                     spans[n].y = y;
3495                     spans[n].coverage = 255;
3496                     int len = 1;
3497                     while (src_x < w-1 && src[(src_x+1) >> 3] & (0x1 << ((src_x+1) & 7))) {
3498                         ++src_x;
3499                         ++len;
3500                     }
3501                     spans[n].len = ((len + spans[n].x) > xmax) ? (xmax - spans[n].x) : len;
3502                     x += len;
3503                     ++n;
3504                     if (n == spanCount) {
3505                         fg->blend(n, spans, fg);
3506                         n = 0;
3507                     }
3508                 }
3509             }
3510         } else {
3511             for (int x = 0; x < xmax - xmin; ++x) {
3512                 int src_x = x + x_offset;
3513                 uchar pixel = src[src_x >> 3];
3514                 if (!pixel) {
3515                     x += 7 - (src_x%8);
3516                     continue;
3517                 }
3518                 if (pixel & (0x80 >> (x & 7))) {
3519                     spans[n].x = xmin + x;
3520                     spans[n].y = y;
3521                     spans[n].coverage = 255;
3522                     int len = 1;
3523                     while (src_x < w-1 && src[(src_x+1) >> 3] & (0x80 >> ((src_x+1) & 7))) {
3524                         ++src_x;
3525                         ++len;
3526                     }
3527                     spans[n].len = ((len + spans[n].x) > xmax) ? (xmax - spans[n].x) : len;
3528                     x += len;
3529                     ++n;
3530                     if (n == spanCount) {
3531                         fg->blend(n, spans, fg);
3532                         n = 0;
3533                     }
3534                 }
3535             }
3536         }
3537     }
3538     if (n) {
3539         fg->blend(n, spans, fg);
3540         n = 0;
3541     }
3542 }
3543
3544 /*!
3545     \enum QRasterPaintEngine::ClipType
3546     \internal
3547
3548     \value RectClip Indicates that the currently set clip is a single rectangle.
3549     \value ComplexClip Indicates that the currently set clip is a combination of several shapes.
3550 */
3551
3552 /*!
3553     \internal
3554     Returns the type of the clip currently set.
3555 */
3556 QRasterPaintEngine::ClipType QRasterPaintEngine::clipType() const
3557 {
3558     Q_D(const QRasterPaintEngine);
3559
3560     const QClipData *clip = d->clip();
3561     if (!clip || clip->hasRectClip)
3562         return RectClip;
3563     else
3564         return ComplexClip;
3565 }
3566
3567 /*!
3568     \internal
3569     Returns the bounding rect of the currently set clip.
3570 */
3571 QRect QRasterPaintEngine::clipBoundingRect() const
3572 {
3573     Q_D(const QRasterPaintEngine);
3574
3575     const QClipData *clip = d->clip();
3576
3577     if (!clip)
3578         return d->deviceRect;
3579
3580     if (clip->hasRectClip)
3581         return clip->clipRect;
3582
3583     return QRect(clip->xmin, clip->ymin, clip->xmax - clip->xmin, clip->ymax - clip->ymin);
3584 }
3585
3586 static void qt_merge_clip(const QClipData *c1, const QClipData *c2, QClipData *result)
3587 {
3588     Q_ASSERT(c1->clipSpanHeight == c2->clipSpanHeight && c1->clipSpanHeight == result->clipSpanHeight);
3589
3590     QVarLengthArray<short, 4096> buffer;
3591
3592     QClipData::ClipLine *c1ClipLines = const_cast<QClipData *>(c1)->clipLines();
3593     QClipData::ClipLine *c2ClipLines = const_cast<QClipData *>(c2)->clipLines();
3594     result->initialize();
3595
3596     for (int y = 0; y < c1->clipSpanHeight; ++y) {
3597         const QSpan *c1_spans = c1ClipLines[y].spans;
3598         int c1_count = c1ClipLines[y].count;
3599         const QSpan *c2_spans = c2ClipLines[y].spans;
3600         int c2_count = c2ClipLines[y].count;
3601
3602         if (c1_count == 0 && c2_count == 0)
3603             continue;
3604         if (c1_count == 0) {
3605             result->appendSpans(c2_spans, c2_count);
3606             continue;
3607         } else if (c2_count == 0) {
3608             result->appendSpans(c1_spans, c1_count);
3609             continue;
3610         }
3611
3612         // we need to merge the two
3613
3614         // find required length
3615         int max = qMax(c1_spans[c1_count - 1].x + c1_spans[c1_count - 1].len,
3616                 c2_spans[c2_count - 1].x + c2_spans[c2_count - 1].len);
3617         buffer.resize(max);
3618         memset(buffer.data(), 0, buffer.size() * sizeof(short));
3619
3620         // Fill with old spans.
3621         for (int i = 0; i < c1_count; ++i) {
3622             const QSpan *cs = c1_spans + i;
3623             for (int j=cs->x; j<cs->x + cs->len; ++j)
3624                 buffer[j] = cs->coverage;
3625         }
3626
3627         // Fill with new spans
3628         for (int i = 0; i < c2_count; ++i) {
3629             const QSpan *cs = c2_spans + i;
3630             for (int j = cs->x; j < cs->x + cs->len; ++j) {
3631                 buffer[j] += cs->coverage;
3632                 if (buffer[j] > 255)
3633                     buffer[j] = 255;
3634             }
3635         }
3636
3637         int x = 0;
3638         while (x<max) {
3639
3640             // Skip to next span
3641             while (x < max && buffer[x] == 0) ++x;
3642             if (x >= max) break;
3643
3644             int sx = x;
3645             int coverage = buffer[x];
3646
3647             // Find length of span
3648             while (x < max && buffer[x] == coverage)
3649                 ++x;
3650
3651             result->appendSpan(sx, x - sx, y, coverage);
3652         }
3653     }
3654 }
3655
3656 void QRasterPaintEnginePrivate::initializeRasterizer(QSpanData *data)
3657 {
3658     Q_Q(QRasterPaintEngine);
3659     QRasterPaintEngineState *s = q->state();
3660
3661     rasterizer->setAntialiased(s->flags.antialiased);
3662
3663     QRect clipRect(deviceRect);
3664     ProcessSpans blend;
3665     // ### get from optimized rectbased QClipData
3666
3667     const QClipData *c = clip();
3668     if (c) {
3669         const QRect r(QPoint(c->xmin, c->ymin),
3670                       QSize(c->xmax - c->xmin, c->ymax - c->ymin));
3671         clipRect = clipRect.intersected(r);
3672         blend = data->blend;
3673     } else {
3674         blend = data->unclipped_blend;
3675     }
3676
3677     rasterizer->setClipRect(clipRect);
3678     rasterizer->initialize(blend, data);
3679 }
3680
3681 void QRasterPaintEnginePrivate::rasterize(QT_FT_Outline *outline,
3682                                           ProcessSpans callback,
3683                                           QSpanData *spanData, QRasterBuffer *rasterBuffer)
3684 {
3685     if (!callback || !outline)
3686         return;
3687
3688     Q_Q(QRasterPaintEngine);
3689     QRasterPaintEngineState *s = q->state();
3690
3691     if (!s->flags.antialiased) {
3692         initializeRasterizer(spanData);
3693
3694         const Qt::FillRule fillRule = outline->flags == QT_FT_OUTLINE_NONE
3695                                       ? Qt::WindingFill
3696                                       : Qt::OddEvenFill;
3697
3698         rasterizer->rasterize(outline, fillRule);
3699         return;
3700     }
3701
3702     rasterize(outline, callback, (void *)spanData, rasterBuffer);
3703 }
3704
3705 extern "C" {
3706     int q_gray_rendered_spans(QT_FT_Raster raster);
3707 }
3708
3709 void QRasterPaintEnginePrivate::rasterize(QT_FT_Outline *outline,
3710                                           ProcessSpans callback,
3711                                           void *userData, QRasterBuffer *)
3712 {
3713     if (!callback || !outline)
3714         return;
3715
3716     Q_Q(QRasterPaintEngine);
3717     QRasterPaintEngineState *s = q->state();
3718
3719     if (!s->flags.antialiased) {
3720         rasterizer->setAntialiased(s->flags.antialiased);
3721         rasterizer->setClipRect(deviceRect);
3722         rasterizer->initialize(callback, userData);
3723
3724         const Qt::FillRule fillRule = outline->flags == QT_FT_OUTLINE_NONE
3725                                       ? Qt::WindingFill
3726                                       : Qt::OddEvenFill;
3727
3728         rasterizer->rasterize(outline, fillRule);
3729         return;
3730     }
3731
3732     // Initial size for raster pool is MINIMUM_POOL_SIZE so as to
3733     // minimize memory reallocations. However if initial size for
3734     // raster pool is changed for lower value, reallocations will
3735     // occur normally.
3736     const int rasterPoolInitialSize = MINIMUM_POOL_SIZE;
3737     int rasterPoolSize = rasterPoolInitialSize;
3738     unsigned char *rasterPoolBase;
3739 #if defined(Q_WS_WIN64)
3740     rasterPoolBase =
3741         // We make use of setjmp and longjmp in qgrayraster.c which requires
3742         // 16-byte alignment, hence we hardcode this requirement here..
3743         (unsigned char *) _aligned_malloc(rasterPoolSize, sizeof(void*) * 2);
3744 #else
3745     unsigned char rasterPoolOnStack[rasterPoolInitialSize];
3746     rasterPoolBase = rasterPoolOnStack;
3747 #endif
3748     Q_CHECK_PTR(rasterPoolBase);
3749
3750     qt_ft_grays_raster.raster_reset(*grayRaster.data(), rasterPoolBase, rasterPoolSize);
3751
3752     void *data = userData;
3753
3754     QT_FT_BBox clip_box = { deviceRect.x(),
3755                             deviceRect.y(),
3756                             deviceRect.x() + deviceRect.width(),
3757                             deviceRect.y() + deviceRect.height() };
3758
3759     QT_FT_Raster_Params rasterParams;
3760     rasterParams.target = 0;
3761     rasterParams.source = outline;
3762     rasterParams.flags = QT_FT_RASTER_FLAG_CLIP;
3763     rasterParams.gray_spans = 0;
3764     rasterParams.black_spans = 0;
3765     rasterParams.bit_test = 0;
3766     rasterParams.bit_set = 0;
3767     rasterParams.user = data;
3768     rasterParams.clip_box = clip_box;
3769
3770     bool done = false;
3771     int error;
3772
3773     int rendered_spans = 0;
3774
3775     while (!done) {
3776
3777         rasterParams.flags |= (QT_FT_RASTER_FLAG_AA | QT_FT_RASTER_FLAG_DIRECT);
3778         rasterParams.gray_spans = callback;
3779         rasterParams.skip_spans = rendered_spans;
3780         error = qt_ft_grays_raster.raster_render(*grayRaster.data(), &rasterParams);
3781
3782         // Out of memory, reallocate some more and try again...
3783         if (error == -6) { // ErrRaster_OutOfMemory from qgrayraster.c
3784             int new_size = rasterPoolSize * 2;
3785             if (new_size > 1024 * 1024) {
3786                 qWarning("QPainter: Rasterization of primitive failed");
3787                 break;
3788             }
3789
3790             rendered_spans += q_gray_rendered_spans(*grayRaster.data());
3791
3792 #if defined(Q_WS_WIN64)
3793             _aligned_free(rasterPoolBase);
3794 #else
3795             if (rasterPoolBase != rasterPoolOnStack) // initially on the stack
3796                 free(rasterPoolBase);
3797 #endif
3798
3799             rasterPoolSize = new_size;
3800             rasterPoolBase =
3801 #if defined(Q_WS_WIN64)
3802                 // We make use of setjmp and longjmp in qgrayraster.c which requires
3803                 // 16-byte alignment, hence we hardcode this requirement here..
3804                 (unsigned char *) _aligned_malloc(rasterPoolSize, sizeof(void*) * 2);
3805 #else
3806                 (unsigned char *) malloc(rasterPoolSize);
3807 #endif
3808             Q_CHECK_PTR(rasterPoolBase); // note: we just freed the old rasterPoolBase. I hope it's not fatal.
3809
3810             qt_ft_grays_raster.raster_done(*grayRaster.data());
3811             qt_ft_grays_raster.raster_new(grayRaster.data());
3812             qt_ft_grays_raster.raster_reset(*grayRaster.data(), rasterPoolBase, rasterPoolSize);
3813         } else {
3814             done = true;
3815         }
3816     }
3817
3818 #if defined(Q_WS_WIN64)
3819     _aligned_free(rasterPoolBase);
3820 #else
3821     if (rasterPoolBase != rasterPoolOnStack) // initially on the stack
3822         free(rasterPoolBase);
3823 #endif
3824 }
3825
3826 void QRasterPaintEnginePrivate::recalculateFastImages()
3827 {
3828     Q_Q(QRasterPaintEngine);
3829     QRasterPaintEngineState *s = q->state();
3830
3831     s->flags.fast_images = !(s->renderHints & QPainter::SmoothPixmapTransform)
3832                            && s->matrix.type() <= QTransform::TxShear;
3833 }
3834
3835 bool QRasterPaintEnginePrivate::canUseFastImageBlending(QPainter::CompositionMode mode, const QImage &image) const
3836 {
3837     Q_Q(const QRasterPaintEngine);
3838     const QRasterPaintEngineState *s = q->state();
3839
3840     return s->flags.fast_images
3841            && (mode == QPainter::CompositionMode_SourceOver
3842                || (mode == QPainter::CompositionMode_Source
3843                    && !image.hasAlphaChannel()));
3844 }
3845
3846 QImage QRasterBuffer::colorizeBitmap(const QImage &image, const QColor &color)
3847 {
3848     Q_ASSERT(image.depth() == 1);
3849
3850     QImage sourceImage = image.convertToFormat(QImage::Format_MonoLSB);
3851     QImage dest = QImage(sourceImage.size(), QImage::Format_ARGB32_Premultiplied);
3852
3853     QRgb fg = PREMUL(color.rgba());
3854     QRgb bg = 0;
3855
3856     int height = sourceImage.height();
3857     int width = sourceImage.width();
3858     for (int y=0; y<height; ++y) {
3859         uchar *source = sourceImage.scanLine(y);
3860         QRgb *target = reinterpret_cast<QRgb *>(dest.scanLine(y));
3861         if (!source || !target)
3862             QT_THROW(std::bad_alloc()); // we must have run out of memory
3863         for (int x=0; x < width; ++x)
3864             target[x] = (source[x>>3] >> (x&7)) & 1 ? fg : bg;
3865     }
3866     return dest;
3867 }
3868
3869 QRasterBuffer::~QRasterBuffer()
3870 {
3871 }
3872
3873 void QRasterBuffer::init()
3874 {
3875     compositionMode = QPainter::CompositionMode_SourceOver;
3876     monoDestinationWithClut = false;
3877     destColor0 = 0;
3878     destColor1 = 0;
3879 }
3880
3881 QImage::Format QRasterBuffer::prepare(QImage *image)
3882 {
3883     m_buffer = (uchar *)image->bits();
3884     m_width = qMin(QT_RASTER_COORD_LIMIT, image->width());
3885     m_height = qMin(QT_RASTER_COORD_LIMIT, image->height());
3886     bytes_per_pixel = image->depth()/8;
3887     bytes_per_line = image->bytesPerLine();
3888
3889     format = image->format();
3890     drawHelper = qDrawHelper + format;
3891     if (image->depth() == 1 && image->colorTable().size() == 2) {
3892         monoDestinationWithClut = true;
3893         destColor0 = PREMUL(image->colorTable()[0]);
3894         destColor1 = PREMUL(image->colorTable()[1]);
3895     }
3896
3897     return format;
3898 }
3899
3900 void QRasterBuffer::resetBuffer(int val)
3901 {
3902     memset(m_buffer, val, m_height*bytes_per_line);
3903 }
3904
3905
3906 #if defined(Q_WS_QWS)
3907 void QRasterBuffer::prepare(QCustomRasterPaintDevice *device)
3908 {
3909     m_buffer = reinterpret_cast<uchar*>(device->memory());
3910     m_width = qMin(QT_RASTER_COORD_LIMIT, device->width());
3911     m_height = qMin(QT_RASTER_COORD_LIMIT, device->height());
3912     bytes_per_pixel = device->depth() / 8;
3913     bytes_per_line = device->bytesPerLine();
3914     format = device->format();
3915 #ifndef QT_NO_RASTERCALLBACKS
3916     if (!m_buffer)
3917         drawHelper = qDrawHelperCallback + format;
3918     else
3919 #endif
3920         drawHelper = qDrawHelper + format;
3921 }
3922
3923 int QCustomRasterPaintDevice::metric(PaintDeviceMetric m) const
3924 {
3925     switch (m) {
3926     case PdmWidth:
3927         return widget->frameGeometry().width();
3928     case PdmHeight:
3929         return widget->frameGeometry().height();
3930     default:
3931         break;
3932     }
3933
3934     return qt_paint_device_metric(widget, m);
3935 }
3936
3937 int QCustomRasterPaintDevice::bytesPerLine() const
3938 {
3939     return (width() * depth() + 7) / 8;
3940 }
3941
3942 #elif defined(Q_OS_SYMBIAN)
3943
3944 void QRasterBuffer::prepareBuffer(int /* width */, int /* height */)
3945 {
3946 }
3947
3948 #endif // Q_OS_SYMBIAN
3949
3950 /*!
3951     \class QCustomRasterPaintDevice
3952     \preliminary
3953     \ingroup qws
3954     \since 4.2
3955
3956     \brief The QCustomRasterPaintDevice class is provided to activate
3957     hardware accelerated paint engines in Qt for Embedded Linux.
3958
3959     Note that this class is only available in \l{Qt for Embedded Linux}.
3960
3961     In \l{Qt for Embedded Linux}, painting is a pure software
3962     implementation. But starting with Qt 4.2, it is
3963     possible to add an accelerated graphics driver to take advantage
3964     of available hardware resources.
3965
3966     Hardware acceleration is accomplished by creating a custom screen
3967     driver, accelerating the copying from memory to the screen, and
3968     implementing a custom paint engine accelerating the various
3969     painting operations. Then a custom paint device (derived from the
3970     QCustomRasterPaintDevice class) and a custom window surface
3971     (derived from QWSWindowSurface) must be implemented to make
3972     \l{Qt for Embedded Linux} aware of the accelerated driver.
3973
3974     See the \l {Adding an Accelerated Graphics Driver to Qt for Embedded Linux}
3975     documentation for details.
3976
3977     \sa QRasterPaintEngine, QPaintDevice
3978 */
3979
3980 /*!
3981     \fn QCustomRasterPaintDevice::QCustomRasterPaintDevice(QWidget *widget)
3982
3983     Constructs a custom raster based paint device for the given
3984     top-level \a widget.
3985 */
3986
3987 /*!
3988     \fn int QCustomRasterPaintDevice::bytesPerLine() const
3989
3990     Returns the number of bytes per line in the framebuffer. Note that
3991     this number might be larger than the framebuffer width.
3992 */
3993
3994 /*!
3995     \fn int QCustomRasterPaintDevice::devType() const
3996     \internal
3997 */
3998
3999 /*!
4000     \fn QImage::Format QCustomRasterPaintDevice::format() const
4001
4002     Returns the format of the device's memory buffet.
4003
4004     The default format is QImage::Format_ARGB32_Premultiplied. The
4005     only other valid format is QImage::Format_RGB16.
4006 */
4007
4008 /*!
4009     \fn void * QCustomRasterPaintDevice::memory () const
4010
4011     Returns a pointer to the paint device's memory buffer, or 0 if no
4012     such buffer exists.
4013 */
4014
4015 /*!
4016     \fn int QCustomRasterPaintDevice::metric ( PaintDeviceMetric m ) const
4017     \reimp
4018 */
4019
4020 /*!
4021     \fn QSize QCustomRasterPaintDevice::size () const
4022     \internal
4023 */
4024
4025
4026 QClipData::QClipData(int height)
4027 {
4028     clipSpanHeight = height;
4029     m_clipLines = 0;
4030
4031     allocated = 0;
4032     m_spans = 0;
4033     xmin = xmax = ymin = ymax = 0;
4034     count = 0;
4035
4036     enabled = true;
4037     hasRectClip = hasRegionClip = false;
4038 }
4039
4040 QClipData::~QClipData()
4041 {
4042     if (m_clipLines)
4043         free(m_clipLines);
4044     if (m_spans)
4045         free(m_spans);
4046 }
4047
4048 void QClipData::initialize()
4049 {
4050     if (m_spans)
4051         return;
4052
4053     if (!m_clipLines)
4054         m_clipLines = (ClipLine *)calloc(sizeof(ClipLine), clipSpanHeight);
4055
4056     Q_CHECK_PTR(m_clipLines);
4057     QT_TRY {
4058         m_spans = (QSpan *)malloc(clipSpanHeight*sizeof(QSpan));
4059         allocated = clipSpanHeight;
4060         Q_CHECK_PTR(m_spans);
4061
4062         QT_TRY {
4063             if (hasRectClip) {
4064                 int y = 0;
4065                 while (y < ymin) {
4066                     m_clipLines[y].spans = 0;
4067                     m_clipLines[y].count = 0;
4068                     ++y;
4069                 }
4070
4071                 const int len = clipRect.width();
4072                 count = 0;
4073                 while (y < ymax) {
4074                     QSpan *span = m_spans + count;
4075                     span->x = xmin;
4076                     span->len = len;
4077                     span->y = y;
4078                     span->coverage = 255;
4079                     ++count;
4080
4081                     m_clipLines[y].spans = span;
4082                     m_clipLines[y].count = 1;
4083                     ++y;
4084                 }
4085
4086                 while (y < clipSpanHeight) {
4087                     m_clipLines[y].spans = 0;
4088                     m_clipLines[y].count = 0;
4089                     ++y;
4090                 }
4091             } else if (hasRegionClip) {
4092
4093                 const QVector<QRect> rects = clipRegion.rects();
4094                 const int numRects = rects.size();
4095
4096                 { // resize
4097                     const int maxSpans = (ymax - ymin) * numRects;
4098                     if (maxSpans > allocated) {
4099                         m_spans = q_check_ptr((QSpan *)realloc(m_spans, maxSpans * sizeof(QSpan)));
4100                         allocated = maxSpans;
4101                     }
4102                 }
4103
4104                 int y = 0;
4105                 int firstInBand = 0;
4106                 count = 0;
4107                 while (firstInBand < numRects) {
4108                     const int currMinY = rects.at(firstInBand).y();
4109                     const int currMaxY = currMinY + rects.at(firstInBand).height();
4110
4111                     while (y < currMinY) {
4112                         m_clipLines[y].spans = 0;
4113                         m_clipLines[y].count = 0;
4114                         ++y;
4115                     }
4116
4117                     int lastInBand = firstInBand;
4118                     while (lastInBand + 1 < numRects && rects.at(lastInBand+1).top() == y)
4119                         ++lastInBand;
4120
4121                     while (y < currMaxY) {
4122
4123                         m_clipLines[y].spans = m_spans + count;
4124                         m_clipLines[y].count = lastInBand - firstInBand + 1;
4125
4126                         for (int r = firstInBand; r <= lastInBand; ++r) {
4127                             const QRect &currRect = rects.at(r);
4128                             QSpan *span = m_spans + count;
4129                             span->x = currRect.x();
4130                             span->len = currRect.width();
4131                             span->y = y;
4132                             span->coverage = 255;
4133                             ++count;
4134                         }
4135                         ++y;
4136                     }
4137
4138                     firstInBand = lastInBand + 1;
4139                 }
4140
4141                 Q_ASSERT(count <= allocated);
4142
4143                 while (y < clipSpanHeight) {
4144                     m_clipLines[y].spans = 0;
4145                     m_clipLines[y].count = 0;
4146                     ++y;
4147                 }
4148
4149             }
4150         } QT_CATCH(...) {
4151             free(m_spans); // have to free m_spans again or someone might think that we were successfully initialized.
4152             m_spans = 0;
4153             QT_RETHROW;
4154         }
4155     } QT_CATCH(...) {
4156         free(m_clipLines); // same for clipLines
4157         m_clipLines = 0;
4158         QT_RETHROW;
4159     }
4160 }
4161
4162 void QClipData::fixup()
4163 {
4164     Q_ASSERT(m_spans);
4165
4166     if (count == 0) {
4167         ymin = ymax = xmin = xmax = 0;
4168         return;
4169     }
4170
4171     int y = -1;
4172     ymin = m_spans[0].y;
4173     ymax = m_spans[count-1].y + 1;
4174     xmin = INT_MAX;
4175     xmax = 0;
4176
4177     const int firstLeft = m_spans[0].x;
4178     const int firstRight = m_spans[0].x + m_spans[0].len;
4179     bool isRect = true;
4180
4181     for (int i = 0; i < count; ++i) {
4182         QT_FT_Span_& span = m_spans[i];
4183
4184         if (span.y != y) {
4185             if (span.y != y + 1 && y != -1)
4186                 isRect = false;
4187             y = span.y;
4188             m_clipLines[y].spans = &span;
4189             m_clipLines[y].count = 1;
4190         } else
4191             ++m_clipLines[y].count;
4192
4193         const int spanLeft = span.x;
4194         const int spanRight = spanLeft + span.len;
4195
4196         if (spanLeft < xmin)
4197             xmin = spanLeft;
4198
4199         if (spanRight > xmax)
4200             xmax = spanRight;
4201
4202         if (spanLeft != firstLeft || spanRight != firstRight)
4203             isRect = false;
4204     }
4205
4206     if (isRect) {
4207         hasRectClip = true;
4208         clipRect.setRect(xmin, ymin, xmax - xmin, ymax - ymin);
4209     }
4210 }
4211
4212 /*
4213     Convert \a rect to clip spans.
4214  */
4215 void QClipData::setClipRect(const QRect &rect)
4216 {
4217     if (hasRectClip && rect == clipRect)
4218         return;
4219
4220 //    qDebug() << "setClipRect" << clipSpanHeight << count << allocated << rect;
4221     hasRectClip = true;
4222     hasRegionClip = false;
4223     clipRect = rect;
4224
4225     xmin = rect.x();
4226     xmax = rect.x() + rect.width();
4227     ymin = qMin(rect.y(), clipSpanHeight);
4228     ymax = qMin(rect.y() + rect.height(), clipSpanHeight);
4229
4230     if (m_spans) {
4231         free(m_spans);
4232         m_spans = 0;
4233     }
4234
4235 //    qDebug() << xmin << xmax << ymin << ymax;
4236 }
4237
4238 /*
4239     Convert \a region to clip spans.
4240  */
4241 void QClipData::setClipRegion(const QRegion &region)
4242 {
4243     if (region.rectCount() == 1) {
4244         setClipRect(region.rects().at(0));
4245         return;
4246     }
4247
4248     hasRegionClip = true;
4249     hasRectClip = false;
4250     clipRegion = region;
4251
4252     { // set bounding rect
4253         const QRect rect = region.boundingRect();
4254         xmin = rect.x();
4255         xmax = rect.x() + rect.width();
4256         ymin = rect.y();
4257         ymax = rect.y() + rect.height();
4258     }
4259
4260     if (m_spans) {
4261         free(m_spans);
4262         m_spans = 0;
4263     }
4264
4265 }
4266
4267 /*!
4268     \internal
4269     spans must be sorted on y
4270 */
4271 static const QSpan *qt_intersect_spans(const QClipData *clip, int *currentClip,
4272                                        const QSpan *spans, const QSpan *end,
4273                                        QSpan **outSpans, int available)
4274 {
4275     const_cast<QClipData *>(clip)->initialize();
4276
4277     QSpan *out = *outSpans;
4278
4279     const QSpan *clipSpans = clip->m_spans + *currentClip;
4280     const QSpan *clipEnd = clip->m_spans + clip->count;
4281
4282     while (available && spans < end ) {
4283         if (clipSpans >= clipEnd) {
4284             spans = end;
4285             break;
4286         }
4287         if (clipSpans->y > spans->y) {
4288             ++spans;
4289             continue;
4290         }
4291         if (spans->y != clipSpans->y) {
4292             if (spans->y < clip->count && clip->m_clipLines[spans->y].spans)
4293                 clipSpans = clip->m_clipLines[spans->y].spans;
4294             else
4295                 ++clipSpans;
4296             continue;
4297         }
4298         Q_ASSERT(spans->y == clipSpans->y);
4299
4300         int sx1 = spans->x;
4301         int sx2 = sx1 + spans->len;
4302         int cx1 = clipSpans->x;
4303         int cx2 = cx1 + clipSpans->len;
4304
4305         if (cx1 < sx1 && cx2 < sx1) {
4306             ++clipSpans;
4307             continue;
4308         } else if (sx1 < cx1 && sx2 < cx1) {
4309             ++spans;
4310             continue;
4311         }
4312         int x = qMax(sx1, cx1);
4313         int len = qMin(sx2, cx2) - x;
4314         if (len) {
4315             out->x = qMax(sx1, cx1);
4316             out->len = qMin(sx2, cx2) - out->x;
4317             out->y = spans->y;
4318             out->coverage = qt_div_255(spans->coverage * clipSpans->coverage);
4319             ++out;
4320             --available;
4321         }
4322         if (sx2 < cx2) {
4323             ++spans;
4324         } else {
4325             ++clipSpans;
4326         }
4327     }
4328
4329     *outSpans = out;
4330     *currentClip = clipSpans - clip->m_spans;
4331     return spans;
4332 }
4333
4334 static void qt_span_fill_clipped(int spanCount, const QSpan *spans, void *userData)
4335 {
4336 //     qDebug() << "qt_span_fill_clipped" << spanCount;
4337     QSpanData *fillData = reinterpret_cast<QSpanData *>(userData);
4338
4339     Q_ASSERT(fillData->blend && fillData->unclipped_blend);
4340
4341     const int NSPANS = 256;
4342     QSpan cspans[NSPANS];
4343     int currentClip = 0;
4344     const QSpan *end = spans + spanCount;
4345     while (spans < end) {
4346         QSpan *clipped = cspans;
4347         spans = qt_intersect_spans(fillData->clip, &currentClip, spans, end, &clipped, NSPANS);
4348 //         qDebug() << "processed " << spanCount - (end - spans) << "clipped" << clipped-cspans
4349 //                  << "span:" << cspans->x << cspans->y << cspans->len << spans->coverage;
4350
4351         if (clipped - cspans)
4352             fillData->unclipped_blend(clipped - cspans, cspans, fillData);
4353     }
4354 }
4355
4356 /*
4357     \internal
4358     Clip spans to \a{clip}-rectangle.
4359     Returns number of unclipped spans
4360 */
4361 static int qt_intersect_spans(QT_FT_Span *spans, int numSpans,
4362                               const QRect &clip)
4363 {
4364     const short minx = clip.left();
4365     const short miny = clip.top();
4366     const short maxx = clip.right();
4367     const short maxy = clip.bottom();
4368
4369     int n = 0;
4370     for (int i = 0; i < numSpans; ++i) {
4371         if (spans[i].y > maxy)
4372             break;
4373         if (spans[i].y < miny
4374             || spans[i].x > maxx
4375             || spans[i].x + spans[i].len <= minx) {
4376             continue;
4377         }
4378         if (spans[i].x < minx) {
4379             spans[n].len = qMin(spans[i].len - (minx - spans[i].x), maxx - minx + 1);
4380             spans[n].x = minx;
4381         } else {
4382             spans[n].x = spans[i].x;
4383             spans[n].len = qMin(spans[i].len, ushort(maxx - spans[n].x + 1));
4384         }
4385         if (spans[n].len == 0)
4386             continue;
4387         spans[n].y = spans[i].y;
4388         spans[n].coverage = spans[i].coverage;
4389         ++n;
4390     }
4391     return n;
4392 }
4393
4394
4395 static void qt_span_fill_clipRect(int count, const QSpan *spans,
4396                                   void *userData)
4397 {
4398     QSpanData *fillData = reinterpret_cast<QSpanData *>(userData);
4399     Q_ASSERT(fillData->blend && fillData->unclipped_blend);
4400
4401     Q_ASSERT(fillData->clip);
4402     Q_ASSERT(!fillData->clip->clipRect.isEmpty());
4403
4404     // hw: check if this const_cast<> is safe!!!
4405     count = qt_intersect_spans(const_cast<QSpan*>(spans), count,
4406                                fillData->clip->clipRect);
4407     if (count > 0)
4408         fillData->unclipped_blend(count, spans, fillData);
4409 }
4410
4411 static void qt_span_clip(int count, const QSpan *spans, void *userData)
4412 {
4413     ClipData *clipData = reinterpret_cast<ClipData *>(userData);
4414
4415 //     qDebug() << " qt_span_clip: " << count << clipData->operation;
4416 //     for (int i = 0; i < qMin(count, 10); ++i) {
4417 //         qDebug() << "    " << spans[i].x << spans[i].y << spans[i].len << spans[i].coverage;
4418 //     }
4419
4420     switch (clipData->operation) {
4421
4422     case Qt::IntersectClip:
4423         {
4424             QClipData *newClip = clipData->newClip;
4425             newClip->initialize();
4426
4427             int currentClip = 0;
4428             const QSpan *end = spans + count;
4429             while (spans < end) {
4430                 QSpan *newspans = newClip->m_spans + newClip->count;
4431                 spans = qt_intersect_spans(clipData->oldClip, &currentClip, spans, end,
4432                                            &newspans, newClip->allocated - newClip->count);
4433                 newClip->count = newspans - newClip->m_spans;
4434                 if (spans < end) {
4435                     newClip->m_spans = q_check_ptr((QSpan *)realloc(newClip->m_spans, newClip->allocated*2*sizeof(QSpan)));
4436                     newClip->allocated *= 2;
4437                 }
4438             }
4439         }
4440         break;
4441
4442     case Qt::UniteClip:
4443     case Qt::ReplaceClip:
4444         clipData->newClip->appendSpans(spans, count);
4445         break;
4446     case Qt::NoClip:
4447         break;
4448     }
4449 }
4450
4451 #ifndef QT_NO_DEBUG
4452 QImage QRasterBuffer::bufferImage() const
4453 {
4454     QImage image(m_width, m_height, QImage::Format_ARGB32_Premultiplied);
4455
4456     for (int y = 0; y < m_height; ++y) {
4457         uint *span = (uint *)const_cast<QRasterBuffer *>(this)->scanLine(y);
4458
4459         for (int x=0; x<m_width; ++x) {
4460             uint argb = span[x];
4461             image.setPixel(x, y, argb);
4462         }
4463     }
4464     return image;
4465 }
4466 #endif
4467
4468
4469 void QRasterBuffer::flushToARGBImage(QImage *target) const
4470 {
4471     int w = qMin(m_width, target->width());
4472     int h = qMin(m_height, target->height());
4473
4474     for (int y=0; y<h; ++y) {
4475         uint *sourceLine = (uint *)const_cast<QRasterBuffer *>(this)->scanLine(y);
4476         QRgb *dest = (QRgb *) target->scanLine(y);
4477         for (int x=0; x<w; ++x) {
4478             QRgb pixel = sourceLine[x];
4479             int alpha = qAlpha(pixel);
4480             if (!alpha) {
4481                 dest[x] = 0;
4482             } else {
4483                 dest[x] = (alpha << 24)
4484                         | ((255*qRed(pixel)/alpha) << 16)
4485                         | ((255*qGreen(pixel)/alpha) << 8)
4486                         | ((255*qBlue(pixel)/alpha) << 0);
4487             }
4488         }
4489     }
4490 }
4491
4492
4493 class QGradientCache
4494 {
4495     struct CacheInfo
4496     {
4497         inline CacheInfo(QGradientStops s, int op, QGradient::InterpolationMode mode) :
4498             stops(s), opacity(op), interpolationMode(mode) {}
4499         uint buffer[GRADIENT_STOPTABLE_SIZE];
4500         QGradientStops stops;
4501         int opacity;
4502         QGradient::InterpolationMode interpolationMode;
4503     };
4504
4505     typedef QMultiHash<quint64, CacheInfo> QGradientColorTableHash;
4506
4507 public:
4508     inline const uint *getBuffer(const QGradient &gradient, int opacity) {
4509         quint64 hash_val = 0;
4510
4511         QGradientStops stops = gradient.stops();
4512         for (int i = 0; i < stops.size() && i <= 2; i++)
4513             hash_val += stops[i].second.rgba();
4514
4515         QMutexLocker lock(&mutex);
4516         QGradientColorTableHash::const_iterator it = cache.constFind(hash_val);
4517
4518         if (it == cache.constEnd())
4519             return addCacheElement(hash_val, gradient, opacity);
4520         else {
4521             do {
4522                 const CacheInfo &cache_info = it.value();
4523                 if (cache_info.stops == stops && cache_info.opacity == opacity && cache_info.interpolationMode == gradient.interpolationMode())
4524                     return cache_info.buffer;
4525                 ++it;
4526             } while (it != cache.constEnd() && it.key() == hash_val);
4527             // an exact match for these stops and opacity was not found, create new cache
4528             return addCacheElement(hash_val, gradient, opacity);
4529         }
4530     }
4531
4532     inline int paletteSize() const { return GRADIENT_STOPTABLE_SIZE; }
4533 protected:
4534     inline int maxCacheSize() const { return 60; }
4535     inline void generateGradientColorTable(const QGradient& g,
4536                                            uint *colorTable,
4537                                            int size, int opacity) const;
4538     uint *addCacheElement(quint64 hash_val, const QGradient &gradient, int opacity) {
4539         if (cache.size() == maxCacheSize()) {
4540             // may remove more than 1, but OK
4541             cache.erase(cache.begin() + (qrand() % maxCacheSize()));
4542         }
4543         CacheInfo cache_entry(gradient.stops(), opacity, gradient.interpolationMode());
4544         generateGradientColorTable(gradient, cache_entry.buffer, paletteSize(), opacity);
4545         return cache.insert(hash_val, cache_entry).value().buffer;
4546     }
4547
4548     QGradientColorTableHash cache;
4549     QMutex mutex;
4550 };
4551
4552 void QGradientCache::generateGradientColorTable(const QGradient& gradient, uint *colorTable, int size, int opacity) const
4553 {
4554     QGradientStops stops = gradient.stops();
4555     int stopCount = stops.count();
4556     Q_ASSERT(stopCount > 0);
4557
4558     bool colorInterpolation = (gradient.interpolationMode() == QGradient::ColorInterpolation);
4559
4560     if (stopCount == 2) {
4561         uint first_color = ARGB_COMBINE_ALPHA(stops[0].second.rgba(), opacity);
4562         uint second_color = ARGB_COMBINE_ALPHA(stops[1].second.rgba(), opacity);
4563
4564         qreal first_stop = stops[0].first;
4565         qreal second_stop = stops[1].first;
4566
4567         if (second_stop < first_stop) {
4568             qSwap(first_color, second_color);
4569             qSwap(first_stop, second_stop);
4570         }
4571
4572         if (colorInterpolation) {
4573             first_color = PREMUL(first_color);
4574             second_color = PREMUL(second_color);
4575         }
4576
4577         int first_index = qRound(first_stop * (GRADIENT_STOPTABLE_SIZE-1));
4578         int second_index = qRound(second_stop * (GRADIENT_STOPTABLE_SIZE-1));
4579
4580         uint red_first = qRed(first_color) << 16;
4581         uint green_first = qGreen(first_color) << 16;
4582         uint blue_first = qBlue(first_color) << 16;
4583         uint alpha_first = qAlpha(first_color) << 16;
4584
4585         uint red_second = qRed(second_color) << 16;
4586         uint green_second = qGreen(second_color) << 16;
4587         uint blue_second = qBlue(second_color) << 16;
4588         uint alpha_second = qAlpha(second_color) << 16;
4589
4590         int i = 0;
4591         for (; i <= qMin(GRADIENT_STOPTABLE_SIZE, first_index); ++i) {
4592             if (colorInterpolation)
4593                 colorTable[i] = first_color;
4594             else
4595                 colorTable[i] = PREMUL(first_color);
4596         }
4597
4598         if (i < second_index) {
4599             qreal reciprocal = qreal(1) / (second_index - first_index);
4600
4601             int red_delta = qRound(int(red_second - red_first) * reciprocal);
4602             int green_delta = qRound(int(green_second - green_first) * reciprocal);
4603             int blue_delta = qRound(int(blue_second - blue_first) * reciprocal);
4604             int alpha_delta = qRound(int(alpha_second - alpha_first) * reciprocal);
4605
4606             // rounding
4607             red_first += 1 << 15;
4608             green_first += 1 << 15;
4609             blue_first += 1 << 15;
4610             alpha_first += 1 << 15;
4611
4612             for (; i < qMin(GRADIENT_STOPTABLE_SIZE, second_index); ++i) {
4613                 red_first += red_delta;
4614                 green_first += green_delta;
4615                 blue_first += blue_delta;
4616                 alpha_first += alpha_delta;
4617
4618                 const uint color = ((alpha_first << 8) & 0xff000000) | (red_first & 0xff0000)
4619                                  | ((green_first >> 8) & 0xff00) | (blue_first >> 16);
4620
4621                 if (colorInterpolation)
4622                     colorTable[i] = color;
4623                 else
4624                     colorTable[i] = PREMUL(color);
4625             }
4626         }
4627
4628         for (; i < GRADIENT_STOPTABLE_SIZE; ++i) {
4629             if (colorInterpolation)
4630                 colorTable[i] = second_color;
4631             else
4632                 colorTable[i] = PREMUL(second_color);
4633         }
4634
4635         return;
4636     }
4637
4638     uint current_color = ARGB_COMBINE_ALPHA(stops[0].second.rgba(), opacity);
4639     if (stopCount == 1) {
4640         current_color = PREMUL(current_color);
4641         for (int i = 0; i < size; ++i)
4642             colorTable[i] = current_color;
4643         return;
4644     }
4645
4646     // The position where the gradient begins and ends
4647     qreal begin_pos = stops[0].first;
4648     qreal end_pos = stops[stopCount-1].first;
4649
4650     int pos = 0; // The position in the color table.
4651     uint next_color;
4652
4653     qreal incr = 1 / qreal(size); // the double increment.
4654     qreal dpos = 1.5 * incr; // current position in gradient stop list (0 to 1)
4655
4656      // Up to first point
4657     colorTable[pos++] = PREMUL(current_color);
4658     while (dpos <= begin_pos) {
4659         colorTable[pos] = colorTable[pos - 1];
4660         ++pos;
4661         dpos += incr;
4662     }
4663
4664     int current_stop = 0; // We always interpolate between current and current + 1.
4665
4666     qreal t; // position between current left and right stops
4667     qreal t_delta; // the t increment per entry in the color table
4668
4669     if (dpos < end_pos) {
4670         // Gradient area
4671         while (dpos > stops[current_stop+1].first)
4672             ++current_stop;
4673
4674         if (current_stop != 0)
4675             current_color = ARGB_COMBINE_ALPHA(stops[current_stop].second.rgba(), opacity);
4676         next_color = ARGB_COMBINE_ALPHA(stops[current_stop+1].second.rgba(), opacity);
4677
4678         if (colorInterpolation) {
4679             current_color = PREMUL(current_color);
4680             next_color = PREMUL(next_color);
4681         }
4682
4683         qreal diff = stops[current_stop+1].first - stops[current_stop].first;
4684         qreal c = (diff == 0) ? qreal(0) : 256 / diff;
4685         t = (dpos - stops[current_stop].first) * c;
4686         t_delta = incr * c;
4687
4688         while (true) {
4689             Q_ASSERT(current_stop < stopCount);
4690
4691             int dist = qRound(t);
4692             int idist = 256 - dist;
4693
4694             if (colorInterpolation)
4695                 colorTable[pos] = INTERPOLATE_PIXEL_256(current_color, idist, next_color, dist);
4696             else
4697                 colorTable[pos] = PREMUL(INTERPOLATE_PIXEL_256(current_color, idist, next_color, dist));
4698
4699             ++pos;
4700             dpos += incr;
4701
4702             if (dpos >= end_pos)
4703                 break;
4704
4705             t += t_delta;
4706
4707             int skip = 0;
4708             while (dpos > stops[current_stop+skip+1].first)
4709                 ++skip;
4710
4711             if (skip != 0) {
4712                 current_stop += skip;
4713                 if (skip == 1)
4714                     current_color = next_color;
4715                 else
4716                     current_color = ARGB_COMBINE_ALPHA(stops[current_stop].second.rgba(), opacity);
4717                 next_color = ARGB_COMBINE_ALPHA(stops[current_stop+1].second.rgba(), opacity);
4718
4719                 if (colorInterpolation) {
4720                     if (skip != 1)
4721                         current_color = PREMUL(current_color);
4722                     next_color = PREMUL(next_color);
4723                 }
4724
4725                 qreal diff = stops[current_stop+1].first - stops[current_stop].first;
4726                 qreal c = (diff == 0) ? qreal(0) : 256 / diff;
4727                 t = (dpos - stops[current_stop].first) * c;
4728                 t_delta = incr * c;
4729             }
4730         }
4731     }
4732
4733     // After last point
4734     current_color = PREMUL(ARGB_COMBINE_ALPHA(stops[stopCount - 1].second.rgba(), opacity));
4735     while (pos < size - 1) {
4736         colorTable[pos] = current_color;
4737         ++pos;
4738     }
4739
4740     // Make sure the last color stop is represented at the end of the table
4741     colorTable[size - 1] = current_color;
4742 }
4743
4744 Q_GLOBAL_STATIC(QGradientCache, qt_gradient_cache)
4745
4746
4747 void QSpanData::init(QRasterBuffer *rb, const QRasterPaintEngine *pe)
4748 {
4749     rasterBuffer = rb;
4750 #ifdef Q_WS_QWS
4751     rasterEngine = const_cast<QRasterPaintEngine *>(pe);
4752 #endif
4753     type = None;
4754     txop = 0;
4755     bilinear = false;
4756     m11 = m22 = m33 = 1.;
4757     m12 = m13 = m21 = m23 = dx = dy = 0.0;
4758     clip = pe ? pe->d_func()->clip() : 0;
4759 }
4760
4761 Q_GUI_EXPORT extern QImage qt_imageForBrush(int brushStyle, bool invert);
4762
4763 void QSpanData::setup(const QBrush &brush, int alpha, QPainter::CompositionMode compositionMode)
4764 {
4765     Qt::BrushStyle brushStyle = qbrush_style(brush);
4766     switch (brushStyle) {
4767     case Qt::SolidPattern: {
4768         type = Solid;
4769         QColor c = qbrush_color(brush);
4770         QRgb rgba = c.rgba();
4771         solid.color = PREMUL(ARGB_COMBINE_ALPHA(rgba, alpha));
4772         if ((solid.color & 0xff000000) == 0
4773             && compositionMode == QPainter::CompositionMode_SourceOver) {
4774             type = None;
4775         }
4776         break;
4777     }
4778
4779     case Qt::LinearGradientPattern:
4780         {
4781             type = LinearGradient;
4782             const QLinearGradient *g = static_cast<const QLinearGradient *>(brush.gradient());
4783             gradient.alphaColor = !brush.isOpaque() || alpha != 256;
4784             gradient.colorTable = const_cast<uint*>(qt_gradient_cache()->getBuffer(*g, alpha));
4785             gradient.spread = g->spread();
4786
4787             QLinearGradientData &linearData = gradient.linear;
4788
4789             linearData.origin.x = g->start().x();
4790             linearData.origin.y = g->start().y();
4791             linearData.end.x = g->finalStop().x();
4792             linearData.end.y = g->finalStop().y();
4793             break;
4794         }
4795
4796     case Qt::RadialGradientPattern:
4797         {
4798             type = RadialGradient;
4799             const QRadialGradient *g = static_cast<const QRadialGradient *>(brush.gradient());
4800             gradient.alphaColor = !brush.isOpaque() || alpha != 256;
4801             gradient.colorTable = const_cast<uint*>(qt_gradient_cache()->getBuffer(*g, alpha));
4802             gradient.spread = g->spread();
4803
4804             QRadialGradientData &radialData = gradient.radial;
4805
4806             QPointF center = g->center();
4807             radialData.center.x = center.x();
4808             radialData.center.y = center.y();
4809             radialData.center.radius = g->centerRadius();
4810             QPointF focal = g->focalPoint();
4811             radialData.focal.x = focal.x();
4812             radialData.focal.y = focal.y();
4813             radialData.focal.radius = g->focalRadius();
4814         }
4815         break;
4816
4817     case Qt::ConicalGradientPattern:
4818         {
4819             type = ConicalGradient;
4820             const QConicalGradient *g = static_cast<const QConicalGradient *>(brush.gradient());
4821             gradient.alphaColor = !brush.isOpaque() || alpha != 256;
4822             gradient.colorTable = const_cast<uint*>(qt_gradient_cache()->getBuffer(*g, alpha));
4823             gradient.spread = QGradient::RepeatSpread;
4824
4825             QConicalGradientData &conicalData = gradient.conical;
4826
4827             QPointF center = g->center();
4828             conicalData.center.x = center.x();
4829             conicalData.center.y = center.y();
4830             conicalData.angle = g->angle() * 2 * Q_PI / 360.0;
4831         }
4832         break;
4833
4834     case Qt::Dense1Pattern:
4835     case Qt::Dense2Pattern:
4836     case Qt::Dense3Pattern:
4837     case Qt::Dense4Pattern:
4838     case Qt::Dense5Pattern:
4839     case Qt::Dense6Pattern:
4840     case Qt::Dense7Pattern:
4841     case Qt::HorPattern:
4842     case Qt::VerPattern:
4843     case Qt::CrossPattern:
4844     case Qt::BDiagPattern:
4845     case Qt::FDiagPattern:
4846     case Qt::DiagCrossPattern:
4847         type = Texture;
4848         if (!tempImage)
4849             tempImage = new QImage();
4850         *tempImage = rasterBuffer->colorizeBitmap(qt_imageForBrush(brushStyle, true), brush.color());
4851         initTexture(tempImage, alpha, QTextureData::Tiled);
4852         break;
4853     case Qt::TexturePattern:
4854         type = Texture;
4855         if (!tempImage)
4856             tempImage = new QImage();
4857
4858         if (qHasPixmapTexture(brush) && brush.texture().isQBitmap())
4859             *tempImage = rasterBuffer->colorizeBitmap(brush.textureImage(), brush.color());
4860         else
4861             *tempImage = brush.textureImage();
4862         initTexture(tempImage, alpha, QTextureData::Tiled, tempImage->rect());
4863         break;
4864
4865     case Qt::NoBrush:
4866     default:
4867         type = None;
4868         break;
4869     }
4870     adjustSpanMethods();
4871 }
4872
4873 void QSpanData::adjustSpanMethods()
4874 {
4875     bitmapBlit = 0;
4876     alphamapBlit = 0;
4877     alphaRGBBlit = 0;
4878
4879     fillRect = 0;
4880
4881     switch(type) {
4882     case None:
4883         unclipped_blend = 0;
4884         break;
4885     case Solid:
4886         unclipped_blend = rasterBuffer->drawHelper->blendColor;
4887         bitmapBlit = rasterBuffer->drawHelper->bitmapBlit;
4888         alphamapBlit = rasterBuffer->drawHelper->alphamapBlit;
4889         alphaRGBBlit = rasterBuffer->drawHelper->alphaRGBBlit;
4890         fillRect = rasterBuffer->drawHelper->fillRect;
4891         break;
4892     case LinearGradient:
4893     case RadialGradient:
4894     case ConicalGradient:
4895         unclipped_blend = rasterBuffer->drawHelper->blendGradient;
4896         break;
4897     case Texture:
4898 #ifdef Q_WS_QWS
4899 #ifndef QT_NO_RASTERCALLBACKS
4900         if (!rasterBuffer->buffer())
4901             unclipped_blend = qBlendTextureCallback;
4902         else
4903 #endif
4904             unclipped_blend = qBlendTexture;
4905 #else
4906         unclipped_blend = qBlendTexture;
4907 #endif
4908         if (!texture.imageData)
4909             unclipped_blend = 0;
4910
4911         break;
4912     }
4913     // setup clipping
4914     if (!unclipped_blend) {
4915         blend = 0;
4916     } else if (!clip) {
4917         blend = unclipped_blend;
4918     } else if (clip->hasRectClip) {
4919         blend = clip->clipRect.isEmpty() ? 0 : qt_span_fill_clipRect;
4920     } else {
4921         blend = qt_span_fill_clipped;
4922     }
4923 }
4924
4925 void QSpanData::setupMatrix(const QTransform &matrix, int bilin)
4926 {
4927     QTransform delta;
4928     // make sure we round off correctly in qdrawhelper.cpp
4929     delta.translate(1.0 / 65536, 1.0 / 65536);
4930
4931     QTransform inv = (delta * matrix).inverted();
4932     m11 = inv.m11();
4933     m12 = inv.m12();
4934     m13 = inv.m13();
4935     m21 = inv.m21();
4936     m22 = inv.m22();
4937     m23 = inv.m23();
4938     m33 = inv.m33();
4939     dx = inv.dx();
4940     dy = inv.dy();
4941     txop = inv.type();
4942     bilinear = bilin;
4943
4944     const bool affine = !m13 && !m23;
4945     fast_matrix = affine
4946         && m11 * m11 + m21 * m21 < 1e4
4947         && m12 * m12 + m22 * m22 < 1e4
4948         && qAbs(dx) < 1e4
4949         && qAbs(dy) < 1e4;
4950
4951     adjustSpanMethods();
4952 }
4953
4954 extern const QVector<QRgb> *qt_image_colortable(const QImage &image);
4955
4956 void QSpanData::initTexture(const QImage *image, int alpha, QTextureData::Type _type, const QRect &sourceRect)
4957 {
4958     const QImageData *d = const_cast<QImage *>(image)->data_ptr();
4959     if (!d || d->height == 0) {
4960         texture.imageData = 0;
4961         texture.width = 0;
4962         texture.height = 0;
4963         texture.x1 = 0;
4964         texture.y1 = 0;
4965         texture.x2 = 0;
4966         texture.y2 = 0;
4967         texture.bytesPerLine = 0;
4968         texture.format = QImage::Format_Invalid;
4969         texture.colorTable = 0;
4970         texture.hasAlpha = alpha != 256;
4971     } else {
4972         texture.imageData = d->data;
4973         texture.width = d->width;
4974         texture.height = d->height;
4975
4976         if (sourceRect.isNull()) {
4977             texture.x1 = 0;
4978             texture.y1 = 0;
4979             texture.x2 = texture.width;
4980             texture.y2 = texture.height;
4981         } else {
4982             texture.x1 = sourceRect.x();
4983             texture.y1 = sourceRect.y();
4984             texture.x2 = qMin(texture.x1 + sourceRect.width(), d->width);
4985             texture.y2 = qMin(texture.y1 + sourceRect.height(), d->height);
4986         }
4987
4988         texture.bytesPerLine = d->bytes_per_line;
4989
4990         texture.format = d->format;
4991         texture.colorTable = (d->format <= QImage::Format_Indexed8 && !d->colortable.isEmpty()) ? &d->colortable : 0;
4992         texture.hasAlpha = image->hasAlphaChannel() || alpha != 256;
4993     }
4994     texture.const_alpha = alpha;
4995     texture.type = _type;
4996
4997     adjustSpanMethods();
4998 }
4999
5000
5001 /*!
5002     \fn void QRasterPaintEngine::drawPoints(const QPoint *points, int pointCount)
5003     \overload
5004
5005     Draws the first \a pointCount points in the buffer \a points
5006
5007     The default implementation converts the first \a pointCount QPoints in \a points
5008     to QPointFs and calls the floating point version of drawPoints.
5009 */
5010
5011 /*!
5012     \fn void QRasterPaintEngine::drawEllipse(const QRect &rect)
5013     \overload
5014
5015     Reimplement this function to draw the largest ellipse that can be
5016     contained within rectangle \a rect.
5017 */
5018
5019 #ifdef QT_DEBUG_DRAW
5020 void dumpClip(int width, int height, const QClipData *clip)
5021 {
5022     QImage clipImg(width, height, QImage::Format_ARGB32_Premultiplied);
5023     clipImg.fill(0xffff0000);
5024
5025     int x0 = width;
5026     int x1 = 0;
5027     int y0 = height;
5028     int y1 = 0;
5029
5030     ((QClipData *) clip)->spans(); // Force allocation of the spans structure...
5031
5032     for (int i = 0; i < clip->count; ++i) {
5033         const QSpan *span = ((QClipData *) clip)->spans() + i;
5034         for (int j = 0; j < span->len; ++j)
5035             clipImg.setPixel(span->x + j, span->y, 0xffffff00);
5036         x0 = qMin(x0, int(span->x));
5037         x1 = qMax(x1, int(span->x + span->len - 1));
5038
5039         y0 = qMin(y0, int(span->y));
5040         y1 = qMax(y1, int(span->y));
5041     }
5042
5043     static int counter = 0;
5044
5045     Q_ASSERT(y0 >= 0);
5046     Q_ASSERT(x0 >= 0);
5047     Q_ASSERT(y1 >= 0);
5048     Q_ASSERT(x1 >= 0);
5049
5050     fprintf(stderr,"clip %d: %d %d - %d %d\n", counter, x0, y0, x1, y1);
5051     clipImg.save(QString::fromLatin1("clip-%0.png").arg(counter++));
5052 }
5053 #endif
5054
5055
5056 QT_END_NAMESPACE