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