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