Improved performance of large text when parts are outside view.
[profile/ivi/qtbase.git] / src / gui / painting / qpaintengine_raster.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
6 **
7 ** This file is part of the QtGui module of the Qt Toolkit.
8 **
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 **
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 **
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
29 **
30 ** Other Usage
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
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 #if defined(Q_OS_WIN)
75 #  include <qt_windows.h>
76 #  include <qvarlengtharray.h>
77 #  include <private/qfontengine_p.h>
78 #endif
79
80 #if defined(Q_OS_WIN64)
81 #  include <malloc.h>
82 #endif
83 #include <limits.h>
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                 || (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 void QRasterPaintEngine::alphaPenBlt(const void* src, int bpl, int depth, int rx,int ry,int w,int h)
2472 {
2473     Q_D(QRasterPaintEngine);
2474     QRasterPaintEngineState *s = state();
2475
2476     if (!s->penData.blend)
2477         return;
2478
2479     QRasterBuffer *rb = d->rasterBuffer.data();
2480
2481     const QRect rect(rx, ry, w, h);
2482     const QClipData *clip = d->clip();
2483     bool unclipped = false;
2484     if (clip) {
2485         // inlined QRect::intersects
2486         const bool intersects = qMax(clip->xmin, rect.left()) <= qMin(clip->xmax - 1, rect.right())
2487                                 && qMax(clip->ymin, rect.top()) <= qMin(clip->ymax - 1, rect.bottom());
2488
2489         if (clip->hasRectClip) {
2490             unclipped = rx > clip->xmin
2491                         && rx + w < clip->xmax
2492                         && ry > clip->ymin
2493                         && ry + h < clip->ymax;
2494         }
2495
2496         if (!intersects)
2497             return;
2498     } else {
2499         // inlined QRect::intersects
2500         const bool intersects = qMax(0, rect.left()) <= qMin(rb->width() - 1, rect.right())
2501                                 && qMax(0, rect.top()) <= qMin(rb->height() - 1, rect.bottom());
2502         if (!intersects)
2503             return;
2504
2505         // inlined QRect::contains
2506         const bool contains = rect.left() >= 0 && rect.right() < rb->width()
2507                               && rect.top() >= 0 && rect.bottom() < rb->height();
2508
2509         unclipped = contains && d->isUnclipped_normalized(rect);
2510     }
2511
2512     ProcessSpans blend = unclipped ? s->penData.unclipped_blend : s->penData.blend;
2513     const uchar * scanline = static_cast<const uchar *>(src);
2514
2515     if (s->flags.fast_text) {
2516         if (unclipped) {
2517             if (depth == 1) {
2518                 if (s->penData.bitmapBlit) {
2519                     s->penData.bitmapBlit(rb, rx, ry, s->penData.solid.color,
2520                                           scanline, w, h, bpl);
2521                     return;
2522                 }
2523             } else if (depth == 8) {
2524                 if (s->penData.alphamapBlit) {
2525                     s->penData.alphamapBlit(rb, rx, ry, s->penData.solid.color,
2526                                             scanline, w, h, bpl, 0);
2527                     return;
2528                 }
2529             } else if (depth == 32) {
2530                 // (A)RGB Alpha mask where the alpha component is not used.
2531                 if (s->penData.alphaRGBBlit) {
2532                     s->penData.alphaRGBBlit(rb, rx, ry, s->penData.solid.color,
2533                                             (const uint *) scanline, w, h, bpl / 4, 0);
2534                     return;
2535                 }
2536             }
2537         } else if (d->deviceDepth == 32 && (depth == 8 || depth == 32)) {
2538             // (A)RGB Alpha mask where the alpha component is not used.
2539             if (!clip) {
2540                 int nx = qMax(0, rx);
2541                 int ny = qMax(0, ry);
2542
2543                 // Move scanline pointer to compensate for moved x and y
2544                 int xdiff = nx - rx;
2545                 int ydiff = ny - ry;
2546                 scanline += ydiff * bpl;
2547                 scanline += xdiff * (depth == 32 ? 4 : 1);
2548
2549                 w -= xdiff;
2550                 h -= ydiff;
2551
2552                 if (nx + w > d->rasterBuffer->width())
2553                     w = d->rasterBuffer->width() - nx;
2554                 if (ny + h > d->rasterBuffer->height())
2555                     h = d->rasterBuffer->height() - ny;
2556
2557                 rx = nx;
2558                 ry = ny;
2559             }
2560             if (depth == 8 && s->penData.alphamapBlit) {
2561                 s->penData.alphamapBlit(rb, rx, ry, s->penData.solid.color,
2562                                         scanline, w, h, bpl, clip);
2563             } else if (depth == 32 && s->penData.alphaRGBBlit) {
2564                 s->penData.alphaRGBBlit(rb, rx, ry, s->penData.solid.color,
2565                                         (const uint *) scanline, w, h, bpl / 4, clip);
2566             }
2567             return;
2568         }
2569     }
2570
2571     int x0 = 0;
2572     if (rx < 0) {
2573         x0 = -rx;
2574         w -= x0;
2575     }
2576
2577     int y0 = 0;
2578     if (ry < 0) {
2579         y0 = -ry;
2580         scanline += bpl * y0;
2581         h -= y0;
2582     }
2583
2584     w = qMin(w, rb->width() - qMax(0, rx));
2585     h = qMin(h, rb->height() - qMax(0, ry));
2586
2587     if (w <= 0 || h <= 0)
2588         return;
2589
2590     const int NSPANS = 256;
2591     QSpan spans[NSPANS];
2592     int current = 0;
2593
2594     const int x1 = x0 + w;
2595     const int y1 = y0 + h;
2596
2597     if (depth == 1) {
2598         for (int y = y0; y < y1; ++y) {
2599             for (int x = x0; x < x1; ) {
2600                 if (!monoVal(scanline, x)) {
2601                     ++x;
2602                     continue;
2603                 }
2604
2605                 if (current == NSPANS) {
2606                     blend(current, spans, &s->penData);
2607                     current = 0;
2608                 }
2609                 spans[current].x = x + rx;
2610                 spans[current].y = y + ry;
2611                 spans[current].coverage = 255;
2612                 int len = 1;
2613                 ++x;
2614                 // extend span until we find a different one.
2615                 while (x < x1 && monoVal(scanline, x)) {
2616                     ++x;
2617                     ++len;
2618                 }
2619                 spans[current].len = len;
2620                 ++current;
2621             }
2622             scanline += bpl;
2623         }
2624     } else if (depth == 8) {
2625         for (int y = y0; y < y1; ++y) {
2626             for (int x = x0; x < x1; ) {
2627                 // Skip those with 0 coverage
2628                 if (scanline[x] == 0) {
2629                     ++x;
2630                     continue;
2631                 }
2632
2633                 if (current == NSPANS) {
2634                     blend(current, spans, &s->penData);
2635                     current = 0;
2636                 }
2637                 int coverage = scanline[x];
2638                 spans[current].x = x + rx;
2639                 spans[current].y = y + ry;
2640                 spans[current].coverage = coverage;
2641                 int len = 1;
2642                 ++x;
2643
2644                 // extend span until we find a different one.
2645                 while (x < x1 && scanline[x] == coverage) {
2646                     ++x;
2647                     ++len;
2648                 }
2649                 spans[current].len = len;
2650                 ++current;
2651             }
2652             scanline += bpl;
2653         }
2654     } else { // 32-bit alpha...
2655         uint *sl = (uint *) src;
2656         for (int y = y0; y < y1; ++y) {
2657             for (int x = x0; x < x1; ) {
2658                 // Skip those with 0 coverage
2659                 if ((sl[x] & 0x00ffffff) == 0) {
2660                     ++x;
2661                     continue;
2662                 }
2663
2664                 if (current == NSPANS) {
2665                     blend(current, spans, &s->penData);
2666                     current = 0;
2667                 }
2668                 uint rgbCoverage = sl[x];
2669                 int coverage = qGreen(rgbCoverage);
2670                 spans[current].x = x + rx;
2671                 spans[current].y = y + ry;
2672                 spans[current].coverage = coverage;
2673                 int len = 1;
2674                 ++x;
2675
2676                 // extend span until we find a different one.
2677                 while (x < x1 && sl[x] == rgbCoverage) {
2678                     ++x;
2679                     ++len;
2680                 }
2681                 spans[current].len = len;
2682                 ++current;
2683             }
2684             sl += bpl / sizeof(uint);
2685         }
2686     }
2687 //     qDebug() << "alphaPenBlt: num spans=" << current
2688 //              << "span:" << spans->x << spans->y << spans->len << spans->coverage;
2689         // Call span func for current set of spans.
2690     if (current != 0)
2691         blend(current, spans, &s->penData);
2692 }
2693
2694 bool QRasterPaintEngine::drawCachedGlyphs(int numGlyphs, const glyph_t *glyphs,
2695                                           const QFixedPoint *positions, QFontEngine *fontEngine)
2696 {
2697     Q_D(QRasterPaintEngine);
2698     QRasterPaintEngineState *s = state();
2699
2700     if (fontEngine->hasInternalCaching()) {
2701         QFontEngine::GlyphFormat neededFormat =
2702             painter()->device()->devType() == QInternal::Widget
2703             ? QFontEngine::Format_None
2704             : QFontEngine::Format_A8;
2705
2706         if (d_func()->mono_surface) // alphaPenBlt can handle mono, too
2707             neededFormat = QFontEngine::Format_Mono;
2708
2709         for (int i = 0; i < numGlyphs; i++) {
2710             QFixed spp = fontEngine->subPixelPositionForX(positions[i].x);
2711
2712             QPoint offset;
2713             QImage *alphaMap = fontEngine->lockedAlphaMapForGlyph(glyphs[i], spp, neededFormat, s->matrix,
2714                                                                   &offset);
2715             if (alphaMap == 0 || alphaMap->isNull())
2716                 continue;
2717
2718             alphaPenBlt(alphaMap->bits(), alphaMap->bytesPerLine(), alphaMap->depth(),
2719                         qFloor(positions[i].x) + offset.x(),
2720                         qFloor(positions[i].y) + offset.y(),
2721                         alphaMap->width(), alphaMap->height());
2722
2723             fontEngine->unlockAlphaMapForGlyph();
2724         }
2725
2726     } else {
2727         QFontEngineGlyphCache::Type glyphType = fontEngine->glyphFormat >= 0 ? QFontEngineGlyphCache::Type(fontEngine->glyphFormat) : d->glyphCacheType;
2728
2729         QImageTextureGlyphCache *cache =
2730             static_cast<QImageTextureGlyphCache *>(fontEngine->glyphCache(0, glyphType, s->matrix));
2731         if (!cache) {
2732             cache = new QImageTextureGlyphCache(glyphType, s->matrix);
2733             fontEngine->setGlyphCache(0, cache);
2734         }
2735
2736         cache->populate(fontEngine, numGlyphs, glyphs, positions);
2737         cache->fillInPendingGlyphs();
2738
2739         const QImage &image = cache->image();
2740         int bpl = image.bytesPerLine();
2741
2742         int depth = image.depth();
2743         int rightShift = 0;
2744         int leftShift = 0;
2745         if (depth == 32)
2746             leftShift = 2; // multiply by 4
2747         else if (depth == 1)
2748             rightShift = 3; // divide by 8
2749
2750         int margin = cache->glyphMargin();
2751         const QFixed offs = QFixed::fromReal(aliasedCoordinateDelta);
2752         const uchar *bits = image.bits();
2753         for (int i=0; i<numGlyphs; ++i) {
2754
2755             QFixed subPixelPosition = fontEngine->subPixelPositionForX(positions[i].x);
2756             QTextureGlyphCache::GlyphAndSubPixelPosition glyph(glyphs[i], subPixelPosition);
2757             const QTextureGlyphCache::Coord &c = cache->coords[glyph];
2758             if (c.isNull())
2759                 continue;
2760
2761             int x = qFloor(positions[i].x) + c.baseLineX - margin;
2762             int y = qFloor(positions[i].y + offs) - c.baseLineY - margin;
2763
2764             // printf("drawing [%d %d %d %d] baseline [%d %d], glyph: %d, to: %d %d, pos: %d %d\n",
2765             //        c.x, c.y,
2766             //        c.w, c.h,
2767             //        c.baseLineX, c.baseLineY,
2768             //        glyphs[i],
2769             //        x, y,
2770             //        positions[i].x.toInt(), positions[i].y.toInt());
2771
2772             alphaPenBlt(bits + ((c.x << leftShift) >> rightShift) + c.y * bpl, bpl, depth, x, y, c.w, c.h);
2773         }
2774     }
2775     return true;
2776 }
2777
2778
2779 /*!
2780  * Returns true if the rectangle is completely within the current clip
2781  * state of the paint engine.
2782  */
2783 bool QRasterPaintEnginePrivate::isUnclipped_normalized(const QRect &r) const
2784 {
2785     const QClipData *cl = clip();
2786     if (!cl) {
2787         // inline contains() for performance (we know the rects are normalized)
2788         const QRect &r1 = deviceRect;
2789         return (r.left() >= r1.left() && r.right() <= r1.right()
2790                 && r.top() >= r1.top() && r.bottom() <= r1.bottom());
2791     }
2792
2793
2794     if (cl->hasRectClip) {
2795         // currently all painting functions clips to deviceRect internally
2796         if (cl->clipRect == deviceRect)
2797             return true;
2798
2799         // inline contains() for performance (we know the rects are normalized)
2800         const QRect &r1 = cl->clipRect;
2801         return (r.left() >= r1.left() && r.right() <= r1.right()
2802                 && r.top() >= r1.top() && r.bottom() <= r1.bottom());
2803     } else {
2804         return qt_region_strictContains(cl->clipRegion, r);
2805     }
2806 }
2807
2808 bool QRasterPaintEnginePrivate::isUnclipped(const QRect &rect,
2809                                             int penWidth) const
2810 {
2811     Q_Q(const QRasterPaintEngine);
2812     const QRasterPaintEngineState *s = q->state();
2813     const QClipData *cl = clip();
2814     if (!cl) {
2815         QRect r = rect.normalized();
2816         // inline contains() for performance (we know the rects are normalized)
2817         const QRect &r1 = deviceRect;
2818         return (r.left() >= r1.left() && r.right() <= r1.right()
2819                 && r.top() >= r1.top() && r.bottom() <= r1.bottom());
2820     }
2821
2822
2823     // currently all painting functions that call this function clip to deviceRect internally
2824     if (cl->hasRectClip && cl->clipRect == deviceRect)
2825         return true;
2826
2827     if (s->flags.antialiased)
2828         ++penWidth;
2829
2830     QRect r = rect.normalized();
2831     if (penWidth > 0) {
2832         r.setX(r.x() - penWidth);
2833         r.setY(r.y() - penWidth);
2834         r.setWidth(r.width() + 2 * penWidth);
2835         r.setHeight(r.height() + 2 * penWidth);
2836     }
2837
2838     if (cl->hasRectClip) {
2839         // inline contains() for performance (we know the rects are normalized)
2840         const QRect &r1 = cl->clipRect;
2841         return (r.left() >= r1.left() && r.right() <= r1.right()
2842                 && r.top() >= r1.top() && r.bottom() <= r1.bottom());
2843     } else {
2844         return qt_region_strictContains(cl->clipRegion, r);
2845     }
2846 }
2847
2848 inline bool QRasterPaintEnginePrivate::isUnclipped(const QRectF &rect,
2849                                                    int penWidth) const
2850 {
2851     return isUnclipped(rect.normalized().toAlignedRect(), penWidth);
2852 }
2853
2854 inline ProcessSpans
2855 QRasterPaintEnginePrivate::getBrushFunc(const QRect &rect,
2856                                         const QSpanData *data) const
2857 {
2858     return isUnclipped(rect, 0) ? data->unclipped_blend : data->blend;
2859 }
2860
2861 inline ProcessSpans
2862 QRasterPaintEnginePrivate::getBrushFunc(const QRectF &rect,
2863                                         const QSpanData *data) const
2864 {
2865     return isUnclipped(rect, 0) ? data->unclipped_blend : data->blend;
2866 }
2867
2868 inline ProcessSpans
2869 QRasterPaintEnginePrivate::getPenFunc(const QRectF &rect,
2870                                       const QSpanData *data) const
2871 {
2872     Q_Q(const QRasterPaintEngine);
2873     const QRasterPaintEngineState *s = q->state();
2874
2875     if (!s->flags.fast_pen && s->matrix.type() > QTransform::TxTranslate)
2876         return data->blend;
2877     const int penWidth = s->flags.fast_pen ? 1 : qCeil(s->lastPen.widthF());
2878     return isUnclipped(rect, penWidth) ? data->unclipped_blend : data->blend;
2879 }
2880
2881 static QPair<int, int> visibleGlyphRange(const QRectF &clip, QFontEngine *fontEngine,
2882                                          glyph_t *glyphs, QFixedPoint *positions, int numGlyphs)
2883 {
2884     QFixed clipLeft = QFixed::fromReal(clip.left());
2885     QFixed clipRight = QFixed::fromReal(clip.right());
2886     QFixed clipTop = QFixed::fromReal(clip.top());
2887     QFixed clipBottom = QFixed::fromReal(clip.bottom());
2888
2889     int first = 0;
2890     while (first < numGlyphs) {
2891         glyph_metrics_t metrics = fontEngine->boundingBox(glyphs[first]);
2892         QFixed left = metrics.x + positions[first].x;
2893         QFixed top = metrics.y + positions[first].y;
2894         QFixed right = left + metrics.width;
2895         QFixed bottom = top + metrics.height;
2896         if (left < clipRight && right > clipLeft && top < clipBottom && bottom > clipTop)
2897             break;
2898         ++first;
2899     }
2900     int last = numGlyphs - 1;
2901     while (last > first) {
2902         glyph_metrics_t metrics = fontEngine->boundingBox(glyphs[last]);
2903         QFixed left = metrics.x + positions[last].x;
2904         QFixed top = metrics.y + positions[last].y;
2905         QFixed right = left + metrics.width;
2906         QFixed bottom = top + metrics.height;
2907         if (left < clipRight && right > clipLeft && top < clipBottom && bottom > clipTop)
2908             break;
2909         --last;
2910     }
2911     return QPair<int, int>(first, last + 1);
2912 }
2913
2914 /*!
2915    \reimp
2916 */
2917 void QRasterPaintEngine::drawStaticTextItem(QStaticTextItem *textItem)
2918 {
2919     if (textItem->numGlyphs == 0)
2920         return;
2921
2922     ensurePen();
2923     ensureRasterState();
2924
2925     QFontEngine *fontEngine = textItem->fontEngine();
2926     if (shouldDrawCachedGlyphs(fontEngine->fontDef.pixelSize, state()->matrix)) {
2927         drawCachedGlyphs(textItem->numGlyphs, textItem->glyphs, textItem->glyphPositions,
2928                          fontEngine);
2929     } else if (state()->matrix.type() < QTransform::TxProject) {
2930         bool invertible;
2931         QTransform invMat = state()->matrix.inverted(&invertible);
2932         if (!invertible)
2933             return;
2934
2935         QPair<int, int> range = visibleGlyphRange(invMat.mapRect(clipBoundingRect()),
2936                                                   textItem->fontEngine(), textItem->glyphs,
2937                                                   textItem->glyphPositions, textItem->numGlyphs);
2938         QStaticTextItem copy = *textItem;
2939         copy.glyphs += range.first;
2940         copy.glyphPositions += range.first;
2941         copy.numGlyphs = range.second - range.first;
2942         QPaintEngineEx::drawStaticTextItem(&copy);
2943     } else {
2944         QPaintEngineEx::drawStaticTextItem(textItem);
2945     }
2946 }
2947
2948 /*!
2949     \reimp
2950 */
2951 void QRasterPaintEngine::drawTextItem(const QPointF &p, const QTextItem &textItem)
2952 {
2953     const QTextItemInt &ti = static_cast<const QTextItemInt &>(textItem);
2954
2955 #ifdef QT_DEBUG_DRAW
2956     Q_D(QRasterPaintEngine);
2957     fprintf(stderr," - QRasterPaintEngine::drawTextItem(), (%.2f,%.2f), string=%s ct=%d\n",
2958            p.x(), p.y(), QString::fromRawData(ti.chars, ti.num_chars).toLatin1().data(),
2959            d->glyphCacheType);
2960 #endif
2961
2962     if (ti.glyphs.numGlyphs == 0)
2963         return;
2964     ensurePen();
2965     ensureRasterState();
2966
2967     QRasterPaintEngineState *s = state();
2968     QTransform matrix = s->matrix;
2969
2970     if (!supportsTransformations(ti.fontEngine)) {
2971         QVarLengthArray<QFixedPoint> positions;
2972         QVarLengthArray<glyph_t> glyphs;
2973
2974         matrix.translate(p.x(), p.y());
2975         ti.fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions);
2976
2977         drawCachedGlyphs(glyphs.size(), glyphs.constData(), positions.constData(), ti.fontEngine);
2978     } else if (matrix.type() < QTransform::TxProject) {
2979         bool invertible;
2980         QTransform invMat = matrix.inverted(&invertible);
2981         if (!invertible)
2982             return;
2983
2984         QVarLengthArray<QFixedPoint> positions;
2985         QVarLengthArray<glyph_t> glyphs;
2986
2987         ti.fontEngine->getGlyphPositions(ti.glyphs, QTransform::fromTranslate(p.x(), p.y()),
2988                                          ti.flags, glyphs, positions);
2989         QPair<int, int> range = visibleGlyphRange(invMat.mapRect(clipBoundingRect()),
2990                                                   ti.fontEngine, glyphs.data(), positions.data(),
2991                                                   glyphs.size());
2992
2993         if (range.first >= range.second)
2994             return;
2995
2996         QStaticTextItem staticTextItem;
2997         staticTextItem.color = s->pen.color();
2998         staticTextItem.font = s->font;
2999         staticTextItem.setFontEngine(ti.fontEngine);
3000         staticTextItem.numGlyphs = range.second - range.first;
3001         staticTextItem.glyphs = glyphs.data() + range.first;
3002         staticTextItem.glyphPositions = positions.data() + range.first;
3003         QPaintEngineEx::drawStaticTextItem(&staticTextItem);
3004     } else {
3005         QPaintEngineEx::drawTextItem(p, ti);
3006     }
3007 }
3008
3009 /*!
3010     \reimp
3011 */
3012 void QRasterPaintEngine::drawPoints(const QPointF *points, int pointCount)
3013 {
3014     Q_D(QRasterPaintEngine);
3015     QRasterPaintEngineState *s = state();
3016
3017     ensurePen();
3018     if (!s->penData.blend)
3019         return;
3020
3021     if (!s->flags.fast_pen) {
3022         QPaintEngineEx::drawPoints(points, pointCount);
3023         return;
3024     }
3025
3026     QCosmeticStroker stroker(s, d->deviceRect);
3027     stroker.drawPoints(points, pointCount);
3028 }
3029
3030
3031 void QRasterPaintEngine::drawPoints(const QPoint *points, int pointCount)
3032 {
3033     Q_D(QRasterPaintEngine);
3034     QRasterPaintEngineState *s = state();
3035
3036     ensurePen();
3037     if (!s->penData.blend)
3038         return;
3039
3040     if (!s->flags.fast_pen) {
3041         QPaintEngineEx::drawPoints(points, pointCount);
3042         return;
3043     }
3044
3045     QCosmeticStroker stroker(s, d->deviceRect);
3046     stroker.drawPoints(points, pointCount);
3047 }
3048
3049 /*!
3050     \reimp
3051 */
3052 void QRasterPaintEngine::drawLines(const QLine *lines, int lineCount)
3053 {
3054 #ifdef QT_DEBUG_DRAW
3055     qDebug() << " - QRasterPaintEngine::drawLines(QLine*)" << lineCount;
3056 #endif
3057     Q_D(QRasterPaintEngine);
3058     QRasterPaintEngineState *s = state();
3059
3060     ensurePen();
3061     if (!s->penData.blend)
3062         return;
3063
3064     if (s->flags.fast_pen) {
3065         QCosmeticStroker stroker(s, d->deviceRect);
3066         for (int i=0; i<lineCount; ++i) {
3067             const QLine &l = lines[i];
3068             stroker.drawLine(l.p1(), l.p2());
3069         }
3070     } else {
3071         QPaintEngineEx::drawLines(lines, lineCount);
3072     }
3073 }
3074
3075 void QRasterPaintEnginePrivate::rasterizeLine_dashed(QLineF line,
3076                                                      qreal width,
3077                                                      int *dashIndex,
3078                                                      qreal *dashOffset,
3079                                                      bool *inDash)
3080 {
3081     Q_Q(QRasterPaintEngine);
3082     QRasterPaintEngineState *s = q->state();
3083
3084     const QPen &pen = s->lastPen;
3085     const bool squareCap = (pen.capStyle() == Qt::SquareCap);
3086     const QVector<qreal> pattern = pen.dashPattern();
3087
3088     qreal patternLength = 0;
3089     for (int i = 0; i < pattern.size(); ++i)
3090         patternLength += pattern.at(i);
3091
3092     if (patternLength <= 0)
3093         return;
3094
3095     qreal length = line.length();
3096     Q_ASSERT(length > 0);
3097     while (length > 0) {
3098         const bool rasterize = *inDash;
3099         qreal dash = (pattern.at(*dashIndex) - *dashOffset) * width;
3100         QLineF l = line;
3101
3102         if (dash >= length) {
3103             dash = length;
3104             *dashOffset += dash / width;
3105             length = 0;
3106         } else {
3107             *dashOffset = 0;
3108             *inDash = !(*inDash);
3109             if (++*dashIndex >= pattern.size())
3110                 *dashIndex = 0;
3111             length -= dash;
3112             l.setLength(dash);
3113             line.setP1(l.p2());
3114         }
3115
3116         if (rasterize && dash > 0)
3117             rasterizer->rasterizeLine(l.p1(), l.p2(), width / dash, squareCap);
3118     }
3119 }
3120
3121 /*!
3122     \reimp
3123 */
3124 void QRasterPaintEngine::drawLines(const QLineF *lines, int lineCount)
3125 {
3126 #ifdef QT_DEBUG_DRAW
3127     qDebug() << " - QRasterPaintEngine::drawLines(QLineF *)" << lineCount;
3128 #endif
3129     Q_D(QRasterPaintEngine);
3130     QRasterPaintEngineState *s = state();
3131
3132     ensurePen();
3133     if (!s->penData.blend)
3134         return;
3135     if (s->flags.fast_pen) {
3136         QCosmeticStroker stroker(s, d->deviceRect);
3137         for (int i=0; i<lineCount; ++i) {
3138             QLineF line = lines[i];
3139             stroker.drawLine(line.p1(), line.p2());
3140         }
3141     } else {
3142         QPaintEngineEx::drawLines(lines, lineCount);
3143     }
3144 }
3145
3146
3147 /*!
3148     \reimp
3149 */
3150 void QRasterPaintEngine::drawEllipse(const QRectF &rect)
3151 {
3152     Q_D(QRasterPaintEngine);
3153     QRasterPaintEngineState *s = state();
3154
3155     ensurePen();
3156     if (((qpen_style(s->lastPen) == Qt::SolidLine && s->flags.fast_pen)
3157            || (qpen_style(s->lastPen) == Qt::NoPen))
3158         && !s->flags.antialiased
3159         && qMax(rect.width(), rect.height()) < QT_RASTER_COORD_LIMIT
3160         && !rect.isEmpty()
3161         && s->matrix.type() <= QTransform::TxScale) // no shear
3162     {
3163         ensureBrush();
3164         const QRectF r = s->matrix.mapRect(rect);
3165         ProcessSpans penBlend = d->getPenFunc(r, &s->penData);
3166         ProcessSpans brushBlend = d->getBrushFunc(r, &s->brushData);
3167         const QRect brect = QRect(int(r.x()), int(r.y()),
3168                                   int_dim(r.x(), r.width()),
3169                                   int_dim(r.y(), r.height()));
3170         if (brect == r) {
3171             drawEllipse_midpoint_i(brect, d->deviceRect, penBlend, brushBlend,
3172                                    &s->penData, &s->brushData);
3173             return;
3174         }
3175     }
3176     QPaintEngineEx::drawEllipse(rect);
3177 }
3178
3179 /*!
3180     \internal
3181 */
3182
3183 #ifdef Q_OS_WIN
3184 /*!
3185     \internal
3186 */
3187 void QRasterPaintEngine::setDC(HDC hdc) {
3188     Q_D(QRasterPaintEngine);
3189     d->hdc = hdc;
3190 }
3191
3192 /*!
3193     \internal
3194 */
3195 HDC QRasterPaintEngine::getDC() const
3196 {
3197     Q_D(const QRasterPaintEngine);
3198     return d->hdc;
3199 }
3200
3201 /*!
3202     \internal
3203 */
3204 void QRasterPaintEngine::releaseDC(HDC) const
3205 {
3206 }
3207
3208 #endif
3209
3210 bool QRasterPaintEngine::supportsTransformations(const QFontEngine *fontEngine) const
3211 {
3212     const QTransform &m = state()->matrix;
3213     return supportsTransformations(fontEngine->fontDef.pixelSize, m);
3214 }
3215
3216 bool QRasterPaintEngine::supportsTransformations(qreal pixelSize, const QTransform &m) const
3217 {
3218     if (m.type() >= QTransform::TxProject)
3219         return true;
3220
3221     return !shouldDrawCachedGlyphs(pixelSize, m);
3222 }
3223
3224 /*!
3225     \internal
3226 */
3227 QPoint QRasterPaintEngine::coordinateOffset() const
3228 {
3229     return QPoint(0, 0);
3230 }
3231
3232 void QRasterPaintEngine::drawBitmap(const QPointF &pos, const QImage &image, QSpanData *fg)
3233 {
3234     Q_ASSERT(fg);
3235     if (!fg->blend)
3236         return;
3237     Q_D(QRasterPaintEngine);
3238
3239     Q_ASSERT(image.depth() == 1);
3240
3241     const int spanCount = 256;
3242     QT_FT_Span spans[spanCount];
3243     int n = 0;
3244
3245     // Boundaries
3246     int w = image.width();
3247     int h = image.height();
3248     int ymax = qMin(qRound(pos.y() + h), d->rasterBuffer->height());
3249     int ymin = qMax(qRound(pos.y()), 0);
3250     int xmax = qMin(qRound(pos.x() + w), d->rasterBuffer->width());
3251     int xmin = qMax(qRound(pos.x()), 0);
3252
3253     int x_offset = xmin - qRound(pos.x());
3254
3255     QImage::Format format = image.format();
3256     for (int y = ymin; y < ymax; ++y) {
3257         const uchar *src = image.scanLine(y - qRound(pos.y()));
3258         if (format == QImage::Format_MonoLSB) {
3259             for (int x = 0; x < xmax - xmin; ++x) {
3260                 int src_x = x + x_offset;
3261                 uchar pixel = src[src_x >> 3];
3262                 if (!pixel) {
3263                     x += 7 - (src_x%8);
3264                     continue;
3265                 }
3266                 if (pixel & (0x1 << (src_x & 7))) {
3267                     spans[n].x = xmin + x;
3268                     spans[n].y = y;
3269                     spans[n].coverage = 255;
3270                     int len = 1;
3271                     while (src_x+1 < w && src[(src_x+1) >> 3] & (0x1 << ((src_x+1) & 7))) {
3272                         ++src_x;
3273                         ++len;
3274                     }
3275                     spans[n].len = ((len + spans[n].x) > xmax) ? (xmax - spans[n].x) : len;
3276                     x += len;
3277                     ++n;
3278                     if (n == spanCount) {
3279                         fg->blend(n, spans, fg);
3280                         n = 0;
3281                     }
3282                 }
3283             }
3284         } else {
3285             for (int x = 0; x < xmax - xmin; ++x) {
3286                 int src_x = x + x_offset;
3287                 uchar pixel = src[src_x >> 3];
3288                 if (!pixel) {
3289                     x += 7 - (src_x%8);
3290                     continue;
3291                 }
3292                 if (pixel & (0x80 >> (x & 7))) {
3293                     spans[n].x = xmin + x;
3294                     spans[n].y = y;
3295                     spans[n].coverage = 255;
3296                     int len = 1;
3297                     while (src_x+1 < w && src[(src_x+1) >> 3] & (0x80 >> ((src_x+1) & 7))) {
3298                         ++src_x;
3299                         ++len;
3300                     }
3301                     spans[n].len = ((len + spans[n].x) > xmax) ? (xmax - spans[n].x) : len;
3302                     x += len;
3303                     ++n;
3304                     if (n == spanCount) {
3305                         fg->blend(n, spans, fg);
3306                         n = 0;
3307                     }
3308                 }
3309             }
3310         }
3311     }
3312     if (n) {
3313         fg->blend(n, spans, fg);
3314         n = 0;
3315     }
3316 }
3317
3318 /*!
3319     \enum QRasterPaintEngine::ClipType
3320     \internal
3321
3322     \value RectClip Indicates that the currently set clip is a single rectangle.
3323     \value ComplexClip Indicates that the currently set clip is a combination of several shapes.
3324 */
3325
3326 /*!
3327     \internal
3328     Returns the type of the clip currently set.
3329 */
3330 QRasterPaintEngine::ClipType QRasterPaintEngine::clipType() const
3331 {
3332     Q_D(const QRasterPaintEngine);
3333
3334     const QClipData *clip = d->clip();
3335     if (!clip || clip->hasRectClip)
3336         return RectClip;
3337     else
3338         return ComplexClip;
3339 }
3340
3341 /*!
3342     \internal
3343     Returns the bounding rect of the currently set clip.
3344 */
3345 QRect QRasterPaintEngine::clipBoundingRect() const
3346 {
3347     Q_D(const QRasterPaintEngine);
3348
3349     const QClipData *clip = d->clip();
3350
3351     if (!clip)
3352         return d->deviceRect;
3353
3354     if (clip->hasRectClip)
3355         return clip->clipRect;
3356
3357     return QRect(clip->xmin, clip->ymin, clip->xmax - clip->xmin, clip->ymax - clip->ymin);
3358 }
3359
3360 void QRasterPaintEnginePrivate::initializeRasterizer(QSpanData *data)
3361 {
3362     Q_Q(QRasterPaintEngine);
3363     QRasterPaintEngineState *s = q->state();
3364
3365     rasterizer->setAntialiased(s->flags.antialiased);
3366
3367     QRect clipRect(deviceRect);
3368     ProcessSpans blend;
3369     // ### get from optimized rectbased QClipData
3370
3371     const QClipData *c = clip();
3372     if (c) {
3373         const QRect r(QPoint(c->xmin, c->ymin),
3374                       QSize(c->xmax - c->xmin, c->ymax - c->ymin));
3375         clipRect = clipRect.intersected(r);
3376         blend = data->blend;
3377     } else {
3378         blend = data->unclipped_blend;
3379     }
3380
3381     rasterizer->setClipRect(clipRect);
3382     rasterizer->initialize(blend, data);
3383 }
3384
3385 void QRasterPaintEnginePrivate::rasterize(QT_FT_Outline *outline,
3386                                           ProcessSpans callback,
3387                                           QSpanData *spanData, QRasterBuffer *rasterBuffer)
3388 {
3389     if (!callback || !outline)
3390         return;
3391
3392     Q_Q(QRasterPaintEngine);
3393     QRasterPaintEngineState *s = q->state();
3394
3395     if (!s->flags.antialiased) {
3396         initializeRasterizer(spanData);
3397
3398         const Qt::FillRule fillRule = outline->flags == QT_FT_OUTLINE_NONE
3399                                       ? Qt::WindingFill
3400                                       : Qt::OddEvenFill;
3401
3402         rasterizer->rasterize(outline, fillRule);
3403         return;
3404     }
3405
3406     rasterize(outline, callback, (void *)spanData, rasterBuffer);
3407 }
3408
3409 extern "C" {
3410     int q_gray_rendered_spans(QT_FT_Raster raster);
3411 }
3412
3413 static inline uchar *alignAddress(uchar *address, quintptr alignmentMask)
3414 {
3415     return (uchar *)(((quintptr)address + alignmentMask) & ~alignmentMask);
3416 }
3417
3418 void QRasterPaintEnginePrivate::rasterize(QT_FT_Outline *outline,
3419                                           ProcessSpans callback,
3420                                           void *userData, QRasterBuffer *)
3421 {
3422     if (!callback || !outline)
3423         return;
3424
3425     Q_Q(QRasterPaintEngine);
3426     QRasterPaintEngineState *s = q->state();
3427
3428     if (!s->flags.antialiased) {
3429         rasterizer->setAntialiased(s->flags.antialiased);
3430         rasterizer->setClipRect(deviceRect);
3431         rasterizer->initialize(callback, userData);
3432
3433         const Qt::FillRule fillRule = outline->flags == QT_FT_OUTLINE_NONE
3434                                       ? Qt::WindingFill
3435                                       : Qt::OddEvenFill;
3436
3437         rasterizer->rasterize(outline, fillRule);
3438         return;
3439     }
3440
3441     // Initial size for raster pool is MINIMUM_POOL_SIZE so as to
3442     // minimize memory reallocations. However if initial size for
3443     // raster pool is changed for lower value, reallocations will
3444     // occur normally.
3445     int rasterPoolSize = MINIMUM_POOL_SIZE;
3446     uchar rasterPoolOnStack[MINIMUM_POOL_SIZE + 0xf];
3447     uchar *rasterPoolBase = alignAddress(rasterPoolOnStack, 0xf);
3448     uchar *rasterPoolOnHeap = 0;
3449
3450     qt_ft_grays_raster.raster_reset(*grayRaster.data(), rasterPoolBase, rasterPoolSize);
3451
3452     void *data = userData;
3453
3454     QT_FT_BBox clip_box = { deviceRect.x(),
3455                             deviceRect.y(),
3456                             deviceRect.x() + deviceRect.width(),
3457                             deviceRect.y() + deviceRect.height() };
3458
3459     QT_FT_Raster_Params rasterParams;
3460     rasterParams.target = 0;
3461     rasterParams.source = outline;
3462     rasterParams.flags = QT_FT_RASTER_FLAG_CLIP;
3463     rasterParams.gray_spans = 0;
3464     rasterParams.black_spans = 0;
3465     rasterParams.bit_test = 0;
3466     rasterParams.bit_set = 0;
3467     rasterParams.user = data;
3468     rasterParams.clip_box = clip_box;
3469
3470     bool done = false;
3471     int error;
3472
3473     int rendered_spans = 0;
3474
3475     while (!done) {
3476
3477         rasterParams.flags |= (QT_FT_RASTER_FLAG_AA | QT_FT_RASTER_FLAG_DIRECT);
3478         rasterParams.gray_spans = callback;
3479         rasterParams.skip_spans = rendered_spans;
3480         error = qt_ft_grays_raster.raster_render(*grayRaster.data(), &rasterParams);
3481
3482         // Out of memory, reallocate some more and try again...
3483         if (error == -6) { // ErrRaster_OutOfMemory from qgrayraster.c
3484             rasterPoolSize *= 2;
3485             if (rasterPoolSize > 1024 * 1024) {
3486                 qWarning("QPainter: Rasterization of primitive failed");
3487                 break;
3488             }
3489
3490             rendered_spans += q_gray_rendered_spans(*grayRaster.data());
3491
3492             free(rasterPoolOnHeap);
3493             rasterPoolOnHeap = (uchar *)malloc(rasterPoolSize + 0xf);
3494
3495             Q_CHECK_PTR(rasterPoolOnHeap); // note: we just freed the old rasterPoolBase. I hope it's not fatal.
3496
3497             rasterPoolBase = alignAddress(rasterPoolOnHeap, 0xf);
3498
3499             qt_ft_grays_raster.raster_done(*grayRaster.data());
3500             qt_ft_grays_raster.raster_new(grayRaster.data());
3501             qt_ft_grays_raster.raster_reset(*grayRaster.data(), rasterPoolBase, rasterPoolSize);
3502         } else {
3503             done = true;
3504         }
3505     }
3506
3507     free(rasterPoolOnHeap);
3508 }
3509
3510 void QRasterPaintEnginePrivate::recalculateFastImages()
3511 {
3512     Q_Q(QRasterPaintEngine);
3513     QRasterPaintEngineState *s = q->state();
3514
3515     s->flags.fast_images = !(s->renderHints & QPainter::SmoothPixmapTransform)
3516                            && s->matrix.type() <= QTransform::TxShear;
3517 }
3518
3519 bool QRasterPaintEnginePrivate::canUseFastImageBlending(QPainter::CompositionMode mode, const QImage &image) const
3520 {
3521     Q_Q(const QRasterPaintEngine);
3522     const QRasterPaintEngineState *s = q->state();
3523
3524     return s->flags.fast_images
3525            && (mode == QPainter::CompositionMode_SourceOver
3526                || (mode == QPainter::CompositionMode_Source
3527                    && !image.hasAlphaChannel()));
3528 }
3529
3530 QImage QRasterBuffer::colorizeBitmap(const QImage &image, const QColor &color)
3531 {
3532     Q_ASSERT(image.depth() == 1);
3533
3534     QImage sourceImage = image.convertToFormat(QImage::Format_MonoLSB);
3535     QImage dest = QImage(sourceImage.size(), QImage::Format_ARGB32_Premultiplied);
3536
3537     QRgb fg = PREMUL(color.rgba());
3538     QRgb bg = 0;
3539
3540     int height = sourceImage.height();
3541     int width = sourceImage.width();
3542     for (int y=0; y<height; ++y) {
3543         uchar *source = sourceImage.scanLine(y);
3544         QRgb *target = reinterpret_cast<QRgb *>(dest.scanLine(y));
3545         if (!source || !target)
3546             QT_THROW(std::bad_alloc()); // we must have run out of memory
3547         for (int x=0; x < width; ++x)
3548             target[x] = (source[x>>3] >> (x&7)) & 1 ? fg : bg;
3549     }
3550     return dest;
3551 }
3552
3553 QRasterBuffer::~QRasterBuffer()
3554 {
3555 }
3556
3557 void QRasterBuffer::init()
3558 {
3559     compositionMode = QPainter::CompositionMode_SourceOver;
3560     monoDestinationWithClut = false;
3561     destColor0 = 0;
3562     destColor1 = 0;
3563 }
3564
3565 QImage::Format QRasterBuffer::prepare(QImage *image)
3566 {
3567     m_buffer = (uchar *)image->bits();
3568     m_width = qMin(QT_RASTER_COORD_LIMIT, image->width());
3569     m_height = qMin(QT_RASTER_COORD_LIMIT, image->height());
3570     bytes_per_pixel = image->depth()/8;
3571     bytes_per_line = image->bytesPerLine();
3572
3573     format = image->format();
3574     drawHelper = qDrawHelper + format;
3575     if (image->depth() == 1 && image->colorTable().size() == 2) {
3576         monoDestinationWithClut = true;
3577         destColor0 = PREMUL(image->colorTable()[0]);
3578         destColor1 = PREMUL(image->colorTable()[1]);
3579     }
3580
3581     return format;
3582 }
3583
3584 void QRasterBuffer::resetBuffer(int val)
3585 {
3586     memset(m_buffer, val, m_height*bytes_per_line);
3587 }
3588
3589 QClipData::QClipData(int height)
3590 {
3591     clipSpanHeight = height;
3592     m_clipLines = 0;
3593
3594     allocated = 0;
3595     m_spans = 0;
3596     xmin = xmax = ymin = ymax = 0;
3597     count = 0;
3598
3599     enabled = true;
3600     hasRectClip = hasRegionClip = false;
3601 }
3602
3603 QClipData::~QClipData()
3604 {
3605     if (m_clipLines)
3606         free(m_clipLines);
3607     if (m_spans)
3608         free(m_spans);
3609 }
3610
3611 void QClipData::initialize()
3612 {
3613     if (m_spans)
3614         return;
3615
3616     if (!m_clipLines)
3617         m_clipLines = (ClipLine *)calloc(sizeof(ClipLine), clipSpanHeight);
3618
3619     Q_CHECK_PTR(m_clipLines);
3620     QT_TRY {
3621         m_spans = (QSpan *)malloc(clipSpanHeight*sizeof(QSpan));
3622         allocated = clipSpanHeight;
3623         Q_CHECK_PTR(m_spans);
3624
3625         QT_TRY {
3626             if (hasRectClip) {
3627                 int y = 0;
3628                 while (y < ymin) {
3629                     m_clipLines[y].spans = 0;
3630                     m_clipLines[y].count = 0;
3631                     ++y;
3632                 }
3633
3634                 const int len = clipRect.width();
3635                 count = 0;
3636                 while (y < ymax) {
3637                     QSpan *span = m_spans + count;
3638                     span->x = xmin;
3639                     span->len = len;
3640                     span->y = y;
3641                     span->coverage = 255;
3642                     ++count;
3643
3644                     m_clipLines[y].spans = span;
3645                     m_clipLines[y].count = 1;
3646                     ++y;
3647                 }
3648
3649                 while (y < clipSpanHeight) {
3650                     m_clipLines[y].spans = 0;
3651                     m_clipLines[y].count = 0;
3652                     ++y;
3653                 }
3654             } else if (hasRegionClip) {
3655
3656                 const QVector<QRect> rects = clipRegion.rects();
3657                 const int numRects = rects.size();
3658
3659                 { // resize
3660                     const int maxSpans = (ymax - ymin) * numRects;
3661                     if (maxSpans > allocated) {
3662                         m_spans = q_check_ptr((QSpan *)realloc(m_spans, maxSpans * sizeof(QSpan)));
3663                         allocated = maxSpans;
3664                     }
3665                 }
3666
3667                 int y = 0;
3668                 int firstInBand = 0;
3669                 count = 0;
3670                 while (firstInBand < numRects) {
3671                     const int currMinY = rects.at(firstInBand).y();
3672                     const int currMaxY = currMinY + rects.at(firstInBand).height();
3673
3674                     while (y < currMinY) {
3675                         m_clipLines[y].spans = 0;
3676                         m_clipLines[y].count = 0;
3677                         ++y;
3678                     }
3679
3680                     int lastInBand = firstInBand;
3681                     while (lastInBand + 1 < numRects && rects.at(lastInBand+1).top() == y)
3682                         ++lastInBand;
3683
3684                     while (y < currMaxY) {
3685
3686                         m_clipLines[y].spans = m_spans + count;
3687                         m_clipLines[y].count = lastInBand - firstInBand + 1;
3688
3689                         for (int r = firstInBand; r <= lastInBand; ++r) {
3690                             const QRect &currRect = rects.at(r);
3691                             QSpan *span = m_spans + count;
3692                             span->x = currRect.x();
3693                             span->len = currRect.width();
3694                             span->y = y;
3695                             span->coverage = 255;
3696                             ++count;
3697                         }
3698                         ++y;
3699                     }
3700
3701                     firstInBand = lastInBand + 1;
3702                 }
3703
3704                 Q_ASSERT(count <= allocated);
3705
3706                 while (y < clipSpanHeight) {
3707                     m_clipLines[y].spans = 0;
3708                     m_clipLines[y].count = 0;
3709                     ++y;
3710                 }
3711
3712             }
3713         } QT_CATCH(...) {
3714             free(m_spans); // have to free m_spans again or someone might think that we were successfully initialized.
3715             m_spans = 0;
3716             QT_RETHROW;
3717         }
3718     } QT_CATCH(...) {
3719         free(m_clipLines); // same for clipLines
3720         m_clipLines = 0;
3721         QT_RETHROW;
3722     }
3723 }
3724
3725 void QClipData::fixup()
3726 {
3727     Q_ASSERT(m_spans);
3728
3729     if (count == 0) {
3730         ymin = ymax = xmin = xmax = 0;
3731         return;
3732     }
3733
3734     int y = -1;
3735     ymin = m_spans[0].y;
3736     ymax = m_spans[count-1].y + 1;
3737     xmin = INT_MAX;
3738     xmax = 0;
3739
3740     const int firstLeft = m_spans[0].x;
3741     const int firstRight = m_spans[0].x + m_spans[0].len;
3742     bool isRect = true;
3743
3744     for (int i = 0; i < count; ++i) {
3745         QT_FT_Span_& span = m_spans[i];
3746
3747         if (span.y != y) {
3748             if (span.y != y + 1 && y != -1)
3749                 isRect = false;
3750             y = span.y;
3751             m_clipLines[y].spans = &span;
3752             m_clipLines[y].count = 1;
3753         } else
3754             ++m_clipLines[y].count;
3755
3756         const int spanLeft = span.x;
3757         const int spanRight = spanLeft + span.len;
3758
3759         if (spanLeft < xmin)
3760             xmin = spanLeft;
3761
3762         if (spanRight > xmax)
3763             xmax = spanRight;
3764
3765         if (spanLeft != firstLeft || spanRight != firstRight)
3766             isRect = false;
3767     }
3768
3769     if (isRect) {
3770         hasRectClip = true;
3771         clipRect.setRect(xmin, ymin, xmax - xmin, ymax - ymin);
3772     }
3773 }
3774
3775 /*
3776     Convert \a rect to clip spans.
3777  */
3778 void QClipData::setClipRect(const QRect &rect)
3779 {
3780     if (hasRectClip && rect == clipRect)
3781         return;
3782
3783 //    qDebug() << "setClipRect" << clipSpanHeight << count << allocated << rect;
3784     hasRectClip = true;
3785     hasRegionClip = false;
3786     clipRect = rect;
3787
3788     xmin = rect.x();
3789     xmax = rect.x() + rect.width();
3790     ymin = qMin(rect.y(), clipSpanHeight);
3791     ymax = qMin(rect.y() + rect.height(), clipSpanHeight);
3792
3793     if (m_spans) {
3794         free(m_spans);
3795         m_spans = 0;
3796     }
3797
3798 //    qDebug() << xmin << xmax << ymin << ymax;
3799 }
3800
3801 /*
3802     Convert \a region to clip spans.
3803  */
3804 void QClipData::setClipRegion(const QRegion &region)
3805 {
3806     if (region.rectCount() == 1) {
3807         setClipRect(region.rects().at(0));
3808         return;
3809     }
3810
3811     hasRegionClip = true;
3812     hasRectClip = false;
3813     clipRegion = region;
3814
3815     { // set bounding rect
3816         const QRect rect = region.boundingRect();
3817         xmin = rect.x();
3818         xmax = rect.x() + rect.width();
3819         ymin = rect.y();
3820         ymax = rect.y() + rect.height();
3821     }
3822
3823     if (m_spans) {
3824         free(m_spans);
3825         m_spans = 0;
3826     }
3827
3828 }
3829
3830 /*!
3831     \internal
3832     spans must be sorted on y
3833 */
3834 static const QSpan *qt_intersect_spans(const QClipData *clip, int *currentClip,
3835                                        const QSpan *spans, const QSpan *end,
3836                                        QSpan **outSpans, int available)
3837 {
3838     const_cast<QClipData *>(clip)->initialize();
3839
3840     QSpan *out = *outSpans;
3841
3842     const QSpan *clipSpans = clip->m_spans + *currentClip;
3843     const QSpan *clipEnd = clip->m_spans + clip->count;
3844
3845     while (available && spans < end ) {
3846         if (clipSpans >= clipEnd) {
3847             spans = end;
3848             break;
3849         }
3850         if (clipSpans->y > spans->y) {
3851             ++spans;
3852             continue;
3853         }
3854         if (spans->y != clipSpans->y) {
3855             if (spans->y < clip->count && clip->m_clipLines[spans->y].spans)
3856                 clipSpans = clip->m_clipLines[spans->y].spans;
3857             else
3858                 ++clipSpans;
3859             continue;
3860         }
3861         Q_ASSERT(spans->y == clipSpans->y);
3862
3863         int sx1 = spans->x;
3864         int sx2 = sx1 + spans->len;
3865         int cx1 = clipSpans->x;
3866         int cx2 = cx1 + clipSpans->len;
3867
3868         if (cx1 < sx1 && cx2 < sx1) {
3869             ++clipSpans;
3870             continue;
3871         } else if (sx1 < cx1 && sx2 < cx1) {
3872             ++spans;
3873             continue;
3874         }
3875         int x = qMax(sx1, cx1);
3876         int len = qMin(sx2, cx2) - x;
3877         if (len) {
3878             out->x = qMax(sx1, cx1);
3879             out->len = qMin(sx2, cx2) - out->x;
3880             out->y = spans->y;
3881             out->coverage = qt_div_255(spans->coverage * clipSpans->coverage);
3882             ++out;
3883             --available;
3884         }
3885         if (sx2 < cx2) {
3886             ++spans;
3887         } else {
3888             ++clipSpans;
3889         }
3890     }
3891
3892     *outSpans = out;
3893     *currentClip = clipSpans - clip->m_spans;
3894     return spans;
3895 }
3896
3897 static void qt_span_fill_clipped(int spanCount, const QSpan *spans, void *userData)
3898 {
3899 //     qDebug() << "qt_span_fill_clipped" << spanCount;
3900     QSpanData *fillData = reinterpret_cast<QSpanData *>(userData);
3901
3902     Q_ASSERT(fillData->blend && fillData->unclipped_blend);
3903
3904     const int NSPANS = 256;
3905     QSpan cspans[NSPANS];
3906     int currentClip = 0;
3907     const QSpan *end = spans + spanCount;
3908     while (spans < end) {
3909         QSpan *clipped = cspans;
3910         spans = qt_intersect_spans(fillData->clip, &currentClip, spans, end, &clipped, NSPANS);
3911 //         qDebug() << "processed " << spanCount - (end - spans) << "clipped" << clipped-cspans
3912 //                  << "span:" << cspans->x << cspans->y << cspans->len << spans->coverage;
3913
3914         if (clipped - cspans)
3915             fillData->unclipped_blend(clipped - cspans, cspans, fillData);
3916     }
3917 }
3918
3919 /*
3920     \internal
3921     Clip spans to \a{clip}-rectangle.
3922     Returns number of unclipped spans
3923 */
3924 static int qt_intersect_spans(QT_FT_Span *spans, int numSpans,
3925                               const QRect &clip)
3926 {
3927     const short minx = clip.left();
3928     const short miny = clip.top();
3929     const short maxx = clip.right();
3930     const short maxy = clip.bottom();
3931
3932     int n = 0;
3933     for (int i = 0; i < numSpans; ++i) {
3934         if (spans[i].y > maxy)
3935             break;
3936         if (spans[i].y < miny
3937             || spans[i].x > maxx
3938             || spans[i].x + spans[i].len <= minx) {
3939             continue;
3940         }
3941         if (spans[i].x < minx) {
3942             spans[n].len = qMin(spans[i].len - (minx - spans[i].x), maxx - minx + 1);
3943             spans[n].x = minx;
3944         } else {
3945             spans[n].x = spans[i].x;
3946             spans[n].len = qMin(spans[i].len, ushort(maxx - spans[n].x + 1));
3947         }
3948         if (spans[n].len == 0)
3949             continue;
3950         spans[n].y = spans[i].y;
3951         spans[n].coverage = spans[i].coverage;
3952         ++n;
3953     }
3954     return n;
3955 }
3956
3957
3958 static void qt_span_fill_clipRect(int count, const QSpan *spans,
3959                                   void *userData)
3960 {
3961     QSpanData *fillData = reinterpret_cast<QSpanData *>(userData);
3962     Q_ASSERT(fillData->blend && fillData->unclipped_blend);
3963
3964     Q_ASSERT(fillData->clip);
3965     Q_ASSERT(!fillData->clip->clipRect.isEmpty());
3966
3967     // hw: check if this const_cast<> is safe!!!
3968     count = qt_intersect_spans(const_cast<QSpan*>(spans), count,
3969                                fillData->clip->clipRect);
3970     if (count > 0)
3971         fillData->unclipped_blend(count, spans, fillData);
3972 }
3973
3974 static void qt_span_clip(int count, const QSpan *spans, void *userData)
3975 {
3976     ClipData *clipData = reinterpret_cast<ClipData *>(userData);
3977
3978 //     qDebug() << " qt_span_clip: " << count << clipData->operation;
3979 //     for (int i = 0; i < qMin(count, 10); ++i) {
3980 //         qDebug() << "    " << spans[i].x << spans[i].y << spans[i].len << spans[i].coverage;
3981 //     }
3982
3983     switch (clipData->operation) {
3984
3985     case Qt::IntersectClip:
3986         {
3987             QClipData *newClip = clipData->newClip;
3988             newClip->initialize();
3989
3990             int currentClip = 0;
3991             const QSpan *end = spans + count;
3992             while (spans < end) {
3993                 QSpan *newspans = newClip->m_spans + newClip->count;
3994                 spans = qt_intersect_spans(clipData->oldClip, &currentClip, spans, end,
3995                                            &newspans, newClip->allocated - newClip->count);
3996                 newClip->count = newspans - newClip->m_spans;
3997                 if (spans < end) {
3998                     newClip->m_spans = q_check_ptr((QSpan *)realloc(newClip->m_spans, newClip->allocated*2*sizeof(QSpan)));
3999                     newClip->allocated *= 2;
4000                 }
4001             }
4002         }
4003         break;
4004
4005     case Qt::ReplaceClip:
4006         clipData->newClip->appendSpans(spans, count);
4007         break;
4008     case Qt::NoClip:
4009         break;
4010     }
4011 }
4012
4013 #ifndef QT_NO_DEBUG
4014 QImage QRasterBuffer::bufferImage() const
4015 {
4016     QImage image(m_width, m_height, QImage::Format_ARGB32_Premultiplied);
4017
4018     for (int y = 0; y < m_height; ++y) {
4019         uint *span = (uint *)const_cast<QRasterBuffer *>(this)->scanLine(y);
4020
4021         for (int x=0; x<m_width; ++x) {
4022             uint argb = span[x];
4023             image.setPixel(x, y, argb);
4024         }
4025     }
4026     return image;
4027 }
4028 #endif
4029
4030
4031 void QRasterBuffer::flushToARGBImage(QImage *target) const
4032 {
4033     int w = qMin(m_width, target->width());
4034     int h = qMin(m_height, target->height());
4035
4036     for (int y=0; y<h; ++y) {
4037         uint *sourceLine = (uint *)const_cast<QRasterBuffer *>(this)->scanLine(y);
4038         QRgb *dest = (QRgb *) target->scanLine(y);
4039         for (int x=0; x<w; ++x) {
4040             QRgb pixel = sourceLine[x];
4041             int alpha = qAlpha(pixel);
4042             if (!alpha) {
4043                 dest[x] = 0;
4044             } else {
4045                 dest[x] = (alpha << 24)
4046                         | ((255*qRed(pixel)/alpha) << 16)
4047                         | ((255*qGreen(pixel)/alpha) << 8)
4048                         | ((255*qBlue(pixel)/alpha) << 0);
4049             }
4050         }
4051     }
4052 }
4053
4054
4055 class QGradientCache
4056 {
4057     struct CacheInfo
4058     {
4059         inline CacheInfo(QGradientStops s, int op, QGradient::InterpolationMode mode) :
4060             stops(s), opacity(op), interpolationMode(mode) {}
4061         uint buffer[GRADIENT_STOPTABLE_SIZE];
4062         QGradientStops stops;
4063         int opacity;
4064         QGradient::InterpolationMode interpolationMode;
4065     };
4066
4067     typedef QMultiHash<quint64, CacheInfo> QGradientColorTableHash;
4068
4069 public:
4070     inline const uint *getBuffer(const QGradient &gradient, int opacity) {
4071         quint64 hash_val = 0;
4072
4073         QGradientStops stops = gradient.stops();
4074         for (int i = 0; i < stops.size() && i <= 2; i++)
4075             hash_val += stops[i].second.rgba();
4076
4077         QMutexLocker lock(&mutex);
4078         QGradientColorTableHash::const_iterator it = cache.constFind(hash_val);
4079
4080         if (it == cache.constEnd())
4081             return addCacheElement(hash_val, gradient, opacity);
4082         else {
4083             do {
4084                 const CacheInfo &cache_info = it.value();
4085                 if (cache_info.stops == stops && cache_info.opacity == opacity && cache_info.interpolationMode == gradient.interpolationMode())
4086                     return cache_info.buffer;
4087                 ++it;
4088             } while (it != cache.constEnd() && it.key() == hash_val);
4089             // an exact match for these stops and opacity was not found, create new cache
4090             return addCacheElement(hash_val, gradient, opacity);
4091         }
4092     }
4093
4094     inline int paletteSize() const { return GRADIENT_STOPTABLE_SIZE; }
4095 protected:
4096     inline int maxCacheSize() const { return 60; }
4097     inline void generateGradientColorTable(const QGradient& g,
4098                                            uint *colorTable,
4099                                            int size, int opacity) const;
4100     uint *addCacheElement(quint64 hash_val, const QGradient &gradient, int opacity) {
4101         if (cache.size() == maxCacheSize()) {
4102             // may remove more than 1, but OK
4103             cache.erase(cache.begin() + (qrand() % maxCacheSize()));
4104         }
4105         CacheInfo cache_entry(gradient.stops(), opacity, gradient.interpolationMode());
4106         generateGradientColorTable(gradient, cache_entry.buffer, paletteSize(), opacity);
4107         return cache.insert(hash_val, cache_entry).value().buffer;
4108     }
4109
4110     QGradientColorTableHash cache;
4111     QMutex mutex;
4112 };
4113
4114 void QGradientCache::generateGradientColorTable(const QGradient& gradient, uint *colorTable, int size, int opacity) const
4115 {
4116     QGradientStops stops = gradient.stops();
4117     int stopCount = stops.count();
4118     Q_ASSERT(stopCount > 0);
4119
4120     bool colorInterpolation = (gradient.interpolationMode() == QGradient::ColorInterpolation);
4121
4122     if (stopCount == 2) {
4123         uint first_color = ARGB_COMBINE_ALPHA(stops[0].second.rgba(), opacity);
4124         uint second_color = ARGB_COMBINE_ALPHA(stops[1].second.rgba(), opacity);
4125
4126         qreal first_stop = stops[0].first;
4127         qreal second_stop = stops[1].first;
4128
4129         if (second_stop < first_stop) {
4130             qSwap(first_color, second_color);
4131             qSwap(first_stop, second_stop);
4132         }
4133
4134         if (colorInterpolation) {
4135             first_color = PREMUL(first_color);
4136             second_color = PREMUL(second_color);
4137         }
4138
4139         int first_index = qRound(first_stop * (GRADIENT_STOPTABLE_SIZE-1));
4140         int second_index = qRound(second_stop * (GRADIENT_STOPTABLE_SIZE-1));
4141
4142         uint red_first = qRed(first_color) << 16;
4143         uint green_first = qGreen(first_color) << 16;
4144         uint blue_first = qBlue(first_color) << 16;
4145         uint alpha_first = qAlpha(first_color) << 16;
4146
4147         uint red_second = qRed(second_color) << 16;
4148         uint green_second = qGreen(second_color) << 16;
4149         uint blue_second = qBlue(second_color) << 16;
4150         uint alpha_second = qAlpha(second_color) << 16;
4151
4152         int i = 0;
4153         for (; i <= qMin(GRADIENT_STOPTABLE_SIZE, first_index); ++i) {
4154             if (colorInterpolation)
4155                 colorTable[i] = first_color;
4156             else
4157                 colorTable[i] = PREMUL(first_color);
4158         }
4159
4160         if (i < second_index) {
4161             qreal reciprocal = qreal(1) / (second_index - first_index);
4162
4163             int red_delta = qRound(int(red_second - red_first) * reciprocal);
4164             int green_delta = qRound(int(green_second - green_first) * reciprocal);
4165             int blue_delta = qRound(int(blue_second - blue_first) * reciprocal);
4166             int alpha_delta = qRound(int(alpha_second - alpha_first) * reciprocal);
4167
4168             // rounding
4169             red_first += 1 << 15;
4170             green_first += 1 << 15;
4171             blue_first += 1 << 15;
4172             alpha_first += 1 << 15;
4173
4174             for (; i < qMin(GRADIENT_STOPTABLE_SIZE, second_index); ++i) {
4175                 red_first += red_delta;
4176                 green_first += green_delta;
4177                 blue_first += blue_delta;
4178                 alpha_first += alpha_delta;
4179
4180                 const uint color = ((alpha_first << 8) & 0xff000000) | (red_first & 0xff0000)
4181                                  | ((green_first >> 8) & 0xff00) | (blue_first >> 16);
4182
4183                 if (colorInterpolation)
4184                     colorTable[i] = color;
4185                 else
4186                     colorTable[i] = PREMUL(color);
4187             }
4188         }
4189
4190         for (; i < GRADIENT_STOPTABLE_SIZE; ++i) {
4191             if (colorInterpolation)
4192                 colorTable[i] = second_color;
4193             else
4194                 colorTable[i] = PREMUL(second_color);
4195         }
4196
4197         return;
4198     }
4199
4200     uint current_color = ARGB_COMBINE_ALPHA(stops[0].second.rgba(), opacity);
4201     if (stopCount == 1) {
4202         current_color = PREMUL(current_color);
4203         for (int i = 0; i < size; ++i)
4204             colorTable[i] = current_color;
4205         return;
4206     }
4207
4208     // The position where the gradient begins and ends
4209     qreal begin_pos = stops[0].first;
4210     qreal end_pos = stops[stopCount-1].first;
4211
4212     int pos = 0; // The position in the color table.
4213     uint next_color;
4214
4215     qreal incr = 1 / qreal(size); // the double increment.
4216     qreal dpos = 1.5 * incr; // current position in gradient stop list (0 to 1)
4217
4218      // Up to first point
4219     colorTable[pos++] = PREMUL(current_color);
4220     while (dpos <= begin_pos) {
4221         colorTable[pos] = colorTable[pos - 1];
4222         ++pos;
4223         dpos += incr;
4224     }
4225
4226     int current_stop = 0; // We always interpolate between current and current + 1.
4227
4228     qreal t; // position between current left and right stops
4229     qreal t_delta; // the t increment per entry in the color table
4230
4231     if (dpos < end_pos) {
4232         // Gradient area
4233         while (dpos > stops[current_stop+1].first)
4234             ++current_stop;
4235
4236         if (current_stop != 0)
4237             current_color = ARGB_COMBINE_ALPHA(stops[current_stop].second.rgba(), opacity);
4238         next_color = ARGB_COMBINE_ALPHA(stops[current_stop+1].second.rgba(), opacity);
4239
4240         if (colorInterpolation) {
4241             current_color = PREMUL(current_color);
4242             next_color = PREMUL(next_color);
4243         }
4244
4245         qreal diff = stops[current_stop+1].first - stops[current_stop].first;
4246         qreal c = (diff == 0) ? qreal(0) : 256 / diff;
4247         t = (dpos - stops[current_stop].first) * c;
4248         t_delta = incr * c;
4249
4250         while (true) {
4251             Q_ASSERT(current_stop < stopCount);
4252
4253             int dist = qRound(t);
4254             int idist = 256 - dist;
4255
4256             if (colorInterpolation)
4257                 colorTable[pos] = INTERPOLATE_PIXEL_256(current_color, idist, next_color, dist);
4258             else
4259                 colorTable[pos] = PREMUL(INTERPOLATE_PIXEL_256(current_color, idist, next_color, dist));
4260
4261             ++pos;
4262             dpos += incr;
4263
4264             if (dpos >= end_pos)
4265                 break;
4266
4267             t += t_delta;
4268
4269             int skip = 0;
4270             while (dpos > stops[current_stop+skip+1].first)
4271                 ++skip;
4272
4273             if (skip != 0) {
4274                 current_stop += skip;
4275                 if (skip == 1)
4276                     current_color = next_color;
4277                 else
4278                     current_color = ARGB_COMBINE_ALPHA(stops[current_stop].second.rgba(), opacity);
4279                 next_color = ARGB_COMBINE_ALPHA(stops[current_stop+1].second.rgba(), opacity);
4280
4281                 if (colorInterpolation) {
4282                     if (skip != 1)
4283                         current_color = PREMUL(current_color);
4284                     next_color = PREMUL(next_color);
4285                 }
4286
4287                 qreal diff = stops[current_stop+1].first - stops[current_stop].first;
4288                 qreal c = (diff == 0) ? qreal(0) : 256 / diff;
4289                 t = (dpos - stops[current_stop].first) * c;
4290                 t_delta = incr * c;
4291             }
4292         }
4293     }
4294
4295     // After last point
4296     current_color = PREMUL(ARGB_COMBINE_ALPHA(stops[stopCount - 1].second.rgba(), opacity));
4297     while (pos < size - 1) {
4298         colorTable[pos] = current_color;
4299         ++pos;
4300     }
4301
4302     // Make sure the last color stop is represented at the end of the table
4303     colorTable[size - 1] = current_color;
4304 }
4305
4306 Q_GLOBAL_STATIC(QGradientCache, qt_gradient_cache)
4307
4308
4309 void QSpanData::init(QRasterBuffer *rb, const QRasterPaintEngine *pe)
4310 {
4311     rasterBuffer = rb;
4312     type = None;
4313     txop = 0;
4314     bilinear = false;
4315     m11 = m22 = m33 = 1.;
4316     m12 = m13 = m21 = m23 = dx = dy = 0.0;
4317     clip = pe ? pe->d_func()->clip() : 0;
4318 }
4319
4320 Q_GUI_EXPORT extern QImage qt_imageForBrush(int brushStyle, bool invert);
4321
4322 void QSpanData::setup(const QBrush &brush, int alpha, QPainter::CompositionMode compositionMode)
4323 {
4324     Qt::BrushStyle brushStyle = qbrush_style(brush);
4325     switch (brushStyle) {
4326     case Qt::SolidPattern: {
4327         type = Solid;
4328         QColor c = qbrush_color(brush);
4329         QRgb rgba = c.rgba();
4330         solid.color = PREMUL(ARGB_COMBINE_ALPHA(rgba, alpha));
4331         if ((solid.color & 0xff000000) == 0
4332             && compositionMode == QPainter::CompositionMode_SourceOver) {
4333             type = None;
4334         }
4335         break;
4336     }
4337
4338     case Qt::LinearGradientPattern:
4339         {
4340             type = LinearGradient;
4341             const QLinearGradient *g = static_cast<const QLinearGradient *>(brush.gradient());
4342             gradient.alphaColor = !brush.isOpaque() || alpha != 256;
4343             gradient.colorTable = const_cast<uint*>(qt_gradient_cache()->getBuffer(*g, alpha));
4344             gradient.spread = g->spread();
4345
4346             QLinearGradientData &linearData = gradient.linear;
4347
4348             linearData.origin.x = g->start().x();
4349             linearData.origin.y = g->start().y();
4350             linearData.end.x = g->finalStop().x();
4351             linearData.end.y = g->finalStop().y();
4352             break;
4353         }
4354
4355     case Qt::RadialGradientPattern:
4356         {
4357             type = RadialGradient;
4358             const QRadialGradient *g = static_cast<const QRadialGradient *>(brush.gradient());
4359             gradient.alphaColor = !brush.isOpaque() || alpha != 256;
4360             gradient.colorTable = const_cast<uint*>(qt_gradient_cache()->getBuffer(*g, alpha));
4361             gradient.spread = g->spread();
4362
4363             QRadialGradientData &radialData = gradient.radial;
4364
4365             QPointF center = g->center();
4366             radialData.center.x = center.x();
4367             radialData.center.y = center.y();
4368             radialData.center.radius = g->centerRadius();
4369             QPointF focal = g->focalPoint();
4370             radialData.focal.x = focal.x();
4371             radialData.focal.y = focal.y();
4372             radialData.focal.radius = g->focalRadius();
4373         }
4374         break;
4375
4376     case Qt::ConicalGradientPattern:
4377         {
4378             type = ConicalGradient;
4379             const QConicalGradient *g = static_cast<const QConicalGradient *>(brush.gradient());
4380             gradient.alphaColor = !brush.isOpaque() || alpha != 256;
4381             gradient.colorTable = const_cast<uint*>(qt_gradient_cache()->getBuffer(*g, alpha));
4382             gradient.spread = QGradient::RepeatSpread;
4383
4384             QConicalGradientData &conicalData = gradient.conical;
4385
4386             QPointF center = g->center();
4387             conicalData.center.x = center.x();
4388             conicalData.center.y = center.y();
4389             conicalData.angle = g->angle() * 2 * Q_PI / 360.0;
4390         }
4391         break;
4392
4393     case Qt::Dense1Pattern:
4394     case Qt::Dense2Pattern:
4395     case Qt::Dense3Pattern:
4396     case Qt::Dense4Pattern:
4397     case Qt::Dense5Pattern:
4398     case Qt::Dense6Pattern:
4399     case Qt::Dense7Pattern:
4400     case Qt::HorPattern:
4401     case Qt::VerPattern:
4402     case Qt::CrossPattern:
4403     case Qt::BDiagPattern:
4404     case Qt::FDiagPattern:
4405     case Qt::DiagCrossPattern:
4406         type = Texture;
4407         if (!tempImage)
4408             tempImage = new QImage();
4409         *tempImage = rasterBuffer->colorizeBitmap(qt_imageForBrush(brushStyle, true), brush.color());
4410         initTexture(tempImage, alpha, QTextureData::Tiled);
4411         break;
4412     case Qt::TexturePattern:
4413         type = Texture;
4414         if (!tempImage)
4415             tempImage = new QImage();
4416
4417         if (qHasPixmapTexture(brush) && brush.texture().isQBitmap())
4418             *tempImage = rasterBuffer->colorizeBitmap(brush.textureImage(), brush.color());
4419         else
4420             *tempImage = brush.textureImage();
4421         initTexture(tempImage, alpha, QTextureData::Tiled, tempImage->rect());
4422         break;
4423
4424     case Qt::NoBrush:
4425     default:
4426         type = None;
4427         break;
4428     }
4429     adjustSpanMethods();
4430 }
4431
4432 void QSpanData::adjustSpanMethods()
4433 {
4434     bitmapBlit = 0;
4435     alphamapBlit = 0;
4436     alphaRGBBlit = 0;
4437
4438     fillRect = 0;
4439
4440     switch(type) {
4441     case None:
4442         unclipped_blend = 0;
4443         break;
4444     case Solid:
4445         unclipped_blend = rasterBuffer->drawHelper->blendColor;
4446         bitmapBlit = rasterBuffer->drawHelper->bitmapBlit;
4447         alphamapBlit = rasterBuffer->drawHelper->alphamapBlit;
4448         alphaRGBBlit = rasterBuffer->drawHelper->alphaRGBBlit;
4449         fillRect = rasterBuffer->drawHelper->fillRect;
4450         break;
4451     case LinearGradient:
4452     case RadialGradient:
4453     case ConicalGradient:
4454         unclipped_blend = rasterBuffer->drawHelper->blendGradient;
4455         break;
4456     case Texture:
4457         unclipped_blend = qBlendTexture;
4458         if (!texture.imageData)
4459             unclipped_blend = 0;
4460
4461         break;
4462     }
4463     // setup clipping
4464     if (!unclipped_blend) {
4465         blend = 0;
4466     } else if (!clip) {
4467         blend = unclipped_blend;
4468     } else if (clip->hasRectClip) {
4469         blend = clip->clipRect.isEmpty() ? 0 : qt_span_fill_clipRect;
4470     } else {
4471         blend = qt_span_fill_clipped;
4472     }
4473 }
4474
4475 void QSpanData::setupMatrix(const QTransform &matrix, int bilin)
4476 {
4477     QTransform delta;
4478     // make sure we round off correctly in qdrawhelper.cpp
4479     delta.translate(1.0 / 65536, 1.0 / 65536);
4480
4481     QTransform inv = (delta * matrix).inverted();
4482     m11 = inv.m11();
4483     m12 = inv.m12();
4484     m13 = inv.m13();
4485     m21 = inv.m21();
4486     m22 = inv.m22();
4487     m23 = inv.m23();
4488     m33 = inv.m33();
4489     dx = inv.dx();
4490     dy = inv.dy();
4491     txop = inv.type();
4492     bilinear = bilin;
4493
4494     const bool affine = !m13 && !m23;
4495     fast_matrix = affine
4496         && m11 * m11 + m21 * m21 < 1e4
4497         && m12 * m12 + m22 * m22 < 1e4
4498         && qAbs(dx) < 1e4
4499         && qAbs(dy) < 1e4;
4500
4501     adjustSpanMethods();
4502 }
4503
4504 extern const QVector<QRgb> *qt_image_colortable(const QImage &image);
4505
4506 void QSpanData::initTexture(const QImage *image, int alpha, QTextureData::Type _type, const QRect &sourceRect)
4507 {
4508     const QImageData *d = const_cast<QImage *>(image)->data_ptr();
4509     if (!d || d->height == 0) {
4510         texture.imageData = 0;
4511         texture.width = 0;
4512         texture.height = 0;
4513         texture.x1 = 0;
4514         texture.y1 = 0;
4515         texture.x2 = 0;
4516         texture.y2 = 0;
4517         texture.bytesPerLine = 0;
4518         texture.format = QImage::Format_Invalid;
4519         texture.colorTable = 0;
4520         texture.hasAlpha = alpha != 256;
4521     } else {
4522         texture.imageData = d->data;
4523         texture.width = d->width;
4524         texture.height = d->height;
4525
4526         if (sourceRect.isNull()) {
4527             texture.x1 = 0;
4528             texture.y1 = 0;
4529             texture.x2 = texture.width;
4530             texture.y2 = texture.height;
4531         } else {
4532             texture.x1 = sourceRect.x();
4533             texture.y1 = sourceRect.y();
4534             texture.x2 = qMin(texture.x1 + sourceRect.width(), d->width);
4535             texture.y2 = qMin(texture.y1 + sourceRect.height(), d->height);
4536         }
4537
4538         texture.bytesPerLine = d->bytes_per_line;
4539
4540         texture.format = d->format;
4541         texture.colorTable = (d->format <= QImage::Format_Indexed8 && !d->colortable.isEmpty()) ? &d->colortable : 0;
4542         texture.hasAlpha = image->hasAlphaChannel() || alpha != 256;
4543     }
4544     texture.const_alpha = alpha;
4545     texture.type = _type;
4546
4547     adjustSpanMethods();
4548 }
4549
4550 /*!
4551     \internal
4552     \a x and \a y is relative to the midpoint of \a rect.
4553 */
4554 static inline void drawEllipsePoints(int x, int y, int length,
4555                                      const QRect &rect,
4556                                      const QRect &clip,
4557                                      ProcessSpans pen_func, ProcessSpans brush_func,
4558                                      QSpanData *pen_data, QSpanData *brush_data)
4559 {
4560     if (length == 0)
4561         return;
4562
4563     QT_FT_Span outline[4];
4564     const int midx = rect.x() + (rect.width() + 1) / 2;
4565     const int midy = rect.y() + (rect.height() + 1) / 2;
4566
4567     x = x + midx;
4568     y = midy - y;
4569
4570     // topleft
4571     outline[0].x = midx + (midx - x) - (length - 1) - (rect.width() & 0x1);
4572     outline[0].len = qMin(length, x - outline[0].x);
4573     outline[0].y = y;
4574     outline[0].coverage = 255;
4575
4576     // topright
4577     outline[1].x = x;
4578     outline[1].len = length;
4579     outline[1].y = y;
4580     outline[1].coverage = 255;
4581
4582     // bottomleft
4583     outline[2].x = outline[0].x;
4584     outline[2].len = outline[0].len;
4585     outline[2].y = midy + (midy - y) - (rect.height() & 0x1);
4586     outline[2].coverage = 255;
4587
4588     // bottomright
4589     outline[3].x = x;
4590     outline[3].len = length;
4591     outline[3].y = outline[2].y;
4592     outline[3].coverage = 255;
4593
4594     if (brush_func && outline[0].x + outline[0].len < outline[1].x) {
4595         QT_FT_Span fill[2];
4596
4597         // top fill
4598         fill[0].x = outline[0].x + outline[0].len - 1;
4599         fill[0].len = qMax(0, outline[1].x - fill[0].x);
4600         fill[0].y = outline[1].y;
4601         fill[0].coverage = 255;
4602
4603         // bottom fill
4604         fill[1].x = outline[2].x + outline[2].len - 1;
4605         fill[1].len = qMax(0, outline[3].x - fill[1].x);
4606         fill[1].y = outline[3].y;
4607         fill[1].coverage = 255;
4608
4609         int n = (fill[0].y >= fill[1].y ? 1 : 2);
4610         n = qt_intersect_spans(fill, n, clip);
4611         if (n > 0)
4612             brush_func(n, fill, brush_data);
4613     }
4614     if (pen_func) {
4615         int n = (outline[1].y >= outline[2].y ? 2 : 4);
4616         n = qt_intersect_spans(outline, n, clip);
4617         if (n > 0)
4618             pen_func(n, outline, pen_data);
4619     }
4620 }
4621
4622 /*!
4623     \internal
4624     Draws an ellipse using the integer point midpoint algorithm.
4625 */
4626 static void drawEllipse_midpoint_i(const QRect &rect, const QRect &clip,
4627                                    ProcessSpans pen_func, ProcessSpans brush_func,
4628                                    QSpanData *pen_data, QSpanData *brush_data)
4629 {
4630     const qreal a = qreal(rect.width()) / 2;
4631     const qreal b = qreal(rect.height()) / 2;
4632     qreal d = b*b - (a*a*b) + 0.25*a*a;
4633
4634     int x = 0;
4635     int y = (rect.height() + 1) / 2;
4636     int startx = x;
4637
4638     // region 1
4639     while (a*a*(2*y - 1) > 2*b*b*(x + 1)) {
4640         if (d < 0) { // select E
4641             d += b*b*(2*x + 3);
4642             ++x;
4643         } else {     // select SE
4644             d += b*b*(2*x + 3) + a*a*(-2*y + 2);
4645             drawEllipsePoints(startx, y, x - startx + 1, rect, clip,
4646                               pen_func, brush_func, pen_data, brush_data);
4647             startx = ++x;
4648             --y;
4649         }
4650     }
4651     drawEllipsePoints(startx, y, x - startx + 1, rect, clip,
4652                       pen_func, brush_func, pen_data, brush_data);
4653
4654     // region 2
4655     d = b*b*(x + 0.5)*(x + 0.5) + a*a*((y - 1)*(y - 1) - b*b);
4656     const int miny = rect.height() & 0x1;
4657     while (y > miny) {
4658         if (d < 0) { // select SE
4659             d += b*b*(2*x + 2) + a*a*(-2*y + 3);
4660             ++x;
4661         } else {     // select S
4662             d += a*a*(-2*y + 3);
4663         }
4664         --y;
4665         drawEllipsePoints(x, y, 1, rect, clip,
4666                           pen_func, brush_func, pen_data, brush_data);
4667     }
4668 }
4669
4670 /*!
4671     \fn void QRasterPaintEngine::drawPoints(const QPoint *points, int pointCount)
4672     \overload
4673
4674     Draws the first \a pointCount points in the buffer \a points
4675
4676     The default implementation converts the first \a pointCount QPoints in \a points
4677     to QPointFs and calls the floating point version of drawPoints.
4678 */
4679
4680 /*!
4681     \fn void QRasterPaintEngine::drawEllipse(const QRect &rect)
4682     \overload
4683
4684     Reimplement this function to draw the largest ellipse that can be
4685     contained within rectangle \a rect.
4686 */
4687
4688 #ifdef QT_DEBUG_DRAW
4689 void dumpClip(int width, int height, const QClipData *clip)
4690 {
4691     QImage clipImg(width, height, QImage::Format_ARGB32_Premultiplied);
4692     clipImg.fill(0xffff0000);
4693
4694     int x0 = width;
4695     int x1 = 0;
4696     int y0 = height;
4697     int y1 = 0;
4698
4699     ((QClipData *) clip)->spans(); // Force allocation of the spans structure...
4700
4701     for (int i = 0; i < clip->count; ++i) {
4702         const QSpan *span = ((QClipData *) clip)->spans() + i;
4703         for (int j = 0; j < span->len; ++j)
4704             clipImg.setPixel(span->x + j, span->y, 0xffffff00);
4705         x0 = qMin(x0, int(span->x));
4706         x1 = qMax(x1, int(span->x + span->len - 1));
4707
4708         y0 = qMin(y0, int(span->y));
4709         y1 = qMax(y1, int(span->y));
4710     }
4711
4712     static int counter = 0;
4713
4714     Q_ASSERT(y0 >= 0);
4715     Q_ASSERT(x0 >= 0);
4716     Q_ASSERT(y1 >= 0);
4717     Q_ASSERT(x1 >= 0);
4718
4719     fprintf(stderr,"clip %d: %d %d - %d %d\n", counter, x0, y0, x1, y1);
4720     clipImg.save(QString::fromLatin1("clip-%0.png").arg(counter++));
4721 }
4722 #endif
4723
4724
4725 QT_END_NAMESPACE