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