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