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