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