Check world matrix is true when seeing if transformations are supported
[qt:qt.git] / src / gui / painting / qpaintengine_raster.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
5 **
6 ** This file is part of the QtGui module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia.  For licensing terms and
14 ** conditions see http://qt.digia.com/licensing.  For further information
15 ** use the contact form at http://qt.digia.com/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file.  Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights.  These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file.  Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include <QtCore/qglobal.h>
43 #include <QtCore/qmutex.h>
44
45 #define QT_FT_BEGIN_HEADER
46 #define QT_FT_END_HEADER
47
48 #include <private/qrasterdefs_p.h>
49 #include <private/qgrayraster_p.h>
50
51 #include <qpainterpath.h>
52 #include <qdebug.h>
53 #include <qhash.h>
54 #include <qlabel.h>
55 #include <qbitmap.h>
56 #include <qmath.h>
57
58 #if defined (Q_WS_X11)
59 #  include <private/qfontengine_ft_p.h>
60 #endif
61
62 //   #include <private/qdatabuffer_p.h>
63 //   #include <private/qpainter_p.h>
64 #include <private/qmath_p.h>
65 #include <private/qtextengine_p.h>
66 #include <private/qfontengine_p.h>
67 #include <private/qpixmap_raster_p.h>
68 //   #include <private/qpolygonclipper_p.h>
69 //   #include <private/qrasterizer_p.h>
70 #include <private/qimage_p.h>
71 #include <private/qstatictext_p.h>
72 #include <private/qcosmeticstroker_p.h>
73 #include "qmemrotate_p.h"
74
75 #include "qpaintengine_raster_p.h"
76 //   #include "qbezier_p.h"
77 #include "qoutlinemapper_p.h"
78
79 #if defined(Q_WS_WIN)
80 #  include <qt_windows.h>
81 #  include <qvarlengtharray.h>
82 #  include <private/qfontengine_p.h>
83 #  if defined(Q_OS_WINCE)
84 #    include "qguifunctions_wince.h"
85 #  endif
86 #elif defined(Q_WS_MAC)
87 #  include <private/qt_mac_p.h>
88 #  include <private/qpixmap_mac_p.h>
89 #  include <private/qpaintengine_mac_p.h>
90 #elif defined(Q_WS_QWS)
91 #  if !defined(QT_NO_FREETYPE)
92 #    include <private/qfontengine_ft_p.h>
93 #  endif
94 #  if !defined(QT_NO_QWS_QPF2)
95 #    include <private/qfontengine_qpf_p.h>
96 #  endif
97 #  include <private/qabstractfontengine_p.h>
98 #elif defined(Q_OS_SYMBIAN) && defined(QT_NO_FREETYPE)
99 #  include <private/qfontengine_s60_p.h>
100 #elif defined(Q_WS_QPA)
101 #  include <private/qfontengine_ft_p.h>
102 #endif
103
104 #if defined(Q_WS_WIN64)
105 #  include <malloc.h>
106 #endif
107 #include <limits.h>
108
109 QT_BEGIN_NAMESPACE
110
111 Q_GUI_EXPORT extern bool qt_scaleForTransform(const QTransform &transform, qreal *scale); // qtransform.cpp
112
113 #define qreal_to_fixed_26_6(f) (int(f * 64))
114 #define qt_swap_int(x, y) { int tmp = (x); (x) = (y); (y) = tmp; }
115 #define qt_swap_qreal(x, y) { qreal tmp = (x); (x) = (y); (y) = tmp; }
116
117 // #define QT_DEBUG_DRAW
118 #ifdef QT_DEBUG_DRAW
119 void dumpClip(int width, int height, const QClipData *clip);
120 #endif
121
122 #define QT_FAST_SPANS
123
124
125 // A little helper macro to get a better approximation of dimensions.
126 // If we have a rect that starting at 0.5 of width 3.5 it should span
127 // 4 pixels.
128 #define int_dim(pos, dim) (int(pos+dim) - int(pos))
129
130 // use the same rounding as in qrasterizer.cpp (6 bit fixed point)
131 static const qreal aliasedCoordinateDelta = 0.5 - 0.015625;
132
133 #ifdef Q_WS_WIN
134 extern bool qt_cleartype_enabled;
135 #endif
136
137 #ifdef Q_WS_MAC
138 extern bool qt_applefontsmoothing_enabled;
139 #endif
140
141
142 /********************************************************************************
143  * Span functions
144  */
145 static void qt_span_fill_clipRect(int count, const QSpan *spans, void *userData);
146 static void qt_span_fill_clipped(int count, const QSpan *spans, void *userData);
147 static void qt_span_clip(int count, const QSpan *spans, void *userData);
148 static void qt_merge_clip(const QClipData *c1, const QClipData *c2, QClipData *result);
149
150 struct ClipData
151 {
152     QClipData *oldClip;
153     QClipData *newClip;
154     Qt::ClipOperation operation;
155 };
156
157 enum LineDrawMode {
158     LineDrawClipped,
159     LineDrawNormal,
160     LineDrawIncludeLastPixel
161 };
162
163 static void drawEllipse_midpoint_i(const QRect &rect, const QRect &clip,
164                                    ProcessSpans pen_func, ProcessSpans brush_func,
165                                    QSpanData *pen_data, QSpanData *brush_data);
166
167 struct QRasterFloatPoint {
168     qreal x;
169     qreal y;
170 };
171
172 #ifdef QT_DEBUG_DRAW
173 static const QRectF boundingRect(const QPointF *points, int pointCount)
174 {
175     const QPointF *e = points;
176     const QPointF *last = points + pointCount;
177     qreal minx, maxx, miny, maxy;
178     minx = maxx = e->x();
179     miny = maxy = e->y();
180     while (++e < last) {
181         if (e->x() < minx)
182             minx = e->x();
183         else if (e->x() > maxx)
184             maxx = e->x();
185         if (e->y() < miny)
186             miny = e->y();
187         else if (e->y() > maxy)
188             maxy = e->y();
189     }
190     return QRectF(QPointF(minx, miny), QPointF(maxx, maxy));
191 }
192 #endif
193
194 template <typename T> static inline bool isRect(const T *pts, int elementCount) {
195     return (elementCount == 5 // 5-point polygon, check for closed rect
196             && pts[0] == pts[8] && pts[1] == pts[9] // last point == first point
197             && pts[0] == pts[6] && pts[2] == pts[4] // x values equal
198             && pts[1] == pts[3] && pts[5] == pts[7] // y values equal...
199             && pts[0] < pts[4] && pts[1] < pts[5]
200             ) ||
201            (elementCount == 4 // 4-point polygon, check for unclosed rect
202             && pts[0] == pts[6] && pts[2] == pts[4] // x values equal
203             && pts[1] == pts[3] && pts[5] == pts[7] // y values equal...
204             && pts[0] < pts[4] && pts[1] < pts[5]
205             );
206 }
207
208
209 static void qt_ft_outline_move_to(qfixed x, qfixed y, void *data)
210 {
211     ((QOutlineMapper *) data)->moveTo(QPointF(qt_fixed_to_real(x), qt_fixed_to_real(y)));
212 }
213
214 static void qt_ft_outline_line_to(qfixed x, qfixed y, void *data)
215 {
216     ((QOutlineMapper *) data)->lineTo(QPointF(qt_fixed_to_real(x), qt_fixed_to_real(y)));
217 }
218
219 static void qt_ft_outline_cubic_to(qfixed c1x, qfixed c1y,
220                              qfixed c2x, qfixed c2y,
221                              qfixed ex, qfixed ey,
222                              void *data)
223 {
224     ((QOutlineMapper *) data)->curveTo(QPointF(qt_fixed_to_real(c1x), qt_fixed_to_real(c1y)),
225                                        QPointF(qt_fixed_to_real(c2x), qt_fixed_to_real(c2y)),
226                                        QPointF(qt_fixed_to_real(ex), qt_fixed_to_real(ey)));
227 }
228
229
230 #if !defined(QT_NO_DEBUG) && 0
231 static void qt_debug_path(const QPainterPath &path)
232 {
233     const char *names[] = {
234         "MoveTo     ",
235         "LineTo     ",
236         "CurveTo    ",
237         "CurveToData"
238     };
239
240     fprintf(stderr,"\nQPainterPath: elementCount=%d\n", path.elementCount());
241     for (int i=0; i<path.elementCount(); ++i) {
242         const QPainterPath::Element &e = path.elementAt(i);
243         Q_ASSERT(e.type >= 0 && e.type <= QPainterPath::CurveToDataElement);
244         fprintf(stderr," - %3d:: %s, (%.2f, %.2f)\n", i, names[e.type], e.x, e.y);
245     }
246 }
247 #endif
248
249 QRasterPaintEnginePrivate::QRasterPaintEnginePrivate() :
250     QPaintEngineExPrivate(),
251     cachedLines(0)
252 {
253 }
254
255
256 /*!
257     \class QRasterPaintEngine
258     \preliminary
259     \ingroup qws
260     \since 4.2
261
262     \brief The QRasterPaintEngine class enables hardware acceleration
263     of painting operations in Qt for Embedded Linux.
264
265     Note that this functionality is only available in
266     \l{Qt for Embedded Linux}.
267
268     In \l{Qt for Embedded Linux}, painting is a pure software
269     implementation. But starting with Qt 4.2, it is
270     possible to add an accelerated graphics driver to take advantage
271     of available hardware resources.
272
273     Hardware acceleration is accomplished by creating a custom screen
274     driver, accelerating the copying from memory to the screen, and
275     implementing a custom paint engine accelerating the various
276     painting operations. Then a custom paint device (derived from the
277     QCustomRasterPaintDevice class) and a custom window surface
278     (derived from QWSWindowSurface) must be implemented to make
279     \l{Qt for Embedded Linux} aware of the accelerated driver.
280
281     \note The QRasterPaintEngine class does not support 8-bit images.
282     Instead, they need to be converted to a supported format, such as
283     QImage::Format_ARGB32_Premultiplied.
284
285     See the \l {Adding an Accelerated Graphics Driver to Qt for Embedded Linux}
286     documentation for details.
287
288     \sa QCustomRasterPaintDevice, QPaintEngine
289 */
290
291 /*!
292     \fn Type QRasterPaintEngine::type() const
293     \reimp
294 */
295
296 /*!
297     \typedef QSpan
298     \relates QRasterPaintEngine
299
300     A struct equivalent to QT_FT_Span, containing a position (x,
301     y), the span's length in pixels and its color/coverage (a value
302     ranging from 0 to 255).
303 */
304
305 /*!
306     \since 4.5
307
308     Creates a raster based paint engine for operating on the given
309     \a device, with the complete set of \l
310     {QPaintEngine::PaintEngineFeature}{paint engine features and
311     capabilities}.
312 */
313 QRasterPaintEngine::QRasterPaintEngine(QPaintDevice *device)
314     : QPaintEngineEx(*(new QRasterPaintEnginePrivate))
315 {
316     d_func()->device = device;
317     init();
318 }
319
320 /*!
321     \internal
322 */
323 QRasterPaintEngine::QRasterPaintEngine(QRasterPaintEnginePrivate &dd, QPaintDevice *device)
324     : QPaintEngineEx(dd)
325 {
326     d_func()->device = device;
327     init();
328 }
329
330 void QRasterPaintEngine::init()
331 {
332     Q_D(QRasterPaintEngine);
333
334
335 #ifdef Q_WS_WIN
336     d->hdc = 0;
337 #endif
338
339     // The antialiasing raster.
340     d->grayRaster.reset(new QT_FT_Raster);
341     Q_CHECK_PTR(d->grayRaster.data());
342     if (qt_ft_grays_raster.raster_new(d->grayRaster.data()))
343         QT_THROW(std::bad_alloc()); // an error creating the raster is caused by a bad malloc
344
345
346     d->rasterizer.reset(new QRasterizer);
347     d->rasterBuffer.reset(new QRasterBuffer());
348     d->outlineMapper.reset(new QOutlineMapper);
349     d->outlinemapper_xform_dirty = true;
350
351     d->basicStroker.setMoveToHook(qt_ft_outline_move_to);
352     d->basicStroker.setLineToHook(qt_ft_outline_line_to);
353     d->basicStroker.setCubicToHook(qt_ft_outline_cubic_to);
354
355     d->baseClip.reset(new QClipData(d->device->height()));
356     d->baseClip->setClipRect(QRect(0, 0, d->device->width(), d->device->height()));
357
358     d->image_filler.init(d->rasterBuffer.data(), this);
359     d->image_filler.type = QSpanData::Texture;
360
361     d->image_filler_xform.init(d->rasterBuffer.data(), this);
362     d->image_filler_xform.type = QSpanData::Texture;
363
364     d->solid_color_filler.init(d->rasterBuffer.data(), this);
365     d->solid_color_filler.type = QSpanData::Solid;
366
367     d->deviceDepth = d->device->depth();
368
369     d->mono_surface = false;
370     gccaps &= ~PorterDuff;
371
372     QImage::Format format = QImage::Format_Invalid;
373
374     switch (d->device->devType()) {
375     case QInternal::Pixmap:
376         qWarning("QRasterPaintEngine: unsupported for pixmaps...");
377         break;
378     case QInternal::Image:
379         format = d->rasterBuffer->prepare(static_cast<QImage *>(d->device));
380         break;
381 #ifdef Q_WS_QWS
382     case QInternal::CustomRaster:
383         d->rasterBuffer->prepare(static_cast<QCustomRasterPaintDevice*>(d->device));
384         break;
385 #endif
386     default:
387         qWarning("QRasterPaintEngine: unsupported target device %d\n", d->device->devType());
388         d->device = 0;
389         return;
390     }
391
392     switch (format) {
393     case QImage::Format_MonoLSB:
394     case QImage::Format_Mono:
395         d->mono_surface = true;
396         break;
397     case QImage::Format_ARGB8565_Premultiplied:
398     case QImage::Format_ARGB8555_Premultiplied:
399     case QImage::Format_ARGB6666_Premultiplied:
400     case QImage::Format_ARGB4444_Premultiplied:
401     case QImage::Format_ARGB32_Premultiplied:
402     case QImage::Format_ARGB32:
403         gccaps |= PorterDuff;
404         break;
405     case QImage::Format_RGB32:
406     case QImage::Format_RGB444:
407     case QImage::Format_RGB555:
408     case QImage::Format_RGB666:
409     case QImage::Format_RGB888:
410     case QImage::Format_RGB16:
411         break;
412     default:
413         break;
414     }
415 }
416
417
418
419
420 /*!
421     Destroys this paint engine.
422 */
423 QRasterPaintEngine::~QRasterPaintEngine()
424 {
425     Q_D(QRasterPaintEngine);
426
427     qt_ft_grays_raster.raster_done(*d->grayRaster.data());
428 }
429
430 /*!
431     \reimp
432 */
433 bool QRasterPaintEngine::begin(QPaintDevice *device)
434 {
435     Q_D(QRasterPaintEngine);
436
437     if (device->devType() == QInternal::Pixmap) {
438         QPixmap *pixmap = static_cast<QPixmap *>(device);
439         QPixmapData *pd = pixmap->pixmapData();
440         if (pd->classId() == QPixmapData::RasterClass || pd->classId() == QPixmapData::BlitterClass)
441             d->device = pd->buffer();
442     } else {
443         d->device = device;
444     }
445
446     // Make sure QPaintEngine::paintDevice() returns the proper device.
447     d->pdev = d->device;
448
449     Q_ASSERT(d->device->devType() == QInternal::Image
450              || d->device->devType() == QInternal::CustomRaster);
451
452     d->systemStateChanged();
453
454     QRasterPaintEngineState *s = state();
455     ensureOutlineMapper();
456     d->outlineMapper->m_clip_rect = d->deviceRect;
457
458     if (d->outlineMapper->m_clip_rect.width() > QT_RASTER_COORD_LIMIT)
459         d->outlineMapper->m_clip_rect.setWidth(QT_RASTER_COORD_LIMIT);
460     if (d->outlineMapper->m_clip_rect.height() > QT_RASTER_COORD_LIMIT)
461         d->outlineMapper->m_clip_rect.setHeight(QT_RASTER_COORD_LIMIT);
462
463     d->rasterizer->setClipRect(d->deviceRect);
464
465     s->penData.init(d->rasterBuffer.data(), this);
466     s->penData.setup(s->pen.brush(), s->intOpacity, s->composition_mode);
467     s->stroker = &d->basicStroker;
468     d->basicStroker.setClipRect(d->deviceRect);
469
470     s->brushData.init(d->rasterBuffer.data(), this);
471     s->brushData.setup(s->brush, s->intOpacity, s->composition_mode);
472
473     d->rasterBuffer->compositionMode = QPainter::CompositionMode_SourceOver;
474
475     setDirty(DirtyBrushOrigin);
476
477 #ifdef QT_DEBUG_DRAW
478     qDebug() << "QRasterPaintEngine::begin(" << (void *) device
479              << ") devType:" << device->devType()
480              << "devRect:" << d->deviceRect;
481     if (d->baseClip) {
482         dumpClip(d->rasterBuffer->width(), d->rasterBuffer->height(), &*d->baseClip);
483     }
484 #endif
485
486 #if defined(Q_WS_WIN)
487     d->isPlain45DegreeRotation = true;
488 #endif
489
490     if (d->mono_surface)
491         d->glyphCacheType = QFontEngineGlyphCache::Raster_Mono;
492 #if defined(Q_WS_WIN)
493     else if (qt_cleartype_enabled)
494 #elif defined (Q_WS_MAC)
495     else if (qt_applefontsmoothing_enabled)
496 #else
497     else if (false)
498 #endif
499     {
500         QImage::Format format = static_cast<QImage *>(d->device)->format();
501         if (format == QImage::Format_ARGB32_Premultiplied || format == QImage::Format_RGB32)
502             d->glyphCacheType = QFontEngineGlyphCache::Raster_RGBMask;
503         else
504             d->glyphCacheType = QFontEngineGlyphCache::Raster_A8;
505     } else
506         d->glyphCacheType = QFontEngineGlyphCache::Raster_A8;
507
508     setActive(true);
509     return true;
510 }
511
512 /*!
513     \reimp
514 */
515 bool QRasterPaintEngine::end()
516 {
517 #ifdef QT_DEBUG_DRAW
518     Q_D(QRasterPaintEngine);
519     qDebug() << "QRasterPaintEngine::end devRect:" << d->deviceRect;
520     if (d->baseClip) {
521         dumpClip(d->rasterBuffer->width(), d->rasterBuffer->height(), &*d->baseClip);
522     }
523 #endif
524
525     return true;
526 }
527
528 /*!
529     \internal
530 */
531 void QRasterPaintEngine::releaseBuffer()
532 {
533     Q_D(QRasterPaintEngine);
534     d->rasterBuffer.reset(new QRasterBuffer);
535 }
536
537 /*!
538     \internal
539 */
540 QSize QRasterPaintEngine::size() const
541 {
542     Q_D(const QRasterPaintEngine);
543     return QSize(d->rasterBuffer->width(), d->rasterBuffer->height());
544 }
545
546 /*!
547     \internal
548 */
549 #ifndef QT_NO_DEBUG
550 void QRasterPaintEngine::saveBuffer(const QString &s) const
551 {
552     Q_D(const QRasterPaintEngine);
553     d->rasterBuffer->bufferImage().save(s, "PNG");
554 }
555 #endif
556
557 /*!
558     \internal
559 */
560 void QRasterPaintEngine::updateMatrix(const QTransform &matrix)
561 {
562     QRasterPaintEngineState *s = state();
563     // FALCON: get rid of this line, see drawImage call below.
564     s->matrix = matrix;
565     QTransform::TransformationType txop = s->matrix.type();
566
567     switch (txop) {
568
569     case QTransform::TxNone:
570         s->flags.int_xform = true;
571         break;
572
573     case QTransform::TxTranslate:
574         s->flags.int_xform = qreal(int(s->matrix.dx())) == s->matrix.dx()
575                             && qreal(int(s->matrix.dy())) == s->matrix.dy();
576         break;
577
578     case QTransform::TxScale:
579         s->flags.int_xform = qreal(int(s->matrix.dx())) == s->matrix.dx()
580                             && qreal(int(s->matrix.dy())) == s->matrix.dy()
581                             && qreal(int(s->matrix.m11())) == s->matrix.m11()
582                             && qreal(int(s->matrix.m22())) == s->matrix.m22();
583         break;
584
585     default: // shear / perspective...
586         s->flags.int_xform = false;
587         break;
588     }
589
590     s->flags.tx_noshear = qt_scaleForTransform(s->matrix, &s->txscale);
591
592     ensureOutlineMapper();
593
594 #ifdef Q_WS_WIN
595     Q_D(QRasterPaintEngine);
596     d->isPlain45DegreeRotation = false;
597     if (txop >= QTransform::TxRotate) {
598         d->isPlain45DegreeRotation =
599             (qFuzzyIsNull(matrix.m11())
600              && qFuzzyIsNull(matrix.m12() - qreal(1))
601              && qFuzzyIsNull(matrix.m21() + qreal(1))
602              && qFuzzyIsNull(matrix.m22())
603                 )
604             ||
605             (qFuzzyIsNull(matrix.m11() + qreal(1))
606              && qFuzzyIsNull(matrix.m12())
607              && qFuzzyIsNull(matrix.m21())
608              && qFuzzyIsNull(matrix.m22() + qreal(1))
609                 )
610             ||
611             (qFuzzyIsNull(matrix.m11())
612              && qFuzzyIsNull(matrix.m12() + qreal(1))
613              && qFuzzyIsNull(matrix.m21() - qreal(1))
614              && qFuzzyIsNull(matrix.m22())
615                 )
616             ;
617     }
618 #endif
619
620 }
621
622
623
624 QRasterPaintEngineState::~QRasterPaintEngineState()
625 {
626     if (flags.has_clip_ownership)
627         delete clip;
628 }
629
630
631 QRasterPaintEngineState::QRasterPaintEngineState()
632 {
633     stroker = 0;
634
635     fillFlags = 0;
636     strokeFlags = 0;
637     pixmapFlags = 0;
638
639     intOpacity = 256;
640
641     txscale = 1.;
642
643     flags.fast_pen = true;
644     flags.antialiased = false;
645     flags.bilinear = false;
646     flags.fast_text = true;
647     flags.int_xform = true;
648     flags.tx_noshear = true;
649     flags.fast_images = true;
650
651     clip = 0;
652     flags.has_clip_ownership = false;
653
654     dirty = 0;
655 }
656
657 QRasterPaintEngineState::QRasterPaintEngineState(QRasterPaintEngineState &s)
658     : QPainterState(s)
659     , lastPen(s.lastPen)
660     , penData(s.penData)
661     , stroker(s.stroker)
662     , strokeFlags(s.strokeFlags)
663     , lastBrush(s.lastBrush)
664     , brushData(s.brushData)
665     , fillFlags(s.fillFlags)
666     , pixmapFlags(s.pixmapFlags)
667     , intOpacity(s.intOpacity)
668     , txscale(s.txscale)
669     , clip(s.clip)
670     , dirty(s.dirty)
671     , flag_bits(s.flag_bits)
672 {
673     brushData.tempImage = 0;
674     penData.tempImage = 0;
675     flags.has_clip_ownership = false;
676 }
677
678 /*!
679     \internal
680 */
681 QPainterState *QRasterPaintEngine::createState(QPainterState *orig) const
682 {
683     QRasterPaintEngineState *s;
684     if (!orig)
685         s = new QRasterPaintEngineState();
686     else
687         s = new QRasterPaintEngineState(*static_cast<QRasterPaintEngineState *>(orig));
688
689     return s;
690 }
691
692 /*!
693     \internal
694 */
695 void QRasterPaintEngine::setState(QPainterState *s)
696 {
697     Q_D(QRasterPaintEngine);
698     QPaintEngineEx::setState(s);
699     d->rasterBuffer->compositionMode = s->composition_mode;
700 }
701
702 /*!
703     \fn QRasterPaintEngineState *QRasterPaintEngine::state()
704     \internal
705 */
706
707 /*!
708     \fn const QRasterPaintEngineState *QRasterPaintEngine::state() const
709     \internal
710 */
711
712 /*!
713     \internal
714 */
715 void QRasterPaintEngine::penChanged()
716 {
717 #ifdef QT_DEBUG_DRAW
718     qDebug() << "QRasterPaintEngine::penChanged():" << state()->pen;
719 #endif
720     QRasterPaintEngineState *s = state();
721     s->strokeFlags |= DirtyPen;
722     s->dirty |= DirtyPen;
723 }
724
725 /*!
726     \internal
727 */
728 void QRasterPaintEngine::updatePen(const QPen &pen)
729 {
730     Q_D(QRasterPaintEngine);
731     QRasterPaintEngineState *s = state();
732 #ifdef QT_DEBUG_DRAW
733     qDebug() << "QRasterPaintEngine::updatePen():" << s->pen;
734 #endif
735
736     Qt::PenStyle pen_style = qpen_style(pen);
737
738     s->lastPen = pen;
739     s->strokeFlags = 0;
740
741     s->penData.clip = d->clip();
742     s->penData.setup(pen_style == Qt::NoPen ? QBrush() : pen.brush(), s->intOpacity, s->composition_mode);
743
744     if (s->strokeFlags & QRasterPaintEngine::DirtyTransform
745         || pen.brush().transform().type() >= QTransform::TxNone) {
746         d->updateMatrixData(&s->penData, pen.brush(), s->matrix);
747     }
748
749     // Slightly ugly handling of an uncommon case... We need to change
750     // the pen because it is reused in draw_midpoint to decide dashed
751     // or non-dashed.
752     if (pen_style == Qt::CustomDashLine && pen.dashPattern().size() == 0) {
753         pen_style = Qt::SolidLine;
754         s->lastPen.setStyle(Qt::SolidLine);
755     }
756
757     d->basicStroker.setJoinStyle(qpen_joinStyle(pen));
758     d->basicStroker.setCapStyle(qpen_capStyle(pen));
759     d->basicStroker.setMiterLimit(pen.miterLimit());
760
761     qreal penWidth = qpen_widthf(pen);
762     if (penWidth == 0)
763         d->basicStroker.setStrokeWidth(1);
764     else
765         d->basicStroker.setStrokeWidth(penWidth);
766
767     if(pen_style == Qt::SolidLine) {
768         s->stroker = &d->basicStroker;
769     } else if (pen_style != Qt::NoPen) {
770         if (!d->dashStroker)
771             d->dashStroker.reset(new QDashStroker(&d->basicStroker));
772         if (pen.isCosmetic()) {
773             d->dashStroker->setClipRect(d->deviceRect);
774         } else {
775             // ### I've seen this inverted devrect multiple places now...
776             QRectF clipRect = s->matrix.inverted().mapRect(QRectF(d->deviceRect));
777             d->dashStroker->setClipRect(clipRect);
778         }
779         d->dashStroker->setDashPattern(pen.dashPattern());
780         d->dashStroker->setDashOffset(pen.dashOffset());
781         s->stroker = d->dashStroker.data();
782     } else {
783         s->stroker = 0;
784     }
785
786     ensureState(); // needed because of tx_noshear...
787     s->flags.fast_pen = pen_style > Qt::NoPen
788             && s->penData.blend
789             && ((pen.isCosmetic() && penWidth <= 1)
790                 || (!pen.isCosmetic() && s->flags.tx_noshear && penWidth * s->txscale <= 1));
791
792     s->flags.non_complex_pen = qpen_capStyle(s->lastPen) <= Qt::SquareCap && s->flags.tx_noshear;
793
794     s->strokeFlags = 0;
795 }
796
797
798
799 /*!
800     \internal
801 */
802 void QRasterPaintEngine::brushOriginChanged()
803 {
804     QRasterPaintEngineState *s = state();
805 #ifdef QT_DEBUG_DRAW
806     qDebug() << "QRasterPaintEngine::brushOriginChanged()" << s->brushOrigin;
807 #endif
808
809     s->fillFlags |= DirtyBrushOrigin;
810 }
811
812
813 /*!
814     \internal
815 */
816 void QRasterPaintEngine::brushChanged()
817 {
818     QRasterPaintEngineState *s = state();
819 #ifdef QT_DEBUG_DRAW
820     qDebug() << "QRasterPaintEngine::brushChanged():" << s->brush;
821 #endif
822     s->fillFlags |= DirtyBrush;
823 }
824
825
826
827
828 /*!
829     \internal
830 */
831 void QRasterPaintEngine::updateBrush(const QBrush &brush)
832 {
833 #ifdef QT_DEBUG_DRAW
834     qDebug() << "QRasterPaintEngine::updateBrush()" << brush;
835 #endif
836     Q_D(QRasterPaintEngine);
837     QRasterPaintEngineState *s = state();
838     // must set clip prior to setup, as setup uses it...
839     s->brushData.clip = d->clip();
840     s->brushData.setup(brush, s->intOpacity, s->composition_mode);
841     if (s->fillFlags & DirtyTransform
842         || brush.transform().type() >= QTransform::TxNone)
843         d_func()->updateMatrixData(&s->brushData, brush, d->brushMatrix());
844     s->lastBrush = brush;
845     s->fillFlags = 0;
846 }
847
848 void QRasterPaintEngine::updateOutlineMapper()
849 {
850     Q_D(QRasterPaintEngine);
851     d->outlineMapper->setMatrix(state()->matrix);
852 }
853
854 void QRasterPaintEngine::updateState()
855 {
856     QRasterPaintEngineState *s = state();
857
858     if (s->dirty & DirtyTransform)
859         updateMatrix(s->matrix);
860
861     if (s->dirty & (DirtyPen|DirtyCompositionMode|DirtyOpacity)) {
862         const QPainter::CompositionMode mode = s->composition_mode;
863         s->flags.fast_text = (s->penData.type == QSpanData::Solid)
864                        && s->intOpacity == 256
865                        && (mode == QPainter::CompositionMode_Source
866                            || (mode == QPainter::CompositionMode_SourceOver
867                                && qAlpha(s->penData.solid.color) == 255));
868     }
869
870     s->dirty = 0;
871 }
872
873
874 /*!
875     \internal
876 */
877 void QRasterPaintEngine::opacityChanged()
878 {
879     QRasterPaintEngineState *s = state();
880
881 #ifdef QT_DEBUG_DRAW
882     qDebug() << "QRasterPaintEngine::opacityChanged()" << s->opacity;
883 #endif
884
885     s->fillFlags |= DirtyOpacity;
886     s->strokeFlags |= DirtyOpacity;
887     s->pixmapFlags |= DirtyOpacity;
888     s->dirty |= DirtyOpacity;
889     s->intOpacity = (int) (s->opacity * 256);
890 }
891
892 /*!
893     \internal
894 */
895 void QRasterPaintEngine::compositionModeChanged()
896 {
897     Q_D(QRasterPaintEngine);
898     QRasterPaintEngineState *s = state();
899
900 #ifdef QT_DEBUG_DRAW
901     qDebug() << "QRasterPaintEngine::compositionModeChanged()" << s->composition_mode;
902 #endif
903
904     s->fillFlags |= DirtyCompositionMode;
905     s->dirty |= DirtyCompositionMode;
906
907     s->strokeFlags |= DirtyCompositionMode;
908     d->rasterBuffer->compositionMode = s->composition_mode;
909
910     d->recalculateFastImages();
911 }
912
913 /*!
914     \internal
915 */
916 void QRasterPaintEngine::renderHintsChanged()
917 {
918     QRasterPaintEngineState *s = state();
919
920 #ifdef QT_DEBUG_DRAW
921     qDebug() << "QRasterPaintEngine::renderHintsChanged()" << hex << s->renderHints;
922 #endif
923
924     bool was_aa = s->flags.antialiased;
925     bool was_bilinear = s->flags.bilinear;
926
927     s->flags.antialiased = bool(s->renderHints & QPainter::Antialiasing);
928     s->flags.bilinear = bool(s->renderHints & QPainter::SmoothPixmapTransform);
929
930     if (was_aa != s->flags.antialiased)
931         s->strokeFlags |= DirtyHints;
932
933     if (was_bilinear != s->flags.bilinear) {
934         s->strokeFlags |= DirtyPen;
935         s->fillFlags |= DirtyBrush;
936     }
937
938     Q_D(QRasterPaintEngine);
939     d->recalculateFastImages();
940 }
941
942 /*!
943     \internal
944 */
945 void QRasterPaintEngine::transformChanged()
946 {
947     QRasterPaintEngineState *s = state();
948
949 #ifdef QT_DEBUG_DRAW
950     qDebug() << "QRasterPaintEngine::transformChanged()" << s->matrix;
951 #endif
952
953     s->fillFlags |= DirtyTransform;
954     s->strokeFlags |= DirtyTransform;
955
956     s->dirty |= DirtyTransform;
957
958     Q_D(QRasterPaintEngine);
959     d->recalculateFastImages();
960 }
961
962 /*!
963     \internal
964 */
965 void QRasterPaintEngine::clipEnabledChanged()
966 {
967     QRasterPaintEngineState *s = state();
968
969 #ifdef QT_DEBUG_DRAW
970     qDebug() << "QRasterPaintEngine::clipEnabledChanged()" << s->clipEnabled;
971 #endif
972
973     if (s->clip) {
974         s->clip->enabled = s->clipEnabled;
975         s->fillFlags |= DirtyClipEnabled;
976         s->strokeFlags |= DirtyClipEnabled;
977         s->pixmapFlags |= DirtyClipEnabled;
978     }
979 }
980
981 #ifdef Q_WS_QWS
982 void QRasterPaintEnginePrivate::prepare(QCustomRasterPaintDevice *device)
983 {
984     rasterBuffer->prepare(device);
985 }
986 #endif
987
988 void QRasterPaintEnginePrivate::drawImage(const QPointF &pt,
989                                           const QImage &img,
990                                           SrcOverBlendFunc func,
991                                           const QRect &clip,
992                                           int alpha,
993                                           const QRect &sr)
994 {
995     if (alpha == 0 || !clip.isValid())
996         return;
997
998     Q_ASSERT(img.depth() >= 8);
999
1000     int srcBPL = img.bytesPerLine();
1001     const uchar *srcBits = img.bits();
1002     int srcSize = img.depth() >> 3; // This is the part that is incompatible with lower than 8-bit..
1003     int iw = img.width();
1004     int ih = img.height();
1005
1006     if (!sr.isEmpty()) {
1007         iw = sr.width();
1008         ih = sr.height();
1009         // Adjust the image according to the source offset...
1010         srcBits += ((sr.y() * srcBPL) + sr.x() * srcSize);
1011     }
1012
1013     // adapt the x parameters
1014     int x = qRound(pt.x());
1015     int cx1 = clip.x();
1016     int cx2 = clip.x() + clip.width();
1017     if (x < cx1) {
1018         int d = cx1 - x;
1019         srcBits += srcSize * d;
1020         iw -= d;
1021         x = cx1;
1022     }
1023     if (x + iw > cx2) {
1024         int d = x + iw - cx2;
1025         iw -= d;
1026     }
1027     if (iw <= 0)
1028         return;
1029
1030     // adapt the y paremeters...
1031     int cy1 = clip.y();
1032     int cy2 = clip.y() + clip.height();
1033     int y = qRound(pt.y());
1034     if (y < cy1) {
1035         int d = cy1 - y;
1036         srcBits += srcBPL * d;
1037         ih -= d;
1038         y = cy1;
1039     }
1040     if (y + ih > cy2) {
1041         int d = y + ih - cy2;
1042         ih -= d;
1043     }
1044     if (ih <= 0)
1045         return;
1046
1047     // call the blend function...
1048     int dstSize = rasterBuffer->bytesPerPixel();
1049     int dstBPL = rasterBuffer->bytesPerLine();
1050     func(rasterBuffer->buffer() + x * dstSize + y * dstBPL, dstBPL,
1051          srcBits, srcBPL,
1052          iw, ih,
1053          alpha);
1054 }
1055
1056
1057 void QRasterPaintEnginePrivate::systemStateChanged()
1058 {
1059     deviceRectUnclipped = QRect(0, 0,
1060             qMin(QT_RASTER_COORD_LIMIT, device->width()),
1061             qMin(QT_RASTER_COORD_LIMIT, device->height()));
1062
1063     if (!systemClip.isEmpty()) {
1064         QRegion clippedDeviceRgn = systemClip & deviceRectUnclipped;
1065         deviceRect = clippedDeviceRgn.boundingRect();
1066         baseClip->setClipRegion(clippedDeviceRgn);
1067     } else {
1068         deviceRect = deviceRectUnclipped;
1069         baseClip->setClipRect(deviceRect);
1070     }
1071 #ifdef QT_DEBUG_DRAW
1072     qDebug() << "systemStateChanged" << this << "deviceRect" << deviceRect << deviceRectUnclipped << systemClip;
1073 #endif
1074
1075     exDeviceRect = deviceRect;
1076
1077     Q_Q(QRasterPaintEngine);
1078     q->state()->strokeFlags |= QPaintEngine::DirtyClipRegion;
1079     q->state()->fillFlags |= QPaintEngine::DirtyClipRegion;
1080     q->state()->pixmapFlags |= QPaintEngine::DirtyClipRegion;
1081 }
1082
1083 void QRasterPaintEnginePrivate::updateMatrixData(QSpanData *spanData, const QBrush &b, const QTransform &m)
1084 {
1085     if (b.d->style == Qt::NoBrush || b.d->style == Qt::SolidPattern)
1086         return;
1087
1088     Q_Q(QRasterPaintEngine);
1089     bool bilinear = q->state()->flags.bilinear;
1090
1091     if (b.d->transform.type() > QTransform::TxNone) { // FALCON: optimize
1092         spanData->setupMatrix(b.transform() * m, bilinear);
1093     } else {
1094         if (m.type() <= QTransform::TxTranslate) {
1095             // specialize setupMatrix for translation matrices
1096             // to avoid needless matrix inversion
1097             spanData->m11 = 1;
1098             spanData->m12 = 0;
1099             spanData->m13 = 0;
1100             spanData->m21 = 0;
1101             spanData->m22 = 1;
1102             spanData->m23 = 0;
1103             spanData->m33 = 1;
1104             spanData->dx = -m.dx();
1105             spanData->dy = -m.dy();
1106             spanData->txop = m.type();
1107             spanData->bilinear = bilinear;
1108             spanData->fast_matrix = qAbs(m.dx()) < 1e4 && qAbs(m.dy()) < 1e4;
1109             spanData->adjustSpanMethods();
1110         } else {
1111             spanData->setupMatrix(m, bilinear);
1112         }
1113     }
1114 }
1115
1116 // #define QT_CLIPPING_RATIOS
1117
1118 #ifdef QT_CLIPPING_RATIOS
1119 int rectClips;
1120 int regionClips;
1121 int totalClips;
1122
1123 static void checkClipRatios(QRasterPaintEnginePrivate *d)
1124 {
1125     if (d->clip()->hasRectClip)
1126         rectClips++;
1127     if (d->clip()->hasRegionClip)
1128         regionClips++;
1129     totalClips++;
1130
1131     if ((totalClips % 5000) == 0) {
1132         printf("Clipping ratio: rectangular=%f%%, region=%f%%, complex=%f%%\n",
1133                rectClips * 100.0 / (qreal) totalClips,
1134                regionClips * 100.0 / (qreal) totalClips,
1135                (totalClips - rectClips - regionClips) * 100.0 / (qreal) totalClips);
1136         totalClips = 0;
1137         rectClips = 0;
1138         regionClips = 0;
1139     }
1140
1141 }
1142 #endif
1143
1144 static void qrasterpaintengine_state_setNoClip(QRasterPaintEngineState *s)
1145 {
1146     if (s->flags.has_clip_ownership)
1147         delete s->clip;
1148     s->clip = 0;
1149     s->flags.has_clip_ownership = false;
1150 }
1151
1152 static void qrasterpaintengine_dirty_clip(QRasterPaintEnginePrivate *d, QRasterPaintEngineState *s)
1153 {
1154     s->fillFlags |= QPaintEngine::DirtyClipPath;
1155     s->strokeFlags |= QPaintEngine::DirtyClipPath;
1156     s->pixmapFlags |= QPaintEngine::DirtyClipPath;
1157
1158     d->solid_color_filler.clip = d->clip();
1159     d->solid_color_filler.adjustSpanMethods();
1160
1161 #ifdef QT_DEBUG_DRAW
1162     dumpClip(d->rasterBuffer->width(), d->rasterBuffer->height(), &*d->clip());
1163 #endif
1164
1165 }
1166
1167
1168 /*!
1169     \internal
1170 */
1171 void QRasterPaintEngine::clip(const QVectorPath &path, Qt::ClipOperation op)
1172 {
1173 #ifdef QT_DEBUG_DRAW
1174     qDebug() << "QRasterPaintEngine::clip(): " << path << op;
1175
1176     if (path.elements()) {
1177         for (int i=0; i<path.elementCount(); ++i) {
1178             qDebug() << " - " << path.elements()[i]
1179                      << '(' << path.points()[i*2] << ", " << path.points()[i*2+1] << ')';
1180         }
1181     } else {
1182         for (int i=0; i<path.elementCount(); ++i) {
1183             qDebug() << " ---- "
1184                      << '(' << path.points()[i*2] << ", " << path.points()[i*2+1] << ')';
1185         }
1186     }
1187 #endif
1188
1189     Q_D(QRasterPaintEngine);
1190     QRasterPaintEngineState *s = state();
1191
1192     const qreal *points = path.points();
1193     const QPainterPath::ElementType *types = path.elements();
1194
1195     // There are some cases that are not supported by clip(QRect)
1196     if (op != Qt::UniteClip && (op != Qt::IntersectClip || !s->clip
1197                                 || s->clip->hasRectClip || s->clip->hasRegionClip)) {
1198         if (s->matrix.type() <= QTransform::TxScale
1199             && ((path.shape() == QVectorPath::RectangleHint)
1200                 || (isRect(points, path.elementCount())
1201                     && (!types || (types[0] == QPainterPath::MoveToElement
1202                                    && types[1] == QPainterPath::LineToElement
1203                                    && types[2] == QPainterPath::LineToElement
1204                                    && types[3] == QPainterPath::LineToElement))))) {
1205 #ifdef QT_DEBUG_DRAW
1206             qDebug() << " --- optimizing vector clip to rect clip...";
1207 #endif
1208
1209             QRectF r(points[0], points[1], points[4]-points[0], points[5]-points[1]);
1210             if (setClipRectInDeviceCoords(s->matrix.mapRect(r).toRect(), op))
1211                 return;
1212         }
1213     }
1214
1215     if (op == Qt::NoClip) {
1216         qrasterpaintengine_state_setNoClip(s);
1217
1218     } else {
1219         QClipData *base = d->baseClip.data();
1220
1221         // Intersect with current clip when available...
1222         if (op == Qt::IntersectClip && s->clip)
1223             base = s->clip;
1224
1225         // We always intersect, except when there is nothing to
1226         // intersect with, in which case we simplify the operation to
1227         // a replace...
1228         Qt::ClipOperation isectOp = Qt::IntersectClip;
1229         if (base == 0)
1230             isectOp = Qt::ReplaceClip;
1231
1232         QClipData *newClip = new QClipData(d->rasterBuffer->height());
1233         newClip->initialize();
1234         ClipData clipData = { base, newClip, isectOp };
1235         ensureOutlineMapper();
1236         d->rasterize(d->outlineMapper->convertPath(path), qt_span_clip, &clipData, 0);
1237
1238         newClip->fixup();
1239
1240         if (op == Qt::UniteClip) {
1241             // merge clips
1242             QClipData *result = new QClipData(d->rasterBuffer->height());
1243             QClipData *current = s->clip ? s->clip : new QClipData(d->rasterBuffer->height());
1244             qt_merge_clip(current, newClip, result);
1245             result->fixup();
1246             delete newClip;
1247             if (!s->clip)
1248                 delete current;
1249             newClip = result;
1250         }
1251
1252         if (s->flags.has_clip_ownership)
1253             delete s->clip;
1254
1255         s->clip = newClip;
1256         s->flags.has_clip_ownership = true;
1257     }
1258     qrasterpaintengine_dirty_clip(d, s);
1259 }
1260
1261
1262
1263 /*!
1264     \internal
1265 */
1266 void QRasterPaintEngine::clip(const QRect &rect, Qt::ClipOperation op)
1267 {
1268 #ifdef QT_DEBUG_DRAW
1269     qDebug() << "QRasterPaintEngine::clip(): " << rect << op;
1270 #endif
1271
1272     QRasterPaintEngineState *s = state();
1273
1274     if (op == Qt::NoClip) {
1275         qrasterpaintengine_state_setNoClip(s);
1276
1277     } else if (op == Qt::UniteClip || s->matrix.type() > QTransform::TxScale) {
1278         QPaintEngineEx::clip(rect, op);
1279         return;
1280
1281     } else if (!setClipRectInDeviceCoords(s->matrix.mapRect(rect), op)) {
1282         QPaintEngineEx::clip(rect, op);
1283         return;
1284     }
1285 }
1286
1287
1288 bool QRasterPaintEngine::setClipRectInDeviceCoords(const QRect &r, Qt::ClipOperation op)
1289 {
1290     Q_D(QRasterPaintEngine);
1291     QRect clipRect = r & d->deviceRect;
1292     QRasterPaintEngineState *s = state();
1293
1294     if (op == Qt::ReplaceClip || s->clip == 0) {
1295
1296         // No current clip, hence we intersect with sysclip and be
1297         // done with it...
1298         QRegion clipRegion = systemClip();
1299         QClipData *clip = new QClipData(d->rasterBuffer->height());
1300
1301         if (clipRegion.isEmpty())
1302             clip->setClipRect(clipRect);
1303         else
1304             clip->setClipRegion(clipRegion & clipRect);
1305
1306         if (s->flags.has_clip_ownership)
1307             delete s->clip;
1308
1309         s->clip = clip;
1310         s->clip->enabled = true;
1311         s->flags.has_clip_ownership = true;
1312
1313     } else if (op == Qt::IntersectClip){ // intersect clip with current clip
1314         QClipData *base = s->clip;
1315
1316         Q_ASSERT(base);
1317         if (base->hasRectClip || base->hasRegionClip) {
1318             if (!s->flags.has_clip_ownership) {
1319                 s->clip = new QClipData(d->rasterBuffer->height());
1320                 s->flags.has_clip_ownership = true;
1321             }
1322             if (base->hasRectClip)
1323                 s->clip->setClipRect(base->clipRect & clipRect);
1324             else
1325                 s->clip->setClipRegion(base->clipRegion & clipRect);
1326             s->clip->enabled = true;
1327         } else {
1328             return false;
1329         }
1330     } else {
1331         return false;
1332     }
1333
1334     qrasterpaintengine_dirty_clip(d, s);
1335     return true;
1336 }
1337
1338
1339 /*!
1340     \internal
1341 */
1342 void QRasterPaintEngine::clip(const QRegion &region, Qt::ClipOperation op)
1343 {
1344 #ifdef QT_DEBUG_DRAW
1345     qDebug() << "QRasterPaintEngine::clip(): " << region << op;
1346 #endif
1347
1348     Q_D(QRasterPaintEngine);
1349
1350     if (region.rectCount() == 1) {
1351         clip(region.boundingRect(), op);
1352         return;
1353     }
1354
1355     QRasterPaintEngineState *s = state();
1356     const QClipData *clip = d->clip();
1357     const QClipData *baseClip = d->baseClip.data();
1358
1359     if (op == Qt::NoClip) {
1360         qrasterpaintengine_state_setNoClip(s);
1361     } else if (s->matrix.type() > QTransform::TxScale
1362                || op == Qt::UniteClip
1363                || (op == Qt::IntersectClip && !clip->hasRectClip && !clip->hasRegionClip)
1364                || (op == Qt::ReplaceClip && !baseClip->hasRectClip && !baseClip->hasRegionClip)) {
1365         QPaintEngineEx::clip(region, op);
1366     } else {
1367         const QClipData *curClip;
1368         QClipData *newClip;
1369
1370         if (op == Qt::IntersectClip)
1371             curClip = clip;
1372         else
1373             curClip = baseClip;
1374
1375         if (s->flags.has_clip_ownership) {
1376             newClip = s->clip;
1377             Q_ASSERT(newClip);
1378         } else {
1379             newClip = new QClipData(d->rasterBuffer->height());
1380             s->clip = newClip;
1381             s->flags.has_clip_ownership = true;
1382         }
1383
1384         QRegion r = s->matrix.map(region);
1385         if (curClip->hasRectClip)
1386             newClip->setClipRegion(r & curClip->clipRect);
1387         else if (curClip->hasRegionClip)
1388             newClip->setClipRegion(r & curClip->clipRegion);
1389
1390         qrasterpaintengine_dirty_clip(d, s);
1391     }
1392 }
1393
1394 /*!
1395     \internal
1396 */
1397 void QRasterPaintEngine::fillPath(const QPainterPath &path, QSpanData *fillData)
1398 {
1399 #ifdef QT_DEBUG_DRAW
1400     qDebug() << " --- fillPath, bounds=" << path.boundingRect();
1401 #endif
1402
1403     if (!fillData->blend)
1404         return;
1405
1406     Q_D(QRasterPaintEngine);
1407
1408     const QRectF controlPointRect = path.controlPointRect();
1409
1410     QRasterPaintEngineState *s = state();
1411     const QRect deviceRect = s->matrix.mapRect(controlPointRect).toRect();
1412     ProcessSpans blend = d->getBrushFunc(deviceRect, fillData);
1413     const bool do_clip = (deviceRect.left() < -QT_RASTER_COORD_LIMIT
1414                           || deviceRect.right() > QT_RASTER_COORD_LIMIT
1415                           || deviceRect.top() < -QT_RASTER_COORD_LIMIT
1416                           || deviceRect.bottom() > QT_RASTER_COORD_LIMIT);
1417
1418     if (!s->flags.antialiased && !do_clip) {
1419         d->initializeRasterizer(fillData);
1420         d->rasterizer->rasterize(path * s->matrix, path.fillRule());
1421         return;
1422     }
1423
1424     ensureOutlineMapper();
1425     d->rasterize(d->outlineMapper->convertPath(path), blend, fillData, d->rasterBuffer.data());
1426 }
1427
1428 static void fillRect_normalized(const QRect &r, QSpanData *data,
1429                                 QRasterPaintEnginePrivate *pe)
1430 {
1431     int x1, x2, y1, y2;
1432
1433     bool rectClipped = true;
1434
1435     if (data->clip) {
1436         x1 = qMax(r.x(), data->clip->xmin);
1437         x2 = qMin(r.x() + r.width(), data->clip->xmax);
1438         y1 = qMax(r.y(), data->clip->ymin);
1439         y2 = qMin(r.y() + r.height(), data->clip->ymax);
1440         rectClipped = data->clip->hasRectClip;
1441
1442     } else if (pe) {
1443         x1 = qMax(r.x(), pe->deviceRect.x());
1444         x2 = qMin(r.x() + r.width(), pe->deviceRect.x() + pe->deviceRect.width());
1445         y1 = qMax(r.y(), pe->deviceRect.y());
1446         y2 = qMin(r.y() + r.height(), pe->deviceRect.y() + pe->deviceRect.height());
1447     } else {
1448         x1 = qMax(r.x(), 0);
1449         x2 = qMin(r.x() + r.width(), data->rasterBuffer->width());
1450         y1 = qMax(r.y(), 0);
1451         y2 = qMin(r.y() + r.height(), data->rasterBuffer->height());
1452     }
1453
1454     if (x2 <= x1 || y2 <= y1)
1455         return;
1456
1457     const int width = x2 - x1;
1458     const int height = y2 - y1;
1459
1460     bool isUnclipped = rectClipped
1461                        || (pe && pe->isUnclipped_normalized(QRect(x1, y1, width, height)));
1462
1463     if (pe && isUnclipped) {
1464         const QPainter::CompositionMode mode = pe->rasterBuffer->compositionMode;
1465
1466         if (data->fillRect && (mode == QPainter::CompositionMode_Source
1467                                || (mode == QPainter::CompositionMode_SourceOver
1468                                    && qAlpha(data->solid.color) == 255)))
1469         {
1470             data->fillRect(data->rasterBuffer, x1, y1, width, height,
1471                            data->solid.color);
1472             return;
1473         }
1474     }
1475
1476     ProcessSpans blend = isUnclipped ? data->unclipped_blend : data->blend;
1477
1478     const int nspans = 256;
1479     QT_FT_Span spans[nspans];
1480
1481     Q_ASSERT(data->blend);
1482     int y = y1;
1483     while (y < y2) {
1484         int n = qMin(nspans, y2 - y);
1485         int i = 0;
1486         while (i < n) {
1487             spans[i].x = x1;
1488             spans[i].len = width;
1489             spans[i].y = y + i;
1490             spans[i].coverage = 255;
1491             ++i;
1492         }
1493
1494         blend(n, spans, data);
1495         y += n;
1496     }
1497 }
1498
1499 /*!
1500     \reimp
1501 */
1502 void QRasterPaintEngine::drawRects(const QRect *rects, int rectCount)
1503 {
1504 #ifdef QT_DEBUG_DRAW
1505     qDebug(" - QRasterPaintEngine::drawRect(), rectCount=%d", rectCount);
1506 #endif
1507     Q_D(QRasterPaintEngine);
1508     ensureState();
1509     QRasterPaintEngineState *s = state();
1510
1511     // Fill
1512     ensureBrush();
1513     if (s->brushData.blend) {
1514         if (!s->flags.antialiased && s->matrix.type() <= QTransform::TxTranslate) {
1515             const QRect *r = rects;
1516             const QRect *lastRect = rects + rectCount;
1517
1518             int offset_x = int(s->matrix.dx());
1519             int offset_y = int(s->matrix.dy());
1520             while (r < lastRect) {
1521                 QRect rect = r->normalized();
1522                 QRect rr = rect.translated(offset_x, offset_y);
1523                 fillRect_normalized(rr, &s->brushData, d);
1524                 ++r;
1525             }
1526         } else {
1527             QRectVectorPath path;
1528             for (int i=0; i<rectCount; ++i) {
1529                 path.set(rects[i]);
1530                 fill(path, s->brush);
1531             }
1532         }
1533     }
1534
1535     ensurePen();
1536     if (s->penData.blend) {
1537         QRectVectorPath path;
1538         if (s->flags.fast_pen) {
1539             QCosmeticStroker stroker(s, d->deviceRect, d->deviceRectUnclipped);
1540             for (int i = 0; i < rectCount; ++i) {
1541                 path.set(rects[i]);
1542                 stroker.drawPath(path);
1543             }
1544         } else {
1545             for (int i = 0; i < rectCount; ++i) {
1546                 path.set(rects[i]);
1547                 stroke(path, s->pen);
1548             }
1549         }
1550     }
1551 }
1552
1553 /*!
1554     \reimp
1555 */
1556 void QRasterPaintEngine::drawRects(const QRectF *rects, int rectCount)
1557 {
1558 #ifdef QT_DEBUG_DRAW
1559     qDebug(" - QRasterPaintEngine::drawRect(QRectF*), rectCount=%d", rectCount);
1560 #endif
1561 #ifdef QT_FAST_SPANS
1562     Q_D(QRasterPaintEngine);
1563     ensureState();
1564     QRasterPaintEngineState *s = state();
1565
1566
1567     if (s->flags.tx_noshear) {
1568         ensureBrush();
1569         if (s->brushData.blend) {
1570             d->initializeRasterizer(&s->brushData);
1571             for (int i = 0; i < rectCount; ++i) {
1572                 const QRectF &rect = rects[i].normalized();
1573                 if (rect.isEmpty())
1574                     continue;
1575                 const QPointF a = s->matrix.map((rect.topLeft() + rect.bottomLeft()) * 0.5f);
1576                 const QPointF b = s->matrix.map((rect.topRight() + rect.bottomRight()) * 0.5f);
1577                 d->rasterizer->rasterizeLine(a, b, rect.height() / rect.width());
1578             }
1579         }
1580
1581         ensurePen();
1582         if (s->penData.blend) {
1583             QRectVectorPath path;
1584             if (s->flags.fast_pen) {
1585                 QCosmeticStroker stroker(s, d->deviceRect, d->deviceRectUnclipped);
1586                 for (int i = 0; i < rectCount; ++i) {
1587                     path.set(rects[i]);
1588                     stroker.drawPath(path);
1589                 }
1590             } else {
1591                 for (int i = 0; i < rectCount; ++i) {
1592                     path.set(rects[i]);
1593                     QPaintEngineEx::stroke(path, s->lastPen);
1594                 }
1595             }
1596         }
1597
1598         return;
1599     }
1600 #endif // QT_FAST_SPANS
1601     QPaintEngineEx::drawRects(rects, rectCount);
1602 }
1603
1604
1605 /*!
1606     \internal
1607 */
1608 void QRasterPaintEngine::stroke(const QVectorPath &path, const QPen &pen)
1609 {
1610     Q_D(QRasterPaintEngine);
1611     QRasterPaintEngineState *s = state();
1612
1613     ensurePen(pen);
1614     if (!s->penData.blend)
1615         return;
1616
1617     if (s->flags.fast_pen) {
1618         QCosmeticStroker stroker(s, d->deviceRect, d->deviceRectUnclipped);
1619         stroker.drawPath(path);
1620     } else if (s->flags.non_complex_pen && path.shape() == QVectorPath::LinesHint) {
1621         qreal width = s->lastPen.isCosmetic()
1622                       ? (qpen_widthf(s->lastPen) == 0 ? 1 : qpen_widthf(s->lastPen))
1623                       : qpen_widthf(s->lastPen) * s->txscale;
1624         int dashIndex = 0;
1625         qreal dashOffset = s->lastPen.dashOffset();
1626         bool inDash = true;
1627         qreal patternLength = 0;
1628         const QVector<qreal> pattern = s->lastPen.dashPattern();
1629         for (int i = 0; i < pattern.size(); ++i)
1630             patternLength += pattern.at(i);
1631
1632         if (patternLength > 0) {
1633             int n = qFloor(dashOffset / patternLength);
1634             dashOffset -= n * patternLength;
1635             while (dashOffset >= pattern.at(dashIndex)) {
1636                 dashOffset -= pattern.at(dashIndex);
1637                 if (++dashIndex >= pattern.size())
1638                     dashIndex = 0;
1639                 inDash = !inDash;
1640             }
1641         }
1642
1643         Q_D(QRasterPaintEngine);
1644         d->initializeRasterizer(&s->penData);
1645         int lineCount = path.elementCount() / 2;
1646         const QLineF *lines = reinterpret_cast<const QLineF *>(path.points());
1647
1648         for (int i = 0; i < lineCount; ++i) {
1649             if (lines[i].p1() == lines[i].p2()) {
1650                 if (s->lastPen.capStyle() != Qt::FlatCap) {
1651                     QPointF p = lines[i].p1();
1652                     QLineF line = s->matrix.map(QLineF(QPointF(p.x() - width*qreal(0.5), p.y()),
1653                                                        QPointF(p.x() + width*qreal(0.5), p.y())));
1654                     d->rasterizer->rasterizeLine(line.p1(), line.p2(), 1);
1655                 }
1656                 continue;
1657             }
1658
1659             const QLineF line = s->matrix.map(lines[i]);
1660             if (qpen_style(s->lastPen) == Qt::SolidLine) {
1661                 d->rasterizer->rasterizeLine(line.p1(), line.p2(),
1662                                             width / line.length(),
1663                                             s->lastPen.capStyle() == Qt::SquareCap);
1664             } else {
1665                 d->rasterizeLine_dashed(line, width,
1666                                         &dashIndex, &dashOffset, &inDash);
1667             }
1668         }
1669     }
1670     else
1671         QPaintEngineEx::stroke(path, pen);
1672 }
1673
1674 static inline QRect toNormalizedFillRect(const QRectF &rect)
1675 {
1676     int x1 = qRound(rect.x() + aliasedCoordinateDelta);
1677     int y1 = qRound(rect.y() + aliasedCoordinateDelta);
1678     int x2 = qRound(rect.right() + aliasedCoordinateDelta);
1679     int y2 = qRound(rect.bottom() + aliasedCoordinateDelta);
1680
1681     if (x2 < x1)
1682         qSwap(x1, x2);
1683     if (y2 < y1)
1684         qSwap(y1, y2);
1685
1686     return QRect(x1, y1, x2 - x1, y2 - y1);
1687 }
1688
1689 /*!
1690     \internal
1691 */
1692 void QRasterPaintEngine::fill(const QVectorPath &path, const QBrush &brush)
1693 {
1694     if (path.isEmpty())
1695         return;
1696 #ifdef QT_DEBUG_DRAW
1697     QRectF rf = path.controlPointRect();
1698     qDebug() << "QRasterPaintEngine::fill(): "
1699              << "size=" << path.elementCount()
1700              << ", hints=" << hex << path.hints()
1701              << rf << brush;
1702 #endif
1703
1704     Q_D(QRasterPaintEngine);
1705     QRasterPaintEngineState *s = state();
1706
1707     ensureBrush(brush);
1708     if (!s->brushData.blend)
1709         return;
1710
1711     if (path.shape() == QVectorPath::RectangleHint) {
1712         if (!s->flags.antialiased && s->matrix.type() <= QTransform::TxScale) {
1713             const qreal *p = path.points();
1714             QPointF tl = QPointF(p[0], p[1]) * s->matrix;
1715             QPointF br = QPointF(p[4], p[5]) * s->matrix;
1716             fillRect_normalized(toNormalizedFillRect(QRectF(tl, br)), &s->brushData, d);
1717             return;
1718         }
1719         ensureState();
1720         if (s->flags.tx_noshear) {
1721             d->initializeRasterizer(&s->brushData);
1722             // ### Is normalizing really necessary here?
1723             const qreal *p = path.points();
1724             QRectF r = QRectF(p[0], p[1], p[2] - p[0], p[7] - p[1]).normalized();
1725             if (!r.isEmpty()) {
1726                 const QPointF a = s->matrix.map((r.topLeft() + r.bottomLeft()) * 0.5f);
1727                 const QPointF b = s->matrix.map((r.topRight() + r.bottomRight()) * 0.5f);
1728                 d->rasterizer->rasterizeLine(a, b, r.height() / r.width());
1729             }
1730             return;
1731         }
1732     }
1733
1734     // ### Optimize for non transformed ellipses and rectangles...
1735     QRectF cpRect = path.controlPointRect();
1736     const QRect deviceRect = s->matrix.mapRect(cpRect).toRect();
1737     ProcessSpans blend = d->getBrushFunc(deviceRect, &s->brushData);
1738
1739         // ### Falcon
1740 //         const bool do_clip = (deviceRect.left() < -QT_RASTER_COORD_LIMIT
1741 //                               || deviceRect.right() > QT_RASTER_COORD_LIMIT
1742 //                               || deviceRect.top() < -QT_RASTER_COORD_LIMIT
1743 //                               || deviceRect.bottom() > QT_RASTER_COORD_LIMIT);
1744
1745         // ### Falonc: implement....
1746 //         if (!s->flags.antialiased && !do_clip) {
1747 //             d->initializeRasterizer(&s->brushData);
1748 //             d->rasterizer->rasterize(path * d->matrix, path.fillRule());
1749 //             return;
1750 //         }
1751
1752     ensureOutlineMapper();
1753     d->rasterize(d->outlineMapper->convertPath(path), blend, &s->brushData, d->rasterBuffer.data());
1754 }
1755
1756 void QRasterPaintEngine::fillRect(const QRectF &r, QSpanData *data)
1757 {
1758     Q_D(QRasterPaintEngine);
1759     QRasterPaintEngineState *s = state();
1760
1761     if (!s->flags.antialiased) {
1762         uint txop = s->matrix.type();
1763         if (txop == QTransform::TxNone) {
1764             fillRect_normalized(toNormalizedFillRect(r), data, d);
1765             return;
1766         } else if (txop == QTransform::TxTranslate) {
1767             const QRect rr = toNormalizedFillRect(r.translated(s->matrix.dx(), s->matrix.dy()));
1768             fillRect_normalized(rr, data, d);
1769             return;
1770         } else if (txop == QTransform::TxScale) {
1771             const QRect rr = toNormalizedFillRect(s->matrix.mapRect(r));
1772             fillRect_normalized(rr, data, d);
1773             return;
1774         }
1775     }
1776     ensureState();
1777     if (s->flags.tx_noshear) {
1778         d->initializeRasterizer(data);
1779         QRectF nr = r.normalized();
1780         if (!nr.isEmpty()) {
1781             const QPointF a = s->matrix.map((nr.topLeft() + nr.bottomLeft()) * 0.5f);
1782             const QPointF b = s->matrix.map((nr.topRight() + nr.bottomRight()) * 0.5f);
1783             d->rasterizer->rasterizeLine(a, b, nr.height() / nr.width());
1784         }
1785         return;
1786     }
1787
1788     QPainterPath path;
1789     path.addRect(r);
1790     ensureOutlineMapper();
1791     fillPath(path, data);
1792 }
1793
1794 /*!
1795     \reimp
1796 */
1797 void QRasterPaintEngine::fillRect(const QRectF &r, const QBrush &brush)
1798 {
1799 #ifdef QT_DEBUG_DRAW
1800     qDebug() << "QRasterPaintEngine::fillRecct(): " << r << brush;
1801 #endif
1802     QRasterPaintEngineState *s = state();
1803
1804     ensureBrush(brush);
1805     if (!s->brushData.blend)
1806         return;
1807
1808     fillRect(r, &s->brushData);
1809 }
1810
1811 /*!
1812     \reimp
1813 */
1814 void QRasterPaintEngine::fillRect(const QRectF &r, const QColor &color)
1815 {
1816 #ifdef QT_DEBUG_DRAW
1817     qDebug() << "QRasterPaintEngine::fillRect(): " << r << color;
1818 #endif
1819     Q_D(QRasterPaintEngine);
1820     QRasterPaintEngineState *s = state();
1821
1822     d->solid_color_filler.solid.color = PREMUL(ARGB_COMBINE_ALPHA(color.rgba(), s->intOpacity));
1823     if ((d->solid_color_filler.solid.color & 0xff000000) == 0
1824         && s->composition_mode == QPainter::CompositionMode_SourceOver) {
1825         return;
1826     }
1827     d->solid_color_filler.clip = d->clip();
1828     d->solid_color_filler.adjustSpanMethods();
1829     fillRect(r, &d->solid_color_filler);
1830 }
1831
1832 static inline bool isAbove(const QPointF *a, const QPointF *b)
1833 {
1834     return a->y() < b->y();
1835 }
1836
1837 static bool splitPolygon(const QPointF *points, int pointCount, QVector<QPointF> *upper, QVector<QPointF> *lower)
1838 {
1839     Q_ASSERT(upper);
1840     Q_ASSERT(lower);
1841
1842     Q_ASSERT(pointCount >= 2);
1843
1844     QVector<const QPointF *> sorted;
1845     sorted.reserve(pointCount);
1846
1847     upper->reserve(pointCount * 3 / 4);
1848     lower->reserve(pointCount * 3 / 4);
1849
1850     for (int i = 0; i < pointCount; ++i)
1851         sorted << points + i;
1852
1853     qSort(sorted.begin(), sorted.end(), isAbove);
1854
1855     qreal splitY = sorted.at(sorted.size() / 2)->y();
1856
1857     const QPointF *end = points + pointCount;
1858     const QPointF *last = end - 1;
1859
1860     QVector<QPointF> *bin[2] = { upper, lower };
1861
1862     for (const QPointF *p = points; p < end; ++p) {
1863         int side = p->y() < splitY;
1864         int lastSide = last->y() < splitY;
1865
1866         if (side != lastSide) {
1867             if (qFuzzyCompare(p->y(), splitY)) {
1868                 bin[!side]->append(*p);
1869             } else if (qFuzzyCompare(last->y(), splitY)) {
1870                 bin[side]->append(*last);
1871             } else {
1872                 QPointF delta = *p - *last;
1873                 QPointF intersection(p->x() + delta.x() * (splitY - p->y()) / delta.y(), splitY);
1874
1875                 bin[0]->append(intersection);
1876                 bin[1]->append(intersection);
1877             }
1878         }
1879
1880         bin[side]->append(*p);
1881
1882         last = p;
1883     }
1884
1885     // give up if we couldn't reduce the point count
1886     return upper->size() < pointCount && lower->size() < pointCount;
1887 }
1888
1889 /*!
1890   \internal
1891  */
1892 void QRasterPaintEngine::fillPolygon(const QPointF *points, int pointCount, PolygonDrawMode mode)
1893 {
1894     Q_D(QRasterPaintEngine);
1895     QRasterPaintEngineState *s = state();
1896
1897     const int maxPoints = 0xffff;
1898
1899     // max amount of points that raster engine can reliably handle
1900     if (pointCount > maxPoints) {
1901         QVector<QPointF> upper, lower;
1902
1903         if (splitPolygon(points, pointCount, &upper, &lower)) {
1904             fillPolygon(upper.constData(), upper.size(), mode);
1905             fillPolygon(lower.constData(), lower.size(), mode);
1906         } else
1907             qWarning("Polygon too complex for filling.");
1908
1909         return;
1910     }
1911
1912     // Compose polygon fill..,
1913     QVectorPath vp((qreal *) points, pointCount, 0, QVectorPath::polygonFlags(mode));
1914     ensureOutlineMapper();
1915     QT_FT_Outline *outline = d->outlineMapper->convertPath(vp);
1916
1917     // scanconvert.
1918     ProcessSpans brushBlend = d->getBrushFunc(d->outlineMapper->controlPointRect,
1919                                               &s->brushData);
1920     d->rasterize(outline, brushBlend, &s->brushData, d->rasterBuffer.data());
1921 }
1922
1923 /*!
1924     \reimp
1925 */
1926 void QRasterPaintEngine::drawPolygon(const QPointF *points, int pointCount, PolygonDrawMode mode)
1927 {
1928     Q_D(QRasterPaintEngine);
1929     QRasterPaintEngineState *s = state();
1930
1931 #ifdef QT_DEBUG_DRAW
1932     qDebug(" - QRasterPaintEngine::drawPolygon(F), pointCount=%d", pointCount);
1933     for (int i=0; i<pointCount; ++i)
1934         qDebug() << "   - " << points[i];
1935 #endif
1936     Q_ASSERT(pointCount >= 2);
1937
1938     if (mode != PolylineMode && isRect((qreal *) points, pointCount)) {
1939         QRectF r(points[0], points[2]);
1940         drawRects(&r, 1);
1941         return;
1942     }
1943
1944     ensurePen();
1945     if (mode != PolylineMode) {
1946         // Do the fill...
1947         ensureBrush();
1948         if (s->brushData.blend)
1949             fillPolygon(points, pointCount, mode);
1950     }
1951
1952     // Do the outline...
1953     if (s->penData.blend) {
1954         QVectorPath vp((qreal *) points, pointCount, 0, QVectorPath::polygonFlags(mode));
1955         if (s->flags.fast_pen) {
1956             QCosmeticStroker stroker(s, d->deviceRect, d->deviceRectUnclipped);
1957             stroker.drawPath(vp);
1958         } else {
1959             QPaintEngineEx::stroke(vp, s->lastPen);
1960         }
1961     }
1962 }
1963
1964 /*!
1965     \reimp
1966 */
1967 void QRasterPaintEngine::drawPolygon(const QPoint *points, int pointCount, PolygonDrawMode mode)
1968 {
1969     Q_D(QRasterPaintEngine);
1970     QRasterPaintEngineState *s = state();
1971
1972 #ifdef QT_DEBUG_DRAW
1973     qDebug(" - QRasterPaintEngine::drawPolygon(I), pointCount=%d", pointCount);
1974     for (int i=0; i<pointCount; ++i)
1975         qDebug() << "   - " << points[i];
1976 #endif
1977     Q_ASSERT(pointCount >= 2);
1978     if (mode != PolylineMode && isRect((int *) points, pointCount)) {
1979         QRect r(points[0].x(),
1980                 points[0].y(),
1981                 points[2].x() - points[0].x(),
1982                 points[2].y() - points[0].y());
1983         drawRects(&r, 1);
1984         return;
1985     }
1986
1987     ensurePen();
1988
1989     // Do the fill
1990     if (mode != PolylineMode) {
1991         ensureBrush();
1992         if (s->brushData.blend) {
1993             // Compose polygon fill..,
1994             ensureOutlineMapper();
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         }
2009     }
2010
2011     // Do the outline...
2012     if (s->penData.blend) {
2013         int count = pointCount * 2;
2014         QVarLengthArray<qreal> fpoints(count);
2015     #ifdef Q_WS_MAC
2016         for (int i=0; i<count; i+=2) {
2017             fpoints[i] = ((int *) points)[i+1];
2018             fpoints[i+1] = ((int *) points)[i];
2019         }
2020     #else
2021         for (int i=0; i<count; ++i)
2022             fpoints[i] = ((int *) points)[i];
2023     #endif
2024         QVectorPath vp((qreal *) fpoints.data(), pointCount, 0, QVectorPath::polygonFlags(mode));
2025
2026         if (s->flags.fast_pen) {
2027             QCosmeticStroker stroker(s, d->deviceRect, d->deviceRectUnclipped);
2028             stroker.drawPath(vp);
2029         } else {
2030             QPaintEngineEx::stroke(vp, s->lastPen);
2031         }
2032     }
2033 }
2034
2035 /*!
2036     \internal
2037 */
2038 void QRasterPaintEngine::drawPixmap(const QPointF &pos, const QPixmap &pixmap)
2039 {
2040 #ifdef QT_DEBUG_DRAW
2041     qDebug() << " - QRasterPaintEngine::drawPixmap(), pos=" << pos << " pixmap=" << pixmap.size() << "depth=" << pixmap.depth();
2042 #endif
2043
2044     QPixmapData *pd = pixmap.pixmapData();
2045     if (pd->classId() == QPixmapData::RasterClass) {
2046         const QImage &image = static_cast<QRasterPixmapData *>(pd)->image;
2047         if (image.depth() == 1) {
2048             Q_D(QRasterPaintEngine);
2049             QRasterPaintEngineState *s = state();
2050             if (s->matrix.type() <= QTransform::TxTranslate) {
2051                 ensurePen();
2052                 drawBitmap(pos + QPointF(s->matrix.dx(), s->matrix.dy()), image, &s->penData);
2053             } else {
2054                 drawImage(pos, d->rasterBuffer->colorizeBitmap(image, s->pen.color()));
2055             }
2056         } else {
2057             QRasterPaintEngine::drawImage(pos, image);
2058         }
2059     } else {
2060         const QImage image = pixmap.toImage();
2061         if (pixmap.depth() == 1) {
2062             Q_D(QRasterPaintEngine);
2063             QRasterPaintEngineState *s = state();
2064             if (s->matrix.type() <= QTransform::TxTranslate) {
2065                 ensurePen();
2066                 drawBitmap(pos + QPointF(s->matrix.dx(), s->matrix.dy()), image, &s->penData);
2067             } else {
2068                 drawImage(pos, d->rasterBuffer->colorizeBitmap(image, s->pen.color()));
2069             }
2070         } else {
2071             QRasterPaintEngine::drawImage(pos, image);
2072         }
2073     }
2074 }
2075
2076 /*!
2077     \reimp
2078 */
2079 void QRasterPaintEngine::drawPixmap(const QRectF &r, const QPixmap &pixmap, const QRectF &sr)
2080 {
2081 #ifdef QT_DEBUG_DRAW
2082     qDebug() << " - QRasterPaintEngine::drawPixmap(), r=" << r << " sr=" << sr << " pixmap=" << pixmap.size() << "depth=" << pixmap.depth();
2083 #endif
2084
2085     QPixmapData* pd = pixmap.pixmapData();
2086     if (pd->classId() == QPixmapData::RasterClass) {
2087         const QImage &image = static_cast<QRasterPixmapData *>(pd)->image;
2088         if (image.depth() == 1) {
2089             Q_D(QRasterPaintEngine);
2090             QRasterPaintEngineState *s = state();
2091             if (s->matrix.type() <= QTransform::TxTranslate
2092                 && r.size() == sr.size()
2093                 && r.size() == pixmap.size()) {
2094                 ensurePen();
2095                 drawBitmap(r.topLeft() + QPointF(s->matrix.dx(), s->matrix.dy()), image, &s->penData);
2096                 return;
2097             } else {
2098                 drawImage(r, d->rasterBuffer->colorizeBitmap(image, s->pen.color()), sr);
2099             }
2100         } else {
2101             drawImage(r, image, sr);
2102         }
2103     } else {
2104         QRect clippedSource = sr.toAlignedRect().intersected(pixmap.rect());
2105         const QImage image = pd->toImage(clippedSource);
2106         QRectF translatedSource = sr.translated(-clippedSource.topLeft());
2107         if (image.depth() == 1) {
2108             Q_D(QRasterPaintEngine);
2109             QRasterPaintEngineState *s = state();
2110             if (s->matrix.type() <= QTransform::TxTranslate
2111                 && r.size() == sr.size()
2112                 && r.size() == pixmap.size()) {
2113                 ensurePen();
2114                 drawBitmap(r.topLeft() + QPointF(s->matrix.dx(), s->matrix.dy()), image, &s->penData);
2115                 return;
2116             } else {
2117                 drawImage(r, d->rasterBuffer->colorizeBitmap(image, s->pen.color()), translatedSource);
2118             }
2119         } else {
2120             drawImage(r, image, translatedSource);
2121         }
2122     }
2123 }
2124
2125 // assumes that rect has positive width and height
2126 static inline const QRect toRect_normalized(const QRectF &rect)
2127 {
2128     const int x = qRound(rect.x());
2129     const int y = qRound(rect.y());
2130     const int w = int(rect.width() + qreal(0.5));
2131     const int h = int(rect.height() + qreal(0.5));
2132
2133     return QRect(x, y, w, h);
2134 }
2135
2136 static inline int fast_ceil_positive(const qreal &v)
2137 {
2138     const int iv = int(v);
2139     if (v - iv == 0)
2140         return iv;
2141     else
2142         return iv + 1;
2143 }
2144
2145 static inline const QRect toAlignedRect_positive(const QRectF &rect)
2146 {
2147     const int xmin = int(rect.x());
2148     const int xmax = int(fast_ceil_positive(rect.right()));
2149     const int ymin = int(rect.y());
2150     const int ymax = int(fast_ceil_positive(rect.bottom()));
2151     return QRect(xmin, ymin, xmax - xmin, ymax - ymin);
2152 }
2153
2154 /*!
2155     \internal
2156 */
2157 void QRasterPaintEngine::drawImage(const QPointF &p, const QImage &img)
2158 {
2159 #ifdef QT_DEBUG_DRAW
2160     qDebug() << " - QRasterPaintEngine::drawImage(), p=" <<  p << " image=" << img.size() << "depth=" << img.depth();
2161 #endif
2162
2163     Q_D(QRasterPaintEngine);
2164     QRasterPaintEngineState *s = state();
2165
2166     if (s->matrix.type() > QTransform::TxTranslate) {
2167         drawImage(QRectF(p.x(), p.y(), img.width(), img.height()),
2168                   img,
2169                   QRectF(0, 0, img.width(), img.height()));
2170     } else {
2171
2172         const QClipData *clip = d->clip();
2173         QPointF pt(p.x() + s->matrix.dx(), p.y() + s->matrix.dy());
2174
2175         if (d->canUseFastImageBlending(d->rasterBuffer->compositionMode, img)) {
2176             SrcOverBlendFunc func = qBlendFunctions[d->rasterBuffer->format][img.format()];
2177             if (func) {
2178                 if (!clip) {
2179                     d->drawImage(pt, img, func, d->deviceRect, s->intOpacity);
2180                     return;
2181                 } else if (clip->hasRectClip) {
2182                     d->drawImage(pt, img, func, clip->clipRect, s->intOpacity);
2183                     return;
2184                 }
2185             }
2186         }
2187
2188
2189
2190         d->image_filler.clip = clip;
2191         d->image_filler.initTexture(&img, s->intOpacity, QTextureData::Plain, img.rect());
2192         if (!d->image_filler.blend)
2193             return;
2194         d->image_filler.dx = -pt.x();
2195         d->image_filler.dy = -pt.y();
2196         QRect rr = img.rect().translated(qRound(pt.x()), qRound(pt.y()));
2197
2198         fillRect_normalized(rr, &d->image_filler, d);
2199     }
2200
2201 }
2202
2203 QRectF qt_mapRect_non_normalizing(const QRectF &r, const QTransform &t)
2204 {
2205     return QRectF(r.topLeft() * t, r.bottomRight() * t);
2206 }
2207
2208 namespace {
2209     enum RotationType {
2210         Rotation90,
2211         Rotation180,
2212         Rotation270,
2213         NoRotation
2214     };
2215
2216     inline RotationType qRotationType(const QTransform &transform)
2217     {
2218         QTransform::TransformationType type = transform.type();
2219
2220         if (type > QTransform::TxRotate)
2221             return NoRotation;
2222
2223         if (type == QTransform::TxRotate && qFuzzyIsNull(transform.m11()) && qFuzzyCompare(transform.m12(), qreal(-1))
2224             && qFuzzyCompare(transform.m21(), qreal(1)) && qFuzzyIsNull(transform.m22()))
2225             return Rotation90;
2226
2227         if (type == QTransform::TxScale && qFuzzyCompare(transform.m11(), qreal(-1)) && qFuzzyIsNull(transform.m12())
2228             && qFuzzyIsNull(transform.m21()) && qFuzzyCompare(transform.m22(), qreal(-1)))
2229             return Rotation180;
2230
2231         if (type == QTransform::TxRotate && qFuzzyIsNull(transform.m11()) && qFuzzyCompare(transform.m12(), qreal(1))
2232             && qFuzzyCompare(transform.m21(), qreal(-1)) && qFuzzyIsNull(transform.m22()))
2233             return Rotation270;
2234
2235         return NoRotation;
2236     }
2237
2238     inline bool isPixelAligned(const QRectF &rect) {
2239         return QRectF(rect.toRect()) == rect;
2240     }
2241 }
2242
2243 /*!
2244     \reimp
2245 */
2246 void QRasterPaintEngine::drawImage(const QRectF &r, const QImage &img, const QRectF &sr,
2247                                    Qt::ImageConversionFlags)
2248 {
2249 #ifdef QT_DEBUG_DRAW
2250     qDebug() << " - QRasterPaintEngine::drawImage(), r=" << r << " sr=" << sr << " image=" << img.size() << "depth=" << img.depth();
2251 #endif
2252
2253     if (r.isEmpty())
2254         return;
2255
2256     Q_D(QRasterPaintEngine);
2257     QRasterPaintEngineState *s = state();
2258     int sr_l = qFloor(sr.left());
2259     int sr_r = qCeil(sr.right()) - 1;
2260     int sr_t = qFloor(sr.top());
2261     int sr_b = qCeil(sr.bottom()) - 1;
2262
2263     if (s->matrix.type() <= QTransform::TxScale && !s->flags.antialiased && sr_l == sr_r && sr_t == sr_b) {
2264         // as fillRect will apply the aliased coordinate delta we need to
2265         // subtract it here as we don't use it for image drawing
2266         QTransform old = s->matrix;
2267         s->matrix = s->matrix * QTransform::fromTranslate(-aliasedCoordinateDelta, -aliasedCoordinateDelta);
2268
2269         // Do whatever fillRect() does, but without premultiplying the color if it's already premultiplied.
2270         QRgb color = img.pixel(sr_l, sr_t);
2271         switch (img.format()) {
2272         case QImage::Format_ARGB32_Premultiplied:
2273         case QImage::Format_ARGB8565_Premultiplied:
2274         case QImage::Format_ARGB6666_Premultiplied:
2275         case QImage::Format_ARGB8555_Premultiplied:
2276         case QImage::Format_ARGB4444_Premultiplied:
2277             // Combine premultiplied color with the opacity set on the painter.
2278             d->solid_color_filler.solid.color =
2279                 ((((color & 0x00ff00ff) * s->intOpacity) >> 8) & 0x00ff00ff)
2280                 | ((((color & 0xff00ff00) >> 8) * s->intOpacity) & 0xff00ff00);
2281             break;
2282         default:
2283             d->solid_color_filler.solid.color = PREMUL(ARGB_COMBINE_ALPHA(color, s->intOpacity));
2284             break;
2285         }
2286
2287         if ((d->solid_color_filler.solid.color & 0xff000000) == 0
2288             && s->composition_mode == QPainter::CompositionMode_SourceOver) {
2289             return;
2290         }
2291
2292         d->solid_color_filler.clip = d->clip();
2293         d->solid_color_filler.adjustSpanMethods();
2294         fillRect(r, &d->solid_color_filler);
2295
2296         s->matrix = old;
2297         return;
2298     }
2299
2300     bool stretch_sr = r.width() != sr.width() || r.height() != sr.height();
2301
2302     const QClipData *clip = d->clip();
2303
2304     if (s->matrix.type() > QTransform::TxTranslate
2305         && !stretch_sr
2306         && (!clip || clip->hasRectClip)
2307         && s->intOpacity == 256
2308         && (d->rasterBuffer->compositionMode == QPainter::CompositionMode_SourceOver
2309             || d->rasterBuffer->compositionMode == QPainter::CompositionMode_Source)
2310         && d->rasterBuffer->format == img.format()
2311         && (d->rasterBuffer->format == QImage::Format_RGB16
2312             || d->rasterBuffer->format == QImage::Format_RGB32
2313             || (d->rasterBuffer->format == QImage::Format_ARGB32_Premultiplied
2314                 && d->rasterBuffer->compositionMode == QPainter::CompositionMode_Source)))
2315     {
2316         RotationType rotationType = qRotationType(s->matrix);
2317
2318         if (rotationType != NoRotation && qMemRotateFunctions[d->rasterBuffer->format][rotationType] && img.rect().contains(sr.toAlignedRect())) {
2319             QRectF transformedTargetRect = s->matrix.mapRect(r);
2320
2321             if ((!(s->renderHints & QPainter::SmoothPixmapTransform) && !(s->renderHints & QPainter::Antialiasing))
2322                 || (isPixelAligned(transformedTargetRect) && isPixelAligned(sr)))
2323             {
2324                 QRect clippedTransformedTargetRect = transformedTargetRect.toRect().intersected(clip ? clip->clipRect : d->deviceRect);
2325                 if (clippedTransformedTargetRect.isNull())
2326                     return;
2327
2328                 QRectF clippedTargetRect = s->matrix.inverted().mapRect(QRectF(clippedTransformedTargetRect));
2329
2330                 QRect clippedSourceRect
2331                     = QRectF(sr.x() + clippedTargetRect.x() - r.x(), sr.y() + clippedTargetRect.y() - r.y(),
2332                             clippedTargetRect.width(), clippedTargetRect.height()).toRect();
2333
2334                 uint dbpl = d->rasterBuffer->bytesPerLine();
2335                 uint sbpl = img.bytesPerLine();
2336
2337                 uchar *dst = d->rasterBuffer->buffer();
2338                 uint bpp = img.depth() >> 3;
2339
2340                 const uchar *srcBase = img.bits() + clippedSourceRect.y() * sbpl + clippedSourceRect.x() * bpp;
2341                 uchar *dstBase = dst + clippedTransformedTargetRect.y() * dbpl + clippedTransformedTargetRect.x() * bpp;
2342
2343                 uint cw = clippedSourceRect.width();
2344                 uint ch = clippedSourceRect.height();
2345
2346                 qMemRotateFunctions[d->rasterBuffer->format][rotationType](srcBase, cw, ch, sbpl, dstBase, dbpl);
2347
2348                 return;
2349             }
2350         }
2351     }
2352
2353     if (s->matrix.type() > QTransform::TxTranslate || stretch_sr) {
2354
2355         QRectF targetBounds = s->matrix.mapRect(r);
2356         bool exceedsPrecision = targetBounds.width() > 0xffff
2357                                 || targetBounds.height() > 0xffff;
2358
2359         if (!exceedsPrecision && d->canUseFastImageBlending(d->rasterBuffer->compositionMode, img)) {
2360             if (s->matrix.type() > QTransform::TxScale) {
2361                 SrcOverTransformFunc func = qTransformFunctions[d->rasterBuffer->format][img.format()];
2362                 if (func && (!clip || clip->hasRectClip)) {
2363                     func(d->rasterBuffer->buffer(), d->rasterBuffer->bytesPerLine(), img.bits(),
2364                          img.bytesPerLine(), r, sr, !clip ? d->deviceRect : clip->clipRect,
2365                          s->matrix, s->intOpacity);
2366                     return;
2367                 }
2368             } else {
2369                 SrcOverScaleFunc func = qScaleFunctions[d->rasterBuffer->format][img.format()];
2370                 if (func && (!clip || clip->hasRectClip)) {
2371                     func(d->rasterBuffer->buffer(), d->rasterBuffer->bytesPerLine(),
2372                          img.bits(), img.bytesPerLine(), img.height(),
2373                          qt_mapRect_non_normalizing(r, s->matrix), sr,
2374                          !clip ? d->deviceRect : clip->clipRect,
2375                          s->intOpacity);
2376                     return;
2377                 }
2378             }
2379         }
2380
2381         QTransform copy = s->matrix;
2382         copy.translate(r.x(), r.y());
2383         if (stretch_sr)
2384             copy.scale(r.width() / sr.width(), r.height() / sr.height());
2385         copy.translate(-sr.x(), -sr.y());
2386
2387         d->image_filler_xform.clip = clip;
2388         d->image_filler_xform.initTexture(&img, s->intOpacity, QTextureData::Plain, toAlignedRect_positive(sr));
2389         if (!d->image_filler_xform.blend)
2390             return;
2391         d->image_filler_xform.setupMatrix(copy, s->flags.bilinear);
2392
2393         if (!s->flags.antialiased && s->matrix.type() == QTransform::TxScale) {
2394             QPointF rr_tl = s->matrix.map(r.topLeft());
2395             QPointF rr_br = s->matrix.map(r.bottomRight());
2396
2397             int x1 = qRound(rr_tl.x());
2398             int y1 = qRound(rr_tl.y());
2399             int x2 = qRound(rr_br.x());
2400             int y2 = qRound(rr_br.y());
2401
2402             if (x1 > x2)
2403                 qSwap(x1, x2);
2404             if (y1 > y2)
2405                 qSwap(y1, y2);
2406
2407             fillRect_normalized(QRect(x1, y1, x2-x1, y2-y1), &d->image_filler_xform, d);
2408             return;
2409         }
2410
2411 #ifdef QT_FAST_SPANS
2412         ensureState();
2413         if (s->flags.tx_noshear || s->matrix.type() == QTransform::TxScale) {
2414             d->initializeRasterizer(&d->image_filler_xform);
2415             d->rasterizer->setAntialiased(s->flags.antialiased);
2416
2417             const QPointF offs = s->flags.antialiased ? QPointF() : QPointF(aliasedCoordinateDelta, aliasedCoordinateDelta);
2418
2419             const QRectF &rect = r.normalized();
2420             const QPointF a = s->matrix.map((rect.topLeft() + rect.bottomLeft()) * 0.5f) - offs;
2421             const QPointF b = s->matrix.map((rect.topRight() + rect.bottomRight()) * 0.5f) - offs;
2422
2423             if (s->flags.tx_noshear)
2424                 d->rasterizer->rasterizeLine(a, b, rect.height() / rect.width());
2425             else
2426                 d->rasterizer->rasterizeLine(a, b, qAbs((s->matrix.m22() * rect.height()) / (s->matrix.m11() * rect.width())));
2427             return;
2428         }
2429 #endif
2430         const qreal offs = s->flags.antialiased ? qreal(0) : aliasedCoordinateDelta;
2431         QPainterPath path;
2432         path.addRect(r);
2433         QTransform m = s->matrix;
2434         s->matrix = QTransform(m.m11(), m.m12(), m.m13(),
2435                                m.m21(), m.m22(), m.m23(),
2436                                m.m31() - offs, m.m32() - offs, m.m33());
2437         fillPath(path, &d->image_filler_xform);
2438         s->matrix = m;
2439     } else {
2440         if (d->canUseFastImageBlending(d->rasterBuffer->compositionMode, img)) {
2441             SrcOverBlendFunc func = qBlendFunctions[d->rasterBuffer->format][img.format()];
2442             if (func) {
2443                 QPointF pt(r.x() + s->matrix.dx(), r.y() + s->matrix.dy());
2444                 if (!clip) {
2445                     d->drawImage(pt, img, func, d->deviceRect, s->intOpacity, sr.toRect());
2446                     return;
2447                 } else if (clip->hasRectClip) {
2448                     d->drawImage(pt, img, func, clip->clipRect, s->intOpacity, sr.toRect());
2449                     return;
2450                 }
2451             }
2452         }
2453
2454         d->image_filler.clip = clip;
2455         d->image_filler.initTexture(&img, s->intOpacity, QTextureData::Plain, toAlignedRect_positive(sr));
2456         if (!d->image_filler.blend)
2457             return;
2458         d->image_filler.dx = -(r.x() + s->matrix.dx()) + sr.x();
2459         d->image_filler.dy = -(r.y() + s->matrix.dy()) + sr.y();
2460
2461         QRectF rr = r;
2462         rr.translate(s->matrix.dx(), s->matrix.dy());
2463
2464         const int x1 = qRound(rr.x());
2465         const int y1 = qRound(rr.y());
2466         const int x2 = qRound(rr.right());
2467         const int y2 = qRound(rr.bottom());
2468
2469         fillRect_normalized(QRect(x1, y1, x2-x1, y2-y1), &d->image_filler, d);
2470     }
2471 }
2472
2473 /*!
2474     \reimp
2475 */
2476 void QRasterPaintEngine::drawTiledPixmap(const QRectF &r, const QPixmap &pixmap, const QPointF &sr)
2477 {
2478 #ifdef QT_DEBUG_DRAW
2479     qDebug() << " - QRasterPaintEngine::drawTiledPixmap(), r=" << r << "pixmap=" << pixmap.size();
2480 #endif
2481     Q_D(QRasterPaintEngine);
2482     QRasterPaintEngineState *s = state();
2483
2484     QImage image;
2485
2486     QPixmapData *pd = pixmap.pixmapData();
2487     if (pd->classId() == QPixmapData::RasterClass) {
2488         image = static_cast<QRasterPixmapData *>(pd)->image;
2489     } else {
2490         image = pixmap.toImage();
2491     }
2492
2493     if (image.depth() == 1)
2494         image = d->rasterBuffer->colorizeBitmap(image, s->pen.color());
2495
2496     if (s->matrix.type() > QTransform::TxTranslate) {
2497         QTransform copy = s->matrix;
2498         copy.translate(r.x(), r.y());
2499         copy.translate(-sr.x(), -sr.y());
2500         d->image_filler_xform.clip = d->clip();
2501         d->image_filler_xform.initTexture(&image, s->intOpacity, QTextureData::Tiled);
2502         if (!d->image_filler_xform.blend)
2503             return;
2504         d->image_filler_xform.setupMatrix(copy, s->flags.bilinear);
2505
2506 #ifdef QT_FAST_SPANS
2507         ensureState();
2508         if (s->flags.tx_noshear || s->matrix.type() == QTransform::TxScale) {
2509             d->initializeRasterizer(&d->image_filler_xform);
2510             d->rasterizer->setAntialiased(s->flags.antialiased);
2511
2512             const QRectF &rect = r.normalized();
2513             const QPointF a = s->matrix.map((rect.topLeft() + rect.bottomLeft()) * 0.5f);
2514             const QPointF b = s->matrix.map((rect.topRight() + rect.bottomRight()) * 0.5f);
2515             if (s->flags.tx_noshear)
2516                 d->rasterizer->rasterizeLine(a, b, rect.height() / rect.width());
2517             else
2518                 d->rasterizer->rasterizeLine(a, b, qAbs((s->matrix.m22() * rect.height()) / (s->matrix.m11() * rect.width())));
2519             return;
2520         }
2521 #endif
2522         QPainterPath path;
2523         path.addRect(r);
2524         fillPath(path, &d->image_filler_xform);
2525     } else {
2526         d->image_filler.clip = d->clip();
2527
2528         d->image_filler.initTexture(&image, s->intOpacity, QTextureData::Tiled);
2529         if (!d->image_filler.blend)
2530             return;
2531         d->image_filler.dx = -(r.x() + s->matrix.dx()) + sr.x();
2532         d->image_filler.dy = -(r.y() + s->matrix.dy()) + sr.y();
2533
2534         QRectF rr = r;
2535         rr.translate(s->matrix.dx(), s->matrix.dy());
2536         fillRect_normalized(rr.toRect().normalized(), &d->image_filler, d);
2537     }
2538 }
2539
2540
2541 //QWS hack
2542 static inline bool monoVal(const uchar* s, int x)
2543 {
2544     return  (s[x>>3] << (x&7)) & 0x80;
2545 }
2546
2547 /*!
2548     \internal
2549 */
2550 void QRasterPaintEngine::alphaPenBlt(const void* src, int bpl, int depth, int rx,int ry,int w,int h)
2551 {
2552     Q_D(QRasterPaintEngine);
2553     QRasterPaintEngineState *s = state();
2554
2555     if (!s->penData.blend)
2556         return;
2557
2558     QRasterBuffer *rb = d->rasterBuffer.data();
2559
2560     const QRect rect(rx, ry, w, h);
2561     const QClipData *clip = d->clip();
2562     bool unclipped = false;
2563     if (clip) {
2564         // inlined QRect::intersects
2565         const bool intersects = qMax(clip->xmin, rect.left()) <= qMin(clip->xmax - 1, rect.right())
2566                                 && qMax(clip->ymin, rect.top()) <= qMin(clip->ymax - 1, rect.bottom());
2567
2568         if (clip->hasRectClip) {
2569             unclipped = rx > clip->xmin
2570                         && rx + w < clip->xmax
2571                         && ry > clip->ymin
2572                         && ry + h < clip->ymax;
2573         }
2574
2575         if (!intersects)
2576             return;
2577     } else {
2578         // inlined QRect::intersects
2579         const bool intersects = qMax(0, rect.left()) <= qMin(rb->width() - 1, rect.right())
2580                                 && qMax(0, rect.top()) <= qMin(rb->height() - 1, rect.bottom());
2581         if (!intersects)
2582             return;
2583
2584         // inlined QRect::contains
2585         const bool contains = rect.left() >= 0 && rect.right() < rb->width()
2586                               && rect.top() >= 0 && rect.bottom() < rb->height();
2587
2588         unclipped = contains && d->isUnclipped_normalized(rect);
2589     }
2590
2591     ProcessSpans blend = unclipped ? s->penData.unclipped_blend : s->penData.blend;
2592     const uchar * scanline = static_cast<const uchar *>(src);
2593
2594     if (s->flags.fast_text) {
2595         if (unclipped) {
2596             if (depth == 1) {
2597                 if (s->penData.bitmapBlit) {
2598                     s->penData.bitmapBlit(rb, rx, ry, s->penData.solid.color,
2599                                           scanline, w, h, bpl);
2600                     return;
2601                 }
2602             } else if (depth == 8) {
2603                 if (s->penData.alphamapBlit) {
2604                     s->penData.alphamapBlit(rb, rx, ry, s->penData.solid.color,
2605                                             scanline, w, h, bpl, 0);
2606                     return;
2607                 }
2608             } else if (depth == 32) {
2609                 // (A)RGB Alpha mask where the alpha component is not used.
2610                 if (s->penData.alphaRGBBlit) {
2611                     s->penData.alphaRGBBlit(rb, rx, ry, s->penData.solid.color,
2612                                             (const uint *) scanline, w, h, bpl / 4, 0);
2613                     return;
2614                 }
2615             }
2616         } else if (d->deviceDepth == 32 && (depth == 8 || depth == 32)) {
2617             // (A)RGB Alpha mask where the alpha component is not used.
2618             if (!clip) {
2619                 int nx = qMax(0, rx);
2620                 int ny = qMax(0, ry);
2621
2622                 // Move scanline pointer to compensate for moved x and y
2623                 int xdiff = nx - rx;
2624                 int ydiff = ny - ry;
2625                 scanline += ydiff * bpl;
2626                 scanline += xdiff * (depth == 32 ? 4 : 1);
2627
2628                 w -= xdiff;
2629                 h -= ydiff;
2630
2631                 if (nx + w > d->rasterBuffer->width())
2632                     w = d->rasterBuffer->width() - nx;
2633                 if (ny + h > d->rasterBuffer->height())
2634                     h = d->rasterBuffer->height() - ny;
2635
2636                 rx = nx;
2637                 ry = ny;
2638             }
2639             if (depth == 8 && s->penData.alphamapBlit) {
2640                 s->penData.alphamapBlit(rb, rx, ry, s->penData.solid.color,
2641                                         scanline, w, h, bpl, clip);
2642             } else if (depth == 32 && s->penData.alphaRGBBlit) {
2643                 s->penData.alphaRGBBlit(rb, rx, ry, s->penData.solid.color,
2644                                         (const uint *) scanline, w, h, bpl / 4, clip);
2645             }
2646             return;
2647         }
2648     }
2649
2650     int x0 = 0;
2651     if (rx < 0) {
2652         x0 = -rx;
2653         w -= x0;
2654     }
2655
2656     int y0 = 0;
2657     if (ry < 0) {
2658         y0 = -ry;
2659         scanline += bpl * y0;
2660         h -= y0;
2661     }
2662
2663     w = qMin(w, rb->width() - qMax(0, rx));
2664     h = qMin(h, rb->height() - qMax(0, ry));
2665
2666     if (w <= 0 || h <= 0)
2667         return;
2668
2669     const int NSPANS = 256;
2670     QSpan spans[NSPANS];
2671     int current = 0;
2672
2673     const int x1 = x0 + w;
2674     const int y1 = y0 + h;
2675
2676     if (depth == 1) {
2677         for (int y = y0; y < y1; ++y) {
2678             for (int x = x0; x < x1; ) {
2679                 if (!monoVal(scanline, x)) {
2680                     ++x;
2681                     continue;
2682                 }
2683
2684                 if (current == NSPANS) {
2685                     blend(current, spans, &s->penData);
2686                     current = 0;
2687                 }
2688                 spans[current].x = x + rx;
2689                 spans[current].y = y + ry;
2690                 spans[current].coverage = 255;
2691                 int len = 1;
2692                 ++x;
2693                 // extend span until we find a different one.
2694                 while (x < x1 && monoVal(scanline, x)) {
2695                     ++x;
2696                     ++len;
2697                 }
2698                 spans[current].len = len;
2699                 ++current;
2700             }
2701             scanline += bpl;
2702         }
2703     } else if (depth == 8) {
2704         for (int y = y0; y < y1; ++y) {
2705             for (int x = x0; x < x1; ) {
2706                 // Skip those with 0 coverage
2707                 if (scanline[x] == 0) {
2708                     ++x;
2709                     continue;
2710                 }
2711
2712                 if (current == NSPANS) {
2713                     blend(current, spans, &s->penData);
2714                     current = 0;
2715                 }
2716                 int coverage = scanline[x];
2717                 spans[current].x = x + rx;
2718                 spans[current].y = y + ry;
2719                 spans[current].coverage = coverage;
2720                 int len = 1;
2721                 ++x;
2722
2723                 // extend span until we find a different one.
2724                 while (x < x1 && scanline[x] == coverage) {
2725                     ++x;
2726                     ++len;
2727                 }
2728                 spans[current].len = len;
2729                 ++current;
2730             }
2731             scanline += bpl;
2732         }
2733     } else { // 32-bit alpha...
2734         uint *sl = (uint *) src;
2735         for (int y = y0; y < y1; ++y) {
2736             for (int x = x0; x < x1; ) {
2737                 // Skip those with 0 coverage
2738                 if ((sl[x] & 0x00ffffff) == 0) {
2739                     ++x;
2740                     continue;
2741                 }
2742
2743                 if (current == NSPANS) {
2744                     blend(current, spans, &s->penData);
2745                     current = 0;
2746                 }
2747                 uint rgbCoverage = sl[x];
2748                 int coverage = qGreen(rgbCoverage);
2749                 spans[current].x = x + rx;
2750                 spans[current].y = y + ry;
2751                 spans[current].coverage = coverage;
2752                 int len = 1;
2753                 ++x;
2754
2755                 // extend span until we find a different one.
2756                 while (x < x1 && sl[x] == rgbCoverage) {
2757                     ++x;
2758                     ++len;
2759                 }
2760                 spans[current].len = len;
2761                 ++current;
2762             }
2763             sl += bpl / sizeof(uint);
2764         }
2765     }
2766 //     qDebug() << "alphaPenBlt: num spans=" << current
2767 //              << "span:" << spans->x << spans->y << spans->len << spans->coverage;
2768         // Call span func for current set of spans.
2769     if (current != 0)
2770         blend(current, spans, &s->penData);
2771 }
2772
2773 bool QRasterPaintEngine::drawCachedGlyphs(int numGlyphs, const glyph_t *glyphs,
2774                                           const QFixedPoint *positions, QFontEngine *fontEngine)
2775 {
2776     Q_D(QRasterPaintEngine);
2777     QRasterPaintEngineState *s = state();
2778     const QFixed offs = QFixed::fromReal(aliasedCoordinateDelta);
2779
2780 #if !defined(QT_NO_FREETYPE)
2781     if (fontEngine->type() == QFontEngine::Freetype) {
2782         QFontEngineFT *fe = static_cast<QFontEngineFT *>(fontEngine);
2783         const QFixed xOffs = fe->supportsSubPixelPositions() ? 0 : offs;
2784         QFontEngineFT::GlyphFormat neededFormat =
2785             painter()->device()->devType() == QInternal::Widget
2786             ? fe->defaultGlyphFormat()
2787             : QFontEngineFT::Format_A8;
2788
2789         if (d_func()->mono_surface
2790             || fe->isBitmapFont() // alphaPenBlt can handle mono, too
2791             )
2792             neededFormat = QFontEngineFT::Format_Mono;
2793
2794         if (neededFormat == QFontEngineFT::Format_None)
2795             neededFormat = QFontEngineFT::Format_A8;
2796
2797         QFontEngineFT::QGlyphSet *gset = fe->defaultGlyphs();
2798         if (s->matrix.type() >= QTransform::TxScale) {
2799             if (s->matrix.isAffine())
2800                 gset = fe->loadTransformedGlyphSet(s->matrix);
2801             else
2802                 gset = 0;
2803         }
2804
2805         if (!gset || gset->outline_drawing
2806             || !fe->loadGlyphs(gset, glyphs, numGlyphs, positions, neededFormat))
2807             return false;
2808
2809         FT_Face lockedFace = 0;
2810
2811         int depth;
2812         switch (neededFormat) {
2813         case QFontEngineFT::Format_Mono:
2814             depth = 1;
2815             break;
2816         case QFontEngineFT::Format_A8:
2817             depth = 8;
2818             break;
2819         case QFontEngineFT::Format_A32:
2820             depth = 32;
2821             break;
2822         default:
2823             Q_ASSERT(false);
2824             depth = 0;
2825         };
2826
2827         for (int i = 0; i < numGlyphs; i++) {
2828             QFixed spp = fe->subPixelPositionForX(positions[i].x);
2829             QFontEngineFT::Glyph *glyph = gset->getGlyph(glyphs[i], spp);
2830
2831             if (!glyph || glyph->format != neededFormat) {
2832                 if (!lockedFace)
2833                     lockedFace = fe->lockFace();
2834                 glyph = fe->loadGlyph(gset, glyphs[i], spp, neededFormat);
2835             }
2836
2837             if (!glyph || !glyph->data)
2838                 continue;
2839
2840             int pitch;
2841             switch (neededFormat) {
2842             case QFontEngineFT::Format_Mono:
2843                 pitch = ((glyph->width + 31) & ~31) >> 3;
2844                 break;
2845             case QFontEngineFT::Format_A8:
2846                 pitch = (glyph->width + 3) & ~3;
2847                 break;
2848             case QFontEngineFT::Format_A32:
2849                 pitch = glyph->width * 4;
2850                 break;
2851             default:
2852                 Q_ASSERT(false);
2853                 pitch = 0;
2854             };
2855
2856             alphaPenBlt(glyph->data, pitch, depth,
2857                         qFloor(positions[i].x + xOffs) + glyph->x,
2858                         qFloor(positions[i].y + offs) - glyph->y,
2859                         glyph->width, glyph->height);
2860         }
2861         if (lockedFace)
2862             fe->unlockFace();
2863     } else
2864 #endif
2865     {
2866         QFontEngineGlyphCache::Type glyphType = fontEngine->glyphFormat >= 0
2867                 ? QFontEngineGlyphCache::Type(fontEngine->glyphFormat)
2868                 : d->glyphCacheType;
2869
2870         QImageTextureGlyphCache *cache =
2871             static_cast<QImageTextureGlyphCache *>(fontEngine->glyphCache(0, glyphType, s->matrix));
2872         if (!cache) {
2873             cache = new QImageTextureGlyphCache(glyphType, s->matrix);
2874             fontEngine->setGlyphCache(0, cache);
2875         }
2876
2877         cache->populate(fontEngine, numGlyphs, glyphs, positions);
2878         cache->fillInPendingGlyphs();
2879
2880         const QImage &image = cache->image();
2881         int bpl = image.bytesPerLine();
2882
2883         int depth = image.depth();
2884         int rightShift = 0;
2885         int leftShift = 0;
2886         if (depth == 32)
2887             leftShift = 2; // multiply by 4
2888         else if (depth == 1)
2889             rightShift = 3; // divide by 8
2890
2891         int margin = cache->glyphMargin();
2892         const uchar *bits = image.bits();
2893         for (int i=0; i<numGlyphs; ++i) {
2894
2895             QFixed subPixelPosition = cache->subPixelPositionForX(positions[i].x);
2896             QTextureGlyphCache::GlyphAndSubPixelPosition glyph(glyphs[i], subPixelPosition);
2897             const QTextureGlyphCache::Coord &c = cache->coords[glyph];
2898             if (c.isNull())
2899                 continue;
2900
2901             int x = qFloor(positions[i].x) + c.baseLineX - margin;
2902             int y = qFloor(positions[i].y + offs) - c.baseLineY - margin;
2903
2904             // printf("drawing [%d %d %d %d] baseline [%d %d], glyph: %d, to: %d %d, pos: %d %d\n",
2905             //        c.x, c.y,
2906             //        c.w, c.h,
2907             //        c.baseLineX, c.baseLineY,
2908             //        glyphs[i],
2909             //        x, y,
2910             //        positions[i].x.toInt(), positions[i].y.toInt());
2911
2912             alphaPenBlt(bits + ((c.x << leftShift) >> rightShift) + c.y * bpl, bpl, depth, x, y, c.w, c.h);
2913         }
2914     }
2915     return true;
2916 }
2917
2918 #if defined(Q_OS_SYMBIAN) && defined(QT_NO_FREETYPE)
2919 void QRasterPaintEngine::drawGlyphsS60(const QPointF &p, const QTextItemInt &ti)
2920 {
2921     Q_D(QRasterPaintEngine);
2922     QRasterPaintEngineState *s = state();
2923
2924     QFontEngine *fontEngine = ti.fontEngine;
2925     if (fontEngine->type() != QFontEngine::S60FontEngine) {
2926         QPaintEngineEx::drawTextItem(p, ti);
2927         return;
2928     }
2929
2930     QFontEngineS60 *fe = static_cast<QFontEngineS60 *>(fontEngine);
2931
2932     QVarLengthArray<QFixedPoint> positions;
2933     QVarLengthArray<glyph_t> glyphs;
2934     QTransform matrix = s->matrix;
2935     matrix.translate(p.x(), p.y());
2936     if (matrix.type() == QTransform::TxScale)
2937         fe->setFontScale(matrix.m11());
2938     ti.fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions);
2939
2940     const QFixed aliasDelta = QFixed::fromReal(aliasedCoordinateDelta);
2941
2942     for (int i=0; i<glyphs.size(); ++i) {
2943         TOpenFontCharMetrics tmetrics;
2944         const TUint8 *glyphBitmapBytes;
2945         TSize glyphBitmapSize;
2946         fe->getCharacterData(glyphs[i], tmetrics, glyphBitmapBytes, glyphBitmapSize);
2947         const int x = qFloor(positions[i].x + tmetrics.HorizBearingX() + aliasDelta);
2948         const int y = qFloor(positions[i].y - tmetrics.HorizBearingY() + aliasDelta);
2949         alphaPenBlt(glyphBitmapBytes, glyphBitmapSize.iWidth, 8, x, y, glyphBitmapSize.iWidth, glyphBitmapSize.iHeight);
2950     }
2951
2952     if (matrix.type() == QTransform::TxScale)
2953         fe->setFontScale(1.0);
2954
2955     return;
2956 }
2957 #endif // Q_OS_SYMBIAN && QT_NO_FREETYPE
2958
2959 /*!
2960  * Returns true if the rectangle is completely within the current clip
2961  * state of the paint engine.
2962  */
2963 bool QRasterPaintEnginePrivate::isUnclipped_normalized(const QRect &r) const
2964 {
2965     const QClipData *cl = clip();
2966     if (!cl) {
2967         // inline contains() for performance (we know the rects are normalized)
2968         const QRect &r1 = deviceRect;
2969         return (r.left() >= r1.left() && r.right() <= r1.right()
2970                 && r.top() >= r1.top() && r.bottom() <= r1.bottom());
2971     }
2972
2973
2974     if (cl->hasRectClip) {
2975         // currently all painting functions clips to deviceRect internally
2976         if (cl->clipRect == deviceRect)
2977             return true;
2978
2979         // inline contains() for performance (we know the rects are normalized)
2980         const QRect &r1 = cl->clipRect;
2981         return (r.left() >= r1.left() && r.right() <= r1.right()
2982                 && r.top() >= r1.top() && r.bottom() <= r1.bottom());
2983     } else {
2984         return qt_region_strictContains(cl->clipRegion, r);
2985     }
2986 }
2987
2988 bool QRasterPaintEnginePrivate::isUnclipped(const QRect &rect,
2989                                             int penWidth) const
2990 {
2991     Q_Q(const QRasterPaintEngine);
2992     const QRasterPaintEngineState *s = q->state();
2993     const QClipData *cl = clip();
2994     if (!cl) {
2995         QRect r = rect.normalized();
2996         // inline contains() for performance (we know the rects are normalized)
2997         const QRect &r1 = deviceRect;
2998         return (r.left() >= r1.left() && r.right() <= r1.right()
2999                 && r.top() >= r1.top() && r.bottom() <= r1.bottom());
3000     }
3001
3002
3003     // currently all painting functions that call this function clip to deviceRect internally
3004     if (cl->hasRectClip && cl->clipRect == deviceRect)
3005         return true;
3006
3007     if (s->flags.antialiased)
3008         ++penWidth;
3009
3010     QRect r = rect.normalized();
3011     if (penWidth > 0) {
3012         r.setX(r.x() - penWidth);
3013         r.setY(r.y() - penWidth);
3014         r.setWidth(r.width() + 2 * penWidth);
3015         r.setHeight(r.height() + 2 * penWidth);
3016     }
3017
3018     if (cl->hasRectClip) {
3019         // inline contains() for performance (we know the rects are normalized)
3020         const QRect &r1 = cl->clipRect;
3021         return (r.left() >= r1.left() && r.right() <= r1.right()
3022                 && r.top() >= r1.top() && r.bottom() <= r1.bottom());
3023     } else {
3024         return qt_region_strictContains(cl->clipRegion, r);
3025     }
3026 }
3027
3028 inline bool QRasterPaintEnginePrivate::isUnclipped(const QRectF &rect,
3029                                                    int penWidth) const
3030 {
3031     return isUnclipped(rect.normalized().toAlignedRect(), penWidth);
3032 }
3033
3034 inline ProcessSpans
3035 QRasterPaintEnginePrivate::getBrushFunc(const QRect &rect,
3036                                         const QSpanData *data) const
3037 {
3038     return isUnclipped(rect, 0) ? data->unclipped_blend : data->blend;
3039 }
3040
3041 inline ProcessSpans
3042 QRasterPaintEnginePrivate::getBrushFunc(const QRectF &rect,
3043                                         const QSpanData *data) const
3044 {
3045     return isUnclipped(rect, 0) ? data->unclipped_blend : data->blend;
3046 }
3047
3048 inline ProcessSpans
3049 QRasterPaintEnginePrivate::getPenFunc(const QRectF &rect,
3050                                       const QSpanData *data) const
3051 {
3052     Q_Q(const QRasterPaintEngine);
3053     const QRasterPaintEngineState *s = q->state();
3054
3055     if (!s->flags.fast_pen && s->matrix.type() > QTransform::TxTranslate)
3056         return data->blend;
3057     const int penWidth = s->flags.fast_pen ? 1 : qCeil(s->lastPen.widthF());
3058     return isUnclipped(rect, penWidth) ? data->unclipped_blend : data->blend;
3059 }
3060
3061 /*!
3062    \reimp
3063 */
3064 void QRasterPaintEngine::drawStaticTextItem(QStaticTextItem *textItem)
3065 {
3066     ensurePen();
3067     ensureState();
3068
3069     QFontEngine *fontEngine = textItem->fontEngine();
3070     if (!supportsTransformations(fontEngine)) {
3071         drawCachedGlyphs(textItem->numGlyphs, textItem->glyphs, textItem->glyphPositions,
3072                          fontEngine);
3073     } else {
3074         QPaintEngineEx::drawStaticTextItem(textItem);
3075     }
3076 }
3077
3078 /*!
3079     \reimp
3080 */
3081 void QRasterPaintEngine::drawTextItem(const QPointF &p, const QTextItem &textItem)
3082 {
3083     const QTextItemInt &ti = static_cast<const QTextItemInt &>(textItem);
3084     QRasterPaintEngineState *s = state();
3085
3086 #ifdef QT_DEBUG_DRAW
3087     Q_D(QRasterPaintEngine);
3088     fprintf(stderr," - QRasterPaintEngine::drawTextItem(), (%.2f,%.2f), string=%s ct=%d\n",
3089            p.x(), p.y(), QString::fromRawData(ti.chars, ti.num_chars).toLatin1().data(),
3090            d->glyphCacheType);
3091 #endif
3092
3093     ensurePen();
3094     ensureState();
3095
3096 #if defined (Q_WS_WIN) || defined(Q_WS_MAC) || (defined(Q_OS_MAC) && defined(Q_WS_QPA))
3097
3098     if (!supportsTransformations(ti.fontEngine)) {
3099         QVarLengthArray<QFixedPoint> positions;
3100         QVarLengthArray<glyph_t> glyphs;
3101
3102         QTransform matrix = s->matrix;
3103         matrix.translate(p.x(), p.y());
3104
3105         ti.fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions);
3106
3107         drawCachedGlyphs(glyphs.size(), glyphs.constData(), positions.constData(), ti.fontEngine);
3108         return;
3109     }
3110
3111 #elif defined (Q_OS_SYMBIAN) && defined(QT_NO_FREETYPE) // Q_WS_WIN || Q_WS_MAC
3112     if (s->matrix.type() <= QTransform::TxTranslate
3113         || (s->matrix.type() == QTransform::TxScale
3114                 && (qFuzzyCompare(s->matrix.m11(), s->matrix.m22())))) {
3115         drawGlyphsS60(p, ti);
3116         return;
3117     }
3118 #else // Q_WS_WIN || Q_WS_MAC
3119
3120     QFontEngine *fontEngine = ti.fontEngine;
3121
3122 #if defined(Q_WS_QWS)
3123     if (fontEngine->type() == QFontEngine::Box) {
3124         fontEngine->draw(this, qFloor(p.x()), qFloor(p.y()), ti);
3125         return;
3126     }
3127
3128     if (s->matrix.type() < QTransform::TxScale
3129         && (fontEngine->type() == QFontEngine::QPF1 || fontEngine->type() == QFontEngine::QPF2
3130             || (fontEngine->type() == QFontEngine::Proxy
3131                 && !(static_cast<QProxyFontEngine *>(fontEngine)->drawAsOutline()))
3132             )) {
3133         fontEngine->draw(this, qFloor(p.x() + aliasedCoordinateDelta), qFloor(p.y() + aliasedCoordinateDelta), ti);
3134         return;
3135     }
3136 #endif // Q_WS_QWS
3137
3138 #ifdef Q_WS_QPA
3139     if (s->matrix.type() < QTransform::TxScale) {
3140
3141         QVarLengthArray<QFixedPoint> positions;
3142         QVarLengthArray<glyph_t> glyphs;
3143         QTransform matrix = state()->transform();
3144
3145         qreal _x = qFloor(p.x());
3146         qreal _y = qFloor(p.y());
3147         matrix.translate(_x, _y);
3148
3149         fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions);
3150         if (glyphs.size() == 0)
3151             return;
3152
3153         for(int i = 0; i < glyphs.size(); i++) {
3154             QImage img = fontEngine->alphaMapForGlyph(glyphs[i]);
3155             glyph_metrics_t metrics = fontEngine->boundingBox(glyphs[i]);
3156             // ### hm, perhaps an QFixed offs = QFixed::fromReal(aliasedCoordinateDelta) is needed here?
3157             alphaPenBlt(img.bits(), img.bytesPerLine(), img.depth(),
3158                                          qRound(positions[i].x + metrics.x),
3159                                          qRound(positions[i].y + metrics.y),
3160                                          img.width(), img.height());
3161         }
3162         return;
3163     }
3164 #endif //Q_WS_QPA
3165
3166 #if (defined(Q_WS_X11) || defined(Q_WS_QWS) || defined(Q_OS_SYMBIAN)) && !defined(QT_NO_FREETYPE)
3167
3168 #if defined(Q_WS_QWS) && !defined(QT_NO_QWS_QPF2)
3169     if (fontEngine->type() == QFontEngine::QPF2) {
3170         QFontEngine *renderingEngine = static_cast<QFontEngineQPF *>(fontEngine)->renderingEngine();
3171         if (renderingEngine)
3172             fontEngine = renderingEngine;
3173     }
3174 #endif
3175
3176     if (fontEngine->type() != QFontEngine::Freetype) {
3177         QPaintEngineEx::drawTextItem(p, ti);
3178         return;
3179     }
3180
3181     QFontEngineFT *fe = static_cast<QFontEngineFT *>(fontEngine);
3182
3183     QTransform matrix = s->matrix;
3184     matrix.translate(p.x(), p.y());
3185
3186     QVarLengthArray<QFixedPoint> positions;
3187     QVarLengthArray<glyph_t> glyphs;
3188     fe->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions);
3189     if (glyphs.size() == 0)
3190         return;
3191
3192     if (!drawCachedGlyphs(glyphs.size(), glyphs.constData(), positions.constData(), fontEngine))
3193         QPaintEngine::drawTextItem(p, ti);
3194
3195     return;
3196 #endif
3197 #endif
3198
3199     QPaintEngineEx::drawTextItem(p, ti);
3200 }
3201
3202 /*!
3203     \reimp
3204 */
3205 void QRasterPaintEngine::drawPoints(const QPointF *points, int pointCount)
3206 {
3207     Q_D(QRasterPaintEngine);
3208     QRasterPaintEngineState *s = state();
3209
3210     ensurePen();
3211     if (!s->penData.blend)
3212         return;
3213
3214     if (!s->flags.fast_pen) {
3215         QPaintEngineEx::drawPoints(points, pointCount);
3216         return;
3217     }
3218
3219     QCosmeticStroker stroker(s, d->deviceRect, d->deviceRectUnclipped);
3220     stroker.drawPoints(points, pointCount);
3221 }
3222
3223
3224 void QRasterPaintEngine::drawPoints(const QPoint *points, int pointCount)
3225 {
3226     Q_D(QRasterPaintEngine);
3227     QRasterPaintEngineState *s = state();
3228
3229     ensurePen();
3230     if (!s->penData.blend)
3231         return;
3232
3233     if (!s->flags.fast_pen) {
3234         QPaintEngineEx::drawPoints(points, pointCount);
3235         return;
3236     }
3237
3238     QCosmeticStroker stroker(s, d->deviceRect, d->deviceRectUnclipped);
3239     stroker.drawPoints(points, pointCount);
3240 }
3241
3242 /*!
3243     \reimp
3244 */
3245 void QRasterPaintEngine::drawLines(const QLine *lines, int lineCount)
3246 {
3247 #ifdef QT_DEBUG_DRAW
3248     qDebug() << " - QRasterPaintEngine::drawLines(QLine*)" << lineCount;
3249 #endif
3250     Q_D(QRasterPaintEngine);
3251     QRasterPaintEngineState *s = state();
3252
3253     ensurePen();
3254     if (!s->penData.blend)
3255         return;
3256
3257     if (s->flags.fast_pen) {
3258         QCosmeticStroker stroker(s, d->deviceRect, d->deviceRectUnclipped);
3259         for (int i=0; i<lineCount; ++i) {
3260             const QLine &l = lines[i];
3261             stroker.drawLine(l.p1(), l.p2());
3262         }
3263     } else {
3264         QPaintEngineEx::drawLines(lines, lineCount);
3265     }
3266 }
3267
3268 void QRasterPaintEnginePrivate::rasterizeLine_dashed(QLineF line,
3269                                                      qreal width,
3270                                                      int *dashIndex,
3271                                                      qreal *dashOffset,
3272                                                      bool *inDash)
3273 {
3274     Q_Q(QRasterPaintEngine);
3275     QRasterPaintEngineState *s = q->state();
3276
3277     const QPen &pen = s->lastPen;
3278     const bool squareCap = (pen.capStyle() == Qt::SquareCap);
3279     const QVector<qreal> pattern = pen.dashPattern();
3280
3281     qreal patternLength = 0;
3282     for (int i = 0; i < pattern.size(); ++i)
3283         patternLength += pattern.at(i);
3284
3285     if (patternLength <= 0)
3286         return;
3287
3288     qreal length = line.length();
3289     Q_ASSERT(length > 0);
3290     while (length > 0) {
3291         const bool rasterize = *inDash;
3292         qreal dash = (pattern.at(*dashIndex) - *dashOffset) * width;
3293         QLineF l = line;
3294
3295         if (dash >= length) {
3296             dash = length;
3297             *dashOffset += dash / width;
3298             length = 0;
3299         } else {
3300             *dashOffset = 0;
3301             *inDash = !(*inDash);
3302             if (++*dashIndex >= pattern.size())
3303                 *dashIndex = 0;
3304             length -= dash;
3305             l.setLength(dash);
3306             line.setP1(l.p2());
3307         }
3308
3309         if (rasterize && dash > 0)
3310             rasterizer->rasterizeLine(l.p1(), l.p2(), width / dash, squareCap);
3311     }
3312 }
3313
3314 /*!
3315     \reimp
3316 */
3317 void QRasterPaintEngine::drawLines(const QLineF *lines, int lineCount)
3318 {
3319 #ifdef QT_DEBUG_DRAW
3320     qDebug() << " - QRasterPaintEngine::drawLines(QLineF *)" << lineCount;
3321 #endif
3322     Q_D(QRasterPaintEngine);
3323     QRasterPaintEngineState *s = state();
3324
3325     ensurePen();
3326     if (!s->penData.blend)
3327         return;
3328     if (s->flags.fast_pen) {
3329         QCosmeticStroker stroker(s, d->deviceRect, d->deviceRectUnclipped);
3330         for (int i=0; i<lineCount; ++i) {
3331             QLineF line = lines[i];
3332             stroker.drawLine(line.p1(), line.p2());
3333         }
3334     } else {
3335         QPaintEngineEx::drawLines(lines, lineCount);
3336     }
3337 }
3338
3339
3340 /*!
3341     \reimp
3342 */
3343 void QRasterPaintEngine::drawEllipse(const QRectF &rect)
3344 {
3345     Q_D(QRasterPaintEngine);
3346     QRasterPaintEngineState *s = state();
3347
3348     ensurePen();
3349     if (((qpen_style(s->lastPen) == Qt::SolidLine && s->flags.fast_pen)
3350            || (qpen_style(s->lastPen) == Qt::NoPen))
3351         && !s->flags.antialiased
3352         && qMax(rect.width(), rect.height()) < QT_RASTER_COORD_LIMIT
3353         && !rect.isEmpty()
3354         && s->matrix.type() <= QTransform::TxScale) // no shear
3355     {
3356         ensureBrush();
3357         const QRectF r = s->matrix.mapRect(rect);
3358         ProcessSpans penBlend = d->getPenFunc(r, &s->penData);
3359         ProcessSpans brushBlend = d->getBrushFunc(r, &s->brushData);
3360         const QRect brect = QRect(int(r.x()), int(r.y()),
3361                                   int_dim(r.x(), r.width()),
3362                                   int_dim(r.y(), r.height()));
3363         if (brect == r) {
3364             drawEllipse_midpoint_i(brect, d->deviceRect, penBlend, brushBlend,
3365                                    &s->penData, &s->brushData);
3366             return;
3367         }
3368     }
3369     QPaintEngineEx::drawEllipse(rect);
3370 }
3371
3372 /*!
3373     \internal
3374 */
3375 #ifdef Q_WS_MAC
3376 void QRasterPaintEngine::setCGContext(CGContextRef ctx)
3377 {
3378     Q_D(QRasterPaintEngine);
3379     d->cgContext = ctx;
3380 }
3381
3382 /*!
3383     \internal
3384 */
3385 CGContextRef QRasterPaintEngine::getCGContext() const
3386 {
3387     Q_D(const QRasterPaintEngine);
3388     return d->cgContext;
3389 }
3390 #endif
3391
3392 #ifdef Q_WS_WIN
3393 /*!
3394     \internal
3395 */
3396 void QRasterPaintEngine::setDC(HDC hdc) {
3397     Q_D(QRasterPaintEngine);
3398     d->hdc = hdc;
3399 }
3400
3401 /*!
3402     \internal
3403 */
3404 HDC QRasterPaintEngine::getDC() const
3405 {
3406     Q_D(const QRasterPaintEngine);
3407     return d->hdc;
3408 }
3409
3410 /*!
3411     \internal
3412 */
3413 void QRasterPaintEngine::releaseDC(HDC) const
3414 {
3415 }
3416
3417 #endif
3418
3419 bool QRasterPaintEngine::supportsTransformations(const QFontEngine *fontEngine) const
3420 {
3421     if (!state()->WxF)
3422         return false;
3423     const QTransform &m = state()->matrix;
3424 #if defined(Q_WS_WIN) && !defined(Q_WS_WINCE)
3425     QFontEngine::Type fontEngineType = fontEngine->type();
3426     if ((fontEngineType == QFontEngine::Win && !((QFontEngineWin *) fontEngine)->ttf && m.type() > QTransform::TxTranslate)
3427         || (m.type() <= QTransform::TxTranslate
3428             && (fontEngineType == QFontEngine::TestFontEngine
3429                 || fontEngineType == QFontEngine::Box))) {
3430             return true;
3431     }
3432 #endif
3433     return supportsTransformations(fontEngine->fontDef.pixelSize, m);
3434 }
3435
3436 bool QRasterPaintEngine::supportsTransformations(qreal pixelSize, const QTransform &m) const
3437 {
3438 #if defined(Q_WS_MAC) || (defined(Q_OS_MAC) && defined(Q_WS_QPA))
3439     // Mac font engines don't support scaling and rotation
3440     if (m.type() > QTransform::TxTranslate)
3441 #else
3442     if (m.type() >= QTransform::TxProject)
3443 #endif
3444         return true;
3445
3446     if (pixelSize * pixelSize * qAbs(m.determinant()) >= 64 *&nbs