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