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