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