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