Merge remote-tracking branch 'base/master' into refactor
[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     QFontEngine *fontEngine = textItem->fontEngine();
3025     if (!supportsTransformations(fontEngine)) {
3026         drawCachedGlyphs(textItem->numGlyphs, textItem->glyphs, textItem->glyphPositions,
3027                          fontEngine);
3028     } else {
3029         QPaintEngineEx::drawStaticTextItem(textItem);
3030     }
3031 }
3032
3033 /*!
3034     \reimp
3035 */
3036 void QRasterPaintEngine::drawTextItem(const QPointF &p, const QTextItem &textItem)
3037 {
3038     const QTextItemInt &ti = static_cast<const QTextItemInt &>(textItem);
3039     QRasterPaintEngineState *s = state();
3040
3041 #ifdef QT_DEBUG_DRAW
3042     Q_D(QRasterPaintEngine);
3043     fprintf(stderr," - QRasterPaintEngine::drawTextItem(), (%.2f,%.2f), string=%s ct=%d\n",
3044            p.x(), p.y(), QString::fromRawData(ti.chars, ti.num_chars).toLatin1().data(),
3045            d->glyphCacheType);
3046 #endif
3047
3048     ensurePen();
3049     ensureState();
3050
3051 #if defined (Q_OS_WIN) || defined(Q_WS_MAC)
3052
3053     if (!supportsTransformations(ti.fontEngine)) {
3054         QVarLengthArray<QFixedPoint> positions;
3055         QVarLengthArray<glyph_t> glyphs;
3056
3057         QTransform matrix = s->matrix;
3058         matrix.translate(p.x(), p.y());
3059
3060         ti.fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions);
3061
3062         drawCachedGlyphs(glyphs.size(), glyphs.constData(), positions.constData(), ti.fontEngine);
3063         return;
3064     }
3065
3066 #elif defined (Q_OS_SYMBIAN) && defined(QT_NO_FREETYPE) // Q_OS_WIN || Q_WS_MAC
3067     if (s->matrix.type() <= QTransform::TxTranslate
3068         || (s->matrix.type() == QTransform::TxScale
3069                 && (qFuzzyCompare(s->matrix.m11(), s->matrix.m22())))) {
3070         drawGlyphsS60(p, ti);
3071         return;
3072     }
3073 #else // Q_OS_WIN || Q_WS_MAC
3074
3075     QFontEngine *fontEngine = ti.fontEngine;
3076
3077 #ifdef Q_WS_QPA
3078     if (s->matrix.type() < QTransform::TxScale) {
3079
3080         QVarLengthArray<QFixedPoint> positions;
3081         QVarLengthArray<glyph_t> glyphs;
3082         QTransform matrix = state()->transform();
3083
3084         qreal _x = qFloor(p.x());
3085         qreal _y = qFloor(p.y());
3086         matrix.translate(_x, _y);
3087
3088         fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions);
3089         if (glyphs.size() == 0)
3090             return;
3091
3092         for(int i = 0; i < glyphs.size(); i++) {
3093             QImage img = fontEngine->alphaMapForGlyph(glyphs[i]);
3094             glyph_metrics_t metrics = fontEngine->boundingBox(glyphs[i]);
3095             alphaPenBlt(img.bits(), img.bytesPerLine(), img.depth(),
3096                                          qRound(positions[i].x + metrics.x),
3097                                          qRound(positions[i].y + metrics.y),
3098                                          img.width(), img.height());
3099         }
3100         return;
3101     }
3102 #endif //Q_WS_QPA
3103
3104 #if (defined(Q_WS_X11) || defined(Q_WS_QWS) || defined(Q_OS_SYMBIAN)) && !defined(QT_NO_FREETYPE)
3105
3106     if (fontEngine->type() != QFontEngine::Freetype) {
3107         QPaintEngineEx::drawTextItem(p, ti);
3108         return;
3109     }
3110
3111     QFontEngineFT *fe = static_cast<QFontEngineFT *>(fontEngine);
3112
3113     QTransform matrix = s->matrix;
3114     matrix.translate(p.x(), p.y());
3115
3116     QVarLengthArray<QFixedPoint> positions;
3117     QVarLengthArray<glyph_t> glyphs;
3118     fe->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions);
3119     if (glyphs.size() == 0)
3120         return;
3121
3122     if (!drawCachedGlyphs(glyphs.size(), glyphs.constData(), positions.constData(), fontEngine))
3123         QPaintEngine::drawTextItem(p, ti);
3124
3125     return;
3126 #endif
3127 #endif
3128
3129     QPaintEngineEx::drawTextItem(p, ti);
3130 }
3131
3132 /*!
3133     \reimp
3134 */
3135 void QRasterPaintEngine::drawPoints(const QPointF *points, int pointCount)
3136 {
3137     Q_D(QRasterPaintEngine);
3138     QRasterPaintEngineState *s = state();
3139
3140     ensurePen();
3141     if (!s->penData.blend)
3142         return;
3143
3144     if (!s->flags.fast_pen) {
3145         QPaintEngineEx::drawPoints(points, pointCount);
3146         return;
3147     }
3148
3149     QCosmeticStroker stroker(s, d->deviceRect);
3150     stroker.drawPoints(points, pointCount);
3151 }
3152
3153
3154 void QRasterPaintEngine::drawPoints(const QPoint *points, int pointCount)
3155 {
3156     Q_D(QRasterPaintEngine);
3157     QRasterPaintEngineState *s = state();
3158
3159     ensurePen();
3160     if (!s->penData.blend)
3161         return;
3162
3163     if (!s->flags.fast_pen) {
3164         QPaintEngineEx::drawPoints(points, pointCount);
3165         return;
3166     }
3167
3168     QCosmeticStroker stroker(s, d->deviceRect);
3169     stroker.drawPoints(points, pointCount);
3170 }
3171
3172 /*!
3173     \reimp
3174 */
3175 void QRasterPaintEngine::drawLines(const QLine *lines, int lineCount)
3176 {
3177 #ifdef QT_DEBUG_DRAW
3178     qDebug() << " - QRasterPaintEngine::drawLines(QLine*)" << lineCount;
3179 #endif
3180     Q_D(QRasterPaintEngine);
3181     QRasterPaintEngineState *s = state();
3182
3183     ensurePen();
3184     if (!s->penData.blend)
3185         return;
3186
3187     if (s->flags.fast_pen) {
3188         QCosmeticStroker stroker(s, d->deviceRect);
3189         for (int i=0; i<lineCount; ++i) {
3190             const QLine &l = lines[i];
3191             stroker.drawLine(l.p1(), l.p2());
3192         }
3193     } else {
3194         QPaintEngineEx::drawLines(lines, lineCount);
3195     }
3196 }
3197
3198 void QRasterPaintEnginePrivate::rasterizeLine_dashed(QLineF line,
3199                                                      qreal width,
3200                                                      int *dashIndex,
3201                                                      qreal *dashOffset,
3202                                                      bool *inDash)
3203 {
3204     Q_Q(QRasterPaintEngine);
3205     QRasterPaintEngineState *s = q->state();
3206
3207     const QPen &pen = s->lastPen;
3208     const bool squareCap = (pen.capStyle() == Qt::SquareCap);
3209     const QVector<qreal> pattern = pen.dashPattern();
3210
3211     qreal patternLength = 0;
3212     for (int i = 0; i < pattern.size(); ++i)
3213         patternLength += pattern.at(i);
3214
3215     if (patternLength <= 0)
3216         return;
3217
3218     qreal length = line.length();
3219     Q_ASSERT(length > 0);
3220     while (length > 0) {
3221         const bool rasterize = *inDash;
3222         qreal dash = (pattern.at(*dashIndex) - *dashOffset) * width;
3223         QLineF l = line;
3224
3225         if (dash >= length) {
3226             dash = length;
3227             *dashOffset += dash / width;
3228             length = 0;
3229         } else {
3230             *dashOffset = 0;
3231             *inDash = !(*inDash);
3232             if (++*dashIndex >= pattern.size())
3233                 *dashIndex = 0;
3234             length -= dash;
3235             l.setLength(dash);
3236             line.setP1(l.p2());
3237         }
3238
3239         if (rasterize && dash > 0)
3240             rasterizer->rasterizeLine(l.p1(), l.p2(), width / dash, squareCap);
3241     }
3242 }
3243
3244 /*!
3245     \reimp
3246 */
3247 void QRasterPaintEngine::drawLines(const QLineF *lines, int lineCount)
3248 {
3249 #ifdef QT_DEBUG_DRAW
3250     qDebug() << " - QRasterPaintEngine::drawLines(QLineF *)" << lineCount;
3251 #endif
3252     Q_D(QRasterPaintEngine);
3253     QRasterPaintEngineState *s = state();
3254
3255     ensurePen();
3256     if (!s->penData.blend)
3257         return;
3258     if (s->flags.fast_pen) {
3259         QCosmeticStroker stroker(s, d->deviceRect);
3260         for (int i=0; i<lineCount; ++i) {
3261             QLineF line = lines[i];
3262             stroker.drawLine(line.p1(), line.p2());
3263         }
3264     } else {
3265         QPaintEngineEx::drawLines(lines, lineCount);
3266     }
3267 }
3268
3269
3270 /*!
3271     \reimp
3272 */
3273 void QRasterPaintEngine::drawEllipse(const QRectF &rect)
3274 {
3275     QPaintEngineEx::drawEllipse(rect);
3276 }
3277
3278 /*!
3279     \internal
3280 */
3281 #ifdef Q_WS_MAC
3282 void QRasterPaintEngine::setCGContext(CGContextRef ctx)
3283 {
3284     Q_D(QRasterPaintEngine);
3285     d->cgContext = ctx;
3286 }
3287
3288 /*!
3289     \internal
3290 */
3291 CGContextRef QRasterPaintEngine::getCGContext() const
3292 {
3293     Q_D(const QRasterPaintEngine);
3294     return d->cgContext;
3295 }
3296 #endif
3297
3298 #ifdef Q_OS_WIN
3299 /*!
3300     \internal
3301 */
3302 void QRasterPaintEngine::setDC(HDC hdc) {
3303     Q_D(QRasterPaintEngine);
3304     d->hdc = hdc;
3305 }
3306
3307 /*!
3308     \internal
3309 */
3310 HDC QRasterPaintEngine::getDC() const
3311 {
3312     Q_D(const QRasterPaintEngine);
3313     return d->hdc;
3314 }
3315
3316 /*!
3317     \internal
3318 */
3319 void QRasterPaintEngine::releaseDC(HDC) const
3320 {
3321 }
3322
3323 #endif
3324
3325 bool QRasterPaintEngine::supportsTransformations(const QFontEngine *fontEngine) const
3326 {
3327     const QTransform &m = state()->matrix;
3328 #if defined(Q_WS_WIN) && !defined(Q_WS_WINCE)
3329     QFontEngine::Type fontEngineType = fontEngine->type();
3330     if ((fontEngineType == QFontEngine::Win && !((QFontEngineWin *) fontEngine)->ttf && m.type() > QTransform::TxTranslate)
3331         || (m.type() <= QTransform::TxTranslate
3332             && (fontEngineType == QFontEngine::TestFontEngine
3333                 || fontEngineType == QFontEngine::Box))) {
3334             return true;
3335     }
3336 #endif
3337     return supportsTransformations(fontEngine->fontDef.pixelSize, m);
3338 }
3339
3340 bool QRasterPaintEngine::supportsTransformations(qreal pixelSize, const QTransform &m) const
3341 {
3342 #if defined(Q_WS_MAC)
3343     // Mac font engines don't support scaling and rotation
3344     if (m.type() > QTransform::TxTranslate)
3345 #else
3346     if (m.type() >= QTransform::TxProject)
3347 #endif
3348         return true;
3349
3350     if (pixelSize * pixelSize * qAbs(m.determinant()) >= 64 * 64)
3351         return true;
3352
3353     return false;
3354 }
3355
3356 /*!
3357     \internal
3358 */
3359 QPoint QRasterPaintEngine::coordinateOffset() const
3360 {
3361     return QPoint(0, 0);
3362 }
3363
3364 void QRasterPaintEngine::drawBitmap(const QPointF &pos, const QImage &image, QSpanData *fg)
3365 {
3366     Q_ASSERT(fg);
3367     if (!fg->blend)
3368         return;
3369     Q_D(QRasterPaintEngine);
3370
3371     Q_ASSERT(image.depth() == 1);
3372
3373     const int spanCount = 256;
3374     QT_FT_Span spans[spanCount];
3375     int n = 0;
3376
3377     // Boundaries
3378     int w = image.width();
3379     int h = image.height();
3380     int ymax = qMin(qRound(pos.y() + h), d->rasterBuffer->height());
3381     int ymin = qMax(qRound(pos.y()), 0);
3382     int xmax = qMin(qRound(pos.x() + w), d->rasterBuffer->width());
3383     int xmin = qMax(qRound(pos.x()), 0);
3384
3385     int x_offset = xmin - qRound(pos.x());
3386
3387     QImage::Format format = image.format();
3388     for (int y = ymin; y < ymax; ++y) {
3389         const uchar *src = image.scanLine(y - qRound(pos.y()));
3390         if (format == QImage::Format_MonoLSB) {
3391             for (int x = 0; x < xmax - xmin; ++x) {
3392                 int src_x = x + x_offset;
3393                 uchar pixel = src[src_x >> 3];
3394                 if (!pixel) {
3395                     x += 7 - (src_x%8);
3396                     continue;
3397                 }
3398                 if (pixel & (0x1 << (src_x & 7))) {
3399                     spans[n].x = xmin + x;
3400                     spans[n].y = y;
3401                     spans[n].coverage = 255;
3402                     int len = 1;
3403                     while (src_x < w-1 && src[(src_x+1) >> 3] & (0x1 << ((src_x+1) & 7))) {
3404                         ++src_x;
3405                         ++len;
3406                     }
3407                     spans[n].len = ((len + spans[n].x) > xmax) ? (xmax - spans[n].x) : len;
3408                     x += len;
3409                     ++n;
3410                     if (n == spanCount) {
3411                         fg->blend(n, spans, fg);
3412                         n = 0;
3413                     }
3414                 }
3415             }
3416         } else {
3417             for (int x = 0; x < xmax - xmin; ++x) {
3418                 int src_x = x + x_offset;
3419                 uchar pixel = src[src_x >> 3];
3420                 if (!pixel) {
3421                     x += 7 - (src_x%8);
3422                     continue;
3423                 }
3424                 if (pixel & (0x80 >> (x & 7))) {
3425                     spans[n].x = xmin + x;
3426                     spans[n].y = y;
3427                     spans[n].coverage = 255;
3428                     int len = 1;
3429                     while (src_x < w-1 && src[(src_x+1) >> 3] & (0x80 >> ((src_x+1) & 7))) {
3430                         ++src_x;
3431                         ++len;
3432                     }
3433                     spans[n].len = ((len + spans[n].x) > xmax) ? (xmax - spans[n].x) : len;
3434                     x += len;
3435                     ++n;
3436                     if (n == spanCount) {
3437                         fg->blend(n, spans, fg);
3438                         n = 0;
3439                     }
3440                 }
3441             }
3442         }
3443     }
3444     if (n) {
3445         fg->blend(n, spans, fg);
3446         n = 0;
3447     }
3448 }
3449
3450 /*!
3451     \enum QRasterPaintEngine::ClipType
3452     \internal
3453
3454     \value RectClip Indicates that the currently set clip is a single rectangle.
3455     \value ComplexClip Indicates that the currently set clip is a combination of several shapes.
3456 */
3457
3458 /*!
3459     \internal
3460     Returns the type of the clip currently set.
3461 */
3462 QRasterPaintEngine::ClipType QRasterPaintEngine::clipType() const
3463 {
3464     Q_D(const QRasterPaintEngine);
3465
3466     const QClipData *clip = d->clip();
3467     if (!clip || clip->hasRectClip)
3468         return RectClip;
3469     else
3470         return ComplexClip;
3471 }
3472
3473 /*!
3474     \internal
3475     Returns the bounding rect of the currently set clip.
3476 */
3477 QRect QRasterPaintEngine::clipBoundingRect() const
3478 {
3479     Q_D(const QRasterPaintEngine);
3480
3481     const QClipData *clip = d->clip();
3482
3483     if (!clip)
3484         return d->deviceRect;
3485
3486     if (clip->hasRectClip)
3487         return clip->clipRect;
3488
3489     return QRect(clip->xmin, clip->ymin, clip->xmax - clip->xmin, clip->ymax - clip->ymin);
3490 }
3491
3492 static void qt_merge_clip(const QClipData *c1, const QClipData *c2, QClipData *result)
3493 {
3494     Q_ASSERT(c1->clipSpanHeight == c2->clipSpanHeight && c1->clipSpanHeight == result->clipSpanHeight);
3495
3496     QVarLengthArray<short, 4096> buffer;
3497
3498     QClipData::ClipLine *c1ClipLines = const_cast<QClipData *>(c1)->clipLines();
3499     QClipData::ClipLine *c2ClipLines = const_cast<QClipData *>(c2)->clipLines();
3500     result->initialize();
3501
3502     for (int y = 0; y < c1->clipSpanHeight; ++y) {
3503         const QSpan *c1_spans = c1ClipLines[y].spans;
3504         int c1_count = c1ClipLines[y].count;
3505         const QSpan *c2_spans = c2ClipLines[y].spans;
3506         int c2_count = c2ClipLines[y].count;
3507
3508         if (c1_count == 0 && c2_count == 0)
3509             continue;
3510         if (c1_count == 0) {
3511             result->appendSpans(c2_spans, c2_count);
3512             continue;
3513         } else if (c2_count == 0) {
3514             result->appendSpans(c1_spans, c1_count);
3515             continue;
3516         }
3517
3518         // we need to merge the two
3519
3520         // find required length
3521         int max = qMax(c1_spans[c1_count - 1].x + c1_spans[c1_count - 1].len,
3522                 c2_spans[c2_count - 1].x + c2_spans[c2_count - 1].len);
3523         buffer.resize(max);
3524         memset(buffer.data(), 0, buffer.size() * sizeof(short));
3525
3526         // Fill with old spans.
3527         for (int i = 0; i < c1_count; ++i) {
3528             const QSpan *cs = c1_spans + i;
3529             for (int j=cs->x; j<cs->x + cs->len; ++j)
3530                 buffer[j] = cs->coverage;
3531         }
3532
3533         // Fill with new spans
3534         for (int i = 0; i < c2_count; ++i) {
3535             const QSpan *cs = c2_spans + i;
3536             for (int j = cs->x; j < cs->x + cs->len; ++j) {
3537                 buffer[j] += cs->coverage;
3538                 if (buffer[j] > 255)
3539                     buffer[j] = 255;
3540             }
3541         }
3542
3543         int x = 0;
3544         while (x<max) {
3545
3546             // Skip to next span
3547             while (x < max && buffer[x] == 0) ++x;
3548             if (x >= max) break;
3549
3550             int sx = x;
3551             int coverage = buffer[x];
3552
3553             // Find length of span
3554             while (x < max && buffer[x] == coverage)
3555                 ++x;
3556
3557             result->appendSpan(sx, x - sx, y, coverage);
3558         }
3559     }
3560 }
3561
3562 void QRasterPaintEnginePrivate::initializeRasterizer(QSpanData *data)
3563 {
3564     Q_Q(QRasterPaintEngine);
3565     QRasterPaintEngineState *s = q->state();
3566
3567     rasterizer->setAntialiased(s->flags.antialiased);
3568
3569     QRect clipRect(deviceRect);
3570     ProcessSpans blend;
3571     // ### get from optimized rectbased QClipData
3572
3573     const QClipData *c = clip();
3574     if (c) {
3575         const QRect r(QPoint(c->xmin, c->ymin),
3576                       QSize(c->xmax - c->xmin, c->ymax - c->ymin));
3577         clipRect = clipRect.intersected(r);
3578         blend = data->blend;
3579     } else {
3580         blend = data->unclipped_blend;
3581     }
3582
3583     rasterizer->setClipRect(clipRect);
3584     rasterizer->initialize(blend, data);
3585 }
3586
3587 void QRasterPaintEnginePrivate::rasterize(QT_FT_Outline *outline,
3588                                           ProcessSpans callback,
3589                                           QSpanData *spanData, QRasterBuffer *rasterBuffer)
3590 {
3591     if (!callback || !outline)
3592         return;
3593
3594     Q_Q(QRasterPaintEngine);
3595     QRasterPaintEngineState *s = q->state();
3596
3597     if (!s->flags.antialiased) {
3598         initializeRasterizer(spanData);
3599
3600         const Qt::FillRule fillRule = outline->flags == QT_FT_OUTLINE_NONE
3601                                       ? Qt::WindingFill
3602                                       : Qt::OddEvenFill;
3603
3604         rasterizer->rasterize(outline, fillRule);
3605         return;
3606     }
3607
3608     rasterize(outline, callback, (void *)spanData, rasterBuffer);
3609 }
3610
3611 extern "C" {
3612     int q_gray_rendered_spans(QT_FT_Raster raster);
3613 }
3614
3615 void QRasterPaintEnginePrivate::rasterize(QT_FT_Outline *outline,
3616                                           ProcessSpans callback,
3617                                           void *userData, QRasterBuffer *)
3618 {
3619     if (!callback || !outline)
3620         return;
3621
3622     Q_Q(QRasterPaintEngine);
3623     QRasterPaintEngineState *s = q->state();
3624
3625     if (!s->flags.antialiased) {
3626         rasterizer->setAntialiased(s->flags.antialiased);
3627         rasterizer->setClipRect(deviceRect);
3628         rasterizer->initialize(callback, userData);
3629
3630         const Qt::FillRule fillRule = outline->flags == QT_FT_OUTLINE_NONE
3631                                       ? Qt::WindingFill
3632                                       : Qt::OddEvenFill;
3633
3634         rasterizer->rasterize(outline, fillRule);
3635         return;
3636     }
3637
3638     // Initial size for raster pool is MINIMUM_POOL_SIZE so as to
3639     // minimize memory reallocations. However if initial size for
3640     // raster pool is changed for lower value, reallocations will
3641     // occur normally.
3642     const int rasterPoolInitialSize = MINIMUM_POOL_SIZE;
3643     int rasterPoolSize = rasterPoolInitialSize;
3644     unsigned char *rasterPoolBase;
3645 #if defined(Q_OS_WIN64)
3646     rasterPoolBase =
3647         // We make use of setjmp and longjmp in qgrayraster.c which requires
3648         // 16-byte alignment, hence we hardcode this requirement here..
3649         (unsigned char *) _aligned_malloc(rasterPoolSize, sizeof(void*) * 2);
3650 #else
3651     unsigned char rasterPoolOnStack[rasterPoolInitialSize];
3652     rasterPoolBase = rasterPoolOnStack;
3653 #endif
3654     Q_CHECK_PTR(rasterPoolBase);
3655
3656     qt_ft_grays_raster.raster_reset(*grayRaster.data(), rasterPoolBase, rasterPoolSize);
3657
3658     void *data = userData;
3659
3660     QT_FT_BBox clip_box = { deviceRect.x(),
3661                             deviceRect.y(),
3662                             deviceRect.x() + deviceRect.width(),
3663                             deviceRect.y() + deviceRect.height() };
3664
3665     QT_FT_Raster_Params rasterParams;
3666     rasterParams.target = 0;
3667     rasterParams.source = outline;
3668     rasterParams.flags = QT_FT_RASTER_FLAG_CLIP;
3669     rasterParams.gray_spans = 0;
3670     rasterParams.black_spans = 0;
3671     rasterParams.bit_test = 0;
3672     rasterParams.bit_set = 0;
3673     rasterParams.user = data;
3674     rasterParams.clip_box = clip_box;
3675
3676     bool done = false;
3677     int error;
3678
3679     int rendered_spans = 0;
3680
3681     while (!done) {
3682
3683         rasterParams.flags |= (QT_FT_RASTER_FLAG_AA | QT_FT_RASTER_FLAG_DIRECT);
3684         rasterParams.gray_spans = callback;
3685         rasterParams.skip_spans = rendered_spans;
3686         error = qt_ft_grays_raster.raster_render(*grayRaster.data(), &rasterParams);
3687
3688         // Out of memory, reallocate some more and try again...
3689         if (error == -6) { // ErrRaster_OutOfMemory from qgrayraster.c
3690             int new_size = rasterPoolSize * 2;
3691             if (new_size > 1024 * 1024) {
3692                 qWarning("QPainter: Rasterization of primitive failed");
3693                 break;
3694             }
3695
3696             rendered_spans += q_gray_rendered_spans(*grayRaster.data());
3697
3698 #if defined(Q_OS_WIN64)
3699             _aligned_free(rasterPoolBase);
3700 #else
3701             if (rasterPoolBase != rasterPoolOnStack) // initially on the stack
3702                 free(rasterPoolBase);
3703 #endif
3704
3705             rasterPoolSize = new_size;
3706             rasterPoolBase =
3707 #if defined(Q_OS_WIN64)
3708                 // We make use of setjmp and longjmp in qgrayraster.c which requires
3709                 // 16-byte alignment, hence we hardcode this requirement here..
3710                 (unsigned char *) _aligned_malloc(rasterPoolSize, sizeof(void*) * 2);
3711 #else
3712                 (unsigned char *) malloc(rasterPoolSize);
3713 #endif
3714             Q_CHECK_PTR(rasterPoolBase); // note: we just freed the old rasterPoolBase. I hope it's not fatal.
3715
3716             qt_ft_grays_raster.raster_done(*grayRaster.data());
3717             qt_ft_grays_raster.raster_new(grayRaster.data());
3718             qt_ft_grays_raster.raster_reset(*grayRaster.data(), rasterPoolBase, rasterPoolSize);
3719         } else {
3720             done = true;
3721         }
3722     }
3723
3724 #if defined(Q_OS_WIN64)
3725     _aligned_free(rasterPoolBase);
3726 #else
3727     if (rasterPoolBase != rasterPoolOnStack) // initially on the stack
3728         free(rasterPoolBase);
3729 #endif
3730 }
3731
3732 void QRasterPaintEnginePrivate::recalculateFastImages()
3733 {
3734     Q_Q(QRasterPaintEngine);
3735     QRasterPaintEngineState *s = q->state();
3736
3737     s->flags.fast_images = !(s->renderHints & QPainter::SmoothPixmapTransform)
3738                            && s->matrix.type() <= QTransform::TxShear;
3739 }
3740
3741 bool QRasterPaintEnginePrivate::canUseFastImageBlending(QPainter::CompositionMode mode, const QImage &image) const
3742 {
3743     Q_Q(const QRasterPaintEngine);
3744     const QRasterPaintEngineState *s = q->state();
3745
3746     return s->flags.fast_images
3747            && (mode == QPainter::CompositionMode_SourceOver
3748                || (mode == QPainter::CompositionMode_Source
3749                    && !image.hasAlphaChannel()));
3750 }
3751
3752 QImage QRasterBuffer::colorizeBitmap(const QImage &image, const QColor &color)
3753 {
3754     Q_ASSERT(image.depth() == 1);
3755
3756     QImage sourceImage = image.convertToFormat(QImage::Format_MonoLSB);
3757     QImage dest = QImage(sourceImage.size(), QImage::Format_ARGB32_Premultiplied);
3758
3759     QRgb fg = PREMUL(color.rgba());
3760     QRgb bg = 0;
3761
3762     int height = sourceImage.height();
3763     int width = sourceImage.width();
3764     for (int y=0; y<height; ++y) {
3765         uchar *source = sourceImage.scanLine(y);
3766         QRgb *target = reinterpret_cast<QRgb *>(dest.scanLine(y));
3767         if (!source || !target)
3768             QT_THROW(std::bad_alloc()); // we must have run out of memory
3769         for (int x=0; x < width; ++x)
3770             target[x] = (source[x>>3] >> (x&7)) & 1 ? fg : bg;
3771     }
3772     return dest;
3773 }
3774
3775 QRasterBuffer::~QRasterBuffer()
3776 {
3777 }
3778
3779 void QRasterBuffer::init()
3780 {
3781     compositionMode = QPainter::CompositionMode_SourceOver;
3782     monoDestinationWithClut = false;
3783     destColor0 = 0;
3784     destColor1 = 0;
3785 }
3786
3787 QImage::Format QRasterBuffer::prepare(QImage *image)
3788 {
3789     m_buffer = (uchar *)image->bits();
3790     m_width = qMin(QT_RASTER_COORD_LIMIT, image->width());
3791     m_height = qMin(QT_RASTER_COORD_LIMIT, image->height());
3792     bytes_per_pixel = image->depth()/8;
3793     bytes_per_line = image->bytesPerLine();
3794
3795     format = image->format();
3796     drawHelper = qDrawHelper + format;
3797     if (image->depth() == 1 && image->colorTable().size() == 2) {
3798         monoDestinationWithClut = true;
3799         destColor0 = PREMUL(image->colorTable()[0]);
3800         destColor1 = PREMUL(image->colorTable()[1]);
3801     }
3802
3803     return format;
3804 }
3805
3806 void QRasterBuffer::resetBuffer(int val)
3807 {
3808     memset(m_buffer, val, m_height*bytes_per_line);
3809 }
3810
3811 QClipData::QClipData(int height)
3812 {
3813     clipSpanHeight = height;
3814     m_clipLines = 0;
3815
3816     allocated = 0;
3817     m_spans = 0;
3818     xmin = xmax = ymin = ymax = 0;
3819     count = 0;
3820
3821     enabled = true;
3822     hasRectClip = hasRegionClip = false;
3823 }
3824
3825 QClipData::~QClipData()
3826 {
3827     if (m_clipLines)
3828         free(m_clipLines);
3829     if (m_spans)
3830         free(m_spans);
3831 }
3832
3833 void QClipData::initialize()
3834 {
3835     if (m_spans)
3836         return;
3837
3838     if (!m_clipLines)
3839         m_clipLines = (ClipLine *)calloc(sizeof(ClipLine), clipSpanHeight);
3840
3841     Q_CHECK_PTR(m_clipLines);
3842     QT_TRY {
3843         m_spans = (QSpan *)malloc(clipSpanHeight*sizeof(QSpan));
3844         allocated = clipSpanHeight;
3845         Q_CHECK_PTR(m_spans);
3846
3847         QT_TRY {
3848             if (hasRectClip) {
3849                 int y = 0;
3850                 while (y < ymin) {
3851                     m_clipLines[y].spans = 0;
3852                     m_clipLines[y].count = 0;
3853                     ++y;
3854                 }
3855
3856                 const int len = clipRect.width();
3857                 count = 0;
3858                 while (y < ymax) {
3859                     QSpan *span = m_spans + count;
3860                     span->x = xmin;
3861                     span->len = len;
3862                     span->y = y;
3863                     span->coverage = 255;
3864                     ++count;
3865
3866                     m_clipLines[y].spans = span;
3867                     m_clipLines[y].count = 1;
3868                     ++y;
3869                 }
3870
3871                 while (y < clipSpanHeight) {
3872                     m_clipLines[y].spans = 0;
3873                     m_clipLines[y].count = 0;
3874                     ++y;
3875                 }
3876             } else if (hasRegionClip) {
3877
3878                 const QVector<QRect> rects = clipRegion.rects();
3879                 const int numRects = rects.size();
3880
3881                 { // resize
3882                     const int maxSpans = (ymax - ymin) * numRects;
3883                     if (maxSpans > allocated) {
3884                         m_spans = q_check_ptr((QSpan *)realloc(m_spans, maxSpans * sizeof(QSpan)));
3885                         allocated = maxSpans;
3886                     }
3887                 }
3888
3889                 int y = 0;
3890                 int firstInBand = 0;
3891                 count = 0;
3892                 while (firstInBand < numRects) {
3893                     const int currMinY = rects.at(firstInBand).y();
3894                     const int currMaxY = currMinY + rects.at(firstInBand).height();
3895
3896                     while (y < currMinY) {
3897                         m_clipLines[y].spans = 0;
3898                         m_clipLines[y].count = 0;
3899                         ++y;
3900                     }
3901
3902                     int lastInBand = firstInBand;
3903                     while (lastInBand + 1 < numRects && rects.at(lastInBand+1).top() == y)
3904                         ++lastInBand;
3905
3906                     while (y < currMaxY) {
3907
3908                         m_clipLines[y].spans = m_spans + count;
3909                         m_clipLines[y].count = lastInBand - firstInBand + 1;
3910
3911                         for (int r = firstInBand; r <= lastInBand; ++r) {
3912                             const QRect &currRect = rects.at(r);
3913                             QSpan *span = m_spans + count;
3914                             span->x = currRect.x();
3915                             span->len = currRect.width();
3916                             span->y = y;
3917                             span->coverage = 255;
3918                             ++count;
3919                         }
3920                         ++y;
3921                     }
3922
3923                     firstInBand = lastInBand + 1;
3924                 }
3925
3926                 Q_ASSERT(count <= allocated);
3927
3928                 while (y < clipSpanHeight) {
3929                     m_clipLines[y].spans = 0;
3930                     m_clipLines[y].count = 0;
3931                     ++y;
3932                 }
3933
3934             }
3935         } QT_CATCH(...) {
3936             free(m_spans); // have to free m_spans again or someone might think that we were successfully initialized.
3937             m_spans = 0;
3938             QT_RETHROW;
3939         }
3940     } QT_CATCH(...) {
3941         free(m_clipLines); // same for clipLines
3942         m_clipLines = 0;
3943         QT_RETHROW;
3944     }
3945 }
3946
3947 void QClipData::fixup()
3948 {
3949     Q_ASSERT(m_spans);
3950
3951     if (count == 0) {
3952         ymin = ymax = xmin = xmax = 0;
3953         return;
3954     }
3955
3956     int y = -1;
3957     ymin = m_spans[0].y;
3958     ymax = m_spans[count-1].y + 1;
3959     xmin = INT_MAX;
3960     xmax = 0;
3961
3962     const int firstLeft = m_spans[0].x;
3963     const int firstRight = m_spans[0].x + m_spans[0].len;
3964     bool isRect = true;
3965
3966     for (int i = 0; i < count; ++i) {
3967         QT_FT_Span_& span = m_spans[i];
3968
3969         if (span.y != y) {
3970             if (span.y != y + 1 && y != -1)
3971                 isRect = false;
3972             y = span.y;
3973             m_clipLines[y].spans = &span;
3974             m_clipLines[y].count = 1;
3975         } else
3976             ++m_clipLines[y].count;
3977
3978         const int spanLeft = span.x;
3979         const int spanRight = spanLeft + span.len;
3980
3981         if (spanLeft < xmin)
3982             xmin = spanLeft;
3983
3984         if (spanRight > xmax)
3985             xmax = spanRight;
3986
3987         if (spanLeft != firstLeft || spanRight != firstRight)
3988             isRect = false;
3989     }
3990
3991     if (isRect) {
3992         hasRectClip = true;
3993         clipRect.setRect(xmin, ymin, xmax - xmin, ymax - ymin);
3994     }
3995 }
3996
3997 /*
3998     Convert \a rect to clip spans.
3999  */
4000 void QClipData::setClipRect(const QRect &rect)
4001 {
4002     if (hasRectClip && rect == clipRect)
4003         return;
4004
4005 //    qDebug() << "setClipRect" << clipSpanHeight << count << allocated << rect;
4006     hasRectClip = true;
4007     hasRegionClip = false;
4008     clipRect = rect;
4009
4010     xmin = rect.x();
4011     xmax = rect.x() + rect.width();
4012     ymin = qMin(rect.y(), clipSpanHeight);
4013     ymax = qMin(rect.y() + rect.height(), clipSpanHeight);
4014
4015     if (m_spans) {
4016         free(m_spans);
4017         m_spans = 0;
4018     }
4019
4020 //    qDebug() << xmin << xmax << ymin << ymax;
4021 }
4022
4023 /*
4024     Convert \a region to clip spans.
4025  */
4026 void QClipData::setClipRegion(const QRegion &region)
4027 {
4028     if (region.rectCount() == 1) {
4029         setClipRect(region.rects().at(0));
4030         return;
4031     }
4032
4033     hasRegionClip = true;
4034     hasRectClip = false;
4035     clipRegion = region;
4036
4037     { // set bounding rect
4038         const QRect rect = region.boundingRect();
4039         xmin = rect.x();
4040         xmax = rect.x() + rect.width();
4041         ymin = rect.y();
4042         ymax = rect.y() + rect.height();
4043     }
4044
4045     if (m_spans) {
4046         free(m_spans);
4047         m_spans = 0;
4048     }
4049
4050 }
4051
4052 /*!
4053     \internal
4054     spans must be sorted on y
4055 */
4056 static const QSpan *qt_intersect_spans(const QClipData *clip, int *currentClip,
4057                                        const QSpan *spans, const QSpan *end,
4058                                        QSpan **outSpans, int available)
4059 {
4060     const_cast<QClipData *>(clip)->initialize();
4061
4062     QSpan *out = *outSpans;
4063
4064     const QSpan *clipSpans = clip->m_spans + *currentClip;
4065     const QSpan *clipEnd = clip->m_spans + clip->count;
4066
4067     while (available && spans < end ) {
4068         if (clipSpans >= clipEnd) {
4069             spans = end;
4070             break;
4071         }
4072         if (clipSpans->y > spans->y) {
4073             ++spans;
4074             continue;
4075         }
4076         if (spans->y != clipSpans->y) {
4077             if (spans->y < clip->count && clip->m_clipLines[spans->y].spans)
4078                 clipSpans = clip->m_clipLines[spans->y].spans;
4079             else
4080                 ++clipSpans;
4081             continue;
4082         }
4083         Q_ASSERT(spans->y == clipSpans->y);
4084
4085         int sx1 = spans->x;
4086         int sx2 = sx1 + spans->len;
4087         int cx1 = clipSpans->x;
4088         int cx2 = cx1 + clipSpans->len;
4089
4090         if (cx1 < sx1 && cx2 < sx1) {
4091             ++clipSpans;
4092             continue;
4093         } else if (sx1 < cx1 && sx2 < cx1) {
4094             ++spans;
4095             continue;
4096         }
4097         int x = qMax(sx1, cx1);
4098         int len = qMin(sx2, cx2) - x;
4099         if (len) {
4100             out->x = qMax(sx1, cx1);
4101             out->len = qMin(sx2, cx2) - out->x;
4102             out->y = spans->y;
4103             out->coverage = qt_div_255(spans->coverage * clipSpans->coverage);
4104             ++out;
4105             --available;
4106         }
4107         if (sx2 < cx2) {
4108             ++spans;
4109         } else {
4110             ++clipSpans;
4111         }
4112     }
4113
4114     *outSpans = out;
4115     *currentClip = clipSpans - clip->m_spans;
4116     return spans;
4117 }
4118
4119 static void qt_span_fill_clipped(int spanCount, const QSpan *spans, void *userData)
4120 {
4121 //     qDebug() << "qt_span_fill_clipped" << spanCount;
4122     QSpanData *fillData = reinterpret_cast<QSpanData *>(userData);
4123
4124     Q_ASSERT(fillData->blend && fillData->unclipped_blend);
4125
4126     const int NSPANS = 256;
4127     QSpan cspans[NSPANS];
4128     int currentClip = 0;
4129     const QSpan *end = spans + spanCount;
4130     while (spans < end) {
4131         QSpan *clipped = cspans;
4132         spans = qt_intersect_spans(fillData->clip, &currentClip, spans, end, &clipped, NSPANS);
4133 //         qDebug() << "processed " << spanCount - (end - spans) << "clipped" << clipped-cspans
4134 //                  << "span:" << cspans->x << cspans->y << cspans->len << spans->coverage;
4135
4136         if (clipped - cspans)
4137             fillData->unclipped_blend(clipped - cspans, cspans, fillData);
4138     }
4139 }
4140
4141 /*
4142     \internal
4143     Clip spans to \a{clip}-rectangle.
4144     Returns number of unclipped spans
4145 */
4146 static int qt_intersect_spans(QT_FT_Span *spans, int numSpans,
4147                               const QRect &clip)
4148 {
4149     const short minx = clip.left();
4150     const short miny = clip.top();
4151     const short maxx = clip.right();
4152     const short maxy = clip.bottom();
4153
4154     int n = 0;
4155     for (int i = 0; i < numSpans; ++i) {
4156         if (spans[i].y > maxy)
4157             break;
4158         if (spans[i].y < miny
4159             || spans[i].x > maxx
4160             || spans[i].x + spans[i].len <= minx) {
4161             continue;
4162         }
4163         if (spans[i].x < minx) {
4164             spans[n].len = qMin(spans[i].len - (minx - spans[i].x), maxx - minx + 1);
4165             spans[n].x = minx;
4166         } else {
4167             spans[n].x = spans[i].x;
4168             spans[n].len = qMin(spans[i].len, ushort(maxx - spans[n].x + 1));
4169         }
4170         if (spans[n].len == 0)
4171             continue;
4172         spans[n].y = spans[i].y;
4173         spans[n].coverage = spans[i].coverage;
4174         ++n;
4175     }
4176     return n;
4177 }
4178
4179
4180 static void qt_span_fill_clipRect(int count, const QSpan *spans,
4181                                   void *userData)
4182 {
4183     QSpanData *fillData = reinterpret_cast<QSpanData *>(userData);
4184     Q_ASSERT(fillData->blend && fillData->unclipped_blend);
4185
4186     Q_ASSERT(fillData->clip);
4187     Q_ASSERT(!fillData->clip->clipRect.isEmpty());
4188
4189     // hw: check if this const_cast<> is safe!!!
4190     count = qt_intersect_spans(const_cast<QSpan*>(spans), count,
4191                                fillData->clip->clipRect);
4192     if (count > 0)
4193         fillData->unclipped_blend(count, spans, fillData);
4194 }
4195
4196 static void qt_span_clip(int count, const QSpan *spans, void *userData)
4197 {
4198     ClipData *clipData = reinterpret_cast<ClipData *>(userData);
4199
4200 //     qDebug() << " qt_span_clip: " << count << clipData->operation;
4201 //     for (int i = 0; i < qMin(count, 10); ++i) {
4202 //         qDebug() << "    " << spans[i].x << spans[i].y << spans[i].len << spans[i].coverage;
4203 //     }
4204
4205     switch (clipData->operation) {
4206
4207     case Qt::IntersectClip:
4208         {
4209             QClipData *newClip = clipData->newClip;
4210             newClip->initialize();
4211
4212             int currentClip = 0;
4213             const QSpan *end = spans + count;
4214             while (spans < end) {
4215                 QSpan *newspans = newClip->m_spans + newClip->count;
4216                 spans = qt_intersect_spans(clipData->oldClip, &currentClip, spans, end,
4217                                            &newspans, newClip->allocated - newClip->count);
4218                 newClip->count = newspans - newClip->m_spans;
4219                 if (spans < end) {
4220                     newClip->m_spans = q_check_ptr((QSpan *)realloc(newClip->m_spans, newClip->allocated*2*sizeof(QSpan)));
4221                     newClip->allocated *= 2;
4222                 }
4223             }
4224         }
4225         break;
4226
4227     case Qt::UniteClip:
4228     case Qt::ReplaceClip:
4229         clipData->newClip->appendSpans(spans, count);
4230         break;
4231     case Qt::NoClip:
4232         break;
4233     }
4234 }
4235
4236 #ifndef QT_NO_DEBUG
4237 QImage QRasterBuffer::bufferImage() const
4238 {
4239     QImage image(m_width, m_height, QImage::Format_ARGB32_Premultiplied);
4240
4241     for (int y = 0; y < m_height; ++y) {
4242         uint *span = (uint *)const_cast<QRasterBuffer *>(this)->scanLine(y);
4243
4244         for (int x=0; x<m_width; ++x) {
4245             uint argb = span[x];
4246             image.setPixel(x, y, argb);
4247         }
4248     }
4249     return image;
4250 }
4251 #endif
4252
4253
4254 void QRasterBuffer::flushToARGBImage(QImage *target) const
4255 {
4256     int w = qMin(m_width, target->width());
4257     int h = qMin(m_height, target->height());
4258
4259     for (int y=0; y<h; ++y) {
4260         uint *sourceLine = (uint *)const_cast<QRasterBuffer *>(this)->scanLine(y);
4261         QRgb *dest = (QRgb *) target->scanLine(y);
4262         for (int x=0; x<w; ++x) {
4263             QRgb pixel = sourceLine[x];
4264             int alpha = qAlpha(pixel);
4265             if (!alpha) {
4266                 dest[x] = 0;
4267             } else {
4268                 dest[x] = (alpha << 24)
4269                         | ((255*qRed(pixel)/alpha) << 16)
4270                         | ((255*qGreen(pixel)/alpha) << 8)
4271                         | ((255*qBlue(pixel)/alpha) << 0);
4272             }
4273         }
4274     }
4275 }
4276
4277
4278 class QGradientCache
4279 {
4280     struct CacheInfo
4281     {
4282         inline CacheInfo(QGradientStops s, int op, QGradient::InterpolationMode mode) :
4283             stops(s), opacity(op), interpolationMode(mode) {}
4284         uint buffer[GRADIENT_STOPTABLE_SIZE];
4285         QGradientStops stops;
4286         int opacity;
4287         QGradient::InterpolationMode interpolationMode;
4288     };
4289
4290     typedef QMultiHash<quint64, CacheInfo> QGradientColorTableHash;
4291
4292 public:
4293     inline const uint *getBuffer(const QGradient &gradient, int opacity) {
4294         quint64 hash_val = 0;
4295
4296         QGradientStops stops = gradient.stops();
4297         for (int i = 0; i < stops.size() && i <= 2; i++)
4298             hash_val += stops[i].second.rgba();
4299
4300         QMutexLocker lock(&mutex);
4301         QGradientColorTableHash::const_iterator it = cache.constFind(hash_val);
4302
4303         if (it == cache.constEnd())
4304             return addCacheElement(hash_val, gradient, opacity);
4305         else {
4306             do {
4307                 const CacheInfo &cache_info = it.value();
4308                 if (cache_info.stops == stops && cache_info.opacity == opacity && cache_info.interpolationMode == gradient.interpolationMode())
4309                     return cache_info.buffer;
4310                 ++it;
4311             } while (it != cache.constEnd() && it.key() == hash_val);
4312             // an exact match for these stops and opacity was not found, create new cache
4313             return addCacheElement(hash_val, gradient, opacity);
4314         }
4315     }
4316
4317     inline int paletteSize() const { return GRADIENT_STOPTABLE_SIZE; }
4318 protected:
4319     inline int maxCacheSize() const { return 60; }
4320     inline void generateGradientColorTable(const QGradient& g,
4321                                            uint *colorTable,
4322                                            int size, int opacity) const;
4323     uint *addCacheElement(quint64 hash_val, const QGradient &gradient, int opacity) {
4324         if (cache.size() == maxCacheSize()) {
4325             // may remove more than 1, but OK
4326             cache.erase(cache.begin() + (qrand() % maxCacheSize()));
4327         }
4328         CacheInfo cache_entry(gradient.stops(), opacity, gradient.interpolationMode());
4329         generateGradientColorTable(gradient, cache_entry.buffer, paletteSize(), opacity);
4330         return cache.insert(hash_val, cache_entry).value().buffer;
4331     }
4332
4333     QGradientColorTableHash cache;
4334     QMutex mutex;
4335 };
4336
4337 void QGradientCache::generateGradientColorTable(const QGradient& gradient, uint *colorTable, int size, int opacity) const
4338 {
4339     QGradientStops stops = gradient.stops();
4340     int stopCount = stops.count();
4341     Q_ASSERT(stopCount > 0);
4342
4343     bool colorInterpolation = (gradient.interpolationMode() == QGradient::ColorInterpolation);
4344
4345     if (stopCount == 2) {
4346         uint first_color = ARGB_COMBINE_ALPHA(stops[0].second.rgba(), opacity);
4347         uint second_color = ARGB_COMBINE_ALPHA(stops[1].second.rgba(), opacity);
4348
4349         qreal first_stop = stops[0].first;
4350         qreal second_stop = stops[1].first;
4351
4352         if (second_stop < first_stop) {
4353             qSwap(first_color, second_color);
4354             qSwap(first_stop, second_stop);
4355         }
4356
4357         if (colorInterpolation) {
4358             first_color = PREMUL(first_color);
4359             second_color = PREMUL(second_color);
4360         }
4361
4362         int first_index = qRound(first_stop * (GRADIENT_STOPTABLE_SIZE-1));
4363         int second_index = qRound(second_stop * (GRADIENT_STOPTABLE_SIZE-1));
4364
4365         uint red_first = qRed(first_color) << 16;
4366         uint green_first = qGreen(first_color) << 16;
4367         uint blue_first = qBlue(first_color) << 16;
4368         uint alpha_first = qAlpha(first_color) << 16;
4369
4370         uint red_second = qRed(second_color) << 16;
4371         uint green_second = qGreen(second_color) << 16;
4372         uint blue_second = qBlue(second_color) << 16;
4373         uint alpha_second = qAlpha(second_color) << 16;
4374
4375         int i = 0;
4376         for (; i <= qMin(GRADIENT_STOPTABLE_SIZE, first_index); ++i) {
4377             if (colorInterpolation)
4378                 colorTable[i] = first_color;
4379             else
4380                 colorTable[i] = PREMUL(first_color);
4381         }
4382
4383         if (i < second_index) {
4384             qreal reciprocal = qreal(1) / (second_index - first_index);
4385
4386             int red_delta = qRound(int(red_second - red_first) * reciprocal);
4387             int green_delta = qRound(int(green_second - green_first) * reciprocal);
4388             int blue_delta = qRound(int(blue_second - blue_first) * reciprocal);
4389             int alpha_delta = qRound(int(alpha_second - alpha_first) * reciprocal);
4390
4391             // rounding
4392             red_first += 1 << 15;
4393             green_first += 1 << 15;
4394             blue_first += 1 << 15;
4395             alpha_first += 1 << 15;
4396
4397             for (; i < qMin(GRADIENT_STOPTABLE_SIZE, second_index); ++i) {
4398                 red_first += red_delta;
4399                 green_first += green_delta;
4400                 blue_first += blue_delta;
4401                 alpha_first += alpha_delta;
4402
4403                 const uint color = ((alpha_first << 8) & 0xff000000) | (red_first & 0xff0000)
4404                                  | ((green_first >> 8) & 0xff00) | (blue_first >> 16);
4405
4406                 if (colorInterpolation)
4407                     colorTable[i] = color;
4408                 else
4409                     colorTable[i] = PREMUL(color);
4410             }
4411         }
4412
4413         for (; i < GRADIENT_STOPTABLE_SIZE; ++i) {
4414             if (colorInterpolation)
4415                 colorTable[i] = second_color;
4416             else
4417                 colorTable[i] = PREMUL(second_color);
4418         }
4419
4420         return;
4421     }
4422
4423     uint current_color = ARGB_COMBINE_ALPHA(stops[0].second.rgba(), opacity);
4424     if (stopCount == 1) {
4425         current_color = PREMUL(current_color);
4426         for (int i = 0; i < size; ++i)
4427             colorTable[i] = current_color;
4428         return;
4429     }
4430
4431     // The position where the gradient begins and ends
4432     qreal begin_pos = stops[0].first;
4433     qreal end_pos = stops[stopCount-1].first;
4434
4435     int pos = 0; // The position in the color table.
4436     uint next_color;
4437
4438     qreal incr = 1 / qreal(size); // the double increment.
4439     qreal dpos = 1.5 * incr; // current position in gradient stop list (0 to 1)
4440
4441      // Up to first point
4442     colorTable[pos++] = PREMUL(current_color);
4443     while (dpos <= begin_pos) {
4444         colorTable[pos] = colorTable[pos - 1];
4445         ++pos;
4446         dpos += incr;
4447     }
4448
4449     int current_stop = 0; // We always interpolate between current and current + 1.
4450
4451     qreal t; // position between current left and right stops
4452     qreal t_delta; // the t increment per entry in the color table
4453
4454     if (dpos < end_pos) {
4455         // Gradient area
4456         while (dpos > stops[current_stop+1].first)
4457             ++current_stop;
4458
4459         if (current_stop != 0)
4460             current_color = ARGB_COMBINE_ALPHA(stops[current_stop].second.rgba(), opacity);
4461         next_color = ARGB_COMBINE_ALPHA(stops[current_stop+1].second.rgba(), opacity);
4462
4463         if (colorInterpolation) {
4464             current_color = PREMUL(current_color);
4465             next_color = PREMUL(next_color);
4466         }
4467
4468         qreal diff = stops[current_stop+1].first - stops[current_stop].first;
4469         qreal c = (diff == 0) ? qreal(0) : 256 / diff;
4470         t = (dpos - stops[current_stop].first) * c;
4471         t_delta = incr * c;
4472
4473         while (true) {
4474             Q_ASSERT(current_stop < stopCount);
4475
4476             int dist = qRound(t);
4477             int idist = 256 - dist;
4478
4479             if (colorInterpolation)
4480                 colorTable[pos] = INTERPOLATE_PIXEL_256(current_color, idist, next_color, dist);
4481             else
4482                 colorTable[pos] = PREMUL(INTERPOLATE_PIXEL_256(current_color, idist, next_color, dist));
4483
4484             ++pos;
4485             dpos += incr;
4486
4487             if (dpos >= end_pos)
4488                 break;
4489
4490             t += t_delta;
4491
4492             int skip = 0;
4493             while (dpos > stops[current_stop+skip+1].first)
4494                 ++skip;
4495
4496             if (skip != 0) {
4497                 current_stop += skip;
4498                 if (skip == 1)
4499                     current_color = next_color;
4500                 else
4501                     current_color = ARGB_COMBINE_ALPHA(stops[current_stop].second.rgba(), opacity);
4502                 next_color = ARGB_COMBINE_ALPHA(stops[current_stop+1].second.rgba(), opacity);
4503
4504                 if (colorInterpolation) {
4505                     if (skip != 1)
4506                         current_color = PREMUL(current_color);
4507                     next_color = PREMUL(next_color);
4508                 }
4509
4510                 qreal diff = stops[current_stop+1].first - stops[current_stop].first;
4511                 qreal c = (diff == 0) ? qreal(0) : 256 / diff;
4512                 t = (dpos - stops[current_stop].first) * c;
4513                 t_delta = incr * c;
4514             }
4515         }
4516     }
4517
4518     // After last point
4519     current_color = PREMUL(ARGB_COMBINE_ALPHA(stops[stopCount - 1].second.rgba(), opacity));
4520     while (pos < size - 1) {
4521         colorTable[pos] = current_color;
4522         ++pos;
4523     }
4524
4525     // Make sure the last color stop is represented at the end of the table
4526     colorTable[size - 1] = current_color;
4527 }
4528
4529 Q_GLOBAL_STATIC(QGradientCache, qt_gradient_cache)
4530
4531
4532 void QSpanData::init(QRasterBuffer *rb, const QRasterPaintEngine *pe)
4533 {
4534     rasterBuffer = rb;
4535     type = None;
4536     txop = 0;
4537     bilinear = false;
4538     m11 = m22 = m33 = 1.;
4539     m12 = m13 = m21 = m23 = dx = dy = 0.0;
4540     clip = pe ? pe->d_func()->clip() : 0;
4541 }
4542
4543 Q_GUI_EXPORT extern QImage qt_imageForBrush(int brushStyle, bool invert);
4544
4545 void QSpanData::setup(const QBrush &brush, int alpha, QPainter::CompositionMode compositionMode)
4546 {
4547     Qt::BrushStyle brushStyle = qbrush_style(brush);
4548     switch (brushStyle) {
4549     case Qt::SolidPattern: {
4550         type = Solid;
4551         QColor c = qbrush_color(brush);
4552         QRgb rgba = c.rgba();
4553         solid.color = PREMUL(ARGB_COMBINE_ALPHA(rgba, alpha));
4554         if ((solid.color & 0xff000000) == 0
4555             && compositionMode == QPainter::CompositionMode_SourceOver) {
4556             type = None;
4557         }
4558         break;
4559     }
4560
4561     case Qt::LinearGradientPattern:
4562         {
4563             type = LinearGradient;
4564             const QLinearGradient *g = static_cast<const QLinearGradient *>(brush.gradient());
4565             gradient.alphaColor = !brush.isOpaque() || alpha != 256;
4566             gradient.colorTable = const_cast<uint*>(qt_gradient_cache()->getBuffer(*g, alpha));
4567             gradient.spread = g->spread();
4568
4569             QLinearGradientData &linearData = gradient.linear;
4570
4571             linearData.origin.x = g->start().x();
4572             linearData.origin.y = g->start().y();
4573             linearData.end.x = g->finalStop().x();
4574             linearData.end.y = g->finalStop().y();
4575             break;
4576         }
4577
4578     case Qt::RadialGradientPattern:
4579         {
4580             type = RadialGradient;
4581             const QRadialGradient *g = static_cast<const QRadialGradient *>(brush.gradient());
4582             gradient.alphaColor = !brush.isOpaque() || alpha != 256;
4583             gradient.colorTable = const_cast<uint*>(qt_gradient_cache()->getBuffer(*g, alpha));
4584             gradient.spread = g->spread();
4585
4586             QRadialGradientData &radialData = gradient.radial;
4587
4588             QPointF center = g->center();
4589             radialData.center.x = center.x();
4590             radialData.center.y = center.y();
4591             radialData.center.radius = g->centerRadius();
4592             QPointF focal = g->focalPoint();
4593             radialData.focal.x = focal.x();
4594             radialData.focal.y = focal.y();
4595             radialData.focal.radius = g->focalRadius();
4596         }
4597         break;
4598
4599     case Qt::ConicalGradientPattern:
4600         {
4601             type = ConicalGradient;
4602             const QConicalGradient *g = static_cast<const QConicalGradient *>(brush.gradient());
4603             gradient.alphaColor = !brush.isOpaque() || alpha != 256;
4604             gradient.colorTable = const_cast<uint*>(qt_gradient_cache()->getBuffer(*g, alpha));
4605             gradient.spread = QGradient::RepeatSpread;
4606
4607             QConicalGradientData &conicalData = gradient.conical;
4608
4609             QPointF center = g->center();
4610             conicalData.center.x = center.x();
4611             conicalData.center.y = center.y();
4612             conicalData.angle = g->angle() * 2 * Q_PI / 360.0;
4613         }
4614         break;
4615
4616     case Qt::Dense1Pattern:
4617     case Qt::Dense2Pattern:
4618     case Qt::Dense3Pattern:
4619     case Qt::Dense4Pattern:
4620     case Qt::Dense5Pattern:
4621     case Qt::Dense6Pattern:
4622     case Qt::Dense7Pattern:
4623     case Qt::HorPattern:
4624     case Qt::VerPattern:
4625     case Qt::CrossPattern:
4626     case Qt::BDiagPattern:
4627     case Qt::FDiagPattern:
4628     case Qt::DiagCrossPattern:
4629         type = Texture;
4630         if (!tempImage)
4631             tempImage = new QImage();
4632         *tempImage = rasterBuffer->colorizeBitmap(qt_imageForBrush(brushStyle, true), brush.color());
4633         initTexture(tempImage, alpha, QTextureData::Tiled);
4634         break;
4635     case Qt::TexturePattern:
4636         type = Texture;
4637         if (!tempImage)
4638             tempImage = new QImage();
4639
4640         if (qHasPixmapTexture(brush) && brush.texture().isQBitmap())
4641             *tempImage = rasterBuffer->colorizeBitmap(brush.textureImage(), brush.color());
4642         else
4643             *tempImage = brush.textureImage();
4644         initTexture(tempImage, alpha, QTextureData::Tiled, tempImage->rect());
4645         break;
4646
4647     case Qt::NoBrush:
4648     default:
4649         type = None;
4650         break;
4651     }
4652     adjustSpanMethods();
4653 }
4654
4655 void QSpanData::adjustSpanMethods()
4656 {
4657     bitmapBlit = 0;
4658     alphamapBlit = 0;
4659     alphaRGBBlit = 0;
4660
4661     fillRect = 0;
4662
4663     switch(type) {
4664     case None:
4665         unclipped_blend = 0;
4666         break;
4667     case Solid:
4668         unclipped_blend = rasterBuffer->drawHelper->blendColor;
4669         bitmapBlit = rasterBuffer->drawHelper->bitmapBlit;
4670         alphamapBlit = rasterBuffer->drawHelper->alphamapBlit;
4671         alphaRGBBlit = rasterBuffer->drawHelper->alphaRGBBlit;
4672         fillRect = rasterBuffer->drawHelper->fillRect;
4673         break;
4674     case LinearGradient:
4675     case RadialGradient:
4676     case ConicalGradient:
4677         unclipped_blend = rasterBuffer->drawHelper->blendGradient;
4678         break;
4679     case Texture:
4680         unclipped_blend = qBlendTexture;
4681         if (!texture.imageData)
4682             unclipped_blend = 0;
4683
4684         break;
4685     }
4686     // setup clipping
4687     if (!unclipped_blend) {
4688         blend = 0;
4689     } else if (!clip) {
4690         blend = unclipped_blend;
4691     } else if (clip->hasRectClip) {
4692         blend = clip->clipRect.isEmpty() ? 0 : qt_span_fill_clipRect;
4693     } else {
4694         blend = qt_span_fill_clipped;
4695     }
4696 }
4697
4698 void QSpanData::setupMatrix(const QTransform &matrix, int bilin)
4699 {
4700     QTransform delta;
4701     // make sure we round off correctly in qdrawhelper.cpp
4702     delta.translate(1.0 / 65536, 1.0 / 65536);
4703
4704     QTransform inv = (delta * matrix).inverted();
4705     m11 = inv.m11();
4706     m12 = inv.m12();
4707     m13 = inv.m13();
4708     m21 = inv.m21();
4709     m22 = inv.m22();
4710     m23 = inv.m23();
4711     m33 = inv.m33();
4712     dx = inv.dx();
4713     dy = inv.dy();
4714     txop = inv.type();
4715     bilinear = bilin;
4716
4717     const bool affine = !m13 && !m23;
4718     fast_matrix = affine
4719         && m11 * m11 + m21 * m21 < 1e4
4720         && m12 * m12 + m22 * m22 < 1e4
4721         && qAbs(dx) < 1e4
4722         && qAbs(dy) < 1e4;
4723
4724     adjustSpanMethods();
4725 }
4726
4727 extern const QVector<QRgb> *qt_image_colortable(const QImage &image);
4728
4729 void QSpanData::initTexture(const QImage *image, int alpha, QTextureData::Type _type, const QRect &sourceRect)
4730 {
4731     const QImageData *d = const_cast<QImage *>(image)->data_ptr();
4732     if (!d || d->height == 0) {
4733         texture.imageData = 0;
4734         texture.width = 0;
4735         texture.height = 0;
4736         texture.x1 = 0;
4737         texture.y1 = 0;
4738         texture.x2 = 0;
4739         texture.y2 = 0;
4740         texture.bytesPerLine = 0;
4741         texture.format = QImage::Format_Invalid;
4742         texture.colorTable = 0;
4743         texture.hasAlpha = alpha != 256;
4744     } else {
4745         texture.imageData = d->data;
4746         texture.width = d->width;
4747         texture.height = d->height;
4748
4749         if (sourceRect.isNull()) {
4750             texture.x1 = 0;
4751             texture.y1 = 0;
4752             texture.x2 = texture.width;
4753             texture.y2 = texture.height;
4754         } else {
4755             texture.x1 = sourceRect.x();
4756             texture.y1 = sourceRect.y();
4757             texture.x2 = qMin(texture.x1 + sourceRect.width(), d->width);
4758             texture.y2 = qMin(texture.y1 + sourceRect.height(), d->height);
4759         }
4760
4761         texture.bytesPerLine = d->bytes_per_line;
4762
4763         texture.format = d->format;
4764         texture.colorTable = (d->format <= QImage::Format_Indexed8 && !d->colortable.isEmpty()) ? &d->colortable : 0;
4765         texture.hasAlpha = image->hasAlphaChannel() || alpha != 256;
4766     }
4767     texture.const_alpha = alpha;
4768     texture.type = _type;
4769
4770     adjustSpanMethods();
4771 }
4772
4773
4774 /*!
4775     \fn void QRasterPaintEngine::drawPoints(const QPoint *points, int pointCount)
4776     \overload
4777
4778     Draws the first \a pointCount points in the buffer \a points
4779
4780     The default implementation converts the first \a pointCount QPoints in \a points
4781     to QPointFs and calls the floating point version of drawPoints.
4782 */
4783
4784 /*!
4785     \fn void QRasterPaintEngine::drawEllipse(const QRect &rect)
4786     \overload
4787
4788     Reimplement this function to draw the largest ellipse that can be
4789     contained within rectangle \a rect.
4790 */
4791
4792 #ifdef QT_DEBUG_DRAW
4793 void dumpClip(int width, int height, const QClipData *clip)
4794 {
4795     QImage clipImg(width, height, QImage::Format_ARGB32_Premultiplied);
4796     clipImg.fill(0xffff0000);
4797
4798     int x0 = width;
4799     int x1 = 0;
4800     int y0 = height;
4801     int y1 = 0;
4802
4803     ((QClipData *) clip)->spans(); // Force allocation of the spans structure...
4804
4805     for (int i = 0; i < clip->count; ++i) {
4806         const QSpan *span = ((QClipData *) clip)->spans() + i;
4807         for (int j = 0; j < span->len; ++j)
4808             clipImg.setPixel(span->x + j, span->y, 0xffffff00);
4809         x0 = qMin(x0, int(span->x));
4810         x1 = qMax(x1, int(span->x + span->len - 1));
4811
4812         y0 = qMin(y0, int(span->y));
4813         y1 = qMax(y1, int(span->y));
4814     }
4815
4816     static int counter = 0;
4817
4818     Q_ASSERT(y0 >= 0);
4819     Q_ASSERT(x0 >= 0);
4820     Q_ASSERT(y1 >= 0);
4821     Q_ASSERT(x1 >= 0);
4822
4823     fprintf(stderr,"clip %d: %d %d - %d %d\n", counter, x0, y0, x1, y1);
4824     clipImg.save(QString::fromLatin1("clip-%0.png").arg(counter++));
4825 }
4826 #endif
4827
4828
4829 QT_END_NAMESPACE