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