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