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