Update licenseheader text in source files for qtbase Qt module
[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     QRasterPaintEngineState *s = state();
3033
3034     QFontEngine *fontEngine = textItem->fontEngine();
3035     const qreal pixelSize = fontEngine->fontDef.pixelSize;
3036     if (pixelSize * pixelSize * qAbs(s->matrix.determinant()) < 64 * 64) {
3037         drawCachedGlyphs(textItem->numGlyphs, textItem->glyphs, textItem->glyphPositions,
3038                          fontEngine);
3039     } else {
3040         QPaintEngineEx::drawStaticTextItem(textItem);
3041     }
3042 }
3043
3044 /*!
3045     \reimp
3046 */
3047 void QRasterPaintEngine::drawTextItem(const QPointF &p, const QTextItem &textItem)
3048 {
3049     const QTextItemInt &ti = static_cast<const QTextItemInt &>(textItem);
3050     QRasterPaintEngineState *s = state();
3051
3052 #ifdef QT_DEBUG_DRAW
3053     Q_D(QRasterPaintEngine);
3054     fprintf(stderr," - QRasterPaintEngine::drawTextItem(), (%.2f,%.2f), string=%s ct=%d\n",
3055            p.x(), p.y(), QString::fromRawData(ti.chars, ti.num_chars).toLatin1().data(),
3056            d->glyphCacheType);
3057 #endif
3058
3059     ensurePen();
3060     ensureState();
3061
3062 #if defined (Q_WS_WIN) || defined(Q_WS_MAC)
3063
3064     bool drawCached = true;
3065
3066     if (s->matrix.type() >= QTransform::TxProject)
3067         drawCached = false;
3068
3069     // don't try to cache huge fonts
3070     const qreal pixelSize = ti.fontEngine->fontDef.pixelSize;
3071     if (pixelSize * pixelSize * qAbs(s->matrix.determinant()) >= 64 * 64)
3072         drawCached = false;
3073
3074     // ### Remove the TestFontEngine and Box engine crap, in these
3075     // ### cases we should delegate painting to the font engine
3076     // ### directly...
3077
3078 #if defined(Q_WS_WIN) && !defined(Q_WS_WINCE)
3079     QFontEngine::Type fontEngineType = ti.fontEngine->type();
3080     // qDebug() << "type" << fontEngineType << s->matrix.type();
3081     if ((fontEngineType == QFontEngine::Win && !((QFontEngineWin *) ti.fontEngine)->ttf && s->matrix.type() > QTransform::TxTranslate)
3082         || (s->matrix.type() <= QTransform::TxTranslate
3083             && (fontEngineType == QFontEngine::TestFontEngine
3084                 || fontEngineType == QFontEngine::Box))) {
3085             drawCached = false;
3086     }
3087 #else
3088     if (s->matrix.type() > QTransform::TxTranslate)
3089         drawCached = false;
3090 #endif
3091     if (drawCached) {
3092         QRasterPaintEngineState *s = state();
3093
3094         QVarLengthArray<QFixedPoint> positions;
3095         QVarLengthArray<glyph_t> glyphs;
3096
3097         QTransform matrix = s->matrix;
3098         matrix.translate(p.x(), p.y());
3099
3100         ti.fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions);
3101
3102         drawCachedGlyphs(glyphs.size(), glyphs.constData(), positions.constData(), ti.fontEngine);
3103         return;
3104     }
3105
3106 #elif defined (Q_OS_SYMBIAN) && defined(QT_NO_FREETYPE) // Q_WS_WIN || Q_WS_MAC
3107     if (s->matrix.type() <= QTransform::TxTranslate
3108         || (s->matrix.type() == QTransform::TxScale
3109                 && (qFuzzyCompare(s->matrix.m11(), s->matrix.m22())))) {
3110         drawGlyphsS60(p, ti);
3111         return;
3112     }
3113 #else // Q_WS_WIN || Q_WS_MAC
3114
3115     QFontEngine *fontEngine = ti.fontEngine;
3116
3117 #if defined(Q_WS_QWS)
3118     if (fontEngine->type() == QFontEngine::Box) {
3119         fontEngine->draw(this, qFloor(p.x()), qFloor(p.y()), ti);
3120         return;
3121     }
3122
3123     if (s->matrix.type() < QTransform::TxScale
3124         && (fontEngine->type() == QFontEngine::QPF1 || fontEngine->type() == QFontEngine::QPF2
3125             || (fontEngine->type() == QFontEngine::Proxy
3126                 && !(static_cast<QProxyFontEngine *>(fontEngine)->drawAsOutline()))
3127             )) {
3128         fontEngine->draw(this, qFloor(p.x()), qFloor(p.y()), ti);
3129         return;
3130     }
3131 #endif // Q_WS_QWS
3132
3133 #ifdef Q_WS_QPA
3134     if (s->matrix.type() < QTransform::TxScale) {
3135
3136         QVarLengthArray<QFixedPoint> positions;
3137         QVarLengthArray<glyph_t> glyphs;
3138         QTransform matrix = state()->transform();
3139
3140         qreal _x = qFloor(p.x());
3141         qreal _y = qFloor(p.y());
3142         matrix.translate(_x, _y);
3143
3144         fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions);
3145         if (glyphs.size() == 0)
3146             return;
3147
3148         for(int i = 0; i < glyphs.size(); i++) {
3149             QImage img = fontEngine->alphaMapForGlyph(glyphs[i]);
3150             glyph_metrics_t metrics = fontEngine->boundingBox(glyphs[i]);
3151             alphaPenBlt(img.bits(), img.bytesPerLine(), img.depth(),
3152                                          qRound(positions[i].x + metrics.x),
3153                                          qRound(positions[i].y + metrics.y),
3154                                          img.width(), img.height());
3155         }
3156         return;
3157     }
3158 #endif //Q_WS_QPA
3159
3160 #if (defined(Q_WS_X11) || defined(Q_WS_QWS) || defined(Q_OS_SYMBIAN)) && !defined(QT_NO_FREETYPE)
3161
3162 #if defined(Q_WS_QWS) && !defined(QT_NO_QWS_QPF2)
3163     if (fontEngine->type() == QFontEngine::QPF2) {
3164         QFontEngine *renderingEngine = static_cast<QFontEngineQPF *>(fontEngine)->renderingEngine();
3165         if (renderingEngine)
3166             fontEngine = renderingEngine;
3167     }
3168 #endif
3169
3170     if (fontEngine->type() != QFontEngine::Freetype) {
3171         QPaintEngineEx::drawTextItem(p, ti);
3172         return;
3173     }
3174
3175     QFontEngineFT *fe = static_cast<QFontEngineFT *>(fontEngine);
3176
3177     QTransform matrix = s->matrix;
3178     matrix.translate(p.x(), p.y());
3179
3180     QVarLengthArray<QFixedPoint> positions;
3181     QVarLengthArray<glyph_t> glyphs;
3182     fe->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions);
3183     if (glyphs.size() == 0)
3184         return;
3185
3186     if (!drawCachedGlyphs(glyphs.size(), glyphs.constData(), positions.constData(), fontEngine))
3187         QPaintEngine::drawTextItem(p, ti);
3188
3189     return;
3190 #endif
3191 #endif
3192
3193     QPaintEngineEx::drawTextItem(p, ti);
3194 }
3195
3196 /*!
3197     \reimp
3198 */
3199 void QRasterPaintEngine::drawPoints(const QPointF *points, int pointCount)
3200 {
3201     Q_D(QRasterPaintEngine);
3202     QRasterPaintEngineState *s = state();
3203
3204     ensurePen();
3205     if (!s->penData.blend)
3206         return;
3207
3208     if (!s->flags.fast_pen) {
3209         QPaintEngineEx::drawPoints(points, pointCount);
3210         return;
3211     }
3212
3213     QCosmeticStroker stroker(s, d->deviceRect);
3214     stroker.drawPoints(points, pointCount);
3215 }
3216
3217
3218 void QRasterPaintEngine::drawPoints(const QPoint *points, int pointCount)
3219 {
3220     Q_D(QRasterPaintEngine);
3221     QRasterPaintEngineState *s = state();
3222
3223     ensurePen();
3224     if (!s->penData.blend)
3225         return;
3226
3227     if (!s->flags.fast_pen) {
3228         QPaintEngineEx::drawPoints(points, pointCount);
3229         return;
3230     }
3231
3232     QCosmeticStroker stroker(s, d->deviceRect);
3233     stroker.drawPoints(points, pointCount);
3234 }
3235
3236 /*!
3237     \reimp
3238 */
3239 void QRasterPaintEngine::drawLines(const QLine *lines, int lineCount)
3240 {
3241 #ifdef QT_DEBUG_DRAW
3242     qDebug() << " - QRasterPaintEngine::drawLines(QLine*)" << lineCount;
3243 #endif
3244     Q_D(QRasterPaintEngine);
3245     QRasterPaintEngineState *s = state();
3246
3247     ensurePen();
3248     if (!s->penData.blend)
3249         return;
3250
3251     if (s->flags.fast_pen) {
3252         QCosmeticStroker stroker(s, d->deviceRect);
3253         for (int i=0; i<lineCount; ++i) {
3254             const QLine &l = lines[i];
3255             stroker.drawLine(l.p1(), l.p2());
3256         }
3257     } else {
3258         QPaintEngineEx::drawLines(lines, lineCount);
3259     }
3260 }
3261
3262 void QRasterPaintEnginePrivate::rasterizeLine_dashed(QLineF line,
3263                                                      qreal width,
3264                                                      int *dashIndex,
3265                                                      qreal *dashOffset,
3266                                                      bool *inDash)
3267 {
3268     Q_Q(QRasterPaintEngine);
3269     QRasterPaintEngineState *s = q->state();
3270
3271     const QPen &pen = s->lastPen;
3272     const bool squareCap = (pen.capStyle() == Qt::SquareCap);
3273     const QVector<qreal> pattern = pen.dashPattern();
3274
3275     qreal patternLength = 0;
3276     for (int i = 0; i < pattern.size(); ++i)
3277         patternLength += pattern.at(i);
3278
3279     if (patternLength <= 0)
3280         return;
3281
3282     qreal length = line.length();
3283     Q_ASSERT(length > 0);
3284     while (length > 0) {
3285         const bool rasterize = *inDash;
3286         qreal dash = (pattern.at(*dashIndex) - *dashOffset) * width;
3287         QLineF l = line;
3288
3289         if (dash >= length) {
3290             dash = length;
3291             *dashOffset += dash / width;
3292             length = 0;
3293         } else {
3294             *dashOffset = 0;
3295             *inDash = !(*inDash);
3296             if (++*dashIndex >= pattern.size())
3297                 *dashIndex = 0;
3298             length -= dash;
3299             l.setLength(dash);
3300             line.setP1(l.p2());
3301         }
3302
3303         if (rasterize && dash > 0)
3304             rasterizer->rasterizeLine(l.p1(), l.p2(), width / dash, squareCap);
3305     }
3306 }
3307
3308 /*!
3309     \reimp
3310 */
3311 void QRasterPaintEngine::drawLines(const QLineF *lines, int lineCount)
3312 {
3313 #ifdef QT_DEBUG_DRAW
3314     qDebug() << " - QRasterPaintEngine::drawLines(QLineF *)" << lineCount;
3315 #endif
3316     Q_D(QRasterPaintEngine);
3317     QRasterPaintEngineState *s = state();
3318
3319     ensurePen();
3320     if (!s->penData.blend)
3321         return;
3322     if (s->flags.fast_pen) {
3323         QCosmeticStroker stroker(s, d->deviceRect);
3324         for (int i=0; i<lineCount; ++i) {
3325             QLineF line = lines[i];
3326             stroker.drawLine(line.p1(), line.p2());
3327         }
3328     } else {
3329         QPaintEngineEx::drawLines(lines, lineCount);
3330     }
3331 }
3332
3333
3334 /*!
3335     \reimp
3336 */
3337 void QRasterPaintEngine::drawEllipse(const QRectF &rect)
3338 {
3339     QPaintEngineEx::drawEllipse(rect);
3340 }
3341
3342 /*!
3343     \internal
3344 */
3345 #ifdef Q_WS_MAC
3346 void QRasterPaintEngine::setCGContext(CGContextRef ctx)
3347 {
3348     Q_D(QRasterPaintEngine);
3349     d->cgContext = ctx;
3350 }
3351
3352 /*!
3353     \internal
3354 */
3355 CGContextRef QRasterPaintEngine::getCGContext() const
3356 {
3357     Q_D(const QRasterPaintEngine);
3358     return d->cgContext;
3359 }
3360 #endif
3361
3362 #ifdef Q_WS_WIN
3363 /*!
3364     \internal
3365 */
3366 void QRasterPaintEngine::setDC(HDC hdc) {
3367     Q_D(QRasterPaintEngine);
3368     d->hdc = hdc;
3369 }
3370
3371 /*!
3372     \internal
3373 */
3374 HDC QRasterPaintEngine::getDC() const
3375 {
3376     Q_D(const QRasterPaintEngine);
3377     return d->hdc;
3378 }
3379
3380 /*!
3381     \internal
3382 */
3383 void QRasterPaintEngine::releaseDC(HDC) const
3384 {
3385 }
3386
3387 #endif
3388
3389 /*!
3390     \internal
3391 */
3392 QPoint QRasterPaintEngine::coordinateOffset() const
3393 {
3394     return QPoint(0, 0);
3395 }
3396
3397 /*!
3398     Draws the given color \a spans with the specified \a color. The \a
3399     count parameter specifies the number of spans.
3400
3401     The default implementation does nothing; reimplement this function
3402     to draw the given color \a spans with the specified \a color. Note
3403     that this function \e must be reimplemented if the framebuffer is
3404     not memory-mapped.
3405
3406     \sa drawBufferSpan()
3407 */
3408 #if defined(Q_WS_QWS) && !defined(QT_NO_RASTERCALLBACKS)
3409 void QRasterPaintEngine::drawColorSpans(const QSpan *spans, int count, uint color)
3410 {
3411     Q_UNUSED(spans);
3412     Q_UNUSED(count);
3413     Q_UNUSED(color);
3414     qFatal("QRasterPaintEngine::drawColorSpans must be reimplemented on "
3415            "a non memory-mapped device");
3416 }
3417
3418 /*!
3419     \fn void QRasterPaintEngine::drawBufferSpan(const uint *buffer, int size, int x, int y, int length, uint alpha)
3420
3421     Draws the given \a buffer.
3422
3423     The default implementation does nothing; reimplement this function
3424     to draw a buffer that contains more than one color. Note that this
3425     function \e must be reimplemented if the framebuffer is not
3426     memory-mapped.
3427
3428     The \a size parameter specifies the total size of the given \a
3429     buffer, while the \a length parameter specifies the number of
3430     pixels to draw. The buffer's position is given by (\a x, \a
3431     y). The provided \a alpha value is added to each pixel in the
3432     buffer when drawing.
3433
3434     \sa drawColorSpans()
3435 */
3436 void QRasterPaintEngine::drawBufferSpan(const uint *buffer, int bufsize,
3437                                         int x, int y, int length, uint const_alpha)
3438 {
3439     Q_UNUSED(buffer);
3440     Q_UNUSED(bufsize);
3441     Q_UNUSED(x);
3442     Q_UNUSED(y);
3443     Q_UNUSED(length);
3444     Q_UNUSED(const_alpha);
3445     qFatal("QRasterPaintEngine::drawBufferSpan must be reimplemented on "
3446            "a non memory-mapped device");
3447 }
3448 #endif // Q_WS_QWS
3449
3450 void QRasterPaintEngine::drawBitmap(const QPointF &pos, const QImage &image, QSpanData *fg)
3451 {
3452     Q_ASSERT(fg);
3453     if (!fg->blend)
3454         return;
3455     Q_D(QRasterPaintEngine);
3456
3457     Q_ASSERT(image.depth() == 1);
3458
3459     const int spanCount = 256;
3460     QT_FT_Span spans[spanCount];
3461     int n = 0;
3462
3463     // Boundaries
3464     int w = image.width();
3465     int h = image.height();
3466     int ymax = qMin(qRound(pos.y() + h), d->rasterBuffer->height());
3467     int ymin = qMax(qRound(pos.y()), 0);
3468     int xmax = qMin(qRound(pos.x() + w), d->rasterBuffer->width());
3469     int xmin = qMax(qRound(pos.x()), 0);
3470
3471     int x_offset = xmin - qRound(pos.x());
3472
3473     QImage::Format format = image.format();
3474     for (int y = ymin; y < ymax; ++y) {
3475         const uchar *src = image.scanLine(y - qRound(pos.y()));
3476         if (format == QImage::Format_MonoLSB) {
3477             for (int x = 0; x < xmax - xmin; ++x) {
3478                 int src_x = x + x_offset;
3479                 uchar pixel = src[src_x >> 3];
3480                 if (!pixel) {
3481                     x += 7 - (src_x%8);
3482                     continue;
3483                 }
3484                 if (pixel & (0x1 << (src_x & 7))) {
3485                     spans[n].x = xmin + x;
3486                     spans[n].y = y;
3487                     spans[n].coverage = 255;
3488                     int len = 1;
3489                     while (src_x < w-1 && src[(src_x+1) >> 3] & (0x1 << ((src_x+1) & 7))) {
3490                         ++src_x;
3491                         ++len;
3492                     }
3493                     spans[n].len = ((len + spans[n].x) > xmax) ? (xmax - spans[n].x) : len;
3494                     x += len;
3495                     ++n;
3496                     if (n == spanCount) {
3497                         fg->blend(n, spans, fg);
3498                         n = 0;
3499                     }
3500                 }
3501             }
3502         } else {
3503             for (int x = 0; x < xmax - xmin; ++x) {
3504                 int src_x = x + x_offset;
3505                 uchar pixel = src[src_x >> 3];
3506                 if (!pixel) {
3507                     x += 7 - (src_x%8);
3508                     continue;
3509                 }
3510                 if (pixel & (0x80 >> (x & 7))) {
3511                     spans[n].x = xmin + x;
3512                     spans[n].y = y;
3513                     spans[n].coverage = 255;
3514                     int len = 1;
3515                     while (src_x < w-1 && src[(src_x+1) >> 3] & (0x80 >> ((src_x+1) & 7))) {
3516                         ++src_x;
3517                         ++len;
3518                     }
3519                     spans[n].len = ((len + spans[n].x) > xmax) ? (xmax - spans[n].x) : len;
3520                     x += len;
3521                     ++n;
3522                     if (n == spanCount) {
3523                         fg->blend(n, spans, fg);
3524                         n = 0;
3525                     }
3526                 }
3527             }
3528         }
3529     }
3530     if (n) {
3531         fg->blend(n, spans, fg);
3532         n = 0;
3533     }
3534 }
3535
3536 /*!
3537     \enum QRasterPaintEngine::ClipType
3538     \internal
3539
3540     \value RectClip Indicates that the currently set clip is a single rectangle.
3541     \value ComplexClip Indicates that the currently set clip is a combination of several shapes.
3542 */
3543
3544 /*!
3545     \internal
3546     Returns the type of the clip currently set.
3547 */
3548 QRasterPaintEngine::ClipType QRasterPaintEngine::clipType() const
3549 {
3550     Q_D(const QRasterPaintEngine);
3551
3552     const QClipData *clip = d->clip();
3553     if (!clip || clip->hasRectClip)
3554         return RectClip;
3555     else
3556         return ComplexClip;
3557 }
3558
3559 /*!
3560     \internal
3561     Returns the bounding rect of the currently set clip.
3562 */
3563 QRect QRasterPaintEngine::clipBoundingRect() const
3564 {
3565     Q_D(const QRasterPaintEngine);
3566
3567     const QClipData *clip = d->clip();
3568
3569     if (!clip)
3570         return d->deviceRect;
3571
3572     if (clip->hasRectClip)
3573         return clip->clipRect;
3574
3575     return QRect(clip->xmin, clip->ymin, clip->xmax - clip->xmin, clip->ymax - clip->ymin);
3576 }
3577
3578 static void qt_merge_clip(const QClipData *c1, const QClipData *c2, QClipData *result)
3579 {
3580     Q_ASSERT(c1->clipSpanHeight == c2->clipSpanHeight && c1->clipSpanHeight == result->clipSpanHeight);
3581
3582     QVarLengthArray<short, 4096> buffer;
3583
3584     QClipData::ClipLine *c1ClipLines = const_cast<QClipData *>(c1)->clipLines();
3585     QClipData::ClipLine *c2ClipLines = const_cast<QClipData *>(c2)->clipLines();
3586     result->initialize();
3587
3588     for (int y = 0; y < c1->clipSpanHeight; ++y) {
3589         const QSpan *c1_spans = c1ClipLines[y].spans;
3590         int c1_count = c1ClipLines[y].count;
3591         const QSpan *c2_spans = c2ClipLines[y].spans;
3592         int c2_count = c2ClipLines[y].count;
3593
3594         if (c1_count == 0 && c2_count == 0)
3595             continue;
3596         if (c1_count == 0) {
3597             result->appendSpans(c2_spans, c2_count);
3598             continue;
3599         } else if (c2_count == 0) {
3600             result->appendSpans(c1_spans, c1_count);
3601             continue;
3602         }
3603
3604         // we need to merge the two
3605
3606         // find required length
3607         int max = qMax(c1_spans[c1_count - 1].x + c1_spans[c1_count - 1].len,
3608                 c2_spans[c2_count - 1].x + c2_spans[c2_count - 1].len);
3609         buffer.resize(max);
3610         memset(buffer.data(), 0, buffer.size() * sizeof(short));
3611
3612         // Fill with old spans.
3613         for (int i = 0; i < c1_count; ++i) {
3614             const QSpan *cs = c1_spans + i;
3615             for (int j=cs->x; j<cs->x + cs->len; ++j)
3616                 buffer[j] = cs->coverage;
3617         }
3618
3619         // Fill with new spans
3620         for (int i = 0; i < c2_count; ++i) {
3621             const QSpan *cs = c2_spans + i;
3622             for (int j = cs->x; j < cs->x + cs->len; ++j) {
3623                 buffer[j] += cs->coverage;
3624                 if (buffer[j] > 255)
3625                     buffer[j] = 255;
3626             }
3627         }
3628
3629         int x = 0;
3630         while (x<max) {
3631
3632             // Skip to next span
3633             while (x < max && buffer[x] == 0) ++x;
3634             if (x >= max) break;
3635
3636             int sx = x;
3637             int coverage = buffer[x];
3638
3639             // Find length of span
3640             while (x < max && buffer[x] == coverage)
3641                 ++x;
3642
3643             result->appendSpan(sx, x - sx, y, coverage);
3644         }
3645     }
3646 }
3647
3648 void QRasterPaintEnginePrivate::initializeRasterizer(QSpanData *data)
3649 {
3650     Q_Q(QRasterPaintEngine);
3651     QRasterPaintEngineState *s = q->state();
3652
3653     rasterizer->setAntialiased(s->flags.antialiased);
3654
3655     QRect clipRect(deviceRect);
3656     ProcessSpans blend;
3657     // ### get from optimized rectbased QClipData
3658
3659     const QClipData *c = clip();
3660     if (c) {
3661         const QRect r(QPoint(c->xmin, c->ymin),
3662                       QSize(c->xmax - c->xmin, c->ymax - c->ymin));
3663         clipRect = clipRect.intersected(r);
3664         blend = data->blend;
3665     } else {
3666         blend = data->unclipped_blend;
3667     }
3668
3669     rasterizer->setClipRect(clipRect);
3670     rasterizer->initialize(blend, data);
3671 }
3672
3673 void QRasterPaintEnginePrivate::rasterize(QT_FT_Outline *outline,
3674                                           ProcessSpans callback,
3675                                           QSpanData *spanData, QRasterBuffer *rasterBuffer)
3676 {
3677     if (!callback || !outline)
3678         return;
3679
3680     Q_Q(QRasterPaintEngine);
3681     QRasterPaintEngineState *s = q->state();
3682
3683     if (!s->flags.antialiased) {
3684         initializeRasterizer(spanData);
3685
3686         const Qt::FillRule fillRule = outline->flags == QT_FT_OUTLINE_NONE
3687                                       ? Qt::WindingFill
3688                                       : Qt::OddEvenFill;
3689
3690         rasterizer->rasterize(outline, fillRule);
3691         return;
3692     }
3693
3694     rasterize(outline, callback, (void *)spanData, rasterBuffer);
3695 }
3696
3697 extern "C" {
3698     int q_gray_rendered_spans(QT_FT_Raster raster);
3699 }
3700
3701 void QRasterPaintEnginePrivate::rasterize(QT_FT_Outline *outline,
3702                                           ProcessSpans callback,
3703                                           void *userData, QRasterBuffer *)
3704 {
3705     if (!callback || !outline)
3706         return;
3707
3708     Q_Q(QRasterPaintEngine);
3709     QRasterPaintEngineState *s = q->state();
3710
3711     if (!s->flags.antialiased) {
3712         rasterizer->setAntialiased(s->flags.antialiased);
3713         rasterizer->setClipRect(deviceRect);
3714         rasterizer->initialize(callback, userData);
3715
3716         const Qt::FillRule fillRule = outline->flags == QT_FT_OUTLINE_NONE
3717                                       ? Qt::WindingFill
3718                                       : Qt::OddEvenFill;
3719
3720         rasterizer->rasterize(outline, fillRule);
3721         return;
3722     }
3723
3724     // Initial size for raster pool is MINIMUM_POOL_SIZE so as to
3725     // minimize memory reallocations. However if initial size for
3726     // raster pool is changed for lower value, reallocations will
3727     // occur normally.
3728     const int rasterPoolInitialSize = MINIMUM_POOL_SIZE;
3729     int rasterPoolSize = rasterPoolInitialSize;
3730     unsigned char *rasterPoolBase;
3731 #if defined(Q_WS_WIN64)
3732     rasterPoolBase =
3733         // We make use of setjmp and longjmp in qgrayraster.c which requires
3734         // 16-byte alignment, hence we hardcode this requirement here..
3735         (unsigned char *) _aligned_malloc(rasterPoolSize, sizeof(void*) * 2);
3736 #else
3737     unsigned char rasterPoolOnStack[rasterPoolInitialSize];
3738     rasterPoolBase = rasterPoolOnStack;
3739 #endif
3740     Q_CHECK_PTR(rasterPoolBase);
3741
3742     qt_ft_grays_raster.raster_reset(*grayRaster.data(), rasterPoolBase, rasterPoolSize);
3743
3744     void *data = userData;
3745
3746     QT_FT_BBox clip_box = { deviceRect.x(),
3747                             deviceRect.y(),
3748                             deviceRect.x() + deviceRect.width(),
3749                             deviceRect.y() + deviceRect.height() };
3750
3751     QT_FT_Raster_Params rasterParams;
3752     rasterParams.target = 0;
3753     rasterParams.source = outline;
3754     rasterParams.flags = QT_FT_RASTER_FLAG_CLIP;
3755     rasterParams.gray_spans = 0;
3756     rasterParams.black_spans = 0;
3757     rasterParams.bit_test = 0;
3758     rasterParams.bit_set = 0;
3759     rasterParams.user = data;
3760     rasterParams.clip_box = clip_box;
3761
3762     bool done = false;
3763     int error;
3764
3765     int rendered_spans = 0;
3766
3767     while (!done) {
3768
3769         rasterParams.flags |= (QT_FT_RASTER_FLAG_AA | QT_FT_RASTER_FLAG_DIRECT);
3770         rasterParams.gray_spans = callback;
3771         rasterParams.skip_spans = rendered_spans;
3772         error = qt_ft_grays_raster.raster_render(*grayRaster.data(), &rasterParams);
3773
3774         // Out of memory, reallocate some more and try again...
3775         if (error == -6) { // ErrRaster_OutOfMemory from qgrayraster.c
3776             int new_size = rasterPoolSize * 2;
3777             if (new_size > 1024 * 1024) {
3778                 qWarning("QPainter: Rasterization of primitive failed");
3779                 break;
3780             }
3781
3782             rendered_spans += q_gray_rendered_spans(*grayRaster.data());
3783
3784 #if defined(Q_WS_WIN64)
3785             _aligned_free(rasterPoolBase);
3786 #else
3787             if (rasterPoolBase != rasterPoolOnStack) // initially on the stack
3788                 free(rasterPoolBase);
3789 #endif
3790
3791             rasterPoolSize = new_size;
3792             rasterPoolBase =
3793 #if defined(Q_WS_WIN64)
3794                 // We make use of setjmp and longjmp in qgrayraster.c which requires
3795                 // 16-byte alignment, hence we hardcode this requirement here..
3796                 (unsigned char *) _aligned_malloc(rasterPoolSize, sizeof(void*) * 2);
3797 #else
3798                 (unsigned char *) malloc(rasterPoolSize);
3799 #endif
3800             Q_CHECK_PTR(rasterPoolBase); // note: we just freed the old rasterPoolBase. I hope it's not fatal.
3801
3802             qt_ft_grays_raster.raster_done(*grayRaster.data());
3803             qt_ft_grays_raster.raster_new(grayRaster.data());
3804             qt_ft_grays_raster.raster_reset(*grayRaster.data(), rasterPoolBase, rasterPoolSize);
3805         } else {
3806             done = true;
3807         }
3808     }
3809
3810 #if defined(Q_WS_WIN64)
3811     _aligned_free(rasterPoolBase);
3812 #else
3813     if (rasterPoolBase != rasterPoolOnStack) // initially on the stack
3814         free(rasterPoolBase);
3815 #endif
3816 }
3817
3818 void QRasterPaintEnginePrivate::recalculateFastImages()
3819 {
3820     Q_Q(QRasterPaintEngine);
3821     QRasterPaintEngineState *s = q->state();
3822
3823     s->flags.fast_images = !(s->renderHints & QPainter::SmoothPixmapTransform)
3824                            && s->matrix.type() <= QTransform::TxShear;
3825 }
3826
3827 bool QRasterPaintEnginePrivate::canUseFastImageBlending(QPainter::CompositionMode mode, const QImage &image) const
3828 {
3829     Q_Q(const QRasterPaintEngine);
3830     const QRasterPaintEngineState *s = q->state();
3831
3832     return s->flags.fast_images
3833            && (mode == QPainter::CompositionMode_SourceOver
3834                || (mode == QPainter::CompositionMode_Source
3835                    && !image.hasAlphaChannel()));
3836 }
3837
3838 QImage QRasterBuffer::colorizeBitmap(const QImage &image, const QColor &color)
3839 {
3840     Q_ASSERT(image.depth() == 1);
3841
3842     QImage sourceImage = image.convertToFormat(QImage::Format_MonoLSB);
3843     QImage dest = QImage(sourceImage.size(), QImage::Format_ARGB32_Premultiplied);
3844
3845     QRgb fg = PREMUL(color.rgba());
3846     QRgb bg = 0;
3847
3848     int height = sourceImage.height();
3849     int width = sourceImage.width();
3850     for (int y=0; y<height; ++y) {
3851         uchar *source = sourceImage.scanLine(y);
3852         QRgb *target = reinterpret_cast<QRgb *>(dest.scanLine(y));
3853         if (!source || !target)
3854             QT_THROW(std::bad_alloc()); // we must have run out of memory
3855         for (int x=0; x < width; ++x)
3856             target[x] = (source[x>>3] >> (x&7)) & 1 ? fg : bg;
3857     }
3858     return dest;
3859 }
3860
3861 QRasterBuffer::~QRasterBuffer()
3862 {
3863 }
3864
3865 void QRasterBuffer::init()
3866 {
3867     compositionMode = QPainter::CompositionMode_SourceOver;
3868     monoDestinationWithClut = false;
3869     destColor0 = 0;
3870     destColor1 = 0;
3871 }
3872
3873 QImage::Format QRasterBuffer::prepare(QImage *image)
3874 {
3875     m_buffer = (uchar *)image->bits();
3876     m_width = qMin(QT_RASTER_COORD_LIMIT, image->width());
3877     m_height = qMin(QT_RASTER_COORD_LIMIT, image->height());
3878     bytes_per_pixel = image->depth()/8;
3879     bytes_per_line = image->bytesPerLine();
3880
3881     format = image->format();
3882     drawHelper = qDrawHelper + format;
3883     if (image->depth() == 1 && image->colorTable().size() == 2) {
3884         monoDestinationWithClut = true;
3885         destColor0 = PREMUL(image->colorTable()[0]);
3886         destColor1 = PREMUL(image->colorTable()[1]);
3887     }
3888
3889     return format;
3890 }
3891
3892 void QRasterBuffer::resetBuffer(int val)
3893 {
3894     memset(m_buffer, val, m_height*bytes_per_line);
3895 }
3896
3897
3898 #if defined(Q_WS_QWS)
3899 void QRasterBuffer::prepare(QCustomRasterPaintDevice *device)
3900 {
3901     m_buffer = reinterpret_cast<uchar*>(device->memory());
3902     m_width = qMin(QT_RASTER_COORD_LIMIT, device->width());
3903     m_height = qMin(QT_RASTER_COORD_LIMIT, device->height());
3904     bytes_per_pixel = device->depth() / 8;
3905     bytes_per_line = device->bytesPerLine();
3906     format = device->format();
3907 #ifndef QT_NO_RASTERCALLBACKS
3908     if (!m_buffer)
3909         drawHelper = qDrawHelperCallback + format;
3910     else
3911 #endif
3912         drawHelper = qDrawHelper + format;
3913 }
3914
3915 int QCustomRasterPaintDevice::metric(PaintDeviceMetric m) const
3916 {
3917     switch (m) {
3918     case PdmWidth:
3919         return widget->frameGeometry().width();
3920     case PdmHeight:
3921         return widget->frameGeometry().height();
3922     default:
3923         break;
3924     }
3925
3926     return qt_paint_device_metric(widget, m);
3927 }
3928
3929 int QCustomRasterPaintDevice::bytesPerLine() const
3930 {
3931     return (width() * depth() + 7) / 8;
3932 }
3933
3934 #elif defined(Q_OS_SYMBIAN)
3935
3936 void QRasterBuffer::prepareBuffer(int /* width */, int /* height */)
3937 {
3938 }
3939
3940 #endif // Q_OS_SYMBIAN
3941
3942 /*!
3943     \class QCustomRasterPaintDevice
3944     \preliminary
3945     \ingroup qws
3946     \since 4.2
3947
3948     \brief The QCustomRasterPaintDevice class is provided to activate
3949     hardware accelerated paint engines in Qt for Embedded Linux.
3950
3951     Note that this class is only available in \l{Qt for Embedded Linux}.
3952
3953     In \l{Qt for Embedded Linux}, painting is a pure software
3954     implementation. But starting with Qt 4.2, it is
3955     possible to add an accelerated graphics driver to take advantage
3956     of available hardware resources.
3957
3958     Hardware acceleration is accomplished by creating a custom screen
3959     driver, accelerating the copying from memory to the screen, and
3960     implementing a custom paint engine accelerating the various
3961     painting operations. Then a custom paint device (derived from the
3962     QCustomRasterPaintDevice class) and a custom window surface
3963     (derived from QWSWindowSurface) must be implemented to make
3964     \l{Qt for Embedded Linux} aware of the accelerated driver.
3965
3966     See the \l {Adding an Accelerated Graphics Driver to Qt for Embedded Linux}
3967     documentation for details.
3968
3969     \sa QRasterPaintEngine, QPaintDevice
3970 */
3971
3972 /*!
3973     \fn QCustomRasterPaintDevice::QCustomRasterPaintDevice(QWidget *widget)
3974
3975     Constructs a custom raster based paint device for the given
3976     top-level \a widget.
3977 */
3978
3979 /*!
3980     \fn int QCustomRasterPaintDevice::bytesPerLine() const
3981
3982     Returns the number of bytes per line in the framebuffer. Note that
3983     this number might be larger than the framebuffer width.
3984 */
3985
3986 /*!
3987     \fn int QCustomRasterPaintDevice::devType() const
3988     \internal
3989 */
3990
3991 /*!
3992     \fn QImage::Format QCustomRasterPaintDevice::format() const
3993
3994     Returns the format of the device's memory buffet.
3995
3996     The default format is QImage::Format_ARGB32_Premultiplied. The
3997     only other valid format is QImage::Format_RGB16.
3998 */
3999
4000 /*!
4001     \fn void * QCustomRasterPaintDevice::memory () const
4002
4003     Returns a pointer to the paint device's memory buffer, or 0 if no
4004     such buffer exists.
4005 */
4006
4007 /*!
4008     \fn int QCustomRasterPaintDevice::metric ( PaintDeviceMetric m ) const
4009     \reimp
4010 */
4011
4012 /*!
4013     \fn QSize QCustomRasterPaintDevice::size () const
4014     \internal
4015 */
4016
4017
4018 QClipData::QClipData(int height)
4019 {
4020     clipSpanHeight = height;
4021     m_clipLines = 0;
4022
4023     allocated = 0;
4024     m_spans = 0;
4025     xmin = xmax = ymin = ymax = 0;
4026     count = 0;
4027
4028     enabled = true;
4029     hasRectClip = hasRegionClip = false;
4030 }
4031
4032 QClipData::~QClipData()
4033 {
4034     if (m_clipLines)
4035         free(m_clipLines);
4036     if (m_spans)
4037         free(m_spans);
4038 }
4039
4040 void QClipData::initialize()
4041 {
4042     if (m_spans)
4043         return;
4044
4045     if (!m_clipLines)
4046         m_clipLines = (ClipLine *)calloc(sizeof(ClipLine), clipSpanHeight);
4047
4048     Q_CHECK_PTR(m_clipLines);
4049     QT_TRY {
4050         m_spans = (QSpan *)malloc(clipSpanHeight*sizeof(QSpan));
4051         allocated = clipSpanHeight;
4052         Q_CHECK_PTR(m_spans);
4053
4054         QT_TRY {
4055             if (hasRectClip) {
4056                 int y = 0;
4057                 while (y < ymin) {
4058                     m_clipLines[y].spans = 0;
4059                     m_clipLines[y].count = 0;
4060                     ++y;
4061                 }
4062
4063                 const int len = clipRect.width();
4064                 count = 0;
4065                 while (y < ymax) {
4066                     QSpan *span = m_spans + count;
4067                     span->x = xmin;
4068                     span->len = len;
4069                     span->y = y;
4070                     span->coverage = 255;
4071                     ++count;
4072
4073                     m_clipLines[y].spans = span;
4074                     m_clipLines[y].count = 1;
4075                     ++y;
4076                 }
4077
4078                 while (y < clipSpanHeight) {
4079                     m_clipLines[y].spans = 0;
4080                     m_clipLines[y].count = 0;
4081                     ++y;
4082                 }
4083             } else if (hasRegionClip) {
4084
4085                 const QVector<QRect> rects = clipRegion.rects();
4086                 const int numRects = rects.size();
4087
4088                 { // resize
4089                     const int maxSpans = (ymax - ymin) * numRects;
4090                     if (maxSpans > allocated) {
4091                         m_spans = q_check_ptr((QSpan *)realloc(m_spans, maxSpans * sizeof(QSpan)));
4092                         allocated = maxSpans;
4093                     }
4094                 }
4095
4096                 int y = 0;
4097                 int firstInBand = 0;
4098                 count = 0;
4099                 while (firstInBand < numRects) {
4100                     const int currMinY = rects.at(firstInBand).y();
4101                     const int currMaxY = currMinY + rects.at(firstInBand).height();
4102
4103                     while (y < currMinY) {
4104                         m_clipLines[y].spans = 0;
4105                         m_clipLines[y].count = 0;
4106                         ++y;
4107                     }
4108
4109                     int lastInBand = firstInBand;
4110                     while (lastInBand + 1 < numRects && rects.at(lastInBand+1).top() == y)
4111                         ++lastInBand;
4112
4113                     while (y < currMaxY) {
4114
4115                         m_clipLines[y].spans = m_spans + count;
4116                         m_clipLines[y].count = lastInBand - firstInBand + 1;
4117
4118                         for (int r = firstInBand; r <= lastInBand; ++r) {
4119                             const QRect &currRect = rects.at(r);
4120                             QSpan *span = m_spans + count;
4121                             span->x = currRect.x();
4122                             span->len = currRect.width();
4123                             span->y = y;
4124                             span->coverage = 255;
4125                             ++count;
4126                         }
4127                         ++y;
4128                     }
4129
4130                     firstInBand = lastInBand + 1;
4131                 }
4132
4133                 Q_ASSERT(count <= allocated);
4134
4135                 while (y < clipSpanHeight) {
4136                     m_clipLines[y].spans = 0;
4137                     m_clipLines[y].count = 0;
4138                     ++y;
4139                 }
4140
4141             }
4142         } QT_CATCH(...) {
4143             free(m_spans); // have to free m_spans again or someone might think that we were successfully initialized.
4144             m_spans = 0;
4145             QT_RETHROW;
4146         }
4147     } QT_CATCH(...) {
4148         free(m_clipLines); // same for clipLines
4149         m_clipLines = 0;
4150         QT_RETHROW;
4151     }
4152 }
4153
4154 void QClipData::fixup()
4155 {
4156     Q_ASSERT(m_spans);
4157
4158     if (count == 0) {
4159         ymin = ymax = xmin = xmax = 0;
4160         return;
4161     }
4162
4163     int y = -1;
4164     ymin = m_spans[0].y;
4165     ymax = m_spans[count-1].y + 1;
4166     xmin = INT_MAX;
4167     xmax = 0;
4168
4169     const int firstLeft = m_spans[0].x;
4170     const int firstRight = m_spans[0].x + m_spans[0].len;
4171     bool isRect = true;
4172
4173     for (int i = 0; i < count; ++i) {
4174         QT_FT_Span_& span = m_spans[i];
4175
4176         if (span.y != y) {
4177             if (span.y != y + 1 && y != -1)
4178                 isRect = false;
4179             y = span.y;
4180             m_clipLines[y].spans = &span;
4181             m_clipLines[y].count = 1;
4182         } else
4183             ++m_clipLines[y].count;
4184
4185         const int spanLeft = span.x;
4186         const int spanRight = spanLeft + span.len;
4187
4188         if (spanLeft < xmin)
4189             xmin = spanLeft;
4190
4191         if (spanRight > xmax)
4192             xmax = spanRight;
4193
4194         if (spanLeft != firstLeft || spanRight != firstRight)
4195             isRect = false;
4196     }
4197
4198     if (isRect) {
4199         hasRectClip = true;
4200         clipRect.setRect(xmin, ymin, xmax - xmin, ymax - ymin);
4201     }
4202 }
4203
4204 /*
4205     Convert \a rect to clip spans.
4206  */
4207 void QClipData::setClipRect(const QRect &rect)
4208 {
4209     if (hasRectClip && rect == clipRect)
4210         return;
4211
4212 //    qDebug() << "setClipRect" << clipSpanHeight << count << allocated << rect;
4213     hasRectClip = true;
4214     hasRegionClip = false;
4215     clipRect = rect;
4216
4217     xmin = rect.x();
4218     xmax = rect.x() + rect.width();
4219     ymin = qMin(rect.y(), clipSpanHeight);
4220     ymax = qMin(rect.y() + rect.height(), clipSpanHeight);
4221
4222     if (m_spans) {
4223         free(m_spans);
4224         m_spans = 0;
4225     }
4226
4227 //    qDebug() << xmin << xmax << ymin << ymax;
4228 }
4229
4230 /*
4231     Convert \a region to clip spans.
4232  */
4233 void QClipData::setClipRegion(const QRegion &region)
4234 {
4235     if (region.rectCount() == 1) {
4236         setClipRect(region.rects().at(0));
4237         return;
4238     }
4239
4240     hasRegionClip = true;
4241     hasRectClip = false;
4242     clipRegion = region;
4243
4244     { // set bounding rect
4245         const QRect rect = region.boundingRect();
4246         xmin = rect.x();
4247         xmax = rect.x() + rect.width();
4248         ymin = rect.y();
4249         ymax = rect.y() + rect.height();
4250     }
4251
4252     if (m_spans) {
4253         free(m_spans);
4254         m_spans = 0;
4255     }
4256
4257 }
4258
4259 /*!
4260     \internal
4261     spans must be sorted on y
4262 */
4263 static const QSpan *qt_intersect_spans(const QClipData *clip, int *currentClip,
4264                                        const QSpan *spans, const QSpan *end,
4265                                        QSpan **outSpans, int available)
4266 {
4267     const_cast<QClipData *>(clip)->initialize();
4268
4269     QSpan *out = *outSpans;
4270
4271     const QSpan *clipSpans = clip->m_spans + *currentClip;
4272     const QSpan *clipEnd = clip->m_spans + clip->count;
4273
4274     while (available && spans < end ) {
4275         if (clipSpans >= clipEnd) {
4276             spans = end;
4277             break;
4278         }
4279         if (clipSpans->y > spans->y) {
4280             ++spans;
4281             continue;
4282         }
4283         if (spans->y != clipSpans->y) {
4284             if (spans->y < clip->count && clip->m_clipLines[spans->y].spans)
4285                 clipSpans = clip->m_clipLines[spans->y].spans;
4286             else
4287                 ++clipSpans;
4288             continue;
4289         }
4290         Q_ASSERT(spans->y == clipSpans->y);
4291
4292         int sx1 = spans->x;
4293         int sx2 = sx1 + spans->len;
4294         int cx1 = clipSpans->x;
4295         int cx2 = cx1 + clipSpans->len;
4296
4297         if (cx1 < sx1 && cx2 < sx1) {
4298             ++clipSpans;
4299             continue;
4300         } else if (sx1 < cx1 && sx2 < cx1) {
4301             ++spans;
4302             continue;
4303         }
4304         int x = qMax(sx1, cx1);
4305         int len = qMin(sx2, cx2) - x;
4306         if (len) {
4307             out->x = qMax(sx1, cx1);
4308             out->len = qMin(sx2, cx2) - out->x;
4309             out->y = spans->y;
4310             out->coverage = qt_div_255(spans->coverage * clipSpans->coverage);
4311             ++out;
4312             --available;
4313         }
4314         if (sx2 < cx2) {
4315             ++spans;
4316         } else {
4317             ++clipSpans;
4318         }
4319     }
4320
4321     *outSpans = out;
4322     *currentClip = clipSpans - clip->m_spans;
4323     return spans;
4324 }
4325
4326 static void qt_span_fill_clipped(int spanCount, const QSpan *spans, void *userData)
4327 {
4328 //     qDebug() << "qt_span_fill_clipped" << spanCount;
4329     QSpanData *fillData = reinterpret_cast<QSpanData *>(userData);
4330
4331     Q_ASSERT(fillData->blend && fillData->unclipped_blend);
4332
4333     const int NSPANS = 256;
4334     QSpan cspans[NSPANS];
4335     int currentClip = 0;
4336     const QSpan *end = spans + spanCount;
4337     while (spans < end) {
4338         QSpan *clipped = cspans;
4339         spans = qt_intersect_spans(fillData->clip, &currentClip, spans, end, &clipped, NSPANS);
4340 //         qDebug() << "processed " << spanCount - (end - spans) << "clipped" << clipped-cspans
4341 //                  << "span:" << cspans->x << cspans->y << cspans->len << spans->coverage;
4342
4343         if (clipped - cspans)
4344             fillData->unclipped_blend(clipped - cspans, cspans, fillData);
4345     }
4346 }
4347
4348 /*
4349     \internal
4350     Clip spans to \a{clip}-rectangle.
4351     Returns number of unclipped spans
4352 */
4353 static int qt_intersect_spans(QT_FT_Span *spans, int numSpans,
4354                               const QRect &clip)
4355 {
4356     const short minx = clip.left();
4357     const short miny = clip.top();
4358     const short maxx = clip.right();
4359     const short maxy = clip.bottom();
4360
4361     int n = 0;
4362     for (int i = 0; i < numSpans; ++i) {
4363         if (spans[i].y > maxy)
4364             break;
4365         if (spans[i].y < miny
4366             || spans[i].x > maxx
4367             || spans[i].x + spans[i].len <= minx) {
4368             continue;
4369         }
4370         if (spans[i].x < minx) {
4371             spans[n].len = qMin(spans[i].len - (minx - spans[i].x), maxx - minx + 1);
4372             spans[n].x = minx;
4373         } else {
4374             spans[n].x = spans[i].x;
4375             spans[n].len = qMin(spans[i].len, ushort(maxx - spans[n].x + 1));
4376         }
4377         if (spans[n].len == 0)
4378             continue;
4379         spans[n].y = spans[i].y;
4380         spans[n].coverage = spans[i].coverage;
4381         ++n;
4382     }
4383     return n;
4384 }
4385
4386
4387 static void qt_span_fill_clipRect(int count, const QSpan *spans,
4388                                   void *userData)
4389 {
4390     QSpanData *fillData = reinterpret_cast<QSpanData *>(userData);
4391     Q_ASSERT(fillData->blend && fillData->unclipped_blend);
4392
4393     Q_ASSERT(fillData->clip);
4394     Q_ASSERT(!fillData->clip->clipRect.isEmpty());
4395
4396     // hw: check if this const_cast<> is safe!!!
4397     count = qt_intersect_spans(const_cast<QSpan*>(spans), count,
4398                                fillData->clip->clipRect);
4399     if (count > 0)
4400         fillData->unclipped_blend(count, spans, fillData);
4401 }
4402
4403 static void qt_span_clip(int count, const QSpan *spans, void *userData)
4404 {
4405     ClipData *clipData = reinterpret_cast<ClipData *>(userData);
4406
4407 //     qDebug() << " qt_span_clip: " << count << clipData->operation;
4408 //     for (int i = 0; i < qMin(count, 10); ++i) {
4409 //         qDebug() << "    " << spans[i].x << spans[i].y << spans[i].len << spans[i].coverage;
4410 //     }
4411
4412     switch (clipData->operation) {
4413
4414     case Qt::IntersectClip:
4415         {
4416             QClipData *newClip = clipData->newClip;
4417             newClip->initialize();
4418
4419             int currentClip = 0;
4420             const QSpan *end = spans + count;
4421             while (spans < end) {
4422                 QSpan *newspans = newClip->m_spans + newClip->count;
4423                 spans = qt_intersect_spans(clipData->oldClip, &currentClip, spans, end,
4424                                            &newspans, newClip->allocated - newClip->count);
4425                 newClip->count = newspans - newClip->m_spans;
4426                 if (spans < end) {
4427                     newClip->m_spans = q_check_ptr((QSpan *)realloc(newClip->m_spans, newClip->allocated*2*sizeof(QSpan)));
4428                     newClip->allocated *= 2;
4429                 }
4430             }
4431         }
4432         break;
4433
4434     case Qt::UniteClip:
4435     case Qt::ReplaceClip:
4436         clipData->newClip->appendSpans(spans, count);
4437         break;
4438     case Qt::NoClip:
4439         break;
4440     }
4441 }
4442
4443 #ifndef QT_NO_DEBUG
4444 QImage QRasterBuffer::bufferImage() const
4445 {
4446     QImage image(m_width, m_height, QImage::Format_ARGB32_Premultiplied);
4447
4448     for (int y = 0; y < m_height; ++y) {
4449         uint *span = (uint *)const_cast<QRasterBuffer *>(this)->scanLine(y);
4450
4451         for (int x=0; x<m_width; ++x) {
4452             uint argb = span[x];
4453             image.setPixel(x, y, argb);
4454         }
4455     }
4456     return image;
4457 }
4458 #endif
4459
4460
4461 void QRasterBuffer::flushToARGBImage(QImage *target) const
4462 {
4463     int w = qMin(m_width, target->width());
4464     int h = qMin(m_height, target->height());
4465
4466     for (int y=0; y<h; ++y) {
4467         uint *sourceLine = (uint *)const_cast<QRasterBuffer *>(this)->scanLine(y);
4468         QRgb *dest = (QRgb *) target->scanLine(y);
4469         for (int x=0; x<w; ++x) {
4470             QRgb pixel = sourceLine[x];
4471             int alpha = qAlpha(pixel);
4472             if (!alpha) {
4473                 dest[x] = 0;
4474             } else {
4475                 dest[x] = (alpha << 24)
4476                         | ((255*qRed(pixel)/alpha) << 16)
4477                         | ((255*qGreen(pixel)/alpha) << 8)
4478                         | ((255*qBlue(pixel)/alpha) << 0);
4479             }
4480         }
4481     }
4482 }
4483
4484
4485 class QGradientCache
4486 {
4487     struct CacheInfo
4488     {
4489         inline CacheInfo(QGradientStops s, int op, QGradient::InterpolationMode mode) :
4490             stops(s), opacity(op), interpolationMode(mode) {}
4491         uint buffer[GRADIENT_STOPTABLE_SIZE];
4492         QGradientStops stops;
4493         int opacity;
4494         QGradient::InterpolationMode interpolationMode;
4495     };
4496
4497     typedef QMultiHash<quint64, CacheInfo> QGradientColorTableHash;
4498
4499 public:
4500     inline const uint *getBuffer(const QGradient &gradient, int opacity) {
4501         quint64 hash_val = 0;
4502
4503         QGradientStops stops = gradient.stops();
4504         for (int i = 0; i < stops.size() && i <= 2; i++)
4505             hash_val += stops[i].second.rgba();
4506
4507         QMutexLocker lock(&mutex);
4508         QGradientColorTableHash::const_iterator it = cache.constFind(hash_val);
4509
4510         if (it == cache.constEnd())
4511             return addCacheElement(hash_val, gradient, opacity);
4512         else {
4513             do {
4514                 const CacheInfo &cache_info = it.value();
4515                 if (cache_info.stops == stops && cache_info.opacity == opacity && cache_info.interpolationMode == gradient.interpolationMode())
4516                     return cache_info.buffer;
4517                 ++it;
4518             } while (it != cache.constEnd() && it.key() == hash_val);
4519             // an exact match for these stops and opacity was not found, create new cache
4520             return addCacheElement(hash_val, gradient, opacity);
4521         }
4522     }
4523
4524     inline int paletteSize() const { return GRADIENT_STOPTABLE_SIZE; }
4525 protected:
4526     inline int maxCacheSize() const { return 60; }
4527     inline void generateGradientColorTable(const QGradient& g,
4528                                            uint *colorTable,
4529                                            int size, int opacity) const;
4530     uint *addCacheElement(quint64 hash_val, const QGradient &gradient, int opacity) {
4531         if (cache.size() == maxCacheSize()) {
4532             // may remove more than 1, but OK
4533             cache.erase(cache.begin() + (qrand() % maxCacheSize()));
4534         }
4535         CacheInfo cache_entry(gradient.stops(), opacity, gradient.interpolationMode());
4536         generateGradientColorTable(gradient, cache_entry.buffer, paletteSize(), opacity);
4537         return cache.insert(hash_val, cache_entry).value().buffer;
4538     }
4539
4540     QGradientColorTableHash cache;
4541     QMutex mutex;
4542 };
4543
4544 void QGradientCache::generateGradientColorTable(const QGradient& gradient, uint *colorTable, int size, int opacity) const
4545 {
4546     QGradientStops stops = gradient.stops();
4547     int stopCount = stops.count();
4548     Q_ASSERT(stopCount > 0);
4549
4550     bool colorInterpolation = (gradient.interpolationMode() == QGradient::ColorInterpolation);
4551
4552     if (stopCount == 2) {
4553         uint first_color = ARGB_COMBINE_ALPHA(stops[0].second.rgba(), opacity);
4554         uint second_color = ARGB_COMBINE_ALPHA(stops[1].second.rgba(), opacity);
4555
4556         qreal first_stop = stops[0].first;
4557         qreal second_stop = stops[1].first;
4558
4559         if (second_stop < first_stop) {
4560             qSwap(first_color, second_color);
4561             qSwap(first_stop, second_stop);
4562         }
4563
4564         if (colorInterpolation) {
4565             first_color = PREMUL(first_color);
4566             second_color = PREMUL(second_color);
4567         }
4568
4569         int first_index = qRound(first_stop * (GRADIENT_STOPTABLE_SIZE-1));
4570         int second_index = qRound(second_stop * (GRADIENT_STOPTABLE_SIZE-1));
4571
4572         uint red_first = qRed(first_color) << 16;
4573         uint green_first = qGreen(first_color) << 16;
4574         uint blue_first = qBlue(first_color) << 16;
4575         uint alpha_first = qAlpha(first_color) << 16;
4576
4577         uint red_second = qRed(second_color) << 16;
4578         uint green_second = qGreen(second_color) << 16;
4579         uint blue_second = qBlue(second_color) << 16;
4580         uint alpha_second = qAlpha(second_color) << 16;
4581
4582         int i = 0;
4583         for (; i <= qMin(GRADIENT_STOPTABLE_SIZE, first_index); ++i) {
4584             if (colorInterpolation)
4585                 colorTable[i] = first_color;
4586             else
4587                 colorTable[i] = PREMUL(first_color);
4588         }
4589
4590         if (i < second_index) {
4591             qreal reciprocal = qreal(1) / (second_index - first_index);
4592
4593             int red_delta = qRound(int(red_second - red_first) * reciprocal);
4594             int green_delta = qRound(int(green_second - green_first) * reciprocal);
4595             int blue_delta = qRound(int(blue_second - blue_first) * reciprocal);
4596             int alpha_delta = qRound(int(alpha_second - alpha_first) * reciprocal);
4597
4598             // rounding
4599             red_first += 1 << 15;
4600             green_first += 1 << 15;
4601             blue_first += 1 << 15;
4602             alpha_first += 1 << 15;
4603
4604             for (; i < qMin(GRADIENT_STOPTABLE_SIZE, second_index); ++i) {
4605                 red_first += red_delta;
4606                 green_first += green_delta;
4607                 blue_first += blue_delta;
4608                 alpha_first += alpha_delta;
4609
4610                 const uint color = ((alpha_first << 8) & 0xff000000) | (red_first & 0xff0000)
4611                                  | ((green_first >> 8) & 0xff00) | (blue_first >> 16);
4612
4613                 if (colorInterpolation)
4614                     colorTable[i] = color;
4615                 else
4616                     colorTable[i] = PREMUL(color);
4617             }
4618         }
4619
4620         for (; i < GRADIENT_STOPTABLE_SIZE; ++i) {
4621             if (colorInterpolation)
4622                 colorTable[i] = second_color;
4623             else
4624                 colorTable[i] = PREMUL(second_color);
4625         }
4626
4627         return;
4628     }
4629
4630     uint current_color = ARGB_COMBINE_ALPHA(stops[0].second.rgba(), opacity);
4631     if (stopCount == 1) {
4632         current_color = PREMUL(current_color);
4633         for (int i = 0; i < size; ++i)
4634             colorTable[i] = current_color;
4635         return;
4636     }
4637
4638     // The position where the gradient begins and ends
4639     qreal begin_pos = stops[0].first;
4640     qreal end_pos = stops[stopCount-1].first;
4641
4642     int pos = 0; // The position in the color table.
4643     uint next_color;
4644
4645     qreal incr = 1 / qreal(size); // the double increment.
4646     qreal dpos = 1.5 * incr; // current position in gradient stop list (0 to 1)
4647
4648      // Up to first point
4649     colorTable[pos++] = PREMUL(current_color);
4650     while (dpos <= begin_pos) {
4651         colorTable[pos] = colorTable[pos - 1];
4652         ++pos;
4653         dpos += incr;
4654     }
4655
4656     int current_stop = 0; // We always interpolate between current and current + 1.
4657
4658     qreal t; // position between current left and right stops
4659     qreal t_delta; // the t increment per entry in the color table
4660
4661     if (dpos < end_pos) {
4662         // Gradient area
4663         while (dpos > stops[current_stop+1].first)
4664             ++current_stop;
4665
4666         if (current_stop != 0)
4667             current_color = ARGB_COMBINE_ALPHA(stops[current_stop].second.rgba(), opacity);
4668         next_color = ARGB_COMBINE_ALPHA(stops[current_stop+1].second.rgba(), opacity);
4669
4670         if (colorInterpolation) {
4671             current_color = PREMUL(current_color);
4672             next_color = PREMUL(next_color);
4673         }
4674
4675         qreal diff = stops[current_stop+1].first - stops[current_stop].first;
4676         qreal c = (diff == 0) ? qreal(0) : 256 / diff;
4677         t = (dpos - stops[current_stop].first) * c;
4678         t_delta = incr * c;
4679
4680         while (true) {
4681             Q_ASSERT(current_stop < stopCount);
4682
4683             int dist = qRound(t);
4684             int idist = 256 - dist;
4685
4686             if (colorInterpolation)
4687                 colorTable[pos] = INTERPOLATE_PIXEL_256(current_color, idist, next_color, dist);
4688             else
4689                 colorTable[pos] = PREMUL(INTERPOLATE_PIXEL_256(current_color, idist, next_color, dist));
4690
4691             ++pos;
4692             dpos += incr;
4693
4694             if (dpos >= end_pos)
4695                 break;
4696
4697             t += t_delta;
4698
4699             int skip = 0;
4700             while (dpos > stops[current_stop+skip+1].first)
4701                 ++skip;
4702
4703             if (skip != 0) {
4704                 current_stop += skip;
4705                 if (skip == 1)
4706                     current_color = next_color;
4707                 else
4708                     current_color = ARGB_COMBINE_ALPHA(stops[current_stop].second.rgba(), opacity);
4709                 next_color = ARGB_COMBINE_ALPHA(stops[current_stop+1].second.rgba(), opacity);
4710
4711                 if (colorInterpolation) {
4712                     if (skip != 1)
4713                         current_color = PREMUL(current_color);
4714                     next_color = PREMUL(next_color);
4715                 }
4716
4717                 qreal diff = stops[current_stop+1].first - stops[current_stop].first;
4718                 qreal c = (diff == 0) ? qreal(0) : 256 / diff;
4719                 t = (dpos - stops[current_stop].first) * c;
4720                 t_delta = incr * c;
4721             }
4722         }
4723     }
4724
4725     // After last point
4726     current_color = PREMUL(ARGB_COMBINE_ALPHA(stops[stopCount - 1].second.rgba(), opacity));
4727     while (pos < size - 1) {
4728         colorTable[pos] = current_color;
4729         ++pos;
4730     }
4731
4732     // Make sure the last color stop is represented at the end of the table
4733     colorTable[size - 1] = current_color;
4734 }
4735
4736 Q_GLOBAL_STATIC(QGradientCache, qt_gradient_cache)
4737
4738
4739 void QSpanData::init(QRasterBuffer *rb, const QRasterPaintEngine *pe)
4740 {
4741     rasterBuffer = rb;
4742 #ifdef Q_WS_QWS
4743     rasterEngine = const_cast<QRasterPaintEngine *>(pe);
4744 #endif
4745     type = None;
4746     txop = 0;
4747     bilinear = false;
4748     m11 = m22 = m33 = 1.;
4749     m12 = m13 = m21 = m23 = dx = dy = 0.0;
4750     clip = pe ? pe->d_func()->clip() : 0;
4751 }
4752
4753 Q_GUI_EXPORT extern QImage qt_imageForBrush(int brushStyle, bool invert);
4754
4755 void QSpanData::setup(const QBrush &brush, int alpha, QPainter::CompositionMode compositionMode)
4756 {
4757     Qt::BrushStyle brushStyle = qbrush_style(brush);
4758     switch (brushStyle) {
4759     case Qt::SolidPattern: {
4760         type = Solid;
4761         QColor c = qbrush_color(brush);
4762         QRgb rgba = c.rgba();
4763         solid.color = PREMUL(ARGB_COMBINE_ALPHA(rgba, alpha));
4764         if ((solid.color & 0xff000000) == 0
4765             && compositionMode == QPainter::CompositionMode_SourceOver) {
4766             type = None;
4767         }
4768         break;
4769     }
4770
4771     case Qt::LinearGradientPattern:
4772         {
4773             type = LinearGradient;
4774             const QLinearGradient *g = static_cast<const QLinearGradient *>(brush.gradient());
4775             gradient.alphaColor = !brush.isOpaque() || alpha != 256;
4776             gradient.colorTable = const_cast<uint*>(qt_gradient_cache()->getBuffer(*g, alpha));
4777             gradient.spread = g->spread();
4778
4779             QLinearGradientData &linearData = gradient.linear;
4780
4781             linearData.origin.x = g->start().x();
4782             linearData.origin.y = g->start().y();
4783             linearData.end.x = g->finalStop().x();
4784             linearData.end.y = g->finalStop().y();
4785             break;
4786         }
4787
4788     case Qt::RadialGradientPattern:
4789         {
4790             type = RadialGradient;
4791             const QRadialGradient *g = static_cast<const QRadialGradient *>(brush.gradient());
4792             gradient.alphaColor = !brush.isOpaque() || alpha != 256;
4793             gradient.colorTable = const_cast<uint*>(qt_gradient_cache()->getBuffer(*g, alpha));
4794             gradient.spread = g->spread();
4795
4796             QRadialGradientData &radialData = gradient.radial;
4797
4798             QPointF center = g->center();
4799             radialData.center.x = center.x();
4800             radialData.center.y = center.y();
4801             radialData.center.radius = g->centerRadius();
4802             QPointF focal = g->focalPoint();
4803             radialData.focal.x = focal.x();
4804             radialData.focal.y = focal.y();
4805             radialData.focal.radius = g->focalRadius();
4806         }
4807         break;
4808
4809     case Qt::ConicalGradientPattern:
4810         {
4811             type = ConicalGradient;
4812             const QConicalGradient *g = static_cast<const QConicalGradient *>(brush.gradient());
4813             gradient.alphaColor = !brush.isOpaque() || alpha != 256;
4814             gradient.colorTable = const_cast<uint*>(qt_gradient_cache()->getBuffer(*g, alpha));
4815             gradient.spread = QGradient::RepeatSpread;
4816
4817             QConicalGradientData &conicalData = gradient.conical;
4818
4819             QPointF center = g->center();
4820             conicalData.center.x = center.x();
4821             conicalData.center.y = center.y();
4822             conicalData.angle = g->angle() * 2 * Q_PI / 360.0;
4823         }
4824         break;
4825
4826     case Qt::Dense1Pattern:
4827     case Qt::Dense2Pattern:
4828     case Qt::Dense3Pattern:
4829     case Qt::Dense4Pattern:
4830     case Qt::Dense5Pattern:
4831     case Qt::Dense6Pattern:
4832     case Qt::Dense7Pattern:
4833     case Qt::HorPattern:
4834     case Qt::VerPattern:
4835     case Qt::CrossPattern:
4836     case Qt::BDiagPattern:
4837     case Qt::FDiagPattern:
4838     case Qt::DiagCrossPattern:
4839         type = Texture;
4840         if (!tempImage)
4841             tempImage = new QImage();
4842         *tempImage = rasterBuffer->colorizeBitmap(qt_imageForBrush(brushStyle, true), brush.color());
4843         initTexture(tempImage, alpha, QTextureData::Tiled);
4844         break;
4845     case Qt::TexturePattern:
4846         type = Texture;
4847         if (!tempImage)
4848             tempImage = new QImage();
4849
4850         if (qHasPixmapTexture(brush) && brush.texture().isQBitmap())
4851             *tempImage = rasterBuffer->colorizeBitmap(brush.textureImage(), brush.color());
4852         else
4853             *tempImage = brush.textureImage();
4854         initTexture(tempImage, alpha, QTextureData::Tiled, tempImage->rect());
4855         break;
4856
4857     case Qt::NoBrush:
4858     default:
4859         type = None;
4860         break;
4861     }
4862     adjustSpanMethods();
4863 }
4864
4865 void QSpanData::adjustSpanMethods()
4866 {
4867     bitmapBlit = 0;
4868     alphamapBlit = 0;
4869     alphaRGBBlit = 0;
4870
4871     fillRect = 0;
4872
4873     switch(type) {
4874     case None:
4875         unclipped_blend = 0;
4876         break;
4877     case Solid:
4878         unclipped_blend = rasterBuffer->drawHelper->blendColor;
4879         bitmapBlit = rasterBuffer->drawHelper->bitmapBlit;
4880         alphamapBlit = rasterBuffer->drawHelper->alphamapBlit;
4881         alphaRGBBlit = rasterBuffer->drawHelper->alphaRGBBlit;
4882         fillRect = rasterBuffer->drawHelper->fillRect;
4883         break;
4884     case LinearGradient:
4885     case RadialGradient:
4886     case ConicalGradient:
4887         unclipped_blend = rasterBuffer->drawHelper->blendGradient;
4888         break;
4889     case Texture:
4890 #ifdef Q_WS_QWS
4891 #ifndef QT_NO_RASTERCALLBACKS
4892         if (!rasterBuffer->buffer())
4893             unclipped_blend = qBlendTextureCallback;
4894         else
4895 #endif
4896             unclipped_blend = qBlendTexture;
4897 #else
4898         unclipped_blend = qBlendTexture;
4899 #endif
4900         if (!texture.imageData)
4901             unclipped_blend = 0;
4902
4903         break;
4904     }
4905     // setup clipping
4906     if (!unclipped_blend) {
4907         blend = 0;
4908     } else if (!clip) {
4909         blend = unclipped_blend;
4910     } else if (clip->hasRectClip) {
4911         blend = clip->clipRect.isEmpty() ? 0 : qt_span_fill_clipRect;
4912     } else {
4913         blend = qt_span_fill_clipped;
4914     }
4915 }
4916
4917 void QSpanData::setupMatrix(const QTransform &matrix, int bilin)
4918 {
4919     QTransform delta;
4920     // make sure we round off correctly in qdrawhelper.cpp
4921     delta.translate(1.0 / 65536, 1.0 / 65536);
4922
4923     QTransform inv = (delta * matrix).inverted();
4924     m11 = inv.m11();
4925     m12 = inv.m12();
4926     m13 = inv.m13();
4927     m21 = inv.m21();
4928     m22 = inv.m22();
4929     m23 = inv.m23();
4930     m33 = inv.m33();
4931     dx = inv.dx();
4932     dy = inv.dy();
4933     txop = inv.type();
4934     bilinear = bilin;
4935
4936     const bool affine = !m13 && !m23;
4937     fast_matrix = affine
4938         && m11 * m11 + m21 * m21 < 1e4
4939         && m12 * m12 + m22 * m22 < 1e4
4940         && qAbs(dx) < 1e4
4941         && qAbs(dy) < 1e4;
4942
4943     adjustSpanMethods();
4944 }
4945
4946 extern const QVector<QRgb> *qt_image_colortable(const QImage &image);
4947
4948 void QSpanData::initTexture(const QImage *image, int alpha, QTextureData::Type _type, const QRect &sourceRect)
4949 {
4950     const QImageData *d = const_cast<QImage *>(image)->data_ptr();
4951     if (!d || d->height == 0) {
4952         texture.imageData = 0;
4953         texture.width = 0;
4954         texture.height = 0;
4955         texture.x1 = 0;
4956         texture.y1 = 0;
4957         texture.x2 = 0;
4958         texture.y2 = 0;
4959         texture.bytesPerLine = 0;
4960         texture.format = QImage::Format_Invalid;
4961         texture.colorTable = 0;
4962         texture.hasAlpha = alpha != 256;
4963     } else {
4964         texture.imageData = d->data;
4965         texture.width = d->width;
4966         texture.height = d->height;
4967
4968         if (sourceRect.isNull()) {
4969             texture.x1 = 0;
4970             texture.y1 = 0;
4971             texture.x2 = texture.width;
4972             texture.y2 = texture.height;
4973         } else {
4974             texture.x1 = sourceRect.x();
4975             texture.y1 = sourceRect.y();
4976             texture.x2 = qMin(texture.x1 + sourceRect.width(), d->width);
4977             texture.y2 = qMin(texture.y1 + sourceRect.height(), d->height);
4978         }
4979
4980         texture.bytesPerLine = d->bytes_per_line;
4981
4982         texture.format = d->format;
4983         texture.colorTable = (d->format <= QImage::Format_Indexed8 && !d->colortable.isEmpty()) ? &d->colortable : 0;
4984         texture.hasAlpha = image->hasAlphaChannel() || alpha != 256;
4985     }
4986     texture.const_alpha = alpha;
4987     texture.type = _type;
4988
4989     adjustSpanMethods();
4990 }
4991
4992
4993 /*!
4994     \fn void QRasterPaintEngine::drawPoints(const QPoint *points, int pointCount)
4995     \overload
4996
4997     Draws the first \a pointCount points in the buffer \a points
4998
4999     The default implementation converts the first \a pointCount QPoints in \a points
5000     to QPointFs and calls the floating point version of drawPoints.
5001 */
5002
5003 /*!
5004     \fn void QRasterPaintEngine::drawEllipse(const QRect &rect)
5005     \overload
5006
5007     Reimplement this function to draw the largest ellipse that can be
5008     contained within rectangle \a rect.
5009 */
5010
5011 #ifdef QT_DEBUG_DRAW
5012 void dumpClip(int width, int height, const QClipData *clip)
5013 {
5014     QImage clipImg(width, height, QImage::Format_ARGB32_Premultiplied);
5015     clipImg.fill(0xffff0000);
5016
5017     int x0 = width;
5018     int x1 = 0;
5019     int y0 = height;
5020     int y1 = 0;
5021
5022     ((QClipData *) clip)->spans(); // Force allocation of the spans structure...
5023
5024     for (int i = 0; i < clip->count; ++i) {
5025         const QSpan *span = ((QClipData *) clip)->spans() + i;
5026         for (int j = 0; j < span->len; ++j)
5027             clipImg.setPixel(span->x + j, span->y, 0xffffff00);
5028         x0 = qMin(x0, int(span->x));
5029         x1 = qMax(x1, int(span->x + span->len - 1));
5030
5031         y0 = qMin(y0, int(span->y));
5032         y1 = qMax(y1, int(span->y));
5033     }
5034
5035     static int counter = 0;
5036
5037     Q_ASSERT(y0 >= 0);
5038     Q_ASSERT(x0 >= 0);
5039     Q_ASSERT(y1 >= 0);
5040     Q_ASSERT(x1 >= 0);
5041
5042     fprintf(stderr,"clip %d: %d %d - %d %d\n", counter, x0, y0, x1, y1);
5043     clipImg.save(QString::fromLatin1("clip-%0.png").arg(counter++));
5044 }
5045 #endif
5046
5047
5048 QT_END_NAMESPACE