Merge remote-tracking branch 'origin/master' into api_changes
[profile/ivi/qtbase.git] / src / gui / painting / qpaintengine_raster.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the QtGui module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
16 **
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
20 **
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
28 **
29 ** Other Usage
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include <QtCore/qglobal.h>
43 #include <QtCore/qmutex.h>
44
45 #define QT_FT_BEGIN_HEADER
46 #define QT_FT_END_HEADER
47
48 #include <private/qrasterdefs_p.h>
49 #include <private/qgrayraster_p.h>
50
51 #include <qpainterpath.h>
52 #include <qdebug.h>
53 #include <qhash.h>
54 #include <qbitmap.h>
55 #include <qmath.h>
56
57 //   #include <private/qdatabuffer_p.h>
58 //   #include <private/qpainter_p.h>
59 #include <private/qmath_p.h>
60 #include <private/qtextengine_p.h>
61 #include <private/qfontengine_p.h>
62 #include <private/qpixmap_raster_p.h>
63 //   #include <private/qpolygonclipper_p.h>
64 //   #include <private/qrasterizer_p.h>
65 #include <private/qimage_p.h>
66 #include <private/qstatictext_p.h>
67 #include <private/qcosmeticstroker_p.h>
68 #include "qmemrotate_p.h"
69
70 #include "qpaintengine_raster_p.h"
71 //   #include "qbezier_p.h"
72 #include "qoutlinemapper_p.h"
73
74 #include <limits.h>
75
76 #ifdef Q_OS_WIN
77 #  include <qvarlengtharray.h>
78 #  include <private/qfontengine_p.h>
79 #  include <qt_windows.h>
80 #ifdef Q_OS_WIN64
81 #    include <malloc.h>
82 #  endif
83 #endif
84
85 QT_BEGIN_NAMESPACE
86
87 class QRectVectorPath : public QVectorPath {
88 public:
89     inline void set(const QRect &r) {
90         qreal left = r.x();
91         qreal right = r.x() + r.width();
92         qreal top = r.y();
93         qreal bottom = r.y() + r.height();
94         pts[0] = left;
95         pts[1] = top;
96         pts[2] = right;
97         pts[3] = top;
98         pts[4] = right;
99         pts[5] = bottom;
100         pts[6] = left;
101         pts[7] = bottom;
102     }
103
104     inline void set(const QRectF &r) {
105         qreal left = r.x();
106         qreal right = r.x() + r.width();
107         qreal top = r.y();
108         qreal bottom = r.y() + r.height();
109         pts[0] = left;
110         pts[1] = top;
111         pts[2] = right;
112         pts[3] = top;
113         pts[4] = right;
114         pts[5] = bottom;
115         pts[6] = left;
116         pts[7] = bottom;
117     }
118     inline QRectVectorPath(const QRect &r)
119         : QVectorPath(pts, 4, 0, QVectorPath::RectangleHint | QVectorPath::ImplicitClose)
120     {
121         set(r);
122     }
123     inline QRectVectorPath(const QRectF &r)
124         : QVectorPath(pts, 4, 0, QVectorPath::RectangleHint | QVectorPath::ImplicitClose)
125     {
126         set(r);
127     }
128     inline QRectVectorPath()
129         : QVectorPath(pts, 4, 0, QVectorPath::RectangleHint | QVectorPath::ImplicitClose)
130     { }
131
132     qreal pts[8];
133 };
134
135 Q_GUI_EXPORT extern bool qt_scaleForTransform(const QTransform &transform, qreal *scale); // qtransform.cpp
136
137 #define qreal_to_fixed_26_6(f) (int(f * 64))
138 #define qt_swap_int(x, y) { int tmp = (x); (x) = (y); (y) = tmp; }
139 #define qt_swap_qreal(x, y) { qreal tmp = (x); (x) = (y); (y) = tmp; }
140
141 // #define QT_DEBUG_DRAW
142 #ifdef QT_DEBUG_DRAW
143 void dumpClip(int width, int height, const QClipData *clip);
144 #endif
145
146 #define QT_FAST_SPANS
147
148
149 // A little helper macro to get a better approximation of dimensions.
150 // If we have a rect that starting at 0.5 of width 3.5 it should span
151 // 4 pixels.
152 #define int_dim(pos, dim) (int(pos+dim) - int(pos))
153
154 static const qreal aliasedCoordinateDelta = 0.5 - 0.015625;
155
156 #ifdef Q_OS_WIN
157
158 static inline bool winClearTypeFontsEnabled()
159 {
160     UINT result = 0;
161 #if !defined(SPI_GETFONTSMOOTHINGTYPE) // MinGW
162 #    define SPI_GETFONTSMOOTHINGTYPE  0x200A
163 #    define FE_FONTSMOOTHINGCLEARTYPE 0x002
164 #endif
165     SystemParametersInfo(SPI_GETFONTSMOOTHINGTYPE, 0, &result, 0);
166     return result == FE_FONTSMOOTHINGCLEARTYPE;
167 }
168
169 bool QRasterPaintEngine::clearTypeFontsEnabled()
170 {
171     static const bool result = winClearTypeFontsEnabled();
172     return result;
173 }
174
175 #endif // Q_OS_WIN
176
177
178
179 /********************************************************************************
180  * Span functions
181  */
182 static void qt_span_fill_clipRect(int count, const QSpan *spans, void *userData);
183 static void qt_span_fill_clipped(int count, const QSpan *spans, void *userData);
184 static void qt_span_clip(int count, const QSpan *spans, void *userData);
185
186 struct ClipData
187 {
188     QClipData *oldClip;
189     QClipData *newClip;
190     Qt::ClipOperation operation;
191 };
192
193 enum LineDrawMode {
194     LineDrawClipped,
195     LineDrawNormal,
196     LineDrawIncludeLastPixel
197 };
198
199 static void drawEllipse_midpoint_i(const QRect &rect, const QRect &clip,
200                                    ProcessSpans pen_func, ProcessSpans brush_func,
201                                    QSpanData *pen_data, QSpanData *brush_data);
202
203 struct QRasterFloatPoint {
204     qreal x;
205     qreal y;
206 };
207
208 #ifdef QT_DEBUG_DRAW
209 static const QRectF boundingRect(const QPointF *points, int pointCount)
210 {
211     const QPointF *e = points;
212     const QPointF *last = points + pointCount;
213     qreal minx, maxx, miny, maxy;
214     minx = maxx = e->x();
215     miny = maxy = e->y();
216     while (++e < last) {
217         if (e->x() < minx)
218             minx = e->x();
219         else if (e->x() > maxx)
220             maxx = e->x();
221         if (e->y() < miny)
222             miny = e->y();
223         else if (e->y() > maxy)
224             maxy = e->y();
225     }
226     return QRectF(QPointF(minx, miny), QPointF(maxx, maxy));
227 }
228 #endif
229
230 template <typename T> static inline bool isRect(const T *pts, int elementCount) {
231     return (elementCount == 5 // 5-point polygon, check for closed rect
232             && pts[0] == pts[8] && pts[1] == pts[9] // last point == first point
233             && pts[0] == pts[6] && pts[2] == pts[4] // x values equal
234             && pts[1] == pts[3] && pts[5] == pts[7] // y values equal...
235             && pts[0] < pts[4] && pts[1] < pts[5]
236             ) ||
237            (elementCount == 4 // 4-point polygon, check for unclosed rect
238             && pts[0] == pts[6] && pts[2] == pts[4] // x values equal
239             && pts[1] == pts[3] && pts[5] == pts[7] // y values equal...
240             && pts[0] < pts[4] && pts[1] < pts[5]
241             );
242 }
243
244
245 static void qt_ft_outline_move_to(qfixed x, qfixed y, void *data)
246 {
247     ((QOutlineMapper *) data)->moveTo(QPointF(qt_fixed_to_real(x), qt_fixed_to_real(y)));
248 }
249
250 static void qt_ft_outline_line_to(qfixed x, qfixed y, void *data)
251 {
252     ((QOutlineMapper *) data)->lineTo(QPointF(qt_fixed_to_real(x), qt_fixed_to_real(y)));
253 }
254
255 static void qt_ft_outline_cubic_to(qfixed c1x, qfixed c1y,
256                              qfixed c2x, qfixed c2y,
257                              qfixed ex, qfixed ey,
258                              void *data)
259 {
260     ((QOutlineMapper *) data)->curveTo(QPointF(qt_fixed_to_real(c1x), qt_fixed_to_real(c1y)),
261                                        QPointF(qt_fixed_to_real(c2x), qt_fixed_to_real(c2y)),
262                                        QPointF(qt_fixed_to_real(ex), qt_fixed_to_real(ey)));
263 }
264
265
266 #if !defined(QT_NO_DEBUG) && 0
267 static void qt_debug_path(const QPainterPath &path)
268 {
269     const char *names[] = {
270         "MoveTo     ",
271         "LineTo     ",
272         "CurveTo    ",
273         "CurveToData"
274     };
275
276     fprintf(stderr,"\nQPainterPath: elementCount=%d\n", path.elementCount());
277     for (int i=0; i<path.elementCount(); ++i) {
278         const QPainterPath::Element &e = path.elementAt(i);
279         Q_ASSERT(e.type >= 0 && e.type <= QPainterPath::CurveToDataElement);
280         fprintf(stderr," - %3d:: %s, (%.2f, %.2f)\n", i, names[e.type], e.x, e.y);
281     }
282 }
283 #endif
284
285 QRasterPaintEnginePrivate::QRasterPaintEnginePrivate() :
286     QPaintEngineExPrivate(),
287     cachedLines(0)
288 {
289 }
290
291
292 /*!
293     \class QRasterPaintEngine
294     \preliminary
295     \ingroup qws
296     \since 4.2
297
298     \brief The QRasterPaintEngine class enables hardware acceleration
299     of painting operations in Qt for Embedded Linux.
300
301     Note that this functionality is only available in
302     \l{Qt for Embedded Linux}.
303
304     In \l{Qt for Embedded Linux}, painting is a pure software
305     implementation. But starting with Qt 4.2, it is
306     possible to add an accelerated graphics driver to take advantage
307     of available hardware resources.
308
309     Hardware acceleration is accomplished by creating a custom screen
310     driver, accelerating the copying from memory to the screen, and
311     implementing a custom paint engine accelerating the various
312     painting operations. Then a custom paint device (derived from the
313     QCustomRasterPaintDevice class) and a custom window surface
314     (derived from QWSWindowSurface) must be implemented to make
315     \l{Qt for Embedded Linux} aware of the accelerated driver.
316
317     \note The QRasterPaintEngine class does not support 8-bit images.
318     Instead, they need to be converted to a supported format, such as
319     QImage::Format_ARGB32_Premultiplied.
320
321     See the \l {Adding an Accelerated Graphics Driver to Qt for Embedded Linux}
322     documentation for details.
323
324     \sa QCustomRasterPaintDevice, QPaintEngine
325 */
326
327 /*!
328     \fn Type QRasterPaintEngine::type() const
329     \reimp
330 */
331
332 /*!
333     \typedef QSpan
334     \relates QRasterPaintEngine
335
336     A struct equivalent to QT_FT_Span, containing a position (x,
337     y), the span's length in pixels and its color/coverage (a value
338     ranging from 0 to 255).
339 */
340
341 /*!
342     \since 4.5
343
344     Creates a raster based paint engine for operating on the given
345     \a device, with the complete set of \l
346     {QPaintEngine::PaintEngineFeature}{paint engine features and
347     capabilities}.
348 */
349 QRasterPaintEngine::QRasterPaintEngine(QPaintDevice *device)
350     : QPaintEngineEx(*(new QRasterPaintEnginePrivate))
351 {
352     d_func()->device = device;
353     init();
354 }
355
356 /*!
357     \internal
358 */
359 QRasterPaintEngine::QRasterPaintEngine(QRasterPaintEnginePrivate &dd, QPaintDevice *device)
360     : QPaintEngineEx(dd)
361 {
362     d_func()->device = device;
363     init();
364 }
365
366 void QRasterPaintEngine::init()
367 {
368     Q_D(QRasterPaintEngine);
369
370
371 #ifdef Q_OS_WIN
372     d->hdc = 0;
373 #endif
374
375     // The antialiasing raster.
376     d->grayRaster.reset(new QT_FT_Raster);
377     Q_CHECK_PTR(d->grayRaster.data());
378     if (qt_ft_grays_raster.raster_new(d->grayRaster.data()))
379         QT_THROW(std::bad_alloc()); // an error creating the raster is caused by a bad malloc
380
381
382     d->rasterizer.reset(new QRasterizer);
383     d->rasterBuffer.reset(new QRasterBuffer());
384     d->outlineMapper.reset(new QOutlineMapper);
385     d->outlinemapper_xform_dirty = true;
386
387     d->basicStroker.setMoveToHook(qt_ft_outline_move_to);
388     d->basicStroker.setLineToHook(qt_ft_outline_line_to);
389     d->basicStroker.setCubicToHook(qt_ft_outline_cubic_to);
390
391     d->baseClip.reset(new QClipData(d->device->height()));
392     d->baseClip->setClipRect(QRect(0, 0, d->device->width(), d->device->height()));
393
394     d->image_filler.init(d->rasterBuffer.data(), this);
395     d->image_filler.type = QSpanData::Texture;
396
397     d->image_filler_xform.init(d->rasterBuffer.data(), this);
398     d->image_filler_xform.type = QSpanData::Texture;
399
400     d->solid_color_filler.init(d->rasterBuffer.data(), this);
401     d->solid_color_filler.type = QSpanData::Solid;
402
403     d->deviceDepth = d->device->depth();
404
405     d->mono_surface = false;
406     gccaps &= ~PorterDuff;
407
408     QImage::Format format = QImage::Format_Invalid;
409
410     switch (d->device->devType()) {
411     case QInternal::Pixmap:
412         qWarning("QRasterPaintEngine: unsupported for pixmaps...");
413         break;
414     case QInternal::Image:
415         format = d->rasterBuffer->prepare(static_cast<QImage *>(d->device));
416         break;
417     default:
418         qWarning("QRasterPaintEngine: unsupported target device %d\n", d->device->devType());
419         d->device = 0;
420         return;
421     }
422
423     switch (format) {
424     case QImage::Format_MonoLSB:
425     case QImage::Format_Mono:
426         d->mono_surface = true;
427         break;
428     case QImage::Format_ARGB8565_Premultiplied:
429     case QImage::Format_ARGB8555_Premultiplied:
430     case QImage::Format_ARGB6666_Premultiplied:
431     case QImage::Format_ARGB4444_Premultiplied:
432     case QImage::Format_ARGB32_Premultiplied:
433     case QImage::Format_ARGB32:
434         gccaps |= PorterDuff;
435         break;
436     case QImage::Format_RGB32:
437     case QImage::Format_RGB444:
438     case QImage::Format_RGB555:
439     case QImage::Format_RGB666:
440     case QImage::Format_RGB888:
441     case QImage::Format_RGB16:
442         break;
443     default:
444         break;
445     }
446 }
447
448
449
450
451 /*!
452     Destroys this paint engine.
453 */
454 QRasterPaintEngine::~QRasterPaintEngine()
455 {
456     Q_D(QRasterPaintEngine);
457
458     qt_ft_grays_raster.raster_done(*d->grayRaster.data());
459 }
460
461 /*!
462     \reimp
463 */
464 bool QRasterPaintEngine::begin(QPaintDevice *device)
465 {
466     Q_D(QRasterPaintEngine);
467
468     if (device->devType() == QInternal::Pixmap) {
469         QPixmap *pixmap = static_cast<QPixmap *>(device);
470         QPlatformPixmap *pd = pixmap->handle();
471         if (pd->classId() == QPlatformPixmap::RasterClass || pd->classId() == QPlatformPixmap::BlitterClass)
472             d->device = pd->buffer();
473     } else {
474         d->device = device;
475     }
476
477     // Make sure QPaintEngine::paintDevice() returns the proper device.
478     d->pdev = d->device;
479
480     Q_ASSERT(d->device->devType() == QInternal::Image
481              || d->device->devType() == QInternal::CustomRaster);
482
483     d->systemStateChanged();
484
485     QRasterPaintEngineState *s = state();
486     ensureOutlineMapper();
487     d->outlineMapper->m_clip_rect = d->deviceRect;
488
489     if (d->outlineMapper->m_clip_rect.width() > QT_RASTER_COORD_LIMIT)
490         d->outlineMapper->m_clip_rect.setWidth(QT_RASTER_COORD_LIMIT);
491     if (d->outlineMapper->m_clip_rect.height() > QT_RASTER_COORD_LIMIT)
492         d->outlineMapper->m_clip_rect.setHeight(QT_RASTER_COORD_LIMIT);
493
494     d->rasterizer->setClipRect(d->deviceRect);
495
496     s->penData.init(d->rasterBuffer.data(), this);
497     s->penData.setup(s->pen.brush(), s->intOpacity, s->composition_mode);
498     s->stroker = &d->basicStroker;
499     d->basicStroker.setClipRect(d->deviceRect);
500
501     s->brushData.init(d->rasterBuffer.data(), this);
502     s->brushData.setup(s->brush, s->intOpacity, s->composition_mode);
503
504     d->rasterBuffer->compositionMode = QPainter::CompositionMode_SourceOver;
505
506     setDirty(DirtyBrushOrigin);
507
508 #ifdef QT_DEBUG_DRAW
509     qDebug() << "QRasterPaintEngine::begin(" << (void *) device
510              << ") devType:" << device->devType()
511              << "devRect:" << d->deviceRect;
512     if (d->baseClip) {
513         dumpClip(d->rasterBuffer->width(), d->rasterBuffer->height(), &*d->baseClip);
514     }
515 #endif
516
517     if (d->mono_surface)
518         d->glyphCacheType = QFontEngineGlyphCache::Raster_Mono;
519 #if defined(Q_OS_WIN)
520     else if (clearTypeFontsEnabled())
521 #else
522     else if (false)
523 #endif
524     {
525         QImage::Format format = static_cast<QImage *>(d->device)->format();
526         if (format == QImage::Format_ARGB32_Premultiplied || format == QImage::Format_RGB32)
527             d->glyphCacheType = QFontEngineGlyphCache::Raster_RGBMask;
528         else
529             d->glyphCacheType = QFontEngineGlyphCache::Raster_A8;
530     } else
531         d->glyphCacheType = QFontEngineGlyphCache::Raster_A8;
532
533     setActive(true);
534     return true;
535 }
536
537 /*!
538     \reimp
539 */
540 bool QRasterPaintEngine::end()
541 {
542 #ifdef QT_DEBUG_DRAW
543     Q_D(QRasterPaintEngine);
544     qDebug() << "QRasterPaintEngine::end devRect:" << d->deviceRect;
545     if (d->baseClip) {
546         dumpClip(d->rasterBuffer->width(), d->rasterBuffer->height(), &*d->baseClip);
547     }
548 #endif
549
550     return true;
551 }
552
553 /*!
554     \internal
555 */
556 void QRasterPaintEngine::releaseBuffer()
557 {
558     Q_D(QRasterPaintEngine);
559     d->rasterBuffer.reset(new QRasterBuffer);
560 }
561
562 /*!
563     \internal
564 */
565 QSize QRasterPaintEngine::size() const
566 {
567     Q_D(const QRasterPaintEngine);
568     return QSize(d->rasterBuffer->width(), d->rasterBuffer->height());
569 }
570
571 /*!
572     \internal
573 */
574 #ifndef QT_NO_DEBUG
575 void QRasterPaintEngine::saveBuffer(const QString &s) const
576 {
577     Q_D(const QRasterPaintEngine);
578     d->rasterBuffer->bufferImage().save(s, "PNG");
579 }
580 #endif
581
582 /*!
583     \internal
584 */
585 void QRasterPaintEngine::updateMatrix(const QTransform &matrix)
586 {
587     QRasterPaintEngineState *s = state();
588     // FALCON: get rid of this line, see drawImage call below.
589     s->matrix = matrix;
590     QTransform::TransformationType txop = s->matrix.type();
591
592     switch (txop) {
593
594     case QTransform::TxNone:
595         s->flags.int_xform = true;
596         break;
597
598     case QTransform::TxTranslate:
599         s->flags.int_xform = qreal(int(s->matrix.dx())) == s->matrix.dx()
600                             && qreal(int(s->matrix.dy())) == s->matrix.dy();
601         break;
602
603     case QTransform::TxScale:
604         s->flags.int_xform = qreal(int(s->matrix.dx())) == s->matrix.dx()
605                             && qreal(int(s->matrix.dy())) == s->matrix.dy()
606                             && qreal(int(s->matrix.m11())) == s->matrix.m11()
607                             && qreal(int(s->matrix.m22())) == s->matrix.m22();
608         break;
609
610     default: // shear / perspective...
611         s->flags.int_xform = false;
612         break;
613     }
614
615     s->flags.tx_noshear = qt_scaleForTransform(s->matrix, &s->txscale);
616
617     ensureOutlineMapper();
618 }
619
620
621
622 QRasterPaintEngineState::~QRasterPaintEngineState()
623 {
624     if (flags.has_clip_ownership)
625         delete clip;
626 }
627
628
629 QRasterPaintEngineState::QRasterPaintEngineState()
630 {
631     stroker = 0;
632
633     fillFlags = 0;
634     strokeFlags = 0;
635     pixmapFlags = 0;
636
637     intOpacity = 256;
638
639     txscale = 1.;
640
641     flags.fast_pen = true;
642     flags.antialiased = false;
643     flags.bilinear = false;
644     flags.fast_text = true;
645     flags.int_xform = true;
646     flags.tx_noshear = true;
647     flags.fast_images = true;
648
649     clip = 0;
650     flags.has_clip_ownership = false;
651
652     dirty = 0;
653 }
654
655 QRasterPaintEngineState::QRasterPaintEngineState(QRasterPaintEngineState &s)
656     : QPainterState(s)
657     , lastPen(s.lastPen)
658     , penData(s.penData)
659     , stroker(s.stroker)
660     , strokeFlags(s.strokeFlags)
661     , lastBrush(s.lastBrush)
662     , brushData(s.brushData)
663     , fillFlags(s.fillFlags)
664     , pixmapFlags(s.pixmapFlags)
665     , intOpacity(s.intOpacity)
666     , txscale(s.txscale)
667     , clip(s.clip)
668     , dirty(s.dirty)
669     , flag_bits(s.flag_bits)
670 {
671     brushData.tempImage = 0;
672     penData.tempImage = 0;
673     flags.has_clip_ownership = false;
674 }
675
676 /*!
677     \internal
678 */
679 QPainterState *QRasterPaintEngine::createState(QPainterState *orig) const
680 {
681     QRasterPaintEngineState *s;
682     if (!orig)
683         s = new QRasterPaintEngineState();
684     else
685         s = new QRasterPaintEngineState(*static_cast<QRasterPaintEngineState *>(orig));
686
687     return s;
688 }
689
690 /*!
691     \internal
692 */
693 void QRasterPaintEngine::setState(QPainterState *s)
694 {
695     Q_D(QRasterPaintEngine);
696     QPaintEngineEx::setState(s);
697     d->rasterBuffer->compositionMode = s->composition_mode;
698 }
699
700 /*!
701     \fn QRasterPaintEngineState *QRasterPaintEngine::state()
702     \internal
703 */
704
705 /*!
706     \fn const QRasterPaintEngineState *QRasterPaintEngine::state() const
707     \internal
708 */
709
710 /*!
711     \internal
712 */
713 void QRasterPaintEngine::penChanged()
714 {
715 #ifdef QT_DEBUG_DRAW
716     qDebug() << "QRasterPaintEngine::penChanged():" << state()->pen;
717 #endif
718     QRasterPaintEngineState *s = state();
719     s->strokeFlags |= DirtyPen;
720     s->dirty |= DirtyPen;
721 }
722
723 /*!
724     \internal
725 */
726 void QRasterPaintEngine::updatePen(const QPen &pen)
727 {
728     Q_D(QRasterPaintEngine);
729     QRasterPaintEngineState *s = state();
730 #ifdef QT_DEBUG_DRAW
731     qDebug() << "QRasterPaintEngine::updatePen():" << s->pen;
732 #endif
733
734     Qt::PenStyle pen_style = qpen_style(pen);
735
736     s->lastPen = pen;
737     s->strokeFlags = 0;
738
739     s->penData.clip = d->clip();
740     s->penData.setup(pen_style == Qt::NoPen ? QBrush() : pen.brush(), s->intOpacity, s->composition_mode);
741
742     if (s->strokeFlags & QRasterPaintEngine::DirtyTransform
743         || pen.brush().transform().type() >= QTransform::TxNone) {
744         d->updateMatrixData(&s->penData, pen.brush(), s->matrix);
745     }
746
747     // Slightly ugly handling of an uncommon case... We need to change
748     // the pen because it is reused in draw_midpoint to decide dashed
749     // or non-dashed.
750     if (pen_style == Qt::CustomDashLine && pen.dashPattern().size() == 0) {
751         pen_style = Qt::SolidLine;
752         s->lastPen.setStyle(Qt::SolidLine);
753     }
754
755     d->basicStroker.setJoinStyle(qpen_joinStyle(pen));
756     d->basicStroker.setCapStyle(qpen_capStyle(pen));
757     d->basicStroker.setMiterLimit(pen.miterLimit());
758
759     qreal penWidth = qpen_widthf(pen);
760     if (penWidth == 0)
761         d->basicStroker.setStrokeWidth(1);
762     else
763         d->basicStroker.setStrokeWidth(penWidth);
764
765     if(pen_style == Qt::SolidLine) {
766         s->stroker = &d->basicStroker;
767     } else if (pen_style != Qt::NoPen) {
768         if (!d->dashStroker)
769             d->dashStroker.reset(new QDashStroker(&d->basicStroker));
770         if (pen.isCosmetic()) {
771             d->dashStroker->setClipRect(d->deviceRect);
772         } else {
773             // ### I've seen this inverted devrect multiple places now...
774             QRectF clipRect = s->matrix.inverted().mapRect(QRectF(d->deviceRect));
775             d->dashStroker->setClipRect(clipRect);
776         }
777         d->dashStroker->setDashPattern(pen.dashPattern());
778         d->dashStroker->setDashOffset(pen.dashOffset());
779         s->stroker = d->dashStroker.data();
780     } else {
781         s->stroker = 0;
782     }
783
784     ensureRasterState(); // needed because of tx_noshear...
785     s->flags.fast_pen = pen_style > Qt::NoPen
786             && s->penData.blend
787             && ((pen.isCosmetic() && penWidth <= 1)
788                 || (!pen.isCosmetic() && s->flags.tx_noshear && penWidth * s->txscale <= 1));
789
790     s->flags.non_complex_pen = qpen_capStyle(s->lastPen) <= Qt::SquareCap && s->flags.tx_noshear;
791
792     s->strokeFlags = 0;
793 }
794
795
796
797 /*!
798     \internal
799 */
800 void QRasterPaintEngine::brushOriginChanged()
801 {
802     QRasterPaintEngineState *s = state();
803 #ifdef QT_DEBUG_DRAW
804     qDebug() << "QRasterPaintEngine::brushOriginChanged()" << s->brushOrigin;
805 #endif
806
807     s->fillFlags |= DirtyBrushOrigin;
808 }
809
810
811 /*!
812     \internal
813 */
814 void QRasterPaintEngine::brushChanged()
815 {
816     QRasterPaintEngineState *s = state();
817 #ifdef QT_DEBUG_DRAW
818     qDebug() << "QRasterPaintEngine::brushChanged():" << s->brush;
819 #endif
820     s->fillFlags |= DirtyBrush;
821 }
822
823
824
825
826 /*!
827     \internal
828 */
829 void QRasterPaintEngine::updateBrush(const QBrush &brush)
830 {
831 #ifdef QT_DEBUG_DRAW
832     qDebug() << "QRasterPaintEngine::updateBrush()" << brush;
833 #endif
834     Q_D(QRasterPaintEngine);
835     QRasterPaintEngineState *s = state();
836     // must set clip prior to setup, as setup uses it...
837     s->brushData.clip = d->clip();
838     s->brushData.setup(brush, s->intOpacity, s->composition_mode);
839     if (s->fillFlags & DirtyTransform
840         || brush.transform().type() >= QTransform::TxNone)
841         d_func()->updateMatrixData(&s->brushData, brush, d->brushMatrix());
842     s->lastBrush = brush;
843     s->fillFlags = 0;
844 }
845
846 void QRasterPaintEngine::updateOutlineMapper()
847 {
848     Q_D(QRasterPaintEngine);
849     d->outlineMapper->setMatrix(state()->matrix);
850 }
851
852 void QRasterPaintEngine::updateRasterState()
853 {
854     QRasterPaintEngineState *s = state();
855
856     if (s->dirty & DirtyTransform)
857         updateMatrix(s->matrix);
858
859     if (s->dirty & (DirtyPen|DirtyCompositionMode|DirtyOpacity)) {
860         const QPainter::CompositionMode mode = s->composition_mode;
861         s->flags.fast_text = (s->penData.type == QSpanData::Solid)
862                        && s->intOpacity == 256
863                        && (mode == QPainter::CompositionMode_Source
864                            || (mode == QPainter::CompositionMode_SourceOver
865                                && qAlpha(s->penData.solid.color) == 255));
866     }
867
868     s->dirty = 0;
869 }
870
871
872 /*!
873     \internal
874 */
875 void QRasterPaintEngine::opacityChanged()
876 {
877     QRasterPaintEngineState *s = state();
878
879 #ifdef QT_DEBUG_DRAW
880     qDebug() << "QRasterPaintEngine::opacityChanged()" << s->opacity;
881 #endif
882
883     s->fillFlags |= DirtyOpacity;
884     s->strokeFlags |= DirtyOpacity;
885     s->pixmapFlags |= DirtyOpacity;
886     s->dirty |= DirtyOpacity;
887     s->intOpacity = (int) (s->opacity * 256);
888 }
889
890 /*!
891     \internal
892 */
893 void QRasterPaintEngine::compositionModeChanged()
894 {
895     Q_D(QRasterPaintEngine);
896     QRasterPaintEngineState *s = state();
897
898 #ifdef QT_DEBUG_DRAW
899     qDebug() << "QRasterPaintEngine::compositionModeChanged()" << s->composition_mode;
900 #endif
901
902     s->fillFlags |= DirtyCompositionMode;
903     s->dirty |= DirtyCompositionMode;
904
905     s->strokeFlags |= DirtyCompositionMode;
906     d->rasterBuffer->compositionMode = s->composition_mode;
907
908     d->recalculateFastImages();
909 }
910
911 /*!
912     \internal
913 */
914 void QRasterPaintEngine::renderHintsChanged()
915 {
916     QRasterPaintEngineState *s = state();
917
918 #ifdef QT_DEBUG_DRAW
919     qDebug() << "QRasterPaintEngine::renderHintsChanged()" << hex << s->renderHints;
920 #endif
921
922     bool was_aa = s->flags.antialiased;
923     bool was_bilinear = s->flags.bilinear;
924
925     s->flags.antialiased = bool(s->renderHints & QPainter::Antialiasing);
926     s->flags.bilinear = bool(s->renderHints & QPainter::SmoothPixmapTransform);
927
928     if (was_aa != s->flags.antialiased)
929         s->strokeFlags |= DirtyHints;
930
931     if (was_bilinear != s->flags.bilinear) {
932         s->strokeFlags |= DirtyPen;
933         s->fillFlags |= DirtyBrush;
934     }
935
936     Q_D(QRasterPaintEngine);
937     d->recalculateFastImages();
938 }
939
940 /*!
941     \internal
942 */
943 void QRasterPaintEngine::transformChanged()
944 {
945     QRasterPaintEngineState *s = state();
946
947 #ifdef QT_DEBUG_DRAW
948     qDebug() << "QRasterPaintEngine::transformChanged()" << s->matrix;
949 #endif
950
951     s->fillFlags |= DirtyTransform;
952     s->strokeFlags |= DirtyTransform;
953
954     s->dirty |= DirtyTransform;
955
956     Q_D(QRasterPaintEngine);
957     d->recalculateFastImages();
958 }
959
960 /*!
961     \internal
962 */
963 void QRasterPaintEngine::clipEnabledChanged()
964 {
965     QRasterPaintEngineState *s = state();
966
967 #ifdef QT_DEBUG_DRAW
968     qDebug() << "QRasterPaintEngine::clipEnabledChanged()" << s->clipEnabled;
969 #endif
970
971     if (s->clip) {
972         s->clip->enabled = s->clipEnabled;
973         s->fillFlags |= DirtyClipEnabled;
974         s->strokeFlags |= DirtyClipEnabled;
975         s->pixmapFlags |= DirtyClipEnabled;
976     }
977 }
978
979 void QRasterPaintEnginePrivate::drawImage(const QPointF &pt,
980                                           const QImage &img,
981                                           SrcOverBlendFunc func,
982                                           const QRect &clip,
983                                           int alpha,
984                                           const QRect &sr)
985 {
986     if (alpha == 0 || !clip.isValid())
987         return;
988
989     Q_ASSERT(img.depth() >= 8);
990
991     int srcBPL = img.bytesPerLine();
992     const uchar *srcBits = img.bits();
993     int srcSize = img.depth() >> 3; // This is the part that is incompatible with lower than 8-bit..
994     int iw = img.width();
995     int ih = img.height();
996
997     if (!sr.isEmpty()) {
998         iw = sr.width();
999         ih = sr.height();
1000         // Adjust the image according to the source offset...
1001         srcBits += ((sr.y() * srcBPL) + sr.x() * srcSize);
1002     }
1003
1004     // adapt the x parameters
1005     int x = qRound(pt.x());
1006     int cx1 = clip.x();
1007     int cx2 = clip.x() + clip.width();
1008     if (x < cx1) {
1009         int d = cx1 - x;
1010         srcBits += srcSize * d;
1011         iw -= d;
1012         x = cx1;
1013     }
1014     if (x + iw > cx2) {
1015         int d = x + iw - cx2;
1016         iw -= d;
1017     }
1018     if (iw <= 0)
1019         return;
1020
1021     // adapt the y paremeters...
1022     int cy1 = clip.y();
1023     int cy2 = clip.y() + clip.height();
1024     int y = qRound(pt.y());
1025     if (y < cy1) {
1026         int d = cy1 - y;
1027         srcBits += srcBPL * d;
1028         ih -= d;
1029         y = cy1;
1030     }
1031     if (y + ih > cy2) {
1032         int d = y + ih - cy2;
1033         ih -= d;
1034     }
1035     if (ih <= 0)
1036         return;
1037
1038     // call the blend function...
1039     int dstSize = rasterBuffer->bytesPerPixel();
1040     int dstBPL = rasterBuffer->bytesPerLine();
1041     func(rasterBuffer->buffer() + x * dstSize + y * dstBPL, dstBPL,
1042          srcBits, srcBPL,
1043          iw, ih,
1044          alpha);
1045 }
1046
1047
1048 void QRasterPaintEnginePrivate::systemStateChanged()
1049 {
1050     QRect clipRect(0, 0,
1051             qMin(QT_RASTER_COORD_LIMIT, device->width()),
1052             qMin(QT_RASTER_COORD_LIMIT, device->height()));
1053
1054     if (!systemClip.isEmpty()) {
1055         QRegion clippedDeviceRgn = systemClip & clipRect;
1056         deviceRect = clippedDeviceRgn.boundingRect();
1057         baseClip->setClipRegion(clippedDeviceRgn);
1058     } else {
1059         deviceRect = clipRect;
1060         baseClip->setClipRect(deviceRect);
1061     }
1062 #ifdef QT_DEBUG_DRAW
1063     qDebug() << "systemStateChanged" << this << "deviceRect" << deviceRect << clipRect << systemClip;
1064 #endif
1065
1066     exDeviceRect = deviceRect;
1067
1068     Q_Q(QRasterPaintEngine);
1069     q->state()->strokeFlags |= QPaintEngine::DirtyClipRegion;
1070     q->state()->fillFlags |= QPaintEngine::DirtyClipRegion;
1071     q->state()->pixmapFlags |= QPaintEngine::DirtyClipRegion;
1072 }
1073
1074 void QRasterPaintEnginePrivate::updateMatrixData(QSpanData *spanData, const QBrush &b, const QTransform &m)
1075 {
1076     if (b.d->style == Qt::NoBrush || b.d->style == Qt::SolidPattern)
1077         return;
1078
1079     Q_Q(QRasterPaintEngine);
1080     bool bilinear = q->state()->flags.bilinear;
1081
1082     if (b.d->transform.type() > QTransform::TxNone) { // FALCON: optimize
1083         spanData->setupMatrix(b.transform() * m, bilinear);
1084     } else {
1085         if (m.type() <= QTransform::TxTranslate) {
1086             // specialize setupMatrix for translation matrices
1087             // to avoid needless matrix inversion
1088             spanData->m11 = 1;
1089             spanData->m12 = 0;
1090             spanData->m13 = 0;
1091             spanData->m21 = 0;
1092             spanData->m22 = 1;
1093             spanData->m23 = 0;
1094             spanData->m33 = 1;
1095             spanData->dx = -m.dx();
1096             spanData->dy = -m.dy();
1097             spanData->txop = m.type();
1098             spanData->bilinear = bilinear;
1099             spanData->fast_matrix = qAbs(m.dx()) < 1e4 && qAbs(m.dy()) < 1e4;
1100             spanData->adjustSpanMethods();
1101         } else {
1102             spanData->setupMatrix(m, bilinear);
1103         }
1104     }
1105 }
1106
1107 // #define QT_CLIPPING_RATIOS
1108
1109 #ifdef QT_CLIPPING_RATIOS
1110 int rectClips;
1111 int regionClips;
1112 int totalClips;
1113
1114 static void checkClipRatios(QRasterPaintEnginePrivate *d)
1115 {
1116     if (d->clip()->hasRectClip)
1117         rectClips++;
1118     if (d->clip()->hasRegionClip)
1119         regionClips++;
1120     totalClips++;
1121
1122     if ((totalClips % 5000) == 0) {
1123         printf("Clipping ratio: rectangular=%f%%, region=%f%%, complex=%f%%\n",
1124                rectClips * 100.0 / (qreal) totalClips,
1125                regionClips * 100.0 / (qreal) totalClips,
1126                (totalClips - rectClips - regionClips) * 100.0 / (qreal) totalClips);
1127         totalClips = 0;
1128         rectClips = 0;
1129         regionClips = 0;
1130     }
1131
1132 }
1133 #endif
1134
1135 static void qrasterpaintengine_state_setNoClip(QRasterPaintEngineState *s)
1136 {
1137     if (s->flags.has_clip_ownership)
1138         delete s->clip;
1139     s->clip = 0;
1140     s->flags.has_clip_ownership = false;
1141 }
1142
1143 static void qrasterpaintengine_dirty_clip(QRasterPaintEnginePrivate *d, QRasterPaintEngineState *s)
1144 {
1145     s->fillFlags |= QPaintEngine::DirtyClipPath;
1146     s->strokeFlags |= QPaintEngine::DirtyClipPath;
1147     s->pixmapFlags |= QPaintEngine::DirtyClipPath;
1148
1149     d->solid_color_filler.clip = d->clip();
1150     d->solid_color_filler.adjustSpanMethods();
1151
1152 #ifdef QT_DEBUG_DRAW
1153     dumpClip(d->rasterBuffer->width(), d->rasterBuffer->height(), &*d->clip());
1154 #endif
1155
1156 }
1157
1158
1159 /*!
1160     \internal
1161 */
1162 void QRasterPaintEngine::clip(const QVectorPath &path, Qt::ClipOperation op)
1163 {
1164 #ifdef QT_DEBUG_DRAW
1165     qDebug() << "QRasterPaintEngine::clip(): " << path << op;
1166
1167     if (path.elements()) {
1168         for (int i=0; i<path.elementCount(); ++i) {
1169             qDebug() << " - " << path.elements()[i]
1170                      << '(' << path.points()[i*2] << ", " << path.points()[i*2+1] << ')';
1171         }
1172     } else {
1173         for (int i=0; i<path.elementCount(); ++i) {
1174             qDebug() << " ---- "
1175                      << '(' << path.points()[i*2] << ", " << path.points()[i*2+1] << ')';
1176         }
1177     }
1178 #endif
1179
1180     Q_D(QRasterPaintEngine);
1181     QRasterPaintEngineState *s = state();
1182
1183     const qreal *points = path.points();
1184     const QPainterPath::ElementType *types = path.elements();
1185
1186     // There are some cases that are not supported by clip(QRect)
1187     if (op != Qt::IntersectClip || !s->clip || s->clip->hasRectClip || s->clip->hasRegionClip) {
1188         if (s->matrix.type() <= QTransform::TxScale
1189             && ((path.shape() == QVectorPath::RectangleHint)
1190                 || (isRect(points, path.elementCount())
1191                     && (!types || (types[0] == QPainterPath::MoveToElement
1192                                    && types[1] == QPainterPath::LineToElement
1193                                    && types[2] == QPainterPath::LineToElement
1194                                    && types[3] == QPainterPath::LineToElement))))) {
1195 #ifdef QT_DEBUG_DRAW
1196             qDebug() << " --- optimizing vector clip to rect clip...";
1197 #endif
1198
1199             QRectF r(points[0], points[1], points[4]-points[0], points[5]-points[1]);
1200             if (setClipRectInDeviceCoords(s->matrix.mapRect(r).toRect(), op))
1201                 return;
1202         }
1203     }
1204
1205     if (op == Qt::NoClip) {
1206         qrasterpaintengine_state_setNoClip(s);
1207
1208     } else {
1209         QClipData *base = d->baseClip.data();
1210
1211         // Intersect with current clip when available...
1212         if (op == Qt::IntersectClip && s->clip)
1213             base = s->clip;
1214
1215         // We always intersect, except when there is nothing to
1216         // intersect with, in which case we simplify the operation to
1217         // a replace...
1218         Qt::ClipOperation isectOp = Qt::IntersectClip;
1219         if (base == 0)
1220             isectOp = Qt::ReplaceClip;
1221
1222         QClipData *newClip = new QClipData(d->rasterBuffer->height());
1223         newClip->initialize();
1224         ClipData clipData = { base, newClip, isectOp };
1225         ensureOutlineMapper();
1226         d->rasterize(d->outlineMapper->convertPath(path), qt_span_clip, &clipData, 0);
1227
1228         newClip->fixup();
1229
1230         if (s->flags.has_clip_ownership)
1231             delete s->clip;
1232
1233         s->clip = newClip;
1234         s->flags.has_clip_ownership = true;
1235     }
1236     qrasterpaintengine_dirty_clip(d, s);
1237 }
1238
1239
1240
1241 /*!
1242     \internal
1243 */
1244 void QRasterPaintEngine::clip(const QRect &rect, Qt::ClipOperation op)
1245 {
1246 #ifdef QT_DEBUG_DRAW
1247     qDebug() << "QRasterPaintEngine::clip(): " << rect << op;
1248 #endif
1249
1250     QRasterPaintEngineState *s = state();
1251
1252     if (op == Qt::NoClip) {
1253         qrasterpaintengine_state_setNoClip(s);
1254
1255     } else if (s->matrix.type() > QTransform::TxScale) {
1256         QPaintEngineEx::clip(rect, op);
1257         return;
1258
1259     } else if (!setClipRectInDeviceCoords(s->matrix.mapRect(rect), op)) {
1260         QPaintEngineEx::clip(rect, op);
1261         return;
1262     }
1263 }
1264
1265
1266 bool QRasterPaintEngine::setClipRectInDeviceCoords(const QRect &r, Qt::ClipOperation op)
1267 {
1268     Q_D(QRasterPaintEngine);
1269     QRect clipRect = r & d->deviceRect;
1270     QRasterPaintEngineState *s = state();
1271
1272     if (op == Qt::ReplaceClip || s->clip == 0) {
1273
1274         // No current clip, hence we intersect with sysclip and be
1275         // done with it...
1276         QRegion clipRegion = systemClip();
1277         QClipData *clip = new QClipData(d->rasterBuffer->height());
1278
1279         if (clipRegion.isEmpty())
1280             clip->setClipRect(clipRect);
1281         else
1282             clip->setClipRegion(clipRegion & clipRect);
1283
1284         if (s->flags.has_clip_ownership)
1285             delete s->clip;
1286
1287         s->clip = clip;
1288         s->clip->enabled = true;
1289         s->flags.has_clip_ownership = true;
1290
1291     } else if (op == Qt::IntersectClip){ // intersect clip with current clip
1292         QClipData *base = s->clip;
1293
1294         Q_ASSERT(base);
1295         if (base->hasRectClip || base->hasRegionClip) {
1296             if (!s->flags.has_clip_ownership) {
1297                 s->clip = new QClipData(d->rasterBuffer->height());
1298                 s->flags.has_clip_ownership = true;
1299             }
1300             if (base->hasRectClip)
1301                 s->clip->setClipRect(base->clipRect & clipRect);
1302             else
1303                 s->clip->setClipRegion(base->clipRegion & clipRect);
1304             s->clip->enabled = true;
1305         } else {
1306             return false;
1307         }
1308     } else {
1309         return false;
1310     }
1311
1312     qrasterpaintengine_dirty_clip(d, s);
1313     return true;
1314 }
1315
1316
1317 /*!
1318     \internal
1319 */
1320 void QRasterPaintEngine::clip(const QRegion &region, Qt::ClipOperation op)
1321 {
1322 #ifdef QT_DEBUG_DRAW
1323     qDebug() << "QRasterPaintEngine::clip(): " << region << op;
1324 #endif
1325
1326     Q_D(QRasterPaintEngine);
1327
1328     if (region.rectCount() == 1) {
1329         clip(region.boundingRect(), op);
1330         return;
1331     }
1332
1333     QRasterPaintEngineState *s = state();
1334     const QClipData *clip = d->clip();
1335     const QClipData *baseClip = d->baseClip.data();
1336
1337     if (op == Qt::NoClip) {
1338         qrasterpaintengine_state_setNoClip(s);
1339     } else if (s->matrix.type() > QTransform::TxScale
1340                || (op == Qt::IntersectClip && !clip->hasRectClip && !clip->hasRegionClip)
1341                || (op == Qt::ReplaceClip && !baseClip->hasRectClip && !baseClip->hasRegionClip)) {
1342         QPaintEngineEx::clip(region, op);
1343     } else {
1344         const QClipData *curClip;
1345         QClipData *newClip;
1346
1347         if (op == Qt::IntersectClip)
1348             curClip = clip;
1349         else
1350             curClip = baseClip;
1351
1352         if (s->flags.has_clip_ownership) {
1353             newClip = s->clip;
1354             Q_ASSERT(newClip);
1355         } else {
1356             newClip = new QClipData(d->rasterBuffer->height());
1357             s->clip = newClip;
1358             s->flags.has_clip_ownership = true;
1359         }
1360
1361         QRegion r = s->matrix.map(region);
1362         if (curClip->hasRectClip)
1363             newClip->setClipRegion(r & curClip->clipRect);
1364         else if (curClip->hasRegionClip)
1365             newClip->setClipRegion(r & curClip->clipRegion);
1366
1367         qrasterpaintengine_dirty_clip(d, s);
1368     }
1369 }
1370
1371 /*!
1372     \internal
1373 */
1374 void QRasterPaintEngine::fillPath(const QPainterPath &path, QSpanData *fillData)
1375 {
1376 #ifdef QT_DEBUG_DRAW
1377     qDebug() << " --- fillPath, bounds=" << path.boundingRect();
1378 #endif
1379
1380     if (!fillData->blend)
1381         return;
1382
1383     Q_D(QRasterPaintEngine);
1384
1385     const QRectF controlPointRect = path.controlPointRect();
1386
1387     QRasterPaintEngineState *s = state();
1388     const QRect deviceRect = s->matrix.mapRect(controlPointRect).toRect();
1389     ProcessSpans blend = d->getBrushFunc(deviceRect, fillData);
1390     const bool do_clip = (deviceRect.left() < -QT_RASTER_COORD_LIMIT
1391                           || deviceRect.right() > QT_RASTER_COORD_LIMIT
1392                           || deviceRect.top() < -QT_RASTER_COORD_LIMIT
1393                           || deviceRect.bottom() > QT_RASTER_COORD_LIMIT);
1394
1395     if (!s->flags.antialiased && !do_clip) {
1396         d->initializeRasterizer(fillData);
1397         d->rasterizer->rasterize(path * s->matrix, path.fillRule());
1398         return;
1399     }
1400
1401     ensureOutlineMapper();
1402     d->rasterize(d->outlineMapper->convertPath(path), blend, fillData, d->rasterBuffer.data());
1403 }
1404
1405 static void fillRect_normalized(const QRect &r, QSpanData *data,
1406                                 QRasterPaintEnginePrivate *pe)
1407 {
1408     int x1, x2, y1, y2;
1409
1410     bool rectClipped = true;
1411
1412     if (data->clip) {
1413         x1 = qMax(r.x(), data->clip->xmin);
1414         x2 = qMin(r.x() + r.width(), data->clip->xmax);
1415         y1 = qMax(r.y(), data->clip->ymin);
1416         y2 = qMin(r.y() + r.height(), data->clip->ymax);
1417         rectClipped = data->clip->hasRectClip;
1418
1419     } else if (pe) {
1420         x1 = qMax(r.x(), pe->deviceRect.x());
1421         x2 = qMin(r.x() + r.width(), pe->deviceRect.x() + pe->deviceRect.width());
1422         y1 = qMax(r.y(), pe->deviceRect.y());
1423         y2 = qMin(r.y() + r.height(), pe->deviceRect.y() + pe->deviceRect.height());
1424     } else {
1425         x1 = qMax(r.x(), 0);
1426         x2 = qMin(r.x() + r.width(), data->rasterBuffer->width());
1427         y1 = qMax(r.y(), 0);
1428         y2 = qMin(r.y() + r.height(), data->rasterBuffer->height());
1429     }
1430
1431     if (x2 <= x1 || y2 <= y1)
1432         return;
1433
1434     const int width = x2 - x1;
1435     const int height = y2 - y1;
1436
1437     bool isUnclipped = rectClipped
1438                        || (pe && pe->isUnclipped_normalized(QRect(x1, y1, width, height)));
1439
1440     if (pe && isUnclipped) {
1441         const QPainter::CompositionMode mode = pe->rasterBuffer->compositionMode;
1442
1443         if (data->fillRect && (mode == QPainter::CompositionMode_Source
1444                                || (mode == QPainter::CompositionMode_SourceOver
1445                                    && qAlpha(data->solid.color) == 255)))
1446         {
1447             data->fillRect(data->rasterBuffer, x1, y1, width, height,
1448                            data->solid.color);
1449             return;
1450         }
1451     }
1452
1453     ProcessSpans blend = isUnclipped ? data->unclipped_blend : data->blend;
1454
1455     const int nspans = 256;
1456     QT_FT_Span spans[nspans];
1457
1458     Q_ASSERT(data->blend);
1459     int y = y1;
1460     while (y < y2) {
1461         int n = qMin(nspans, y2 - y);
1462         int i = 0;
1463         while (i < n) {
1464             spans[i].x = x1;
1465             spans[i].len = width;
1466             spans[i].y = y + i;
1467             spans[i].coverage = 255;
1468             ++i;
1469         }
1470
1471         blend(n, spans, data);
1472         y += n;
1473     }
1474 }
1475
1476 /*!
1477     \reimp
1478 */
1479 void QRasterPaintEngine::drawRects(const QRect *rects, int rectCount)
1480 {
1481 #ifdef QT_DEBUG_DRAW
1482     qDebug(" - QRasterPaintEngine::drawRect(), rectCount=%d", rectCount);
1483 #endif
1484     Q_D(QRasterPaintEngine);
1485     ensureRasterState();
1486     QRasterPaintEngineState *s = state();
1487
1488     // Fill
1489     ensureBrush();
1490     if (s->brushData.blend) {
1491         if (!s->flags.antialiased && s->matrix.type() <= QTransform::TxTranslate) {
1492             const QRect *r = rects;
1493             const QRect *lastRect = rects + rectCount;
1494
1495             int offset_x = int(s->matrix.dx());
1496             int offset_y = int(s->matrix.dy());
1497             while (r < lastRect) {
1498                 QRect rect = r->normalized();
1499                 QRect rr = rect.translated(offset_x, offset_y);
1500                 fillRect_normalized(rr, &s->brushData, d);
1501                 ++r;
1502             }
1503         } else {
1504             QRectVectorPath path;
1505             for (int i=0; i<rectCount; ++i) {
1506                 path.set(rects[i]);
1507                 fill(path, s->brush);
1508             }
1509         }
1510     }
1511
1512     ensurePen();
1513     if (s->penData.blend) {
1514         QRectVectorPath path;
1515         if (s->flags.fast_pen) {
1516             QCosmeticStroker stroker(s, d->deviceRect);
1517             for (int i = 0; i < rectCount; ++i) {
1518                 path.set(rects[i]);
1519                 stroker.drawPath(path);
1520             }
1521         } else {
1522             for (int i = 0; i < rectCount; ++i) {
1523                 path.set(rects[i]);
1524                 stroke(path, s->pen);
1525             }
1526         }
1527     }
1528 }
1529
1530 /*!
1531     \reimp
1532 */
1533 void QRasterPaintEngine::drawRects(const QRectF *rects, int rectCount)
1534 {
1535 #ifdef QT_DEBUG_DRAW
1536     qDebug(" - QRasterPaintEngine::drawRect(QRectF*), rectCount=%d", rectCount);
1537 #endif
1538 #ifdef QT_FAST_SPANS
1539     Q_D(QRasterPaintEngine);
1540     ensureRasterState();
1541     QRasterPaintEngineState *s = state();
1542
1543
1544     if (s->flags.tx_noshear) {
1545         ensureBrush();
1546         if (s->brushData.blend) {
1547             d->initializeRasterizer(&s->brushData);
1548             for (int i = 0; i < rectCount; ++i) {
1549                 const QRectF &rect = rects[i].normalized();
1550                 if (rect.isEmpty())
1551                     continue;
1552                 const QPointF a = s->matrix.map((rect.topLeft() + rect.bottomLeft()) * 0.5f);
1553                 const QPointF b = s->matrix.map((rect.topRight() + rect.bottomRight()) * 0.5f);
1554                 d->rasterizer->rasterizeLine(a, b, rect.height() / rect.width());
1555             }
1556         }
1557
1558         ensurePen();
1559         if (s->penData.blend) {
1560             QRectVectorPath path;
1561             if (s->flags.fast_pen) {
1562                 QCosmeticStroker stroker(s, d->deviceRect);
1563                 for (int i = 0; i < rectCount; ++i) {
1564                     path.set(rects[i]);
1565                     stroker.drawPath(path);
1566                 }
1567             } else {
1568                 for (int i = 0; i < rectCount; ++i) {
1569                     path.set(rects[i]);
1570                     QPaintEngineEx::stroke(path, s->lastPen);
1571                 }
1572             }
1573         }
1574
1575         return;
1576     }
1577 #endif // QT_FAST_SPANS
1578     QPaintEngineEx::drawRects(rects, rectCount);
1579 }
1580
1581
1582 /*!
1583     \internal
1584 */
1585 void QRasterPaintEngine::stroke(const QVectorPath &path, const QPen &pen)
1586 {
1587     Q_D(QRasterPaintEngine);
1588     QRasterPaintEngineState *s = state();
1589
1590     ensurePen(pen);
1591     if (!s->penData.blend)
1592         return;
1593
1594     if (s->flags.fast_pen) {
1595         QCosmeticStroker stroker(s, d->deviceRect);
1596         stroker.drawPath(path);
1597     } else if (s->flags.non_complex_pen && path.shape() == QVectorPath::LinesHint) {
1598         qreal width = s->lastPen.isCosmetic()
1599                       ? (qpen_widthf(s->lastPen) == 0 ? 1 : qpen_widthf(s->lastPen))
1600                       : qpen_widthf(s->lastPen) * s->txscale;
1601         int dashIndex = 0;
1602         qreal dashOffset = s->lastPen.dashOffset();
1603         bool inDash = true;
1604         qreal patternLength = 0;
1605         const QVector<qreal> pattern = s->lastPen.dashPattern();
1606         for (int i = 0; i < pattern.size(); ++i)
1607             patternLength += pattern.at(i);
1608
1609         if (patternLength > 0) {
1610             int n = qFloor(dashOffset / patternLength);
1611             dashOffset -= n * patternLength;
1612             while (dashOffset >= pattern.at(dashIndex)) {
1613                 dashOffset -= pattern.at(dashIndex);
1614                 if (++dashIndex >= pattern.size())
1615                     dashIndex = 0;
1616                 inDash = !inDash;
1617             }
1618         }
1619
1620         Q_D(QRasterPaintEngine);
1621         d->initializeRasterizer(&s->penData);
1622         int lineCount = path.elementCount() / 2;
1623         const QLineF *lines = reinterpret_cast<const QLineF *>(path.points());
1624
1625         for (int i = 0; i < lineCount; ++i) {
1626             if (lines[i].p1() == lines[i].p2()) {
1627                 if (s->lastPen.capStyle() != Qt::FlatCap) {
1628                     QPointF p = lines[i].p1();
1629                     QLineF line = s->matrix.map(QLineF(QPointF(p.x() - width*0.5, p.y()),
1630                                                        QPointF(p.x() + width*0.5, p.y())));
1631                     d->rasterizer->rasterizeLine(line.p1(), line.p2(), 1);
1632                 }
1633                 continue;
1634             }
1635
1636             const QLineF line = s->matrix.map(lines[i]);
1637             if (qpen_style(s->lastPen) == Qt::SolidLine) {
1638                 d->rasterizer->rasterizeLine(line.p1(), line.p2(),
1639                                             width / line.length(),
1640                                             s->lastPen.capStyle() == Qt::SquareCap);
1641             } else {
1642                 d->rasterizeLine_dashed(line, width,
1643                                         &dashIndex, &dashOffset, &inDash);
1644             }
1645         }
1646     }
1647     else
1648         QPaintEngineEx::stroke(path, pen);
1649 }
1650
1651 static inline QRect toNormalizedFillRect(const QRectF &rect)
1652 {
1653     int x1 = qRound(rect.x() + aliasedCoordinateDelta);
1654     int y1 = qRound(rect.y() + aliasedCoordinateDelta);
1655     int x2 = qRound(rect.right() + aliasedCoordinateDelta);
1656     int y2 = qRound(rect.bottom() + aliasedCoordinateDelta);
1657
1658     if (x2 < x1)
1659         qSwap(x1, x2);
1660     if (y2 < y1)
1661         qSwap(y1, y2);
1662
1663     return QRect(x1, y1, x2 - x1, y2 - y1);
1664 }
1665
1666 /*!
1667     \internal
1668 */
1669 void QRasterPaintEngine::fill(const QVectorPath &path, const QBrush &brush)
1670 {
1671     if (path.isEmpty())
1672         return;
1673 #ifdef QT_DEBUG_DRAW
1674     QRectF rf = path.controlPointRect();
1675     qDebug() << "QRasterPaintEngine::fill(): "
1676              << "size=" << path.elementCount()
1677              << ", hints=" << hex << path.hints()
1678              << rf << brush;
1679 #endif
1680
1681     Q_D(QRasterPaintEngine);
1682     QRasterPaintEngineState *s = state();
1683
1684     ensureBrush(brush);
1685     if (!s->brushData.blend)
1686         return;
1687
1688     if (path.shape() == QVectorPath::RectangleHint) {
1689         if (!s->flags.antialiased && s->matrix.type() <= QTransform::TxScale) {
1690             const qreal *p = path.points();
1691             QPointF tl = QPointF(p[0], p[1]) * s->matrix;
1692             QPointF br = QPointF(p[4], p[5]) * s->matrix;
1693             fillRect_normalized(toNormalizedFillRect(QRectF(tl, br)), &s->brushData, d);
1694             return;
1695         }
1696         ensureRasterState();
1697         if (s->flags.tx_noshear) {
1698             d->initializeRasterizer(&s->brushData);
1699             // ### Is normalizing really necessary here?
1700             const qreal *p = path.points();
1701             QRectF r = QRectF(p[0], p[1], p[2] - p[0], p[7] - p[1]).normalized();
1702             if (!r.isEmpty()) {
1703                 const QPointF a = s->matrix.map((r.topLeft() + r.bottomLeft()) * 0.5f);
1704                 const QPointF b = s->matrix.map((r.topRight() + r.bottomRight()) * 0.5f);
1705                 d->rasterizer->rasterizeLine(a, b, r.height() / r.width());
1706             }
1707             return;
1708         }
1709     }
1710
1711     // ### Optimize for non transformed ellipses and rectangles...
1712     QRectF cpRect = path.controlPointRect();
1713     const QRect deviceRect = s->matrix.mapRect(cpRect).toRect();
1714     ProcessSpans blend = d->getBrushFunc(deviceRect, &s->brushData);
1715
1716         // ### Falcon
1717 //         const bool do_clip = (deviceRect.left() < -QT_RASTER_COORD_LIMIT
1718 //                               || deviceRect.right() > QT_RASTER_COORD_LIMIT
1719 //                               || deviceRect.top() < -QT_RASTER_COORD_LIMIT
1720 //                               || deviceRect.bottom() > QT_RASTER_COORD_LIMIT);
1721
1722         // ### Falonc: implement....
1723 //         if (!s->flags.antialiased && !do_clip) {
1724 //             d->initializeRasterizer(&s->brushData);
1725 //             d->rasterizer->rasterize(path * d->matrix, path.fillRule());
1726 //             return;
1727 //         }
1728
1729     ensureOutlineMapper();
1730     d->rasterize(d->outlineMapper->convertPath(path), blend, &s->brushData, d->rasterBuffer.data());
1731 }
1732
1733 void QRasterPaintEngine::fillRect(const QRectF &r, QSpanData *data)
1734 {
1735     Q_D(QRasterPaintEngine);
1736     QRasterPaintEngineState *s = state();
1737
1738     if (!s->flags.antialiased) {
1739         uint txop = s->matrix.type();
1740         if (txop == QTransform::TxNone) {
1741             fillRect_normalized(toNormalizedFillRect(r), data, d);
1742             return;
1743         } else if (txop == QTransform::TxTranslate) {
1744             const QRect rr = toNormalizedFillRect(r.translated(s->matrix.dx(), s->matrix.dy()));
1745             fillRect_normalized(rr, data, d);
1746             return;
1747         } else if (txop == QTransform::TxScale) {
1748             const QRect rr = toNormalizedFillRect(s->matrix.mapRect(r));
1749             fillRect_normalized(rr, data, d);
1750             return;
1751         }
1752     }
1753     ensureRasterState();
1754     if (s->flags.tx_noshear) {
1755         d->initializeRasterizer(data);
1756         QRectF nr = r.normalized();
1757         if (!nr.isEmpty()) {
1758             const QPointF a = s->matrix.map((nr.topLeft() + nr.bottomLeft()) * 0.5f);
1759             const QPointF b = s->matrix.map((nr.topRight() + nr.bottomRight()) * 0.5f);
1760             d->rasterizer->rasterizeLine(a, b, nr.height() / nr.width());
1761         }
1762         return;
1763     }
1764
1765     QPainterPath path;
1766     path.addRect(r);
1767     ensureOutlineMapper();
1768     fillPath(path, data);
1769 }
1770
1771 /*!
1772     \reimp
1773 */
1774 void QRasterPaintEngine::fillRect(const QRectF &r, const QBrush &brush)
1775 {
1776 #ifdef QT_DEBUG_DRAW
1777     qDebug() << "QRasterPaintEngine::fillRecct(): " << r << brush;
1778 #endif
1779     QRasterPaintEngineState *s = state();
1780
1781     ensureBrush(brush);
1782     if (!s->brushData.blend)
1783         return;
1784
1785     fillRect(r, &s->brushData);
1786 }
1787
1788 /*!
1789     \reimp
1790 */
1791 void QRasterPaintEngine::fillRect(const QRectF &r, const QColor &color)
1792 {
1793 #ifdef QT_DEBUG_DRAW
1794     qDebug() << "QRasterPaintEngine::fillRect(): " << r << color;
1795 #endif
1796     Q_D(QRasterPaintEngine);
1797     QRasterPaintEngineState *s = state();
1798
1799     d->solid_color_filler.solid.color = PREMUL(ARGB_COMBINE_ALPHA(color.rgba(), s->intOpacity));
1800     if ((d->solid_color_filler.solid.color & 0xff000000) == 0
1801         && s->composition_mode == QPainter::CompositionMode_SourceOver) {
1802         return;
1803     }
1804     d->solid_color_filler.clip = d->clip();
1805     d->solid_color_filler.adjustSpanMethods();
1806     fillRect(r, &d->solid_color_filler);
1807 }
1808
1809 static inline bool isAbove(const QPointF *a, const QPointF *b)
1810 {
1811     return a->y() < b->y();
1812 }
1813
1814 static bool splitPolygon(const QPointF *points, int pointCount, QVector<QPointF> *upper, QVector<QPointF> *lower)
1815 {
1816     Q_ASSERT(upper);
1817     Q_ASSERT(lower);
1818
1819     Q_ASSERT(pointCount >= 2);
1820
1821     QVector<const QPointF *> sorted;
1822     sorted.reserve(pointCount);
1823
1824     upper->reserve(pointCount * 3 / 4);
1825     lower->reserve(pointCount * 3 / 4);
1826
1827     for (int i = 0; i < pointCount; ++i)
1828         sorted << points + i;
1829
1830     qSort(sorted.begin(), sorted.end(), isAbove);
1831
1832     qreal splitY = sorted.at(sorted.size() / 2)->y();
1833
1834     const QPointF *end = points + pointCount;
1835     const QPointF *last = end - 1;
1836
1837     QVector<QPointF> *bin[2] = { upper, lower };
1838
1839     for (const QPointF *p = points; p < end; ++p) {
1840         int side = p->y() < splitY;
1841         int lastSide = last->y() < splitY;
1842
1843         if (side != lastSide) {
1844             if (qFuzzyCompare(p->y(), splitY)) {
1845                 bin[!side]->append(*p);
1846             } else if (qFuzzyCompare(last->y(), splitY)) {
1847                 bin[side]->append(*last);
1848             } else {
1849                 QPointF delta = *p - *last;
1850                 QPointF intersection(p->x() + delta.x() * (splitY - p->y()) / delta.y(), splitY);
1851
1852                 bin[0]->append(intersection);
1853                 bin[1]->append(intersection);
1854             }
1855         }
1856
1857         bin[side]->append(*p);
1858
1859         last = p;
1860     }
1861
1862     // give up if we couldn't reduce the point count
1863     return upper->size() < pointCount && lower->size() < pointCount;
1864 }
1865
1866 /*!
1867   \internal
1868  */
1869 void QRasterPaintEngine::fillPolygon(const QPointF *points, int pointCount, PolygonDrawMode mode)
1870 {
1871     Q_D(QRasterPaintEngine);
1872     QRasterPaintEngineState *s = state();
1873
1874     const int maxPoints = 0xffff;
1875
1876     // max amount of points that raster engine can reliably handle
1877     if (pointCount > maxPoints) {
1878         QVector<QPointF> upper, lower;
1879
1880         if (splitPolygon(points, pointCount, &upper, &lower)) {
1881             fillPolygon(upper.constData(), upper.size(), mode);
1882             fillPolygon(lower.constData(), lower.size(), mode);
1883         } else
1884             qWarning("Polygon too complex for filling.");
1885
1886         return;
1887     }
1888
1889     // Compose polygon fill..,
1890     QVectorPath vp((qreal *) points, pointCount, 0, QVectorPath::polygonFlags(mode));
1891     ensureOutlineMapper();
1892     QT_FT_Outline *outline = d->outlineMapper->convertPath(vp);
1893
1894     // scanconvert.
1895     ProcessSpans brushBlend = d->getBrushFunc(d->outlineMapper->controlPointRect,
1896                                               &s->brushData);
1897     d->rasterize(outline, brushBlend, &s->brushData, d->rasterBuffer.data());
1898 }
1899
1900 /*!
1901     \reimp
1902 */
1903 void QRasterPaintEngine::drawPolygon(const QPointF *points, int pointCount, PolygonDrawMode mode)
1904 {
1905     Q_D(QRasterPaintEngine);
1906     QRasterPaintEngineState *s = state();
1907
1908 #ifdef QT_DEBUG_DRAW
1909     qDebug(" - QRasterPaintEngine::drawPolygon(F), pointCount=%d", pointCount);
1910     for (int i=0; i<pointCount; ++i)
1911         qDebug() << "   - " << points[i];
1912 #endif
1913     Q_ASSERT(pointCount >= 2);
1914
1915     if (mode != PolylineMode && isRect((qreal *) points, pointCount)) {
1916         QRectF r(points[0], points[2]);
1917         drawRects(&r, 1);
1918         return;
1919     }
1920
1921     ensurePen();
1922     if (mode != PolylineMode) {
1923         // Do the fill...
1924         ensureBrush();
1925         if (s->brushData.blend) {
1926             d->outlineMapper->setCoordinateRounding(s->penData.blend && s->flags.fast_pen && s->lastPen.brush().isOpaque());
1927             fillPolygon(points, pointCount, mode);
1928             d->outlineMapper->setCoordinateRounding(false);
1929         }
1930     }
1931
1932     // Do the outline...
1933     if (s->penData.blend) {
1934         QVectorPath vp((qreal *) points, pointCount, 0, QVectorPath::polygonFlags(mode));
1935         if (s->flags.fast_pen) {
1936             QCosmeticStroker stroker(s, d->deviceRect);
1937             stroker.drawPath(vp);
1938         } else {
1939             QPaintEngineEx::stroke(vp, s->lastPen);
1940         }
1941     }
1942 }
1943
1944 /*!
1945     \reimp
1946 */
1947 void QRasterPaintEngine::drawPolygon(const QPoint *points, int pointCount, PolygonDrawMode mode)
1948 {
1949     Q_D(QRasterPaintEngine);
1950     QRasterPaintEngineState *s = state();
1951
1952 #ifdef QT_DEBUG_DRAW
1953     qDebug(" - QRasterPaintEngine::drawPolygon(I), pointCount=%d", pointCount);
1954     for (int i=0; i<pointCount; ++i)
1955         qDebug() << "   - " << points[i];
1956 #endif
1957     Q_ASSERT(pointCount >= 2);
1958     if (mode != PolylineMode && isRect((int *) points, pointCount)) {
1959         QRect r(points[0].x(),
1960                 points[0].y(),
1961                 points[2].x() - points[0].x(),
1962                 points[2].y() - points[0].y());
1963         drawRects(&r, 1);
1964         return;
1965     }
1966
1967     ensurePen();
1968
1969     // Do the fill
1970     if (mode != PolylineMode) {
1971         ensureBrush();
1972         if (s->brushData.blend) {
1973             // Compose polygon fill..,
1974             ensureOutlineMapper();
1975             d->outlineMapper->setCoordinateRounding(s->penData.blend != 0);
1976             d->outlineMapper->beginOutline(mode == WindingMode ? Qt::WindingFill : Qt::OddEvenFill);
1977             d->outlineMapper->moveTo(*points);
1978             const QPoint *p = points;
1979             const QPoint *ep = points + pointCount - 1;
1980             do {
1981                 d->outlineMapper->lineTo(*(++p));
1982             } while (p < ep);
1983             d->outlineMapper->endOutline();
1984
1985             // scanconvert.
1986             ProcessSpans brushBlend = d->getBrushFunc(d->outlineMapper->controlPointRect,
1987                                                       &s->brushData);
1988             d->rasterize(d->outlineMapper->outline(), brushBlend, &s->brushData, d->rasterBuffer.data());
1989             d->outlineMapper->setCoordinateRounding(false);
1990         }
1991     }
1992
1993     // Do the outline...
1994     if (s->penData.blend) {
1995         int count = pointCount * 2;
1996         QVarLengthArray<qreal> fpoints(count);
1997         for (int i=0; i<count; ++i)
1998             fpoints[i] = ((int *) points)[i];
1999         QVectorPath vp((qreal *) fpoints.data(), pointCount, 0, QVectorPath::polygonFlags(mode));
2000
2001         if (s->flags.fast_pen) {
2002             QCosmeticStroker stroker(s, d->deviceRect);
2003             stroker.drawPath(vp);
2004         } else {
2005             QPaintEngineEx::stroke(vp, s->lastPen);
2006         }
2007     }
2008 }
2009
2010 /*!
2011     \internal
2012 */
2013 void QRasterPaintEngine::drawPixmap(const QPointF &pos, const QPixmap &pixmap)
2014 {
2015 #ifdef QT_DEBUG_DRAW
2016     qDebug() << " - QRasterPaintEngine::drawPixmap(), pos=" << pos << " pixmap=" << pixmap.size() << "depth=" << pixmap.depth();
2017 #endif
2018
2019     QPlatformPixmap *pd = pixmap.handle();
2020     if (pd->classId() == QPlatformPixmap::RasterClass) {
2021         const QImage &image = static_cast<QRasterPlatformPixmap *>(pd)->image;
2022         if (image.depth() == 1) {
2023             Q_D(QRasterPaintEngine);
2024             QRasterPaintEngineState *s = state();
2025             if (s->matrix.type() <= QTransform::TxTranslate) {
2026                 ensurePen();
2027                 drawBitmap(pos + QPointF(s->matrix.dx(), s->matrix.dy()), image, &s->penData);
2028             } else {
2029                 drawImage(pos, d->rasterBuffer->colorizeBitmap(image, s->pen.color()));
2030             }
2031         } else {
2032             QRasterPaintEngine::drawImage(pos, image);
2033         }
2034     } else {
2035         const QImage image = pixmap.toImage();
2036         if (pixmap.depth() == 1) {
2037             Q_D(QRasterPaintEngine);
2038             QRasterPaintEngineState *s = state();
2039             if (s->matrix.type() <= QTransform::TxTranslate) {
2040                 ensurePen();
2041                 drawBitmap(pos + QPointF(s->matrix.dx(), s->matrix.dy()), image, &s->penData);
2042             } else {
2043                 drawImage(pos, d->rasterBuffer->colorizeBitmap(image, s->pen.color()));
2044             }
2045         } else {
2046             QRasterPaintEngine::drawImage(pos, image);
2047         }
2048     }
2049 }
2050
2051 /*!
2052     \reimp
2053 */
2054 void QRasterPaintEngine::drawPixmap(const QRectF &r, const QPixmap &pixmap, const QRectF &sr)
2055 {
2056 #ifdef QT_DEBUG_DRAW
2057     qDebug() << " - QRasterPaintEngine::drawPixmap(), r=" << r << " sr=" << sr << " pixmap=" << pixmap.size() << "depth=" << pixmap.depth();
2058 #endif
2059
2060     QPlatformPixmap* pd = pixmap.handle();
2061     if (pd->classId() == QPlatformPixmap::RasterClass) {
2062         const QImage &image = static_cast<QRasterPlatformPixmap *>(pd)->image;
2063         if (image.depth() == 1) {
2064             Q_D(QRasterPaintEngine);
2065             QRasterPaintEngineState *s = state();
2066             if (s->matrix.type() <= QTransform::TxTranslate
2067                 && r.size() == sr.size()
2068                 && r.size() == pixmap.size()) {
2069                 ensurePen();
2070                 drawBitmap(r.topLeft() + QPointF(s->matrix.dx(), s->matrix.dy()), image, &s->penData);
2071                 return;
2072             } else {
2073                 drawImage(r, d->rasterBuffer->colorizeBitmap(image, s->pen.color()), sr);
2074             }
2075         } else {
2076             drawImage(r, image, sr);
2077         }
2078     } else {
2079         QRect clippedSource = sr.toAlignedRect().intersected(pixmap.rect());
2080         const QImage image = pd->toImage(clippedSource);
2081         QRectF translatedSource = sr.translated(-clippedSource.topLeft());
2082         if (image.depth() == 1) {
2083             Q_D(QRasterPaintEngine);
2084             QRasterPaintEngineState *s = state();
2085             if (s->matrix.type() <= QTransform::TxTranslate
2086                 && r.size() == sr.size()
2087                 && r.size() == pixmap.size()) {
2088                 ensurePen();
2089                 drawBitmap(r.topLeft() + QPointF(s->matrix.dx(), s->matrix.dy()), image, &s->penData);
2090                 return;
2091             } else {
2092                 drawImage(r, d->rasterBuffer->colorizeBitmap(image, s->pen.color()), translatedSource);
2093             }
2094         } else {
2095             drawImage(r, image, translatedSource);
2096         }
2097     }
2098 }
2099
2100 // assumes that rect has positive width and height
2101 static inline const QRect toRect_normalized(const QRectF &rect)
2102 {
2103     const int x = qRound(rect.x());
2104     const int y = qRound(rect.y());
2105     const int w = int(rect.width() + qreal(0.5));
2106     const int h = int(rect.height() + qreal(0.5));
2107
2108     return QRect(x, y, w, h);
2109 }
2110
2111 static inline int fast_ceil_positive(const qreal &v)
2112 {
2113     const int iv = int(v);
2114     if (v - iv == 0)
2115         return iv;
2116     else
2117         return iv + 1;
2118 }
2119
2120 static inline const QRect toAlignedRect_positive(const QRectF &rect)
2121 {
2122     const int xmin = int(rect.x());
2123     const int xmax = int(fast_ceil_positive(rect.right()));
2124     const int ymin = int(rect.y());
2125     const int ymax = int(fast_ceil_positive(rect.bottom()));
2126     return QRect(xmin, ymin, xmax - xmin, ymax - ymin);
2127 }
2128
2129 /*!
2130     \internal
2131 */
2132 void QRasterPaintEngine::drawImage(const QPointF &p, const QImage &img)
2133 {
2134 #ifdef QT_DEBUG_DRAW
2135     qDebug() << " - QRasterPaintEngine::drawImage(), p=" <<  p << " image=" << img.size() << "depth=" << img.depth();
2136 #endif
2137
2138     Q_D(QRasterPaintEngine);
2139     QRasterPaintEngineState *s = state();
2140
2141     if (s->matrix.type() > QTransform::TxTranslate) {
2142         drawImage(QRectF(p.x(), p.y(), img.width(), img.height()),
2143                   img,
2144                   QRectF(0, 0, img.width(), img.height()));
2145     } else {
2146
2147         const QClipData *clip = d->clip();
2148         QPointF pt(p.x() + s->matrix.dx(), p.y() + s->matrix.dy());
2149
2150         if (d->canUseFastImageBlending(d->rasterBuffer->compositionMode, img)) {
2151             SrcOverBlendFunc func = qBlendFunctions[d->rasterBuffer->format][img.format()];
2152             if (func) {
2153                 if (!clip) {
2154                     d->drawImage(pt, img, func, d->deviceRect, s->intOpacity);
2155                     return;
2156                 } else if (clip->hasRectClip) {
2157                     d->drawImage(pt, img, func, clip->clipRect, s->intOpacity);
2158                     return;
2159                 }
2160             }
2161         }
2162
2163
2164
2165         d->image_filler.clip = clip;
2166         d->image_filler.initTexture(&img, s->intOpacity, QTextureData::Plain, img.rect());
2167         if (!d->image_filler.blend)
2168             return;
2169         d->image_filler.dx = -pt.x();
2170         d->image_filler.dy = -pt.y();
2171         QRect rr = img.rect().translated(qRound(pt.x()), qRound(pt.y()));
2172
2173         fillRect_normalized(rr, &d->image_filler, d);
2174     }
2175
2176 }
2177
2178 QRectF qt_mapRect_non_normalizing(const QRectF &r, const QTransform &t)
2179 {
2180     return QRectF(r.topLeft() * t, r.bottomRight() * t);
2181 }
2182
2183 namespace {
2184     enum RotationType {
2185         Rotation90,
2186         Rotation180,
2187         Rotation270,
2188         NoRotation
2189     };
2190
2191     inline RotationType qRotationType(const QTransform &transform)
2192     {
2193         QTransform::TransformationType type = transform.type();
2194
2195         if (type > QTransform::TxRotate)
2196             return NoRotation;
2197
2198         if (type == QTransform::TxRotate && qFuzzyIsNull(transform.m11()) && qFuzzyCompare(transform.m12(), qreal(-1))
2199             && qFuzzyCompare(transform.m21(), qreal(1)) && qFuzzyIsNull(transform.m22()))
2200             return Rotation90;
2201
2202         if (type == QTransform::TxScale && qFuzzyCompare(transform.m11(), qreal(-1)) && qFuzzyIsNull(transform.m12())
2203             && qFuzzyIsNull(transform.m21()) && qFuzzyCompare(transform.m22(), qreal(-1)))
2204             return Rotation180;
2205
2206         if (type == QTransform::TxRotate && qFuzzyIsNull(transform.m11()) && qFuzzyCompare(transform.m12(), qreal(1))
2207             && qFuzzyCompare(transform.m21(), qreal(-1)) && qFuzzyIsNull(transform.m22()))
2208             return Rotation270;
2209
2210         return NoRotation;
2211     }
2212
2213     inline bool isPixelAligned(const QRectF &rect) {
2214         return QRectF(rect.toRect()) == rect;
2215     }
2216 }
2217
2218 /*!
2219     \reimp
2220 */
2221 void QRasterPaintEngine::drawImage(const QRectF &r, const QImage &img, const QRectF &sr,
2222                                    Qt::ImageConversionFlags)
2223 {
2224 #ifdef QT_DEBUG_DRAW
2225     qDebug() << " - QRasterPaintEngine::drawImage(), r=" << r << " sr=" << sr << " image=" << img.size() << "depth=" << img.depth();
2226 #endif
2227
2228     if (r.isEmpty())
2229         return;
2230
2231     Q_D(QRasterPaintEngine);
2232     QRasterPaintEngineState *s = state();
2233     int sr_l = qFloor(sr.left());
2234     int sr_r = qCeil(sr.right()) - 1;
2235     int sr_t = qFloor(sr.top());
2236     int sr_b = qCeil(sr.bottom()) - 1;
2237
2238     if (s->matrix.type() <= QTransform::TxScale && !s->flags.antialiased && sr_l == sr_r && sr_t == sr_b) {
2239         // as fillRect will apply the aliased coordinate delta we need to
2240         // subtract it here as we don't use it for image drawing
2241         QTransform old = s->matrix;
2242         s->matrix = s->matrix * QTransform::fromTranslate(-aliasedCoordinateDelta, -aliasedCoordinateDelta);
2243
2244         // Do whatever fillRect() does, but without premultiplying the color if it's already premultiplied.
2245         QRgb color = img.pixel(sr_l, sr_t);
2246         switch (img.format()) {
2247         case QImage::Format_ARGB32_Premultiplied:
2248         case QImage::Format_ARGB8565_Premultiplied:
2249         case QImage::Format_ARGB6666_Premultiplied:
2250         case QImage::Format_ARGB8555_Premultiplied:
2251         case QImage::Format_ARGB4444_Premultiplied:
2252             // Combine premultiplied color with the opacity set on the painter.
2253             d->solid_color_filler.solid.color =
2254                 ((((color & 0x00ff00ff) * s->intOpacity) >> 8) & 0x00ff00ff)
2255                 | ((((color & 0xff00ff00) >> 8) * s->intOpacity) & 0xff00ff00);
2256             break;
2257         default:
2258             d->solid_color_filler.solid.color = PREMUL(ARGB_COMBINE_ALPHA(color, s->intOpacity));
2259             break;
2260         }
2261
2262         if ((d->solid_color_filler.solid.color & 0xff000000) == 0
2263             && s->composition_mode == QPainter::CompositionMode_SourceOver) {
2264             return;
2265         }
2266
2267         d->solid_color_filler.clip = d->clip();
2268         d->solid_color_filler.adjustSpanMethods();
2269         fillRect(r, &d->solid_color_filler);
2270
2271         s->matrix = old;
2272         return;
2273     }
2274
2275     bool stretch_sr = r.width() != sr.width() || r.height() != sr.height();
2276
2277     const QClipData *clip = d->clip();
2278
2279     if (s->matrix.type() > QTransform::TxTranslate
2280         && !stretch_sr
2281         && (!clip || clip->hasRectClip)
2282         && s->intOpacity == 256
2283         && (d->rasterBuffer->compositionMode == QPainter::CompositionMode_SourceOver
2284             || d->rasterBuffer->compositionMode == QPainter::CompositionMode_Source)
2285         && d->rasterBuffer->format == img.format()
2286         && (d->rasterBuffer->format == QImage::Format_RGB16
2287             || d->rasterBuffer->format == QImage::Format_RGB32
2288             || (d->rasterBuffer->format == QImage::Format_ARGB32_Premultiplied
2289                 && d->rasterBuffer->compositionMode == QPainter::CompositionMode_Source)))
2290     {
2291         RotationType rotationType = qRotationType(s->matrix);
2292
2293         if (rotationType != NoRotation && qMemRotateFunctions[d->rasterBuffer->format][rotationType] && img.rect().contains(sr.toAlignedRect())) {
2294             QRectF transformedTargetRect = s->matrix.mapRect(r);
2295
2296             if ((!(s->renderHints & QPainter::SmoothPixmapTransform) && !(s->renderHints & QPainter::Antialiasing))
2297                 || (isPixelAligned(transformedTargetRect) && isPixelAligned(sr)))
2298             {
2299                 QRect clippedTransformedTargetRect = transformedTargetRect.toRect().intersected(clip ? clip->clipRect : d->deviceRect);
2300                 if (clippedTransformedTargetRect.isNull())
2301                     return;
2302
2303                 QRectF clippedTargetRect = s->matrix.inverted().mapRect(QRectF(clippedTransformedTargetRect));
2304
2305                 QRect clippedSourceRect
2306                     = QRectF(sr.x() + clippedTargetRect.x() - r.x(), sr.y() + clippedTargetRect.y() - r.y(),
2307                             clippedTargetRect.width(), clippedTargetRect.height()).toRect();
2308
2309                 uint dbpl = d->rasterBuffer->bytesPerLine();
2310                 uint sbpl = img.bytesPerLine();
2311
2312                 uchar *dst = d->rasterBuffer->buffer();
2313                 uint bpp = img.depth() >> 3;
2314
2315                 const uchar *srcBase = img.bits() + clippedSourceRect.y() * sbpl + clippedSourceRect.x() * bpp;
2316                 uchar *dstBase = dst + clippedTransformedTargetRect.y() * dbpl + clippedTransformedTargetRect.x() * bpp;
2317
2318                 uint cw = clippedSourceRect.width();
2319                 uint ch = clippedSourceRect.height();
2320
2321                 qMemRotateFunctions[d->rasterBuffer->format][rotationType](srcBase, cw, ch, sbpl, dstBase, dbpl);
2322
2323                 return;
2324             }
2325         }
2326     }
2327
2328     if (s->matrix.type() > QTransform::TxTranslate || stretch_sr) {
2329
2330         QRectF targetBounds = s->matrix.mapRect(r);
2331         bool exceedsPrecision = targetBounds.width() > 0xffff
2332                                 || targetBounds.height() > 0xffff;
2333
2334         if (!exceedsPrecision && d->canUseFastImageBlending(d->rasterBuffer->compositionMode, img)) {
2335             if (s->matrix.type() > QTransform::TxScale) {
2336                 SrcOverTransformFunc func = qTransformFunctions[d->rasterBuffer->format][img.format()];
2337                 if (func && (!clip || clip->hasRectClip)) {
2338                     func(d->rasterBuffer->buffer(), d->rasterBuffer->bytesPerLine(), img.bits(),
2339                          img.bytesPerLine(), r, sr, !clip ? d->deviceRect : clip->clipRect,
2340                          s->matrix, s->intOpacity);
2341                     return;
2342                 }
2343             } else {
2344                 SrcOverScaleFunc func = qScaleFunctions[d->rasterBuffer->format][img.format()];
2345                 if (func && (!clip || clip->hasRectClip)) {
2346                     func(d->rasterBuffer->buffer(), d->rasterBuffer->bytesPerLine(),
2347                          img.bits(), img.bytesPerLine(),
2348                          qt_mapRect_non_normalizing(r, s->matrix), sr,
2349                          !clip ? d->deviceRect : clip->clipRect,
2350                          s->intOpacity);
2351                     return;
2352                 }
2353             }
2354         }
2355
2356         QTransform copy = s->matrix;
2357         copy.translate(r.x(), r.y());
2358         if (stretch_sr)
2359             copy.scale(r.width() / sr.width(), r.height() / sr.height());
2360         copy.translate(-sr.x(), -sr.y());
2361
2362         d->image_filler_xform.clip = clip;
2363         d->image_filler_xform.initTexture(&img, s->intOpacity, QTextureData::Plain, toAlignedRect_positive(sr));
2364         if (!d->image_filler_xform.blend)
2365             return;
2366         d->image_filler_xform.setupMatrix(copy, s->flags.bilinear);
2367
2368         if (!s->flags.antialiased && s->matrix.type() == QTransform::TxScale) {
2369             QRectF rr = s->matrix.mapRect(r);
2370
2371             const int x1 = qRound(rr.x());
2372             const int y1 = qRound(rr.y());
2373             const int x2 = qRound(rr.right());
2374             const int y2 = qRound(rr.bottom());
2375
2376             fillRect_normalized(QRect(x1, y1, x2-x1, y2-y1), &d->image_filler_xform, d);
2377             return;
2378         }
2379
2380 #ifdef QT_FAST_SPANS
2381         ensureRasterState();
2382         if (s->flags.tx_noshear || s->matrix.type() == QTransform::TxScale) {
2383             d->initializeRasterizer(&d->image_filler_xform);
2384             d->rasterizer->setAntialiased(s->flags.antialiased);
2385
2386             const QPointF offs = s->flags.antialiased ? QPointF() : QPointF(aliasedCoordinateDelta, aliasedCoordinateDelta);
2387
2388             const QRectF &rect = r.normalized();
2389             const QPointF a = s->matrix.map((rect.topLeft() + rect.bottomLeft()) * 0.5f) - offs;
2390             const QPointF b = s->matrix.map((rect.topRight() + rect.bottomRight()) * 0.5f) - offs;
2391
2392             if (s->flags.tx_noshear)
2393                 d->rasterizer->rasterizeLine(a, b, rect.height() / rect.width());
2394             else
2395                 d->rasterizer->rasterizeLine(a, b, qAbs((s->matrix.m22() * rect.height()) / (s->matrix.m11() * rect.width())));
2396             return;
2397         }
2398 #endif
2399         const qreal offs = s->flags.antialiased ? qreal(0) : aliasedCoordinateDelta;
2400         QPainterPath path;
2401         path.addRect(r);
2402         QTransform m = s->matrix;
2403         s->matrix = QTransform(m.m11(), m.m12(), m.m13(),
2404                                m.m21(), m.m22(), m.m23(),
2405                                m.m31() - offs, m.m32() - offs, m.m33());
2406         fillPath(path, &d->image_filler_xform);
2407         s->matrix = m;
2408     } else {
2409         if (d->canUseFastImageBlending(d->rasterBuffer->compositionMode, img)) {
2410             SrcOverBlendFunc func = qBlendFunctions[d->rasterBuffer->format][img.format()];
2411             if (func) {
2412                 QPointF pt(r.x() + s->matrix.dx(), r.y() + s->matrix.dy());
2413                 if (!clip) {
2414                     d->drawImage(pt, img, func, d->deviceRect, s->intOpacity, sr.toRect());
2415                     return;
2416                 } else if (clip->hasRectClip) {
2417                     d->drawImage(pt, img, func, clip->clipRect, s->intOpacity, sr.toRect());
2418                     return;
2419                 }
2420             }
2421         }
2422
2423         d->image_filler.clip = clip;
2424         d->image_filler.initTexture(&img, s->intOpacity, QTextureData::Plain, toAlignedRect_positive(sr));
2425         if (!d->image_filler.blend)
2426             return;
2427         d->image_filler.dx = -(r.x() + s->matrix.dx()) + sr.x();
2428         d->image_filler.dy = -(r.y() + s->matrix.dy()) + sr.y();
2429
2430         QRectF rr = r;
2431         rr.translate(s->matrix.dx(), s->matrix.dy());
2432
2433         const int x1 = qRound(rr.x());
2434         const int y1 = qRound(rr.y());
2435         const int x2 = qRound(rr.right());
2436         const int y2 = qRound(rr.bottom());
2437
2438         fillRect_normalized(QRect(x1, y1, x2-x1, y2-y1), &d->image_filler, d);
2439     }
2440 }
2441
2442 /*!
2443     \reimp
2444 */
2445 void QRasterPaintEngine::drawTiledPixmap(const QRectF &r, const QPixmap &pixmap, const QPointF &sr)
2446 {
2447 #ifdef QT_DEBUG_DRAW
2448     qDebug() << " - QRasterPaintEngine::drawTiledPixmap(), r=" << r << "pixmap=" << pixmap.size();
2449 #endif
2450     Q_D(QRasterPaintEngine);
2451     QRasterPaintEngineState *s = state();
2452
2453     QImage image;
2454
2455     QPlatformPixmap *pd = pixmap.handle();
2456     if (pd->classId() == QPlatformPixmap::RasterClass) {
2457         image = static_cast<QRasterPlatformPixmap *>(pd)->image;
2458     } else {
2459         image = pixmap.toImage();
2460     }
2461
2462     if (image.depth() == 1)
2463         image = d->rasterBuffer->colorizeBitmap(image, s->pen.color());
2464
2465     if (s->matrix.type() > QTransform::TxTranslate) {
2466         QTransform copy = s->matrix;
2467         copy.translate(r.x(), r.y());
2468         copy.translate(-sr.x(), -sr.y());
2469         d->image_filler_xform.clip = d->clip();
2470         d->image_filler_xform.initTexture(&image, s->intOpacity, QTextureData::Tiled);
2471         if (!d->image_filler_xform.blend)
2472             return;
2473         d->image_filler_xform.setupMatrix(copy, s->flags.bilinear);
2474
2475 #ifdef QT_FAST_SPANS
2476         ensureRasterState();
2477         if (s->flags.tx_noshear || s->matrix.type() == QTransform::TxScale) {
2478             d->initializeRasterizer(&d->image_filler_xform);
2479             d->rasterizer->setAntialiased(s->flags.antialiased);
2480
2481             const QRectF &rect = r.normalized();
2482             const QPointF a = s->matrix.map((rect.topLeft() + rect.bottomLeft()) * 0.5f);
2483             const QPointF b = s->matrix.map((rect.topRight() + rect.bottomRight()) * 0.5f);
2484             if (s->flags.tx_noshear)
2485                 d->rasterizer->rasterizeLine(a, b, rect.height() / rect.width());
2486             else
2487                 d->rasterizer->rasterizeLine(a, b, qAbs((s->matrix.m22() * rect.height()) / (s->matrix.m11() * rect.width())));
2488             return;
2489         }
2490 #endif
2491         QPainterPath path;
2492         path.addRect(r);
2493         fillPath(path, &d->image_filler_xform);
2494     } else {
2495         d->image_filler.clip = d->clip();
2496
2497         d->image_filler.initTexture(&image, s->intOpacity, QTextureData::Tiled);
2498         if (!d->image_filler.blend)
2499             return;
2500         d->image_filler.dx = -(r.x() + s->matrix.dx()) + sr.x();
2501         d->image_filler.dy = -(r.y() + s->matrix.dy()) + sr.y();
2502
2503         QRectF rr = r;
2504         rr.translate(s->matrix.dx(), s->matrix.dy());
2505         fillRect_normalized(rr.toRect().normalized(), &d->image_filler, d);
2506     }
2507 }
2508
2509
2510 //QWS hack
2511 static inline bool monoVal(const uchar* s, int x)
2512 {
2513     return  (s[x>>3] << (x&7)) & 0x80;
2514 }
2515
2516 /*!
2517     \internal
2518  */
2519 QRasterBuffer *QRasterPaintEngine::rasterBuffer()
2520 {
2521     Q_D(QRasterPaintEngine);
2522     return d->rasterBuffer.data();
2523 }
2524
2525 /*!
2526     \internal
2527 */
2528 void QRasterPaintEngine::alphaPenBlt(const void* src, int bpl, int depth, int rx,int ry,int w,int h)
2529 {
2530     Q_D(QRasterPaintEngine);
2531     QRasterPaintEngineState *s = state();
2532
2533     if (!s->penData.blend)
2534         return;
2535
2536     QRasterBuffer *rb = d->rasterBuffer.data();
2537
2538     const QRect rect(rx, ry, w, h);
2539     const QClipData *clip = d->clip();
2540     bool unclipped = false;
2541     if (clip) {
2542         // inlined QRect::intersects
2543         const bool intersects = qMax(clip->xmin, rect.left()) <= qMin(clip->xmax - 1, rect.right())
2544                                 && qMax(clip->ymin, rect.top()) <= qMin(clip->ymax - 1, rect.bottom());
2545
2546         if (clip->hasRectClip) {
2547             unclipped = rx > clip->xmin
2548                         && rx + w < clip->xmax
2549                         && ry > clip->ymin
2550                         && ry + h < clip->ymax;
2551         }
2552
2553         if (!intersects)
2554             return;
2555     } else {
2556         // inlined QRect::intersects
2557         const bool intersects = qMax(0, rect.left()) <= qMin(rb->width() - 1, rect.right())
2558                                 && qMax(0, rect.top()) <= qMin(rb->height() - 1, rect.bottom());
2559         if (!intersects)
2560             return;
2561
2562         // inlined QRect::contains
2563         const bool contains = rect.left() >= 0 && rect.right() < rb->width()
2564                               && rect.top() >= 0 && rect.bottom() < rb->height();
2565
2566         unclipped = contains && d->isUnclipped_normalized(rect);
2567     }
2568
2569     ProcessSpans blend = unclipped ? s->penData.unclipped_blend : s->penData.blend;
2570     const uchar * scanline = static_cast<const uchar *>(src);
2571
2572     if (s->flags.fast_text) {
2573         if (unclipped) {
2574             if (depth == 1) {
2575                 if (s->penData.bitmapBlit) {
2576                     s->penData.bitmapBlit(rb, rx, ry, s->penData.solid.color,
2577                                           scanline, w, h, bpl);
2578                     return;
2579                 }
2580             } else if (depth == 8) {
2581                 if (s->penData.alphamapBlit) {
2582                     s->penData.alphamapBlit(rb, rx, ry, s->penData.solid.color,
2583                                             scanline, w, h, bpl, 0);
2584                     return;
2585                 }
2586             } else if (depth == 32) {
2587                 // (A)RGB Alpha mask where the alpha component is not used.
2588                 if (s->penData.alphaRGBBlit) {
2589                     s->penData.alphaRGBBlit(rb, rx, ry, s->penData.solid.color,
2590                                             (const uint *) scanline, w, h, bpl / 4, 0);
2591                     return;
2592                 }
2593             }
2594         } else if (d->deviceDepth == 32 && (depth == 8 || depth == 32)) {
2595             // (A)RGB Alpha mask where the alpha component is not used.
2596             if (!clip) {
2597                 int nx = qMax(0, rx);
2598                 int ny = qMax(0, ry);
2599
2600                 // Move scanline pointer to compensate for moved x and y
2601                 int xdiff = nx - rx;
2602                 int ydiff = ny - ry;
2603                 scanline += ydiff * bpl;
2604                 scanline += xdiff * (depth == 32 ? 4 : 1);
2605
2606                 w -= xdiff;
2607                 h -= ydiff;
2608
2609                 if (nx + w > d->rasterBuffer->width())
2610                     w = d->rasterBuffer->width() - nx;
2611                 if (ny + h > d->rasterBuffer->height())
2612                     h = d->rasterBuffer->height() - ny;
2613
2614                 rx = nx;
2615                 ry = ny;
2616             }
2617             if (depth == 8 && s->penData.alphamapBlit) {
2618                 s->penData.alphamapBlit(rb, rx, ry, s->penData.solid.color,
2619                                         scanline, w, h, bpl, clip);
2620             } else if (depth == 32 && s->penData.alphaRGBBlit) {
2621                 s->penData.alphaRGBBlit(rb, rx, ry, s->penData.solid.color,
2622                                         (const uint *) scanline, w, h, bpl / 4, clip);
2623             }
2624             return;
2625         }
2626     }
2627
2628     int x0 = 0;
2629     if (rx < 0) {
2630         x0 = -rx;
2631         w -= x0;
2632     }
2633
2634     int y0 = 0;
2635     if (ry < 0) {
2636         y0 = -ry;
2637         scanline += bpl * y0;
2638         h -= y0;
2639     }
2640
2641     w = qMin(w, rb->width() - qMax(0, rx));
2642     h = qMin(h, rb->height() - qMax(0, ry));
2643
2644     if (w <= 0 || h <= 0)
2645         return;
2646
2647     const int NSPANS = 256;
2648     QSpan spans[NSPANS];
2649     int current = 0;
2650
2651     const int x1 = x0 + w;
2652     const int y1 = y0 + h;
2653
2654     if (depth == 1) {
2655         for (int y = y0; y < y1; ++y) {
2656             for (int x = x0; x < x1; ) {
2657                 if (!monoVal(scanline, x)) {
2658                     ++x;
2659                     continue;
2660                 }
2661
2662                 if (current == NSPANS) {
2663                     blend(current, spans, &s->penData);
2664                     current = 0;
2665                 }
2666                 spans[current].x = x + rx;
2667                 spans[current].y = y + ry;
2668                 spans[current].coverage = 255;
2669                 int len = 1;
2670                 ++x;
2671                 // extend span until we find a different one.
2672                 while (x < x1 && monoVal(scanline, x)) {
2673                     ++x;
2674                     ++len;
2675                 }
2676                 spans[current].len = len;
2677                 ++current;
2678             }
2679             scanline += bpl;
2680         }
2681     } else if (depth == 8) {
2682         for (int y = y0; y < y1; ++y) {
2683             for (int x = x0; x < x1; ) {
2684                 // Skip those with 0 coverage
2685                 if (scanline[x] == 0) {
2686                     ++x;
2687                     continue;
2688                 }
2689
2690                 if (current == NSPANS) {
2691                     blend(current, spans, &s->penData);
2692                     current = 0;
2693                 }
2694                 int coverage = scanline[x];
2695                 spans[current].x = x + rx;
2696                 spans[current].y = y + ry;
2697                 spans[current].coverage = coverage;
2698                 int len = 1;
2699                 ++x;
2700
2701                 // extend span until we find a different one.
2702                 while (x < x1 && scanline[x] == coverage) {
2703                     ++x;
2704                     ++len;
2705                 }
2706                 spans[current].len = len;
2707                 ++current;
2708             }
2709             scanline += bpl;
2710         }
2711     } else { // 32-bit alpha...
2712         uint *sl = (uint *) src;
2713         for (int y = y0; y < y1; ++y) {
2714             for (int x = x0; x < x1; ) {
2715                 // Skip those with 0 coverage
2716                 if ((sl[x] & 0x00ffffff) == 0) {
2717                     ++x;
2718                     continue;
2719                 }
2720
2721                 if (current == NSPANS) {
2722                     blend(current, spans, &s->penData);
2723                     current = 0;
2724                 }
2725                 uint rgbCoverage = sl[x];
2726                 int coverage = qGreen(rgbCoverage);
2727                 spans[current].x = x + rx;
2728                 spans[current].y = y + ry;
2729                 spans[current].coverage = coverage;
2730                 int len = 1;
2731                 ++x;
2732
2733                 // extend span until we find a different one.
2734                 while (x < x1 && sl[x] == rgbCoverage) {
2735                     ++x;
2736                     ++len;
2737                 }
2738                 spans[current].len = len;
2739                 ++current;
2740             }
2741             sl += bpl / sizeof(uint);
2742         }
2743     }
2744 //     qDebug() << "alphaPenBlt: num spans=" << current
2745 //              << "span:" << spans->x << spans->y << spans->len << spans->coverage;
2746         // Call span func for current set of spans.
2747     if (current != 0)
2748         blend(current, spans, &s->penData);
2749 }
2750
2751 bool QRasterPaintEngine::drawCachedGlyphs(int numGlyphs, const glyph_t *glyphs,
2752                                           const QFixedPoint *positions, QFontEngine *fontEngine)
2753 {
2754     Q_D(QRasterPaintEngine);
2755     QRasterPaintEngineState *s = state();
2756
2757     if (fontEngine->hasInternalCaching()) {
2758         QFontEngine::GlyphFormat neededFormat =
2759             painter()->device()->devType() == QInternal::Widget
2760             ? QFontEngine::Format_None
2761             : QFontEngine::Format_A8;
2762
2763         if (d_func()->mono_surface) // alphaPenBlt can handle mono, too
2764             neededFormat = QFontEngine::Format_Mono;
2765
2766         for (int i = 0; i < numGlyphs; i++) {
2767             QFixed spp = fontEngine->subPixelPositionForX(positions[i].x);
2768
2769             QPoint offset;
2770             QImage *alphaMap = fontEngine->lockedAlphaMapForGlyph(glyphs[i], spp, neededFormat, s->matrix,
2771                                                                   &offset);
2772             if (alphaMap == 0 || alphaMap->isNull())
2773                 continue;
2774
2775             alphaPenBlt(alphaMap->bits(), alphaMap->bytesPerLine(), alphaMap->depth(),
2776                         qFloor(positions[i].x) + offset.x(),
2777                         qFloor(positions[i].y) + offset.y(),
2778                         alphaMap->width(), alphaMap->height());
2779
2780             fontEngine->unlockAlphaMapForGlyph();
2781         }
2782
2783     } else {
2784         QFontEngineGlyphCache::Type glyphType = fontEngine->glyphFormat >= 0 ? QFontEngineGlyphCache::Type(fontEngine->glyphFormat) : d->glyphCacheType;
2785
2786         QImageTextureGlyphCache *cache =
2787             static_cast<QImageTextureGlyphCache *>(fontEngine->glyphCache(0, glyphType, s->matrix));
2788         if (!cache) {
2789             cache = new QImageTextureGlyphCache(glyphType, s->matrix);
2790             fontEngine->setGlyphCache(0, cache);
2791         }
2792
2793         cache->populate(fontEngine, numGlyphs, glyphs, positions);
2794         cache->fillInPendingGlyphs();
2795
2796         const QImage &image = cache->image();
2797         int bpl = image.bytesPerLine();
2798
2799         int depth = image.depth();
2800         int rightShift = 0;
2801         int leftShift = 0;
2802         if (depth == 32)
2803             leftShift = 2; // multiply by 4
2804         else if (depth == 1)
2805             rightShift = 3; // divide by 8
2806
2807         int margin = fontEngine->glyphMargin(glyphType);
2808         const QFixed offs = QFixed::fromReal(aliasedCoordinateDelta);
2809         const uchar *bits = image.bits();
2810         for (int i=0; i<numGlyphs; ++i) {
2811
2812             QFixed subPixelPosition = fontEngine->subPixelPositionForX(positions[i].x);
2813             QTextureGlyphCache::GlyphAndSubPixelPosition glyph(glyphs[i], subPixelPosition);
2814             const QTextureGlyphCache::Coord &c = cache->coords[glyph];
2815             if (c.isNull())
2816                 continue;
2817
2818             int x = qFloor(positions[i].x) + c.baseLineX - margin;
2819             int y = qFloor(positions[i].y + offs) - c.baseLineY - margin;
2820
2821             // printf("drawing [%d %d %d %d] baseline [%d %d], glyph: %d, to: %d %d, pos: %d %d\n",
2822             //        c.x, c.y,
2823             //        c.w, c.h,
2824             //        c.baseLineX, c.baseLineY,
2825             //        glyphs[i],
2826             //        x, y,
2827             //        positions[i].x.toInt(), positions[i].y.toInt());
2828
2829             alphaPenBlt(bits + ((c.x << leftShift) >> rightShift) + c.y * bpl, bpl, depth, x, y, c.w, c.h);
2830         }
2831     }
2832     return true;
2833 }
2834
2835
2836 /*!
2837  * Returns true if the rectangle is completely within the current clip
2838  * state of the paint engine.
2839  */
2840 bool QRasterPaintEnginePrivate::isUnclipped_normalized(const QRect &r) const
2841 {
2842     const QClipData *cl = clip();
2843     if (!cl) {
2844         // inline contains() for performance (we know the rects are normalized)
2845         const QRect &r1 = deviceRect;
2846         return (r.left() >= r1.left() && r.right() <= r1.right()
2847                 && r.top() >= r1.top() && r.bottom() <= r1.bottom());
2848     }
2849
2850
2851     if (cl->hasRectClip) {
2852         // currently all painting functions clips to deviceRect internally
2853         if (cl->clipRect == deviceRect)
2854             return true;
2855
2856         // inline contains() for performance (we know the rects are normalized)
2857         const QRect &r1 = cl->clipRect;
2858         return (r.left() >= r1.left() && r.right() <= r1.right()
2859                 && r.top() >= r1.top() && r.bottom() <= r1.bottom());
2860     } else {
2861         return qt_region_strictContains(cl->clipRegion, r);
2862     }
2863 }
2864
2865 bool QRasterPaintEnginePrivate::isUnclipped(const QRect &rect,
2866                                             int penWidth) const
2867 {
2868     Q_Q(const QRasterPaintEngine);
2869     const QRasterPaintEngineState *s = q->state();
2870     const QClipData *cl = clip();
2871     if (!cl) {
2872         QRect r = rect.normalized();
2873         // inline contains() for performance (we know the rects are normalized)
2874         const QRect &r1 = deviceRect;
2875         return (r.left() >= r1.left() && r.right() <= r1.right()
2876                 && r.top() >= r1.top() && r.bottom() <= r1.bottom());
2877     }
2878
2879
2880     // currently all painting functions that call this function clip to deviceRect internally
2881     if (cl->hasRectClip && cl->clipRect == deviceRect)
2882         return true;
2883
2884     if (s->flags.antialiased)
2885         ++penWidth;
2886
2887     QRect r = rect.normalized();
2888     if (penWidth > 0) {
2889         r.setX(r.x() - penWidth);
2890         r.setY(r.y() - penWidth);
2891         r.setWidth(r.width() + 2 * penWidth);
2892         r.setHeight(r.height() + 2 * penWidth);
2893     }
2894
2895     if (cl->hasRectClip) {
2896         // inline contains() for performance (we know the rects are normalized)
2897         const QRect &r1 = cl->clipRect;
2898         return (r.left() >= r1.left() && r.right() <= r1.right()
2899                 && r.top() >= r1.top() && r.bottom() <= r1.bottom());
2900     } else {
2901         return qt_region_strictContains(cl->clipRegion, r);
2902     }
2903 }
2904
2905 inline bool QRasterPaintEnginePrivate::isUnclipped(const QRectF &rect,
2906                                                    int penWidth) const
2907 {
2908     return isUnclipped(rect.normalized().toAlignedRect(), penWidth);
2909 }
2910
2911 inline ProcessSpans
2912 QRasterPaintEnginePrivate::getBrushFunc(const QRect &rect,
2913                                         const QSpanData *data) const
2914 {
2915     return isUnclipped(rect, 0) ? data->unclipped_blend : data->blend;
2916 }
2917
2918 inline ProcessSpans
2919 QRasterPaintEnginePrivate::getBrushFunc(const QRectF &rect,
2920                                         const QSpanData *data) const
2921 {
2922     return isUnclipped(rect, 0) ? data->unclipped_blend : data->blend;
2923 }
2924
2925 inline ProcessSpans
2926 QRasterPaintEnginePrivate::getPenFunc(const QRectF &rect,
2927                                       const QSpanData *data) const
2928 {
2929     Q_Q(const QRasterPaintEngine);
2930     const QRasterPaintEngineState *s = q->state();
2931
2932     if (!s->flags.fast_pen && s->matrix.type() > QTransform::TxTranslate)
2933         return data->blend;
2934     const int penWidth = s->flags.fast_pen ? 1 : qCeil(s->lastPen.widthF());
2935     return isUnclipped(rect, penWidth) ? data->unclipped_blend : data->blend;
2936 }
2937
2938 static QPair<int, int> visibleGlyphRange(const QRectF &clip, QFontEngine *fontEngine,
2939                                          glyph_t *glyphs, QFixedPoint *positions, int numGlyphs)
2940 {
2941     QFixed clipLeft = QFixed::fromReal(clip.left());
2942     QFixed clipRight = QFixed::fromReal(clip.right());
2943     QFixed clipTop = QFixed::fromReal(clip.top());
2944     QFixed clipBottom = QFixed::fromReal(clip.bottom());
2945
2946     int first = 0;
2947     while (first < numGlyphs) {
2948         glyph_metrics_t metrics = fontEngine->boundingBox(glyphs[first]);
2949         QFixed left = metrics.x + positions[first].x;
2950         QFixed top = metrics.y + positions[first].y;
2951         QFixed right = left + metrics.width;
2952         QFixed bottom = top + metrics.height;
2953         if (left < clipRight && right > clipLeft && top < clipBottom && bottom > clipTop)
2954             break;
2955         ++first;
2956     }
2957     int last = numGlyphs - 1;
2958     while (last > first) {
2959         glyph_metrics_t metrics = fontEngine->boundingBox(glyphs[last]);
2960         QFixed left = metrics.x + positions[last].x;
2961         QFixed top = metrics.y + positions[last].y;
2962         QFixed right = left + metrics.width;
2963         QFixed bottom = top + metrics.height;
2964         if (left < clipRight && right > clipLeft && top < clipBottom && bottom > clipTop)
2965             break;
2966         --last;
2967     }
2968     return QPair<int, int>(first, last + 1);
2969 }
2970
2971 /*!
2972    \reimp
2973 */
2974 void QRasterPaintEngine::drawStaticTextItem(QStaticTextItem *textItem)
2975 {
2976     if (textItem->numGlyphs == 0)
2977         return;
2978
2979     ensurePen();
2980     ensureRasterState();
2981
2982     QFontEngine *fontEngine = textItem->fontEngine();
2983     if (shouldDrawCachedGlyphs(fontEngine, state()->matrix)) {
2984         drawCachedGlyphs(textItem->numGlyphs, textItem->glyphs, textItem->glyphPositions,
2985                          fontEngine);
2986     } else if (state()->matrix.type() < QTransform::TxProject) {
2987         bool invertible;
2988         QTransform invMat = state()->matrix.inverted(&invertible);
2989         if (!invertible)
2990             return;
2991
2992         QPair<int, int> range = visibleGlyphRange(invMat.mapRect(clipBoundingRect()),
2993                                                   textItem->fontEngine(), textItem->glyphs,
2994                                                   textItem->glyphPositions, textItem->numGlyphs);
2995         QStaticTextItem copy = *textItem;
2996         copy.glyphs += range.first;
2997         copy.glyphPositions += range.first;
2998         copy.numGlyphs = range.second - range.first;
2999         QPaintEngineEx::drawStaticTextItem(&copy);
3000     } else {
3001         QPaintEngineEx::drawStaticTextItem(textItem);
3002     }
3003 }
3004
3005 /*!
3006     \reimp
3007 */
3008 void QRasterPaintEngine::drawTextItem(const QPointF &p, const QTextItem &textItem)
3009 {
3010     const QTextItemInt &ti = static_cast<const QTextItemInt &>(textItem);
3011
3012 #ifdef QT_DEBUG_DRAW
3013     Q_D(QRasterPaintEngine);
3014     fprintf(stderr," - QRasterPaintEngine::drawTextItem(), (%.2f,%.2f), string=%s ct=%d\n",
3015            p.x(), p.y(), QString::fromRawData(ti.chars, ti.num_chars).toLatin1().data(),
3016            d->glyphCacheType);
3017 #endif
3018
3019     if (ti.glyphs.numGlyphs == 0)
3020         return;
3021     ensurePen();
3022     ensureRasterState();
3023
3024     QRasterPaintEngineState *s = state();
3025     QTransform matrix = s->matrix;
3026
3027     if (!supportsTransformations(ti.fontEngine)) {
3028         QVarLengthArray<QFixedPoint> positions;
3029         QVarLengthArray<glyph_t> glyphs;
3030
3031         matrix.translate(p.x(), p.y());
3032         ti.fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions);
3033
3034         drawCachedGlyphs(glyphs.size(), glyphs.constData(), positions.constData(), ti.fontEngine);
3035     } else if (matrix.type() < QTransform::TxProject) {
3036         bool invertible;
3037         QTransform invMat = matrix.inverted(&invertible);
3038         if (!invertible)
3039             return;
3040
3041         QVarLengthArray<QFixedPoint> positions;
3042         QVarLengthArray<glyph_t> glyphs;
3043
3044         ti.fontEngine->getGlyphPositions(ti.glyphs, QTransform::fromTranslate(p.x(), p.y()),
3045                                          ti.flags, glyphs, positions);
3046         QPair<int, int> range = visibleGlyphRange(invMat.mapRect(clipBoundingRect()),
3047                                                   ti.fontEngine, glyphs.data(), positions.data(),
3048                                                   glyphs.size());
3049
3050         if (range.first >= range.second)
3051             return;
3052
3053         QStaticTextItem staticTextItem;
3054         staticTextItem.color = s->pen.color();
3055         staticTextItem.font = s->font;
3056         staticTextItem.setFontEngine(ti.fontEngine);
3057         staticTextItem.numGlyphs = range.second - range.first;
3058         staticTextItem.glyphs = glyphs.data() + range.first;
3059         staticTextItem.glyphPositions = positions.data() + range.first;
3060         QPaintEngineEx::drawStaticTextItem(&staticTextItem);
3061     } else {
3062         QPaintEngineEx::drawTextItem(p, ti);
3063     }
3064 }
3065
3066 /*!
3067     \reimp
3068 */
3069 void QRasterPaintEngine::drawPoints(const QPointF *points, int pointCount)
3070 {
3071     Q_D(QRasterPaintEngine);
3072     QRasterPaintEngineState *s = state();
3073
3074     ensurePen();
3075     if (!s->penData.blend)
3076         return;
3077
3078     if (!s->flags.fast_pen) {
3079         QPaintEngineEx::drawPoints(points, pointCount);
3080         return;
3081     }
3082
3083     QCosmeticStroker stroker(s, d->deviceRect);
3084     stroker.drawPoints(points, pointCount);
3085 }
3086
3087
3088 void QRasterPaintEngine::drawPoints(const QPoint *points, int pointCount)
3089 {
3090     Q_D(QRasterPaintEngine);
3091     QRasterPaintEngineState *s = state();
3092
3093     ensurePen();
3094     if (!s->penData.blend)
3095         return;
3096
3097     if (!s->flags.fast_pen) {
3098         QPaintEngineEx::drawPoints(points, pointCount);
3099         return;
3100     }
3101
3102     QCosmeticStroker stroker(s, d->deviceRect);
3103     stroker.drawPoints(points, pointCount);
3104 }
3105
3106 /*!
3107     \reimp
3108 */
3109 void QRasterPaintEngine::drawLines(const QLine *lines, int lineCount)
3110 {
3111 #ifdef QT_DEBUG_DRAW
3112     qDebug() << " - QRasterPaintEngine::drawLines(QLine*)" << lineCount;
3113 #endif
3114     Q_D(QRasterPaintEngine);
3115     QRasterPaintEngineState *s = state();
3116
3117     ensurePen();
3118     if (!s->penData.blend)
3119         return;
3120
3121     if (s->flags.fast_pen) {
3122         QCosmeticStroker stroker(s, d->deviceRect);
3123         for (int i=0; i<lineCount; ++i) {
3124             const QLine &l = lines[i];
3125             stroker.drawLine(l.p1(), l.p2());
3126         }
3127     } else {
3128         QPaintEngineEx::drawLines(lines, lineCount);
3129     }
3130 }
3131
3132 void QRasterPaintEnginePrivate::rasterizeLine_dashed(QLineF line,
3133                                                      qreal width,
3134                                                      int *dashIndex,
3135                                                      qreal *dashOffset,
3136                                                      bool *inDash)
3137 {
3138     Q_Q(QRasterPaintEngine);
3139     QRasterPaintEngineState *s = q->state();
3140
3141     const QPen &pen = s->lastPen;
3142     const bool squareCap = (pen.capStyle() == Qt::SquareCap);
3143     const QVector<qreal> pattern = pen.dashPattern();
3144
3145     qreal patternLength = 0;
3146     for (int i = 0; i < pattern.size(); ++i)
3147         patternLength += pattern.at(i);
3148
3149     if (patternLength <= 0)
3150         return;
3151
3152     qreal length = line.length();
3153     Q_ASSERT(length > 0);
3154     while (length > 0) {
3155         const bool rasterize = *inDash;
3156         qreal dash = (pattern.at(*dashIndex) - *dashOffset) * width;
3157         QLineF l = line;
3158
3159         if (dash >= length) {
3160             dash = length;
3161             *dashOffset += dash / width;
3162             length = 0;
3163         } else {
3164             *dashOffset = 0;
3165             *inDash = !(*inDash);
3166             if (++*dashIndex >= pattern.size())
3167                 *dashIndex = 0;
3168             length -= dash;
3169             l.setLength(dash);
3170             line.setP1(l.p2());
3171         }
3172
3173         if (rasterize && dash > 0)
3174             rasterizer->rasterizeLine(l.p1(), l.p2(), width / dash, squareCap);
3175     }
3176 }
3177
3178 /*!
3179     \reimp
3180 */
3181 void QRasterPaintEngine::drawLines(const QLineF *lines, int lineCount)
3182 {
3183 #ifdef QT_DEBUG_DRAW
3184     qDebug() << " - QRasterPaintEngine::drawLines(QLineF *)" << lineCount;
3185 #endif
3186     Q_D(QRasterPaintEngine);
3187     QRasterPaintEngineState *s = state();
3188
3189     ensurePen();
3190     if (!s->penData.blend)
3191         return;
3192     if (s->flags.fast_pen) {
3193         QCosmeticStroker stroker(s, d->deviceRect);
3194         for (int i=0; i<lineCount; ++i) {
3195             QLineF line = lines[i];
3196             stroker.drawLine(line.p1(), line.p2());
3197         }
3198     } else {
3199         QPaintEngineEx::drawLines(lines, lineCount);
3200     }
3201 }
3202
3203
3204 /*!
3205     \reimp
3206 */
3207 void QRasterPaintEngine::drawEllipse(const QRectF &rect)
3208 {
3209     Q_D(QRasterPaintEngine);
3210     QRasterPaintEngineState *s = state();
3211
3212     ensurePen();
3213     if (((qpen_style(s->lastPen) == Qt::SolidLine && s->flags.fast_pen)
3214            || (qpen_style(s->lastPen) == Qt::NoPen))
3215         && !s->flags.antialiased
3216         && qMax(rect.width(), rect.height()) < QT_RASTER_COORD_LIMIT
3217         && !rect.isEmpty()
3218         && s->matrix.type() <= QTransform::TxScale) // no shear
3219     {
3220         ensureBrush();
3221         const QRectF r = s->matrix.mapRect(rect);
3222         ProcessSpans penBlend = d->getPenFunc(r, &s->penData);
3223         ProcessSpans brushBlend = d->getBrushFunc(r, &s->brushData);
3224         const QRect brect = QRect(int(r.x()), int(r.y()),
3225                                   int_dim(r.x(), r.width()),
3226                                   int_dim(r.y(), r.height()));
3227         if (brect == r) {
3228             drawEllipse_midpoint_i(brect, d->deviceRect, penBlend, brushBlend,
3229                                    &s->penData, &s->brushData);
3230             return;
3231         }
3232     }
3233     QPaintEngineEx::drawEllipse(rect);
3234 }
3235
3236 /*!
3237     \internal
3238 */
3239
3240 #ifdef Q_OS_WIN
3241 /*!
3242     \internal
3243 */
3244 void QRasterPaintEngine::setDC(HDC hdc) {
3245     Q_D(QRasterPaintEngine);
3246     d->hdc = hdc;
3247 }
3248
3249 /*!
3250     \internal
3251 */
3252 HDC QRasterPaintEngine::getDC() const
3253 {
3254     Q_D(const QRasterPaintEngine);
3255     return d->hdc;
3256 }
3257
3258 /*!
3259     \internal
3260 */
3261 void QRasterPaintEngine::releaseDC(HDC) const
3262 {
3263 }
3264
3265 #endif
3266
3267 bool QRasterPaintEngine::supportsTransformations(QFontEngine *fontEngine) const
3268 {
3269     const QTransform &m = state()->matrix;
3270     return supportsTransformations(fontEngine, m);
3271 }
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
4729     Draws the first \a pointCount points in the buffer \a points
4730
4731     The default implementation converts the first \a pointCount QPoints in \a points
4732     to QPointFs and calls the floating point version of drawPoints.
4733 */
4734
4735 /*!
4736     \fn void QRasterPaintEngine::drawEllipse(const QRect &rect)
4737     \overload
4738
4739     Reimplement this function to draw the largest ellipse that can be
4740     contained within rectangle \a rect.
4741 */
4742
4743 #ifdef QT_DEBUG_DRAW
4744 void dumpClip(int width, int height, const QClipData *clip)
4745 {
4746     QImage clipImg(width, height, QImage::Format_ARGB32_Premultiplied);
4747     clipImg.fill(0xffff0000);
4748
4749     int x0 = width;
4750     int x1 = 0;
4751     int y0 = height;
4752     int y1 = 0;
4753
4754     ((QClipData *) clip)->spans(); // Force allocation of the spans structure...
4755
4756     for (int i = 0; i < clip->count; ++i) {
4757         const QSpan *span = ((QClipData *) clip)->spans() + i;
4758         for (int j = 0; j < span->len; ++j)
4759             clipImg.setPixel(span->x + j, span->y, 0xffffff00);
4760         x0 = qMin(x0, int(span->x));
4761         x1 = qMax(x1, int(span->x + span->len - 1));
4762
4763         y0 = qMin(y0, int(span->y));
4764         y1 = qMax(y1, int(span->y));
4765     }
4766
4767     static int counter = 0;
4768
4769     Q_ASSERT(y0 >= 0);
4770     Q_ASSERT(x0 >= 0);
4771     Q_ASSERT(y1 >= 0);
4772     Q_ASSERT(x1 >= 0);
4773
4774     fprintf(stderr,"clip %d: %d %d - %d %d\n", counter, x0, y0, x1, y1);
4775     clipImg.save(QString::fromLatin1("clip-%0.png").arg(counter++));
4776 }
4777 #endif
4778
4779
4780 QT_END_NAMESPACE