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