OSDN Git Service

drop support for static text [ci reset]
[kde/Katie.git] / src / gui / painting / qpaintengine_raster.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2015 The Qt Company Ltd.
4 ** Copyright (C) 2016 Ivailo Monev
5 **
6 ** This file is part of the QtGui module of the Katie Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 **
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser
12 ** General Public License version 2.1 as published by the Free Software
13 ** Foundation and appearing in the file LICENSE.LGPL included in the
14 ** packaging of this file.  Please review the following information to
15 ** ensure the GNU Lesser General Public License version 2.1 requirements
16 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 **
18 ** $QT_END_LICENSE$
19 **
20 ****************************************************************************/
21
22 #include "qmutex.h"
23 #include "qrasterdefs_p.h"
24 #include "qpainterpath.h"
25 #include "qdebug.h"
26 #include "qcache.h"
27 #include "qlabel.h"
28 #include "qbitmap.h"
29 #include "qmath.h"
30 #include "qpixmap_raster_p.h"
31 #include "qimage_p.h"
32 #include "qpaintengine_raster_p.h"
33 #include "qoutlinemapper_p.h"
34 #include "qguicommon_p.h"
35 #include "qcorecommon_p.h"
36
37 #include <limits.h>
38
39 QT_BEGIN_NAMESPACE
40
41 Q_GUI_EXPORT extern bool qt_scaleForTransform(const QTransform &transform, qreal *scale); // qtransform.cpp
42
43 // #define QT_DEBUG_DRAW
44 #ifdef QT_DEBUG_DRAW
45 void dumpClip(int width, int height, const QClipData *clip);
46 #endif
47
48 /********************************************************************************
49  * Span functions
50  */
51 static void qt_span_fill_clipRect(int count, const QSpan *spans, void *userData);
52 static void qt_span_fill_clipped(int count, const QSpan *spans, void *userData);
53 static void qt_span_clip(int count, const QSpan *spans, void *userData);
54 static void qt_merge_clip(const QClipData *c1, const QClipData *c2, QClipData *result);
55
56 struct ClipData
57 {
58     QClipData *oldClip;
59     QClipData *newClip;
60     Qt::ClipOperation operation;
61 };
62
63 #ifdef QT_DEBUG_DRAW
64 static const QRectF boundingRect(const QPointF *points, int pointCount)
65 {
66     const QPointF *e = points;
67     const QPointF *last = points + pointCount;
68     qreal minx, maxx, miny, maxy;
69     minx = maxx = e->x();
70     miny = maxy = e->y();
71     while (++e < last) {
72         if (e->x() < minx)
73             minx = e->x();
74         else if (e->x() > maxx)
75             maxx = e->x();
76         if (e->y() < miny)
77             miny = e->y();
78         else if (e->y() > maxy)
79             maxy = e->y();
80     }
81     return QRectF(QPointF(minx, miny), QPointF(maxx, maxy));
82 }
83 #endif
84
85 template <typename T> static inline bool isRect(const T *pts, int elementCount) {
86     return (elementCount == 5 // 5-point polygon, check for closed rect
87             && pts[0] == pts[8] && pts[1] == pts[9] // last point == first point
88             && pts[0] == pts[6] && pts[2] == pts[4] // x values equal
89             && pts[1] == pts[3] && pts[5] == pts[7] // y values equal...
90             && pts[0] < pts[4] && pts[1] < pts[5]
91             ) ||
92            (elementCount == 4 // 4-point polygon, check for unclosed rect
93             && pts[0] == pts[6] && pts[2] == pts[4] // x values equal
94             && pts[1] == pts[3] && pts[5] == pts[7] // y values equal...
95             && pts[0] < pts[4] && pts[1] < pts[5]
96             );
97 }
98
99
100 static void qt_ft_outline_move_to(qfixed x, qfixed y, void *data)
101 {
102     ((QOutlineMapper *) data)->moveTo(QPointF(x, y));
103 }
104
105 static void qt_ft_outline_line_to(qfixed x, qfixed y, void *data)
106 {
107     ((QOutlineMapper *) data)->lineTo(QPointF(x, y));
108 }
109
110 static void qt_ft_outline_cubic_to(qfixed c1x, qfixed c1y,
111                              qfixed c2x, qfixed c2y,
112                              qfixed ex, qfixed ey,
113                              void *data)
114 {
115     ((QOutlineMapper *) data)->curveTo(QPointF(c1x, c1y),
116                                        QPointF(c2x, c2y),
117                                        QPointF(ex, ey));
118 }
119
120
121
122 QRasterPaintEnginePrivate::QRasterPaintEnginePrivate() :
123     QPaintEngineExPrivate()
124 {
125 }
126
127 /*!
128     \class QRasterPaintEngine
129     \preliminary
130     \since 4.2
131
132     \brief The QRasterPaintEngine class enables hardware acceleration
133     of painting operations in Qt for Embedded Linux.
134
135     Note that this functionality is only available in
136     \l{Qt for Embedded Linux}.
137
138     \note The QRasterPaintEngine class does not support 8-bit images.
139     Instead, they need to be converted to a supported format, such as
140     QImage::Format_ARGB32_Premultiplied.
141
142     See the \l {Adding an Accelerated Graphics Driver to Qt for Embedded Linux}
143     documentation for details.
144
145     \sa QPaintEngine
146 */
147
148 /*!
149     \fn Type QRasterPaintEngine::type() const
150     \reimp
151 */
152
153 /*!
154     \typedef QSpan
155     \relates QRasterPaintEngine
156
157     A struct equivalent to QT_FT_Span, containing a position (x,
158     y), the span's length in pixels and its color/coverage (a value
159     ranging from 0 to 255).
160 */
161
162 /*!
163     \since 4.5
164
165     Creates a raster based paint engine for operating on the given
166     \a device, with the complete set of \l
167     {QPaintEngine::PaintEngineFeature}{paint engine features and
168     capabilities}.
169 */
170 QRasterPaintEngine::QRasterPaintEngine(QPaintDevice *device)
171     : QPaintEngineEx(*(new QRasterPaintEnginePrivate))
172 {
173     d_func()->device = device;
174     init();
175 }
176
177 /*!
178     \internal
179 */
180 QRasterPaintEngine::QRasterPaintEngine(QRasterPaintEnginePrivate &dd, QPaintDevice *device)
181     : QPaintEngineEx(dd)
182 {
183     d_func()->device = device;
184     init();
185 }
186
187 void QRasterPaintEngine::init()
188 {
189     Q_D(QRasterPaintEngine);
190
191     d->rasterizer.reset(new QRasterizer);
192     d->rasterBuffer.reset(new QRasterBuffer());
193     d->outlineMapper.reset(new QOutlineMapper);
194
195     d->basicStroker.setMoveToHook(qt_ft_outline_move_to);
196     d->basicStroker.setLineToHook(qt_ft_outline_line_to);
197     d->basicStroker.setCubicToHook(qt_ft_outline_cubic_to);
198
199     d->baseClip.reset(new QClipData(d->device->height()));
200     d->baseClip->setClipRect(QRect(0, 0, d->device->width(), d->device->height()));
201
202     d->image_filler.init(d->rasterBuffer.data(), this);
203     d->image_filler.type = QSpanData::Texture;
204
205     d->image_filler_xform.init(d->rasterBuffer.data(), this);
206     d->image_filler_xform.type = QSpanData::Texture;
207
208     d->solid_color_filler.init(d->rasterBuffer.data(), this);
209     d->solid_color_filler.type = QSpanData::Solid;
210
211     d->deviceDepth = d->device->depth();
212
213     gccaps &= ~PorterDuff;
214
215     if (Q_UNLIKELY(d->device->devType() != QInternal::Image)) {
216         qWarning("QRasterPaintEngine: unsupported target device %d\n", d->device->devType());
217         d->device = 0;
218         return;
219     }
220
221     QImage::Format format = d->rasterBuffer->prepare(static_cast<QImage *>(d->device));
222     switch (format) {
223     case QImage::Format_ARGB32_Premultiplied:
224     case QImage::Format_ARGB32:
225         gccaps |= PorterDuff;
226         break;
227     default:
228         break;
229     }
230 }
231
232 /*!
233     \reimp
234 */
235 bool QRasterPaintEngine::begin(QPaintDevice *device)
236 {
237     Q_D(QRasterPaintEngine);
238
239     if (device->devType() == QInternal::Pixmap) {
240         QPixmap *pixmap = static_cast<QPixmap *>(device);
241         QPixmapData *pd = pixmap->pixmapData();
242         if (pd->classId() == QPixmapData::RasterClass)
243             d->device = pd->buffer();
244     } else {
245         d->device = device;
246     }
247
248     // Make sure QPaintEngine::paintDevice() returns the proper device.
249     d->pdev = d->device;
250
251     Q_ASSERT(d->device->devType() == QInternal::Image);
252
253     d->systemStateChanged();
254
255     QRasterPaintEngineState *s = state();
256     updateOutlineMapper();
257     d->outlineMapper->m_clip_rect = d->deviceRect;
258
259     if (d->outlineMapper->m_clip_rect.width() > RASTER_COORD_LIMIT)
260         d->outlineMapper->m_clip_rect.setWidth(RASTER_COORD_LIMIT);
261     if (d->outlineMapper->m_clip_rect.height() > RASTER_COORD_LIMIT)
262         d->outlineMapper->m_clip_rect.setHeight(RASTER_COORD_LIMIT);
263
264     d->rasterizer->setClipRect(d->deviceRect);
265
266     s->penData.init(d->rasterBuffer.data(), this);
267     s->penData.setup(s->pen.brush(), s->intOpacity, s->composition_mode);
268     s->stroker = &d->basicStroker;
269     d->basicStroker.setClipRect(d->deviceRect);
270
271     s->brushData.init(d->rasterBuffer.data(), this);
272     s->brushData.setup(s->brush, s->intOpacity, s->composition_mode);
273
274     d->rasterBuffer->compositionMode = QPainter::CompositionMode_SourceOver;
275
276     setDirty(DirtyBrushOrigin);
277
278 #ifdef QT_DEBUG_DRAW
279     qDebug() << "QRasterPaintEngine::begin(" << (void *) device
280              << ") devType:" << device->devType()
281              << "devRect:" << d->deviceRect;
282     if (d->baseClip) {
283         dumpClip(d->rasterBuffer->width(), d->rasterBuffer->height(), &*d->baseClip);
284     }
285 #endif
286
287     setActive(true);
288     return true;
289 }
290
291 /*!
292     \reimp
293 */
294 bool QRasterPaintEngine::end()
295 {
296 #ifdef QT_DEBUG_DRAW
297     Q_D(QRasterPaintEngine);
298     qDebug() << "QRasterPaintEngine::end devRect:" << d->deviceRect;
299     if (d->baseClip) {
300         dumpClip(d->rasterBuffer->width(), d->rasterBuffer->height(), &*d->baseClip);
301     }
302 #endif
303
304     return true;
305 }
306
307 /*!
308     \internal
309 */
310 #ifndef QT_NO_DEBUG
311 void QRasterPaintEngine::saveBuffer(const QString &s) const
312 {
313     Q_D(const QRasterPaintEngine);
314     d->rasterBuffer->bufferImage().save(s, "PNG");
315 }
316 #endif
317
318 /*!
319     \internal
320 */
321 void QRasterPaintEngine::updateMatrix(const QTransform &matrix)
322 {
323     QRasterPaintEngineState *s = state();
324     // FALCON: get rid of this line, see drawImage call below.
325     s->matrix = matrix;
326     s->flags.tx_noshear = qt_scaleForTransform(s->matrix, &s->txscale);
327
328     updateOutlineMapper();
329 }
330
331
332
333 QRasterPaintEngineState::~QRasterPaintEngineState()
334 {
335     if (flags.has_clip_ownership)
336         delete clip;
337 }
338
339
340 QRasterPaintEngineState::QRasterPaintEngineState()
341 {
342     stroker = 0;
343
344     fillFlags = 0;
345     strokeFlags = 0;
346
347     intOpacity = 256;
348
349     txscale = 1.;
350
351     flags.antialiased = false;
352     flags.bilinear = false;
353     flags.tx_noshear = true;
354
355     clip = 0;
356     flags.has_clip_ownership = false;
357
358     dirty = 0;
359 }
360
361 QRasterPaintEngineState::QRasterPaintEngineState(QRasterPaintEngineState &s)
362     : QPainterState(s)
363     , lastPen(s.lastPen)
364     , penData(s.penData)
365     , stroker(s.stroker)
366     , strokeFlags(s.strokeFlags)
367     , lastBrush(s.lastBrush)
368     , brushData(s.brushData)
369     , fillFlags(s.fillFlags)
370     , intOpacity(s.intOpacity)
371     , txscale(s.txscale)
372     , clip(s.clip)
373     , dirty(s.dirty)
374     , flags(s.flags)
375 {
376     brushData.tempImage = 0;
377     penData.tempImage = 0;
378     flags.has_clip_ownership = false;
379 }
380
381 /*!
382     \internal
383 */
384 QPainterState *QRasterPaintEngine::createState(QPainterState *orig) const
385 {
386     if (!orig)
387         return new QRasterPaintEngineState();
388     return new QRasterPaintEngineState(*static_cast<QRasterPaintEngineState *>(orig));
389 }
390
391 /*!
392     \internal
393 */
394 void QRasterPaintEngine::setState(QPainterState *s)
395 {
396     Q_D(QRasterPaintEngine);
397     QPaintEngineEx::setState(s);
398     d->rasterBuffer->compositionMode = s->composition_mode;
399 }
400
401 /*!
402     \fn QRasterPaintEngineState *QRasterPaintEngine::state()
403     \internal
404 */
405
406 /*!
407     \fn const QRasterPaintEngineState *QRasterPaintEngine::state() const
408     \internal
409 */
410
411 /*!
412     \internal
413 */
414 void QRasterPaintEngine::penChanged()
415 {
416 #ifdef QT_DEBUG_DRAW
417     qDebug() << "QRasterPaintEngine::penChanged():" << state()->pen;
418 #endif
419     QRasterPaintEngineState *s = state();
420     s->strokeFlags |= DirtyPen;
421     s->dirty |= DirtyPen;
422 }
423
424 /*!
425     \internal
426 */
427 void QRasterPaintEngine::updatePen(const QPen &pen)
428 {
429     Q_D(QRasterPaintEngine);
430     QRasterPaintEngineState *s = state();
431 #ifdef QT_DEBUG_DRAW
432     qDebug() << "QRasterPaintEngine::updatePen():" << s->pen;
433 #endif
434
435     Qt::PenStyle pen_style = pen.style();
436
437     s->lastPen = pen;
438     s->strokeFlags = 0;
439
440     s->penData.clip = d->clip();
441     s->penData.setup(pen_style == Qt::NoPen ? QBrush() : pen.brush(), s->intOpacity, s->composition_mode);
442
443     if (s->strokeFlags & QRasterPaintEngine::DirtyTransform
444         || pen.brush().transform().type() >= QTransform::TxNone) {
445         d->updateMatrixData(&s->penData, pen.brush(), s->matrix);
446     }
447
448     // Slightly ugly handling of an uncommon case... We need to change
449     // the pen because it is reused in draw_midpoint to decide dashed
450     // or non-dashed.
451     if (pen_style == Qt::CustomDashLine && pen.dashPattern().size() == 0) {
452         pen_style = Qt::SolidLine;
453         s->lastPen.setStyle(Qt::SolidLine);
454     }
455
456     d->basicStroker.setJoinStyle(pen.joinStyle());
457     d->basicStroker.setCapStyle(pen.capStyle());
458     d->basicStroker.setMiterLimit(pen.miterLimit());
459
460     const qreal penWidth = pen.widthF();
461     if (penWidth == 0)
462         d->basicStroker.setStrokeWidth(1);
463     else
464         d->basicStroker.setStrokeWidth(penWidth);
465
466     if(pen_style == Qt::SolidLine) {
467         s->stroker = &d->basicStroker;
468     } else if (pen_style != Qt::NoPen) {
469         if (!d->dashStroker)
470             d->dashStroker.reset(new QDashStroker(&d->basicStroker));
471         if (pen.isCosmetic()) {
472             d->dashStroker->setClipRect(d->deviceRect);
473         } else {
474             // ### I've seen this inverted devrect multiple places now...
475             QRectF clipRect = s->matrix.inverted().mapRect(QRectF(d->deviceRect));
476             d->dashStroker->setClipRect(clipRect);
477         }
478         d->dashStroker->setDashPattern(pen.dashPattern());
479         d->dashStroker->setDashOffset(pen.dashOffset());
480         s->stroker = d->dashStroker.data();
481     } else {
482         s->stroker = 0;
483     }
484
485     ensureRasterState(); // needed because of tx_noshear...
486
487     s->flags.non_complex_pen = s->lastPen.capStyle() <= Qt::SquareCap && s->flags.tx_noshear;
488
489     s->strokeFlags = 0;
490 }
491
492
493
494 /*!
495     \internal
496 */
497 void QRasterPaintEngine::brushOriginChanged()
498 {
499     QRasterPaintEngineState *s = state();
500 #ifdef QT_DEBUG_DRAW
501     qDebug() << "QRasterPaintEngine::brushOriginChanged()" << s->brushOrigin;
502 #endif
503
504     s->fillFlags |= DirtyBrushOrigin;
505 }
506
507
508 /*!
509     \internal
510 */
511 void QRasterPaintEngine::brushChanged()
512 {
513     QRasterPaintEngineState *s = state();
514 #ifdef QT_DEBUG_DRAW
515     qDebug() << "QRasterPaintEngine::brushChanged():" << s->brush;
516 #endif
517     s->fillFlags |= DirtyBrush;
518 }
519
520
521
522
523 /*!
524     \internal
525 */
526 void QRasterPaintEngine::updateBrush(const QBrush &brush)
527 {
528 #ifdef QT_DEBUG_DRAW
529     qDebug() << "QRasterPaintEngine::updateBrush()" << brush;
530 #endif
531     Q_D(QRasterPaintEngine);
532     QRasterPaintEngineState *s = state();
533     // must set clip prior to setup, as setup uses it...
534     s->brushData.clip = d->clip();
535     s->brushData.setup(brush, s->intOpacity, s->composition_mode);
536     if (s->fillFlags & DirtyTransform
537         || brush.transform().type() >= QTransform::TxNone)
538         d_func()->updateMatrixData(&s->brushData, brush, d->brushMatrix());
539     s->lastBrush = brush;
540     s->fillFlags = 0;
541 }
542
543 void QRasterPaintEngine::updateOutlineMapper()
544 {
545     Q_D(QRasterPaintEngine);
546     d->outlineMapper->setMatrix(state()->matrix);
547 }
548
549 void QRasterPaintEngine::updateRasterState()
550 {
551     QRasterPaintEngineState *s = state();
552
553     if (s->dirty & DirtyTransform) {
554         updateMatrix(s->matrix);
555     }
556
557     s->dirty = 0;
558 }
559
560
561 /*!
562     \internal
563 */
564 void QRasterPaintEngine::opacityChanged()
565 {
566     QRasterPaintEngineState *s = state();
567
568 #ifdef QT_DEBUG_DRAW
569     qDebug() << "QRasterPaintEngine::opacityChanged()" << s->opacity;
570 #endif
571
572     s->fillFlags |= DirtyOpacity;
573     s->strokeFlags |= DirtyOpacity;
574     s->dirty |= DirtyOpacity;
575     s->intOpacity = (int) (s->opacity * 256);
576 }
577
578 /*!
579     \internal
580 */
581 void QRasterPaintEngine::compositionModeChanged()
582 {
583     Q_D(QRasterPaintEngine);
584     QRasterPaintEngineState *s = state();
585
586 #ifdef QT_DEBUG_DRAW
587     qDebug() << "QRasterPaintEngine::compositionModeChanged()" << s->composition_mode;
588 #endif
589
590     s->fillFlags |= DirtyCompositionMode;
591     s->dirty |= DirtyCompositionMode;
592
593     s->strokeFlags |= DirtyCompositionMode;
594     d->rasterBuffer->compositionMode = s->composition_mode;
595 }
596
597 /*!
598     \internal
599 */
600 void QRasterPaintEngine::renderHintsChanged()
601 {
602     QRasterPaintEngineState *s = state();
603
604 #ifdef QT_DEBUG_DRAW
605     qDebug() << "QRasterPaintEngine::renderHintsChanged()" << hex << s->renderHints;
606 #endif
607
608     bool was_aa = s->flags.antialiased;
609     bool was_bilinear = s->flags.bilinear;
610
611     s->flags.antialiased = bool(s->renderHints & QPainter::Antialiasing);
612     s->flags.bilinear = bool(s->renderHints & QPainter::SmoothPixmapTransform);
613
614     if (was_aa != s->flags.antialiased)
615         s->strokeFlags |= DirtyHints;
616
617     if (was_bilinear != s->flags.bilinear) {
618         s->strokeFlags |= DirtyPen;
619         s->fillFlags |= DirtyBrush;
620     }
621 }
622
623 /*!
624     \internal
625 */
626 void QRasterPaintEngine::transformChanged()
627 {
628     QRasterPaintEngineState *s = state();
629
630 #ifdef QT_DEBUG_DRAW
631     qDebug() << "QRasterPaintEngine::transformChanged()" << s->matrix;
632 #endif
633
634     s->fillFlags |= DirtyTransform;
635     s->strokeFlags |= DirtyTransform;
636
637     s->dirty |= DirtyTransform;
638 }
639
640 /*!
641     \internal
642 */
643 void QRasterPaintEngine::clipEnabledChanged()
644 {
645     QRasterPaintEngineState *s = state();
646
647 #ifdef QT_DEBUG_DRAW
648     qDebug() << "QRasterPaintEngine::clipEnabledChanged()" << s->clipEnabled;
649 #endif
650
651     if (s->clip) {
652         s->clip->enabled = s->clipEnabled;
653         s->fillFlags |= DirtyClipEnabled;
654         s->strokeFlags |= DirtyClipEnabled;
655     }
656 }
657
658 void QRasterPaintEnginePrivate::systemStateChanged()
659 {
660     const QRect deviceRectUnclipped = QRect(0, 0,
661             qMin(RASTER_COORD_LIMIT, device->width()),
662             qMin(RASTER_COORD_LIMIT, device->height()));
663
664     if (!systemClip.isEmpty()) {
665         QRegion clippedDeviceRgn = systemClip & deviceRectUnclipped;
666         deviceRect = clippedDeviceRgn.boundingRect();
667         baseClip->setClipRegion(clippedDeviceRgn);
668     } else {
669         deviceRect = deviceRectUnclipped;
670         baseClip->setClipRect(deviceRect);
671     }
672 #ifdef QT_DEBUG_DRAW
673     qDebug() << "systemStateChanged" << this << "deviceRect" << deviceRect << deviceRectUnclipped << systemClip;
674 #endif
675
676     exDeviceRect = deviceRect;
677
678     Q_Q(QRasterPaintEngine);
679     q->state()->strokeFlags |= QPaintEngine::DirtyClipRegion;
680     q->state()->fillFlags |= QPaintEngine::DirtyClipRegion;
681 }
682
683 void QRasterPaintEnginePrivate::updateMatrixData(QSpanData *spanData, const QBrush &b, const QTransform &m)
684 {
685     const Qt::BrushStyle bstyle(b.style());
686     if (bstyle == Qt::NoBrush || bstyle == Qt::SolidPattern)
687         return;
688
689     Q_Q(QRasterPaintEngine);
690     bool bilinear = q->state()->flags.bilinear;
691
692     const QTransform btransform(b.transform());
693     if (btransform.type() > QTransform::TxNone) { // FALCON: optimize
694         spanData->setupMatrix(btransform * m, bilinear);
695     } else if (m.type() <= QTransform::TxTranslate) {
696         // specialize setupMatrix for translation matrices
697         // to avoid needless matrix inversion
698         spanData->m11 = 1;
699         spanData->m12 = 0;
700         spanData->m13 = 0;
701         spanData->m21 = 0;
702         spanData->m22 = 1;
703         spanData->m23 = 0;
704         spanData->m33 = 1;
705         spanData->dx = -m.dx();
706         spanData->dy = -m.dy();
707         spanData->txop = m.type();
708         spanData->bilinear = bilinear;
709         spanData->adjustSpanMethods();
710     } else {
711         spanData->setupMatrix(m, bilinear);
712     }
713 }
714
715 // #define QT_CLIPPING_RATIOS
716
717 #ifdef QT_CLIPPING_RATIOS
718 int rectClips;
719 int regionClips;
720 int totalClips;
721
722 static void checkClipRatios(QRasterPaintEnginePrivate *d)
723 {
724     if (d->clip()->hasRectClip)
725         rectClips++;
726     if (d->clip()->hasRegionClip)
727         regionClips++;
728     totalClips++;
729
730     if ((totalClips % 5000) == 0) {
731         printf("Clipping ratio: rectangular=%f%%, region=%f%%, complex=%f%%\n",
732                rectClips * 100.0 / (qreal) totalClips,
733                regionClips * 100.0 / (qreal) totalClips,
734                (totalClips - rectClips - regionClips) * 100.0 / (qreal) totalClips);
735         totalClips = 0;
736         rectClips = 0;
737         regionClips = 0;
738     }
739
740 }
741 #endif
742
743 static inline void qrasterpaintengine_state_setNoClip(QRasterPaintEngineState *s)
744 {
745     if (s->flags.has_clip_ownership)
746         delete s->clip;
747     s->clip = 0;
748     s->flags.has_clip_ownership = false;
749 }
750
751 static void qrasterpaintengine_dirty_clip(QRasterPaintEnginePrivate *d, QRasterPaintEngineState *s)
752 {
753     s->fillFlags |= QPaintEngine::DirtyClipPath;
754     s->strokeFlags |= QPaintEngine::DirtyClipPath;
755
756     d->solid_color_filler.clip = d->clip();
757     d->solid_color_filler.adjustSpanMethods();
758
759 #ifdef QT_DEBUG_DRAW
760     dumpClip(d->rasterBuffer->width(), d->rasterBuffer->height(), &*d->clip());
761 #endif
762
763 }
764
765
766 /*!
767     \internal
768 */
769 void QRasterPaintEngine::clip(const QVectorPath &path, Qt::ClipOperation op)
770 {
771 #ifdef QT_DEBUG_DRAW
772     qDebug() << "QRasterPaintEngine::clip(): " << path << op;
773
774     if (path.elements()) {
775         for (int i=0; i<path.elementCount(); ++i) {
776             qDebug() << " - " << path.elements()[i]
777                      << '(' << path.points()[i*2] << ", " << path.points()[i*2+1] << ')';
778         }
779     } else {
780         for (int i=0; i<path.elementCount(); ++i) {
781             qDebug() << " ---- "
782                      << '(' << path.points()[i*2] << ", " << path.points()[i*2+1] << ')';
783         }
784     }
785 #endif
786
787     Q_D(QRasterPaintEngine);
788     QRasterPaintEngineState *s = state();
789
790     const qreal *points = path.points();
791     const QPainterPath::ElementType *types = path.elements();
792
793     // There are some cases that are not supported by clip(QRect)
794     if (op != Qt::UniteClip && (op != Qt::IntersectClip || !s->clip
795                                 || s->clip->hasRectClip || s->clip->hasRegionClip)) {
796         if (s->matrix.type() <= QTransform::TxScale
797             && ((path.shape() == QVectorPath::RectangleHint)
798                 || (isRect(points, path.elementCount())
799                     && (!types || (types[0] == QPainterPath::MoveToElement
800                                    && types[1] == QPainterPath::LineToElement
801                                    && types[2] == QPainterPath::LineToElement
802                                    && types[3] == QPainterPath::LineToElement))))) {
803 #ifdef QT_DEBUG_DRAW
804             qDebug() << " --- optimizing vector clip to rect clip...";
805 #endif
806
807             QRectF r(points[0], points[1], points[4]-points[0], points[5]-points[1]);
808             if (setClipRectInDeviceCoords(s->matrix.mapRect(r).toRect(), op))
809                 return;
810         }
811     }
812
813     if (op == Qt::NoClip) {
814         qrasterpaintengine_state_setNoClip(s);
815
816     } else {
817         QClipData *base = d->baseClip.data();
818
819         // Intersect with current clip when available...
820         if (op == Qt::IntersectClip && s->clip)
821             base = s->clip;
822
823         // We always intersect, except when there is nothing to
824         // intersect with, in which case we simplify the operation to
825         // a replace...
826         Qt::ClipOperation isectOp = Qt::IntersectClip;
827         if (!base)
828             isectOp = Qt::ReplaceClip;
829
830         QClipData *newClip = new QClipData(d->rasterBuffer->height());
831         newClip->initialize();
832         ClipData clipData = { base, newClip, isectOp };
833         updateOutlineMapper();
834         d->rasterize(d->outlineMapper->convertPath(path), qt_span_clip, &clipData);
835
836         newClip->fixup();
837
838         if (op == Qt::UniteClip) {
839             // merge clips
840             QClipData *result = new QClipData(d->rasterBuffer->height());
841             QClipData *current = s->clip ? s->clip : new QClipData(d->rasterBuffer->height());
842             qt_merge_clip(current, newClip, result);
843             result->fixup();
844             delete newClip;
845             if (!s->clip)
846                 delete current;
847             newClip = result;
848         }
849
850         if (s->flags.has_clip_ownership)
851             delete s->clip;
852
853         s->clip = newClip;
854         s->flags.has_clip_ownership = true;
855     }
856     qrasterpaintengine_dirty_clip(d, s);
857 }
858
859
860
861 /*!
862     \internal
863 */
864 void QRasterPaintEngine::clip(const QRect &rect, Qt::ClipOperation op)
865 {
866 #ifdef QT_DEBUG_DRAW
867     qDebug() << "QRasterPaintEngine::clip(): " << rect << op;
868 #endif
869
870     QRasterPaintEngineState *s = state();
871
872     if (op == Qt::NoClip) {
873         qrasterpaintengine_state_setNoClip(s);
874
875     } else if (op == Qt::UniteClip || s->matrix.type() > QTransform::TxScale
876         || !setClipRectInDeviceCoords(s->matrix.mapRect(rect), op)) {
877         QPaintEngineEx::clip(rect, op);
878     }
879 }
880
881
882 bool QRasterPaintEngine::setClipRectInDeviceCoords(const QRect &r, Qt::ClipOperation op)
883 {
884     Q_D(QRasterPaintEngine);
885     const QRect clipRect = r & d->deviceRect;
886     QRasterPaintEngineState *s = state();
887
888     if (op == Qt::ReplaceClip || s->clip == 0) {
889
890         // No current clip, hence we intersect with sysclip and be
891         // done with it...
892         QRegion clipRegion = systemClip();
893         QClipData *clip = new QClipData(d->rasterBuffer->height());
894
895         if (clipRegion.isEmpty())
896             clip->setClipRect(clipRect);
897         else
898             clip->setClipRegion(clipRegion & clipRect);
899
900         if (s->flags.has_clip_ownership)
901             delete s->clip;
902
903         s->clip = clip;
904         s->clip->enabled = true;
905         s->flags.has_clip_ownership = true;
906
907     } else if (op == Qt::IntersectClip){ // intersect clip with current clip
908         QClipData *base = s->clip;
909
910         Q_ASSERT(base);
911         if (base->hasRectClip || base->hasRegionClip) {
912             if (!s->flags.has_clip_ownership) {
913                 s->clip = new QClipData(d->rasterBuffer->height());
914                 s->flags.has_clip_ownership = true;
915             }
916             if (base->hasRectClip)
917                 s->clip->setClipRect(base->clipRect & clipRect);
918             else
919                 s->clip->setClipRegion(base->clipRegion & clipRect);
920             s->clip->enabled = true;
921         } else {
922             return false;
923         }
924     } else {
925         return false;
926     }
927
928     qrasterpaintengine_dirty_clip(d, s);
929     return true;
930 }
931
932
933 /*!
934     \internal
935 */
936 void QRasterPaintEngine::clip(const QRegion &region, Qt::ClipOperation op)
937 {
938 #ifdef QT_DEBUG_DRAW
939     qDebug() << "QRasterPaintEngine::clip(): " << region << op;
940 #endif
941
942     Q_D(QRasterPaintEngine);
943
944     if (region.rectCount() == 1) {
945         clip(region.boundingRect(), op);
946         return;
947     }
948
949     QRasterPaintEngineState *s = state();
950     const QClipData *clip = d->clip();
951     const QClipData *baseClip = d->baseClip.data();
952
953     if (op == Qt::NoClip) {
954         qrasterpaintengine_state_setNoClip(s);
955     } else if (s->matrix.type() > QTransform::TxScale
956                || op == Qt::UniteClip
957                || (op == Qt::IntersectClip && !clip->hasRectClip && !clip->hasRegionClip)
958                || (op == Qt::ReplaceClip && !baseClip->hasRectClip && !baseClip->hasRegionClip)) {
959         QPaintEngineEx::clip(region, op);
960     } else {
961         const QClipData *curClip;
962         QClipData *newClip;
963
964         if (op == Qt::IntersectClip)
965             curClip = clip;
966         else
967             curClip = baseClip;
968
969         if (s->flags.has_clip_ownership) {
970             newClip = s->clip;
971             Q_ASSERT(newClip);
972         } else {
973             newClip = new QClipData(d->rasterBuffer->height());
974             s->clip = newClip;
975             s->flags.has_clip_ownership = true;
976         }
977
978         QRegion r = s->matrix.map(region);
979         if (curClip->hasRectClip)
980             newClip->setClipRegion(r & curClip->clipRect);
981         else if (curClip->hasRegionClip)
982             newClip->setClipRegion(r & curClip->clipRegion);
983
984         qrasterpaintengine_dirty_clip(d, s);
985     }
986 }
987
988 /*!
989     \internal
990 */
991 void QRasterPaintEngine::fillPath(const QPainterPath &path, QSpanData *fillData)
992 {
993 #ifdef QT_DEBUG_DRAW
994     qDebug() << " --- fillPath, bounds=" << path.boundingRect();
995 #endif
996
997     if (!fillData->blend)
998         return;
999
1000     Q_D(QRasterPaintEngine);
1001
1002     const QRectF controlPointRect = path.controlPointRect();
1003
1004     QRasterPaintEngineState *s = state();
1005     const QRect deviceRect = s->matrix.mapRect(controlPointRect).toRect();
1006     ProcessSpans blend = d->getBrushFunc(deviceRect, fillData);
1007     const bool do_clip = (deviceRect.left() < -RASTER_COORD_LIMIT
1008                           || deviceRect.right() > RASTER_COORD_LIMIT
1009                           || deviceRect.top() < -RASTER_COORD_LIMIT
1010                           || deviceRect.bottom() > RASTER_COORD_LIMIT);
1011
1012     if (!s->flags.antialiased && !do_clip) {
1013         d->initializeRasterizer(fillData);
1014         d->rasterizer->rasterize(path * s->matrix, path.fillRule());
1015         return;
1016     }
1017
1018     updateOutlineMapper();
1019     d->rasterize(d->outlineMapper->convertPath(path), blend, fillData);
1020 }
1021
1022 static void fillRect_normalized(const QRect &r, QSpanData *data,
1023                                 QRasterPaintEnginePrivate *pe)
1024 {
1025     int x1, x2, y1, y2;
1026
1027     bool rectClipped = true;
1028
1029     if (data->clip) {
1030         x1 = qMax(r.x(), data->clip->xmin);
1031         x2 = qMin(r.x() + r.width(), data->clip->xmax);
1032         y1 = qMax(r.y(), data->clip->ymin);
1033         y2 = qMin(r.y() + r.height(), data->clip->ymax);
1034         rectClipped = data->clip->hasRectClip;
1035
1036     } else if (pe) {
1037         x1 = qMax(r.x(), pe->deviceRect.x());
1038         x2 = qMin(r.x() + r.width(), pe->deviceRect.x() + pe->deviceRect.width());
1039         y1 = qMax(r.y(), pe->deviceRect.y());
1040         y2 = qMin(r.y() + r.height(), pe->deviceRect.y() + pe->deviceRect.height());
1041     } else {
1042         x1 = qMax(r.x(), 0);
1043         x2 = qMin(r.x() + r.width(), data->rasterBuffer->width());
1044         y1 = qMax(r.y(), 0);
1045         y2 = qMin(r.y() + r.height(), data->rasterBuffer->height());
1046     }
1047
1048     if (x2 <= x1 || y2 <= y1)
1049         return;
1050
1051     const int width = x2 - x1;
1052     const int height = y2 - y1;
1053
1054     bool isUnclipped = rectClipped
1055                        || (pe && pe->isUnclipped_normalized(QRect(x1, y1, width, height)));
1056
1057     if (pe && isUnclipped) {
1058         const QPainter::CompositionMode mode = pe->rasterBuffer->compositionMode;
1059
1060         if (data->fillRect && (mode == QPainter::CompositionMode_Source
1061                                || (mode == QPainter::CompositionMode_SourceOver
1062                                    && qAlpha(data->solid.color) == 255)))
1063         {
1064             data->fillRect(data->rasterBuffer, x1, y1, width, height,
1065                            data->solid.color);
1066             return;
1067         }
1068     }
1069
1070     ProcessSpans blend = isUnclipped ? data->unclipped_blend : data->blend;
1071
1072     const int nspans = 256;
1073     QSTACKARRAY(QT_FT_Span, spans, nspans);
1074
1075     Q_ASSERT(data->blend);
1076     int y = y1;
1077     while (y < y2) {
1078         int n = qMin(nspans, y2 - y);
1079         int i = 0;
1080         while (i < n) {
1081             spans[i].x = x1;
1082             spans[i].len = width;
1083             spans[i].y = y + i;
1084             spans[i].coverage = 255;
1085             ++i;
1086         }
1087
1088         blend(n, spans, data);
1089         y += n;
1090     }
1091 }
1092
1093 /*!
1094     \reimp
1095 */
1096 void QRasterPaintEngine::drawRects(const QRect *rects, int rectCount)
1097 {
1098 #ifdef QT_DEBUG_DRAW
1099     qDebug(" - QRasterPaintEngine::drawRect(), rectCount=%d", rectCount);
1100 #endif
1101     Q_D(QRasterPaintEngine);
1102     ensureRasterState();
1103     QRasterPaintEngineState *s = state();
1104
1105     // Fill
1106     ensureBrush();
1107     if (s->brushData.blend) {
1108         if (!s->flags.antialiased && s->matrix.type() <= QTransform::TxTranslate) {
1109             const QRect *r = rects;
1110             const QRect *lastRect = rects + rectCount;
1111
1112             int offset_x = int(s->matrix.dx());
1113             int offset_y = int(s->matrix.dy());
1114             while (r < lastRect) {
1115                 QRect rect = r->normalized();
1116                 fillRect_normalized(rect.translated(offset_x, offset_y), &s->brushData, d);
1117                 ++r;
1118             }
1119         } else {
1120             QRectVectorPath path;
1121             for (int i=0; i<rectCount; ++i) {
1122                 path.set(rects[i]);
1123                 fill(path, s->brush);
1124             }
1125         }
1126     }
1127
1128     ensurePen();
1129     if (s->penData.blend) {
1130         QRectVectorPath path;
1131         for (int i = 0; i < rectCount; ++i) {
1132             path.set(rects[i]);
1133             stroke(path, s->pen);
1134         }
1135     }
1136 }
1137
1138
1139 /*!
1140     \internal
1141 */
1142 void QRasterPaintEngine::stroke(const QVectorPath &path, const QPen &pen)
1143 {
1144     QRasterPaintEngineState *s = state();
1145
1146     ensurePen(pen);
1147     if (!s->penData.blend)
1148         return;
1149
1150     if (s->flags.non_complex_pen && path.shape() == QVectorPath::LinesHint) {
1151         const qreal lastwidthf = s->lastPen.widthF();
1152         const qreal width = s->lastPen.isCosmetic()
1153                             ? (lastwidthf == 0 ? 1 : lastwidthf)
1154                             : lastwidthf * s->txscale;
1155         int dashIndex = 0;
1156         qreal dashOffset = s->lastPen.dashOffset();
1157         bool inDash = true;
1158         qreal patternLength = 0;
1159         const QVector<qreal> pattern = s->lastPen.dashPattern();
1160         for (int i = 0; i < pattern.size(); ++i)
1161             patternLength += pattern.at(i);
1162
1163         if (patternLength > 0) {
1164             int n = qFloor(dashOffset / patternLength);
1165             dashOffset -= n * patternLength;
1166             while (dashOffset >= pattern.at(dashIndex)) {
1167                 dashOffset -= pattern.at(dashIndex);
1168                 if (++dashIndex >= pattern.size())
1169                     dashIndex = 0;
1170                 inDash = !inDash;
1171             }
1172         }
1173
1174         Q_D(QRasterPaintEngine);
1175         d->initializeRasterizer(&s->penData);
1176         int lineCount = path.elementCount() / 2;
1177         const QLineF *lines = reinterpret_cast<const QLineF *>(path.points());
1178
1179         for (int i = 0; i < lineCount; ++i) {
1180             if (lines[i].p1() == lines[i].p2()) {
1181                 if (s->lastPen.capStyle() != Qt::FlatCap) {
1182                     QPointF p = lines[i].p1();
1183                     QLineF line = s->matrix.map(QLineF(QPointF(p.x() - width*qreal(0.5), p.y()),
1184                                                        QPointF(p.x() + width*qreal(0.5), p.y())));
1185                     d->rasterizer->rasterizeLine(line.p1(), line.p2(), 1);
1186                 }
1187                 continue;
1188             }
1189
1190             const QLineF line = s->matrix.map(lines[i]);
1191             if (s->lastPen.style() == Qt::SolidLine) {
1192                 d->rasterizer->rasterizeLine(line.p1(), line.p2(),
1193                                             width / line.length(),
1194                                             s->lastPen.capStyle() == Qt::SquareCap);
1195             } else {
1196                 d->rasterizeLine_dashed(line, width,
1197                                         &dashIndex, &dashOffset, &inDash);
1198             }
1199         }
1200     } else {
1201         QPaintEngineEx::stroke(path, pen);
1202     }
1203 }
1204
1205 static inline QRect toNormalizedFillRect(const QRectF &rect)
1206 {
1207     int x1 = qRound(rect.x() + aliasedCoordinateDelta);
1208     int y1 = qRound(rect.y() + aliasedCoordinateDelta);
1209     int x2 = qRound(rect.right() + aliasedCoordinateDelta);
1210     int y2 = qRound(rect.bottom() + aliasedCoordinateDelta);
1211
1212     if (x2 < x1)
1213         qSwap(x1, x2);
1214     if (y2 < y1)
1215         qSwap(y1, y2);
1216
1217     return QRect(x1, y1, x2 - x1, y2 - y1);
1218 }
1219
1220 /*!
1221     \internal
1222 */
1223 void QRasterPaintEngine::fill(const QVectorPath &path, const QBrush &brush)
1224 {
1225     if (path.isEmpty())
1226         return;
1227 #ifdef QT_DEBUG_DRAW
1228     QRectF rf = path.controlPointRect();
1229     qDebug() << "QRasterPaintEngine::fill(): "
1230              << "size=" << path.elementCount()
1231              << ", hints=" << hex << path.hints()
1232              << rf << brush;
1233 #endif
1234
1235     Q_D(QRasterPaintEngine);
1236     QRasterPaintEngineState *s = state();
1237
1238     ensureBrush(brush);
1239     if (!s->brushData.blend)
1240         return;
1241
1242     if (path.shape() == QVectorPath::RectangleHint) {
1243         if (!s->flags.antialiased && s->matrix.type() <= QTransform::TxScale) {
1244             const qreal *p = path.points();
1245             QPointF tl = QPointF(p[0], p[1]) * s->matrix;
1246             QPointF br = QPointF(p[4], p[5]) * s->matrix;
1247             fillRect_normalized(toNormalizedFillRect(QRectF(tl, br)), &s->brushData, d);
1248             return;
1249         }
1250         ensureRasterState();
1251         if (s->flags.tx_noshear) {
1252             d->initializeRasterizer(&s->brushData);
1253             // ### Is normalizing really necessary here?
1254             const qreal *p = path.points();
1255             QRectF r = QRectF(p[0], p[1], p[2] - p[0], p[7] - p[1]).normalized();
1256             if (!r.isEmpty()) {
1257                 const QPointF a = s->matrix.map((r.topLeft() + r.bottomLeft()) * 0.5f);
1258                 const QPointF b = s->matrix.map((r.topRight() + r.bottomRight()) * 0.5f);
1259                 d->rasterizer->rasterizeLine(a, b, r.height() / r.width());
1260             }
1261             return;
1262         }
1263     }
1264
1265     // ### Optimize for non transformed ellipses and rectangles...
1266     QRectF cpRect = path.controlPointRect();
1267     const QRect deviceRect = s->matrix.mapRect(cpRect).toRect();
1268     ProcessSpans blend = d->getBrushFunc(deviceRect, &s->brushData);
1269
1270         // ### Falcon
1271 //         const bool do_clip = (deviceRect.left() < -RASTER_COORD_LIMIT
1272 //                               || deviceRect.right() > RASTER_COORD_LIMIT
1273 //                               || deviceRect.top() < -RASTER_COORD_LIMIT
1274 //                               || deviceRect.bottom() > RASTER_COORD_LIMIT);
1275
1276         // ### Falonc: implement....
1277 //         if (!s->flags.antialiased && !do_clip) {
1278 //             d->initializeRasterizer(&s->brushData);
1279 //             d->rasterizer->rasterize(path * d->matrix, path.fillRule());
1280 //             return;
1281 //         }
1282
1283     updateOutlineMapper();
1284     d->rasterize(d->outlineMapper->convertPath(path), blend, &s->brushData);
1285 }
1286
1287 void QRasterPaintEngine::fillRect(const QRectF &r, QSpanData *data)
1288 {
1289     Q_D(QRasterPaintEngine);
1290     QRasterPaintEngineState *s = state();
1291
1292     if (!s->flags.antialiased) {
1293         QTransform::TransformationType txop = s->matrix.type();
1294         if (txop == QTransform::TxNone) {
1295             fillRect_normalized(toNormalizedFillRect(r), data, d);
1296             return;
1297         } else if (txop == QTransform::TxTranslate) {
1298             const QRect rr = toNormalizedFillRect(r.translated(s->matrix.dx(), s->matrix.dy()));
1299             fillRect_normalized(rr, data, d);
1300             return;
1301         } else if (txop == QTransform::TxScale) {
1302             const QRect rr = toNormalizedFillRect(s->matrix.mapRect(r));
1303             fillRect_normalized(rr, data, d);
1304             return;
1305         }
1306     }
1307     ensureRasterState();
1308     if (s->flags.tx_noshear) {
1309         d->initializeRasterizer(data);
1310         QRectF nr = r.normalized();
1311         if (!nr.isEmpty()) {
1312             const QPointF a = s->matrix.map((nr.topLeft() + nr.bottomLeft()) * 0.5f);
1313             const QPointF b = s->matrix.map((nr.topRight() + nr.bottomRight()) * 0.5f);
1314             d->rasterizer->rasterizeLine(a, b, nr.height() / nr.width());
1315         }
1316         return;
1317     }
1318
1319     QPainterPath path;
1320     path.addRect(r);
1321     updateOutlineMapper();
1322     fillPath(path, data);
1323 }
1324
1325 /*!
1326     \reimp
1327 */
1328 void QRasterPaintEngine::fillRect(const QRectF &r, const QBrush &brush)
1329 {
1330 #ifdef QT_DEBUG_DRAW
1331     qDebug() << "QRasterPaintEngine::fillRecct(): " << r << brush;
1332 #endif
1333     QRasterPaintEngineState *s = state();
1334
1335     ensureBrush(brush);
1336     if (!s->brushData.blend)
1337         return;
1338
1339     fillRect(r, &s->brushData);
1340 }
1341
1342 /*!
1343     \reimp
1344 */
1345 void QRasterPaintEngine::fillRect(const QRectF &r, const QColor &color)
1346 {
1347 #ifdef QT_DEBUG_DRAW
1348     qDebug() << "QRasterPaintEngine::fillRect(): " << r << color;
1349 #endif
1350     Q_D(QRasterPaintEngine);
1351     QRasterPaintEngineState *s = state();
1352
1353     d->solid_color_filler.solid.color = PREMUL(ARGB_COMBINE_ALPHA(color.rgba(), s->intOpacity));
1354     if ((d->solid_color_filler.solid.color & 0xff000000) == 0
1355         && s->composition_mode == QPainter::CompositionMode_SourceOver) {
1356         return;
1357     }
1358     d->solid_color_filler.clip = d->clip();
1359     d->solid_color_filler.adjustSpanMethods();
1360     fillRect(r, &d->solid_color_filler);
1361 }
1362
1363 /*!
1364   \internal
1365  */
1366 void QRasterPaintEngine::fillPolygon(const QPointF *points, int pointCount, PolygonDrawMode mode)
1367 {
1368     Q_D(QRasterPaintEngine);
1369     QRasterPaintEngineState *s = state();
1370
1371     // max amount of points that raster engine can reliably handle
1372     const int maxPoints = 0xffff;
1373     if (Q_UNLIKELY(pointCount > maxPoints)) {
1374         qWarning("Polygon too complex for filling.");
1375         return;
1376     }
1377
1378     // Compose polygon fill..,
1379     QVectorPath vp((qreal *) points, pointCount, 0, QVectorPath::polygonFlags(mode));
1380     updateOutlineMapper();
1381     QT_FT_Outline *outline = d->outlineMapper->convertPath(vp);
1382
1383     // scanconvert.
1384     ProcessSpans brushBlend = d->getBrushFunc(d->outlineMapper->controlPointRect,
1385                                               &s->brushData);
1386     d->rasterize(outline, brushBlend, &s->brushData);
1387 }
1388
1389 /*!
1390     \reimp
1391 */
1392 void QRasterPaintEngine::drawPolygon(const QPointF *points, int pointCount, PolygonDrawMode mode)
1393 {
1394     QRasterPaintEngineState *s = state();
1395
1396 #ifdef QT_DEBUG_DRAW
1397     qDebug(" - QRasterPaintEngine::drawPolygon(F), pointCount=%d", pointCount);
1398     for (int i=0; i<pointCount; ++i)
1399         qDebug() << "   - " << points[i];
1400 #endif
1401     Q_ASSERT(pointCount >= 2);
1402
1403     if (mode != PolylineMode && isRect((qreal *) points, pointCount)) {
1404         QRectF r(points[0], points[2]);
1405         QPaintEngineEx::drawRects(&r, 1);
1406         return;
1407     }
1408
1409     ensurePen();
1410     if (mode != PolylineMode) {
1411         // Do the fill...
1412         ensureBrush();
1413         if (s->brushData.blend)
1414             fillPolygon(points, pointCount, mode);
1415     }
1416
1417     // Do the outline...
1418     if (s->penData.blend) {
1419         QVectorPath vp((qreal *) points, pointCount, 0, QVectorPath::polygonFlags(mode));
1420         QPaintEngineEx::stroke(vp, s->lastPen);
1421     }
1422 }
1423
1424 /*!
1425     \reimp
1426 */
1427 void QRasterPaintEngine::drawPolygon(const QPoint *points, int pointCount, PolygonDrawMode mode)
1428 {
1429     Q_D(QRasterPaintEngine);
1430     QRasterPaintEngineState *s = state();
1431
1432 #ifdef QT_DEBUG_DRAW
1433     qDebug(" - QRasterPaintEngine::drawPolygon(I), pointCount=%d", pointCount);
1434     for (int i=0; i<pointCount; ++i)
1435         qDebug() << "   - " << points[i];
1436 #endif
1437     Q_ASSERT(pointCount >= 2);
1438     if (mode != PolylineMode && isRect((int *) points, pointCount)) {
1439         QRect r(points[0].x(),
1440                 points[0].y(),
1441                 points[2].x() - points[0].x(),
1442                 points[2].y() - points[0].y());
1443         drawRects(&r, 1);
1444         return;
1445     }
1446
1447     ensurePen();
1448
1449     // Do the fill
1450     if (mode != PolylineMode) {
1451         ensureBrush();
1452         if (s->brushData.blend) {
1453             // Compose polygon fill..,
1454             updateOutlineMapper();
1455             d->outlineMapper->beginOutline(mode == WindingMode ? Qt::WindingFill : Qt::OddEvenFill);
1456             d->outlineMapper->moveTo(*points);
1457             const QPoint *p = points;
1458             const QPoint *ep = points + pointCount - 1;
1459             do {
1460                 d->outlineMapper->lineTo(*(++p));
1461             } while (p < ep);
1462             d->outlineMapper->endOutline();
1463
1464             // scanconvert.
1465             ProcessSpans brushBlend = d->getBrushFunc(d->outlineMapper->controlPointRect,
1466                                                       &s->brushData);
1467             d->rasterize(d->outlineMapper->outline(), brushBlend, &s->brushData);
1468         }
1469     }
1470
1471     // Do the outline...
1472     if (s->penData.blend) {
1473         const int count = pointCount * 2;
1474         QSTACKARRAY(qreal, fpoints, count);
1475         for (int i=0; i<count; ++i)
1476             fpoints[i] = ((int *) points)[i];
1477         QVectorPath vp((qreal *) fpoints, pointCount, 0, QVectorPath::polygonFlags(mode));
1478
1479         QPaintEngineEx::stroke(vp, s->lastPen);
1480     }
1481 }
1482
1483 /*!
1484     \internal
1485 */
1486 void QRasterPaintEngine::drawPixmap(const QPointF &pos, const QPixmap &pixmap)
1487 {
1488 #ifdef QT_DEBUG_DRAW
1489     qDebug() << " - QRasterPaintEngine::drawPixmap(), pos=" << pos << " pixmap=" << pixmap.size() << "depth=" << pixmap.depth();
1490 #endif
1491
1492     QPixmapData *pd = pixmap.pixmapData();
1493     if (pd->classId() == QPixmapData::RasterClass) {
1494         const QImage &image = static_cast<QRasterPixmapData *>(pd)->image;
1495         if (image.depth() == 1) {
1496             Q_D(QRasterPaintEngine);
1497             QRasterPaintEngineState *s = state();
1498             if (s->matrix.type() <= QTransform::TxTranslate) {
1499                 ensurePen();
1500                 drawBitmap(pos + QPointF(s->matrix.dx(), s->matrix.dy()), image, &s->penData);
1501             } else {
1502                 drawImage(pos, d->rasterBuffer->colorizeBitmap(image, s->pen.color()));
1503             }
1504         } else {
1505             QRasterPaintEngine::drawImage(pos, image);
1506         }
1507     } else {
1508         const QImage image = pixmap.toImage();
1509         if (pixmap.depth() == 1) {
1510             Q_D(QRasterPaintEngine);
1511             QRasterPaintEngineState *s = state();
1512             if (s->matrix.type() <= QTransform::TxTranslate) {
1513                 ensurePen();
1514                 drawBitmap(pos + QPointF(s->matrix.dx(), s->matrix.dy()), image, &s->penData);
1515             } else {
1516                 drawImage(pos, d->rasterBuffer->colorizeBitmap(image, s->pen.color()));
1517             }
1518         } else {
1519             QRasterPaintEngine::drawImage(pos, image);
1520         }
1521     }
1522 }
1523
1524 /*!
1525     \reimp
1526 */
1527 void QRasterPaintEngine::drawPixmap(const QRectF &r, const QPixmap &pixmap, const QRectF &sr)
1528 {
1529 #ifdef QT_DEBUG_DRAW
1530     qDebug() << " - QRasterPaintEngine::drawPixmap(), r=" << r << " sr=" << sr << " pixmap=" << pixmap.size() << "depth=" << pixmap.depth();
1531 #endif
1532
1533     QPixmapData* pd = pixmap.pixmapData();
1534     if (pd->classId() == QPixmapData::RasterClass) {
1535         const QImage &image = static_cast<QRasterPixmapData *>(pd)->image;
1536         if (image.depth() == 1) {
1537             Q_D(QRasterPaintEngine);
1538             QRasterPaintEngineState *s = state();
1539             if (s->matrix.type() <= QTransform::TxTranslate
1540                 && r.size() == sr.size()
1541                 && r.size() == pixmap.size()) {
1542                 ensurePen();
1543                 drawBitmap(r.topLeft() + QPointF(s->matrix.dx(), s->matrix.dy()), image, &s->penData);
1544                 return;
1545             } else {
1546                 drawImage(r, d->rasterBuffer->colorizeBitmap(image, s->pen.color()), sr);
1547             }
1548         } else {
1549             drawImage(r, image, sr);
1550         }
1551     } else {
1552         QRect clippedSource = sr.toAlignedRect().intersected(pixmap.rect());
1553         const QImage image = pd->toImage(clippedSource);
1554         QRectF translatedSource = sr.translated(-clippedSource.topLeft());
1555         if (image.depth() == 1) {
1556             Q_D(QRasterPaintEngine);
1557             QRasterPaintEngineState *s = state();
1558             if (s->matrix.type() <= QTransform::TxTranslate
1559                 && r.size() == sr.size()
1560                 && r.size() == pixmap.size()) {
1561                 ensurePen();
1562                 drawBitmap(r.topLeft() + QPointF(s->matrix.dx(), s->matrix.dy()), image, &s->penData);
1563                 return;
1564             } else {
1565                 drawImage(r, d->rasterBuffer->colorizeBitmap(image, s->pen.color()), translatedSource);
1566             }
1567         } else {
1568             drawImage(r, image, translatedSource);
1569         }
1570     }
1571 }
1572
1573 static inline int fast_ceil_positive(const qreal &v)
1574 {
1575     const int iv = int(v);
1576     if (v - iv == 0)
1577         return iv;
1578     else
1579         return iv + 1;
1580 }
1581
1582 static inline const QRect toAlignedRect_positive(const QRectF &rect)
1583 {
1584     const int xmin = int(rect.x());
1585     const int xmax = int(fast_ceil_positive(rect.right()));
1586     const int ymin = int(rect.y());
1587     const int ymax = int(fast_ceil_positive(rect.bottom()));
1588     return QRect(xmin, ymin, xmax - xmin, ymax - ymin);
1589 }
1590
1591 /*!
1592     \internal
1593 */
1594 void QRasterPaintEngine::drawImage(const QPointF &p, const QImage &img)
1595 {
1596 #ifdef QT_DEBUG_DRAW
1597     qDebug() << " - QRasterPaintEngine::drawImage(), p=" <<  p << " image=" << img.size() << "depth=" << img.depth();
1598 #endif
1599
1600     Q_D(QRasterPaintEngine);
1601     QRasterPaintEngineState *s = state();
1602
1603     if (s->matrix.type() > QTransform::TxTranslate) {
1604         drawImage(QRectF(p.x(), p.y(), img.width(), img.height()),
1605                   img,
1606                   QRectF(0, 0, img.width(), img.height()));
1607     } else {
1608
1609         const QClipData *clip = d->clip();
1610         QPointF pt(p.x() + s->matrix.dx(), p.y() + s->matrix.dy());
1611
1612         d->image_filler.clip = clip;
1613         d->image_filler.initTexture(&img, s->intOpacity, QTextureData::Plain, img.rect());
1614         if (!d->image_filler.blend)
1615             return;
1616         d->image_filler.dx = -pt.x();
1617         d->image_filler.dy = -pt.y();
1618         QRect rr = img.rect().translated(qRound(pt.x()), qRound(pt.y()));
1619
1620         fillRect_normalized(rr, &d->image_filler, d);
1621     }
1622
1623 }
1624
1625 /*!
1626     \reimp
1627 */
1628 void QRasterPaintEngine::drawImage(const QRectF &r, const QImage &img, const QRectF &sr,
1629                                    Qt::ImageConversionFlags)
1630 {
1631 #ifdef QT_DEBUG_DRAW
1632     qDebug() << " - QRasterPaintEngine::drawImage(), r=" << r << " sr=" << sr << " image=" << img.size() << "depth=" << img.depth();
1633 #endif
1634
1635     if (r.isEmpty())
1636         return;
1637
1638     Q_D(QRasterPaintEngine);
1639     QRasterPaintEngineState *s = state();
1640     int sr_l = qFloor(sr.left());
1641     int sr_r = qCeil(sr.right()) - 1;
1642     int sr_t = qFloor(sr.top());
1643     int sr_b = qCeil(sr.bottom()) - 1;
1644
1645     if (s->matrix.type() <= QTransform::TxScale && !s->flags.antialiased && sr_l == sr_r && sr_t == sr_b) {
1646         // as fillRect will apply the aliased coordinate delta we need to
1647         // subtract it here as we don't use it for image drawing
1648         QTransform old = s->matrix;
1649         s->matrix = s->matrix * QTransform::fromTranslate(-aliasedCoordinateDelta, -aliasedCoordinateDelta);
1650
1651         // Do whatever fillRect() does, but without premultiplying the color if it's already premultiplied.
1652         QRgb color = img.pixel(sr_l, sr_t);
1653         switch (img.format()) {
1654         case QImage::Format_ARGB32_Premultiplied:
1655             // Combine premultiplied color with the opacity set on the painter.
1656             d->solid_color_filler.solid.color =
1657                 ((((color & 0x00ff00ff) * s->intOpacity) >> 8) & 0x00ff00ff)
1658                 | ((((color & 0xff00ff00) >> 8) * s->intOpacity) & 0xff00ff00);
1659             break;
1660         default:
1661             d->solid_color_filler.solid.color = PREMUL(ARGB_COMBINE_ALPHA(color, s->intOpacity));
1662             break;
1663         }
1664
1665         if ((d->solid_color_filler.solid.color & 0xff000000) == 0
1666             && s->composition_mode == QPainter::CompositionMode_SourceOver) {
1667             return;
1668         }
1669
1670         d->solid_color_filler.clip = d->clip();
1671         d->solid_color_filler.adjustSpanMethods();
1672         fillRect(r, &d->solid_color_filler);
1673
1674         s->matrix = old;
1675         return;
1676     }
1677
1678     bool stretch_sr = r.width() != sr.width() || r.height() != sr.height();
1679
1680     const QClipData *clip = d->clip();
1681
1682     if (s->matrix.type() > QTransform::TxTranslate || stretch_sr) {
1683         QTransform copy = s->matrix;
1684         copy.translate(r.x(), r.y());
1685         if (stretch_sr)
1686             copy.scale(r.width() / sr.width(), r.height() / sr.height());
1687         copy.translate(-sr.x(), -sr.y());
1688
1689         d->image_filler_xform.clip = clip;
1690         d->image_filler_xform.initTexture(&img, s->intOpacity, QTextureData::Plain, toAlignedRect_positive(sr));
1691         if (!d->image_filler_xform.blend)
1692             return;
1693         d->image_filler_xform.setupMatrix(copy, s->flags.bilinear);
1694
1695         if (!s->flags.antialiased && s->matrix.type() == QTransform::TxScale) {
1696             QPointF rr_tl = s->matrix.map(r.topLeft());
1697             QPointF rr_br = s->matrix.map(r.bottomRight());
1698
1699             int x1 = qRound(rr_tl.x());
1700             int y1 = qRound(rr_tl.y());
1701             int x2 = qRound(rr_br.x());
1702             int y2 = qRound(rr_br.y());
1703
1704             if (x1 > x2)
1705                 qSwap(x1, x2);
1706             if (y1 > y2)
1707                 qSwap(y1, y2);
1708
1709             fillRect_normalized(QRect(x1, y1, x2-x1, y2-y1), &d->image_filler_xform, d);
1710             return;
1711         }
1712
1713         const qreal offs = s->flags.antialiased ? qreal(0) : aliasedCoordinateDelta;
1714         QPainterPath path;
1715         path.addRect(r);
1716         QTransform m = s->matrix;
1717         s->matrix = QTransform(m.m11(), m.m12(), m.m13(),
1718                                m.m21(), m.m22(), m.m23(),
1719                                m.m31() - offs, m.m32() - offs, m.m33());
1720         fillPath(path, &d->image_filler_xform);
1721         s->matrix = m;
1722     } else {
1723         d->image_filler.clip = clip;
1724         d->image_filler.initTexture(&img, s->intOpacity, QTextureData::Plain, toAlignedRect_positive(sr));
1725         if (!d->image_filler.blend)
1726             return;
1727         d->image_filler.dx = -(r.x() + s->matrix.dx()) + sr.x();
1728         d->image_filler.dy = -(r.y() + s->matrix.dy()) + sr.y();
1729
1730         QRectF rr = r.translated(s->matrix.dx(), s->matrix.dy());
1731
1732         const int x1 = qRound(rr.x());
1733         const int y1 = qRound(rr.y());
1734         const int x2 = qRound(rr.right());
1735         const int y2 = qRound(rr.bottom());
1736
1737         fillRect_normalized(QRect(x1, y1, x2-x1, y2-y1), &d->image_filler, d);
1738     }
1739 }
1740
1741 /*!
1742     \reimp
1743 */
1744 void QRasterPaintEngine::drawTiledPixmap(const QRectF &r, const QPixmap &pixmap, const QPointF &sr)
1745 {
1746 #ifdef QT_DEBUG_DRAW
1747     qDebug() << " - QRasterPaintEngine::drawTiledPixmap(), r=" << r << "pixmap=" << pixmap.size();
1748 #endif
1749     Q_D(QRasterPaintEngine);
1750     QRasterPaintEngineState *s = state();
1751
1752     QImage image;
1753
1754     QPixmapData *pd = pixmap.pixmapData();
1755     if (pd->classId() == QPixmapData::RasterClass) {
1756         image = static_cast<QRasterPixmapData *>(pd)->image;
1757     } else {
1758         image = pixmap.toImage();
1759     }
1760
1761     if (image.depth() == 1)
1762         image = d->rasterBuffer->colorizeBitmap(image, s->pen.color());
1763
1764     if (s->matrix.type() > QTransform::TxTranslate) {
1765         QTransform copy = s->matrix;
1766         copy.translate(r.x(), r.y());
1767         copy.translate(-sr.x(), -sr.y());
1768         d->image_filler_xform.clip = d->clip();
1769         d->image_filler_xform.initTexture(&image, s->intOpacity, QTextureData::Tiled);
1770         if (!d->image_filler_xform.blend)
1771             return;
1772         d->image_filler_xform.setupMatrix(copy, s->flags.bilinear);
1773
1774         QPainterPath path;
1775         path.addRect(r);
1776         fillPath(path, &d->image_filler_xform);
1777     } else {
1778         d->image_filler.clip = d->clip();
1779
1780         d->image_filler.initTexture(&image, s->intOpacity, QTextureData::Tiled);
1781         if (!d->image_filler.blend)
1782             return;
1783         d->image_filler.dx = -(r.x() + s->matrix.dx()) + sr.x();
1784         d->image_filler.dy = -(r.y() + s->matrix.dy()) + sr.y();
1785
1786         QRectF rr = r.translated(s->matrix.dx(), s->matrix.dy());
1787         fillRect_normalized(rr.toRect().normalized(), &d->image_filler, d);
1788     }
1789 }
1790
1791 /*!
1792  * Returns true if the rectangle is completely within the current clip
1793  * state of the paint engine.
1794  */
1795 bool QRasterPaintEnginePrivate::isUnclipped_normalized(const QRect &r) const
1796 {
1797     const QClipData *cl = clip();
1798     if (!cl) {
1799         // inline contains() for performance (we know the rects are normalized)
1800         const QRect &r1 = deviceRect;
1801         return (r.left() >= r1.left() && r.right() <= r1.right()
1802                 && r.top() >= r1.top() && r.bottom() <= r1.bottom());
1803     }
1804
1805
1806     if (cl->hasRectClip) {
1807         // currently all painting functions clips to deviceRect internally
1808         if (cl->clipRect == deviceRect)
1809             return true;
1810
1811         // inline contains() for performance (we know the rects are normalized)
1812         const QRect &r1 = cl->clipRect;
1813         return (r.left() >= r1.left() && r.right() <= r1.right()
1814                 && r.top() >= r1.top() && r.bottom() <= r1.bottom());
1815     } else {
1816         return qt_region_strictContains(cl->clipRegion, r);
1817     }
1818 }
1819
1820 bool QRasterPaintEnginePrivate::isUnclipped(const QRect &rect) const
1821 {
1822     Q_Q(const QRasterPaintEngine);
1823     const QRasterPaintEngineState *s = q->state();
1824     const QClipData *cl = clip();
1825     if (!cl) {
1826         QRect r = rect.normalized();
1827         // inline contains() for performance (we know the rects are normalized)
1828         const QRect &r1 = deviceRect;
1829         return (r.left() >= r1.left() && r.right() <= r1.right()
1830                 && r.top() >= r1.top() && r.bottom() <= r1.bottom());
1831     }
1832
1833
1834     // currently all painting functions that call this function clip to deviceRect internally
1835     if (cl->hasRectClip && cl->clipRect == deviceRect)
1836         return true;
1837
1838     QRect r = rect.normalized();
1839     if (s->flags.antialiased) {
1840         r.setX(r.x() - 1);
1841         r.setY(r.y() - 1);
1842         r.setWidth(r.width() + 2);
1843         r.setHeight(r.height() + 2);
1844     }
1845
1846     if (cl->hasRectClip) {
1847         // inline contains() for performance (we know the rects are normalized)
1848         const QRect &r1 = cl->clipRect;
1849         return (r.left() >= r1.left() && r.right() <= r1.right()
1850                 && r.top() >= r1.top() && r.bottom() <= r1.bottom());
1851     } else {
1852         return qt_region_strictContains(cl->clipRegion, r);
1853     }
1854 }
1855
1856 inline bool QRasterPaintEnginePrivate::isUnclipped(const QRectF &rect) const
1857 {
1858     return isUnclipped(rect.normalized().toAlignedRect());
1859 }
1860
1861 inline ProcessSpans
1862 QRasterPaintEnginePrivate::getBrushFunc(const QRect &rect,
1863                                         const QSpanData *data) const
1864 {
1865     return isUnclipped(rect) ? data->unclipped_blend : data->blend;
1866 }
1867
1868 inline ProcessSpans
1869 QRasterPaintEnginePrivate::getBrushFunc(const QRectF &rect,
1870                                         const QSpanData *data) const
1871 {
1872     return isUnclipped(rect) ? data->unclipped_blend : data->blend;
1873 }
1874
1875 /*!
1876     \reimp
1877 */
1878 void QRasterPaintEngine::drawTextItem(const QPointF &p, const QTextItem &textItem)
1879 {
1880     const QTextItemInt &ti = static_cast<const QTextItemInt &>(textItem);
1881
1882 #ifdef QT_DEBUG_DRAW
1883     Q_D(QRasterPaintEngine);
1884     fprintf(stderr," - QRasterPaintEngine::drawTextItem(), (%.2f,%.2f), string=%s\n",
1885            p.x(), p.y(), QString::fromRawData(ti.chars, ti.num_chars).toLatin1().data());
1886 #endif
1887
1888     ensurePen();
1889     ensureRasterState();
1890
1891     QPaintEngineEx::drawTextItem(p, ti);
1892 }
1893
1894 /*!
1895     \reimp
1896 */
1897 void QRasterPaintEngine::drawPoints(const QPointF *points, int pointCount)
1898 {
1899     QRasterPaintEngineState *s = state();
1900
1901     ensurePen();
1902     if (!s->penData.blend)
1903         return;
1904
1905     QPaintEngineEx::drawPoints(points, pointCount);
1906 }
1907
1908
1909 void QRasterPaintEngine::drawPoints(const QPoint *points, int pointCount)
1910 {
1911     QRasterPaintEngineState *s = state();
1912
1913     ensurePen();
1914     if (!s->penData.blend)
1915         return;
1916
1917     QPaintEngineEx::drawPoints(points, pointCount);
1918 }
1919
1920 /*!
1921     \reimp
1922 */
1923 void QRasterPaintEngine::drawLines(const QLine *lines, int lineCount)
1924 {
1925 #ifdef QT_DEBUG_DRAW
1926     qDebug() << " - QRasterPaintEngine::drawLines(QLine*)" << lineCount;
1927 #endif
1928     QRasterPaintEngineState *s = state();
1929
1930     ensurePen();
1931     if (!s->penData.blend)
1932         return;
1933
1934     QPaintEngineEx::drawLines(lines, lineCount);
1935 }
1936
1937 void QRasterPaintEnginePrivate::rasterizeLine_dashed(QLineF line,
1938                                                      qreal width,
1939                                                      int *dashIndex,
1940                                                      qreal *dashOffset,
1941                                                      bool *inDash)
1942 {
1943     Q_Q(QRasterPaintEngine);
1944     QRasterPaintEngineState *s = q->state();
1945
1946     const bool squareCap = (s->lastPen.capStyle() == Qt::SquareCap);
1947     const QVector<qreal> pattern = s->lastPen.dashPattern();
1948
1949     qreal patternLength = 0;
1950     for (int i = 0; i < pattern.size(); ++i)
1951         patternLength += pattern.at(i);
1952
1953     if (patternLength <= 0)
1954         return;
1955
1956     qreal length = line.length();
1957     Q_ASSERT(length > 0);
1958     while (length > 0) {
1959         const bool rasterize = *inDash;
1960         qreal dash = (pattern.at(*dashIndex) - *dashOffset) * width;
1961         QLineF l = line;
1962
1963         if (dash >= length) {
1964             dash = length;
1965             *dashOffset += dash / width;
1966             length = 0;
1967         } else {
1968             *dashOffset = 0;
1969             *inDash = !(*inDash);
1970             if (++*dashIndex >= pattern.size())
1971                 *dashIndex = 0;
1972             length -= dash;
1973             l.setLength(dash);
1974             line.setP1(l.p2());
1975         }
1976
1977         if (rasterize && dash > 0)
1978             rasterizer->rasterizeLine(l.p1(), l.p2(), width / dash, squareCap);
1979     }
1980 }
1981
1982 /*!
1983     \reimp
1984 */
1985 void QRasterPaintEngine::drawLines(const QLineF *lines, int lineCount)
1986 {
1987 #ifdef QT_DEBUG_DRAW
1988     qDebug() << " - QRasterPaintEngine::drawLines(QLineF *)" << lineCount;
1989 #endif
1990     QRasterPaintEngineState *s = state();
1991
1992     ensurePen();
1993     if (!s->penData.blend)
1994         return;
1995
1996     QPaintEngineEx::drawLines(lines, lineCount);
1997 }
1998
1999
2000 /*!
2001     \reimp
2002 */
2003 void QRasterPaintEngine::drawEllipse(const QRectF &rect)
2004 {
2005     ensurePen();
2006
2007     QPaintEngineEx::drawEllipse(rect);
2008 }
2009
2010 void QRasterPaintEngine::drawBitmap(const QPointF &pos, const QImage &image, QSpanData *fg)
2011 {
2012     Q_ASSERT(fg);
2013     if (!fg->blend)
2014         return;
2015     Q_D(QRasterPaintEngine);
2016
2017     Q_ASSERT(image.depth() == 1);
2018
2019     const int spanCount = 256;
2020     QSTACKARRAY(QT_FT_Span, spans, spanCount);
2021     int n = 0;
2022
2023     // Boundaries
2024     int w = image.width();
2025     int h = image.height();
2026     int ymax = qMin(qRound(pos.y() + h), d->rasterBuffer->height());
2027     int ymin = qMax(qRound(pos.y()), 0);
2028     int xmax = qMin(qRound(pos.x() + w), d->rasterBuffer->width());
2029     int xmin = qMax(qRound(pos.x()), 0);
2030
2031     int x_offset = xmin - qRound(pos.x());
2032
2033     QImage::Format format = image.format();
2034     for (int y = ymin; y < ymax; ++y) {
2035         const uchar *src = image.constScanLine(y - qRound(pos.y()));
2036         if (format == QImage::Format_MonoLSB) {
2037             for (int x = 0; x < xmax - xmin; ++x) {
2038                 int src_x = x + x_offset;
2039                 uchar pixel = src[src_x >> 3];
2040                 if (!pixel) {
2041                     x += 7 - (src_x%8);
2042                     continue;
2043                 }
2044                 if (pixel & (0x1 << (src_x & 7))) {
2045                     spans[n].x = xmin + x;
2046                     spans[n].y = y;
2047                     spans[n].coverage = 255;
2048                     int len = 1;
2049                     while (src_x+1 < w && src[(src_x+1) >> 3] & (0x1 << ((src_x+1) & 7))) {
2050                         ++src_x;
2051                         ++len;
2052                     }
2053                     spans[n].len = ((len + spans[n].x) > xmax) ? (xmax - spans[n].x) : len;
2054                     x += len;
2055                     ++n;
2056                     if (n == spanCount) {
2057                         fg->blend(n, spans, fg);
2058                         n = 0;
2059                     }
2060                 }
2061             }
2062         } else {
2063             for (int x = 0; x < xmax - xmin; ++x) {
2064                 int src_x = x + x_offset;
2065                 uchar pixel = src[src_x >> 3];
2066                 if (!pixel) {
2067                     x += 7 - (src_x%8);
2068                     continue;
2069                 }
2070                 if (pixel & (0x80 >> (x & 7))) {
2071                     spans[n].x = xmin + x;
2072                     spans[n].y = y;
2073                     spans[n].coverage = 255;
2074                     int len = 1;
2075                     while (src_x+1 < w && src[(src_x+1) >> 3] & (0x80 >> ((src_x+1) & 7))) {
2076                         ++src_x;
2077                         ++len;
2078                     }
2079                     spans[n].len = ((len + spans[n].x) > xmax) ? (xmax - spans[n].x) : len;
2080                     x += len;
2081                     ++n;
2082                     if (n == spanCount) {
2083                         fg->blend(n, spans, fg);
2084                         n = 0;
2085                     }
2086                 }
2087             }
2088         }
2089     }
2090     if (n) {
2091         fg->blend(n, spans, fg);
2092     }
2093 }
2094
2095 static void qt_merge_clip(const QClipData *c1, const QClipData *c2, QClipData *result)
2096 {
2097     Q_ASSERT(c1->clipSpanHeight == c2->clipSpanHeight && c1->clipSpanHeight == result->clipSpanHeight);
2098
2099     QVarLengthArray<short, 4096> buffer;
2100
2101     QClipData::ClipLine *c1ClipLines = const_cast<QClipData *>(c1)->clipLines();
2102     QClipData::ClipLine *c2ClipLines = const_cast<QClipData *>(c2)->clipLines();
2103     result->initialize();
2104
2105     for (int y = 0; y < c1->clipSpanHeight; ++y) {
2106         const QSpan *c1_spans = c1ClipLines[y].spans;
2107         int c1_count = c1ClipLines[y].count;
2108         const QSpan *c2_spans = c2ClipLines[y].spans;
2109         int c2_count = c2ClipLines[y].count;
2110
2111         if (c1_count == 0 && c2_count == 0)
2112             continue;
2113         if (c1_count == 0) {
2114             result->appendSpans(c2_spans, c2_count);
2115             continue;
2116         } else if (c2_count == 0) {
2117             result->appendSpans(c1_spans, c1_count);
2118             continue;
2119         }
2120
2121         // we need to merge the two
2122
2123         // find required length
2124         int max = qMax(c1_spans[c1_count - 1].x + c1_spans[c1_count - 1].len,
2125                 c2_spans[c2_count - 1].x + c2_spans[c2_count - 1].len);
2126         buffer.resize(max);
2127         memset(buffer.data(), 0, buffer.size() * sizeof(short));
2128
2129         // Fill with old spans.
2130         for (int i = 0; i < c1_count; ++i) {
2131             const QSpan *cs = c1_spans + i;
2132             for (int j=cs->x; j<cs->x + cs->len; ++j)
2133                 buffer[j] = cs->coverage;
2134         }
2135
2136         // Fill with new spans
2137         for (int i = 0; i < c2_count; ++i) {
2138             const QSpan *cs = c2_spans + i;
2139             for (int j = cs->x; j < cs->x + cs->len; ++j) {
2140                 buffer[j] += cs->coverage;
2141                 if (buffer[j] > 255)
2142                     buffer[j] = 255;
2143             }
2144         }
2145
2146         int x = 0;
2147         while (x<max) {
2148
2149             // Skip to next span
2150             while (x < max && buffer[x] == 0) ++x;
2151             if (x >= max) break;
2152
2153             int sx = x;
2154             int coverage = buffer[x];
2155
2156             // Find length of span
2157             while (x < max && buffer[x] == coverage)
2158                 ++x;
2159
2160             result->appendSpan(sx, x - sx, y, coverage);
2161         }
2162     }
2163 }
2164
2165 void QRasterPaintEnginePrivate::initializeRasterizer(QSpanData *data)
2166 {
2167     Q_Q(QRasterPaintEngine);
2168     QRasterPaintEngineState *s = q->state();
2169
2170     rasterizer->setAntialiased(s->flags.antialiased);
2171
2172     QRect clipRect(deviceRect);
2173     ProcessSpans blend;
2174     // ### get from optimized rectbased QClipData
2175
2176     const QClipData *c = clip();
2177     if (c) {
2178         const QRect r(QPoint(c->xmin, c->ymin),
2179                       QSize(c->xmax - c->xmin, c->ymax - c->ymin));
2180         clipRect = clipRect.intersected(r);
2181         blend = data->blend;
2182     } else {
2183         blend = data->unclipped_blend;
2184     }
2185
2186     rasterizer->setClipRect(clipRect);
2187     rasterizer->initialize(blend, data);
2188 }
2189
2190 void QRasterPaintEnginePrivate::rasterize(QT_FT_Outline *outline,
2191                                           ProcessSpans callback,
2192                                           void *userData)
2193 {
2194     if (!callback || !outline)
2195         return;
2196
2197     Q_Q(QRasterPaintEngine);
2198     QRasterPaintEngineState *s = q->state();
2199
2200     if (!s->flags.antialiased) {
2201         rasterizer->setAntialiased(s->flags.antialiased);
2202         rasterizer->setClipRect(deviceRect);
2203         rasterizer->initialize(callback, userData);
2204
2205         const Qt::FillRule fillRule = outline->flags == QT_FT_OUTLINE_NONE
2206                                       ? Qt::WindingFill
2207                                       : Qt::OddEvenFill;
2208
2209         rasterizer->rasterize(outline, fillRule);
2210         return;
2211     }
2212
2213     gray_raster_reset();
2214
2215     QT_FT_BBox clip_box = { deviceRect.x(),
2216                             deviceRect.y(),
2217                             deviceRect.x() + deviceRect.width(),
2218                             deviceRect.y() + deviceRect.height() };
2219
2220     QT_FT_Raster_Params rasterParams;
2221     rasterParams.source = outline;
2222     rasterParams.user = userData;
2223     rasterParams.clip_box = clip_box;
2224     rasterParams.gray_spans = callback;
2225     gray_raster_render(&rasterParams);
2226 }
2227
2228 QImage QRasterBuffer::colorizeBitmap(const QImage &image, const QColor &color)
2229 {
2230     Q_ASSERT(image.depth() == 1);
2231
2232     QImage sourceImage = image.convertToFormat(QImage::Format_MonoLSB);
2233     QImage dest = QImage(sourceImage.size(), QImage::Format_ARGB32_Premultiplied);
2234
2235     QRgb fg = PREMUL(color.rgba());
2236     QRgb bg = 0;
2237
2238     int height = sourceImage.height();
2239     int width = sourceImage.width();
2240     int bpl = dest.bytesPerLine();
2241     uchar *data = dest.bits();
2242     for (int y=0; y<height; ++y) {
2243         const uchar *source = sourceImage.constScanLine(y);
2244         QRgb *target = reinterpret_cast<QRgb *>(QFAST_SCAN_LINE(data, bpl, y));
2245         for (int x=0; x < width; ++x)
2246             target[x] = (source[x>>3] >> (x&7)) & 1 ? fg : bg;
2247     }
2248     return dest;
2249 }
2250
2251 QRasterBuffer::~QRasterBuffer()
2252 {
2253 }
2254
2255 QRasterBuffer::QRasterBuffer()
2256     : monoDestinationWithClut(false),
2257     destColor0(0),
2258     destColor1(0),
2259     compositionMode(QPainter::CompositionMode_SourceOver),
2260     m_width(0),
2261     m_height(0),
2262     m_buffer(nullptr)
2263 {
2264 }
2265
2266 QImage::Format QRasterBuffer::prepare(QImage *image)
2267 {
2268     m_buffer = image->bits();
2269     m_width = qMin(RASTER_COORD_LIMIT, image->width());
2270     m_height = qMin(RASTER_COORD_LIMIT, image->height());
2271     bytes_per_pixel = image->depth()/8;
2272     bytes_per_line = image->bytesPerLine();
2273
2274     format = image->format();
2275     drawHelper = qDrawHelper + format;
2276     if (image->depth() == 1) {
2277         monoDestinationWithClut = true;
2278         destColor0 = PREMUL(image->colorTable()[0]);
2279         destColor1 = PREMUL(image->colorTable()[1]);
2280     }
2281
2282     return format;
2283 }
2284
2285 QClipData::QClipData(int height)
2286 {
2287     clipSpanHeight = height;
2288     m_clipLines = 0;
2289
2290     allocated = 0;
2291     m_spans = 0;
2292     xmin = xmax = ymin = ymax = 0;
2293     count = 0;
2294
2295     enabled = true;
2296     hasRectClip = hasRegionClip = false;
2297 }
2298
2299 QClipData::~QClipData()
2300 {
2301     if (m_clipLines)
2302         free(m_clipLines);
2303     if (m_spans)
2304         free(m_spans);
2305 }
2306
2307 void QClipData::initialize()
2308 {
2309     if (m_spans)
2310         return;
2311
2312     if (!m_clipLines)
2313         m_clipLines = (ClipLine *)calloc(sizeof(ClipLine), clipSpanHeight);
2314
2315     Q_CHECK_PTR(m_clipLines);
2316     m_spans = (QSpan *)malloc(clipSpanHeight*sizeof(QSpan));
2317     allocated = clipSpanHeight;
2318     Q_CHECK_PTR(m_spans);
2319
2320     if (hasRectClip) {
2321         int y = 0;
2322         while (y < ymin) {
2323             m_clipLines[y].spans = 0;
2324             m_clipLines[y].count = 0;
2325             ++y;
2326         }
2327
2328         const int len = clipRect.width();
2329         count = 0;
2330         while (y < ymax) {
2331             QSpan *span = m_spans + count;
2332             span->x = xmin;
2333             span->len = len;
2334             span->y = y;
2335             span->coverage = 255;
2336             ++count;
2337
2338             m_clipLines[y].spans = span;
2339             m_clipLines[y].count = 1;
2340             ++y;
2341         }
2342
2343         while (y < clipSpanHeight) {
2344             m_clipLines[y].spans = 0;
2345             m_clipLines[y].count = 0;
2346             ++y;
2347         }
2348     } else if (hasRegionClip) {
2349
2350         const QVector<QRect> rects = clipRegion.rects();
2351         const int numRects = rects.size();
2352
2353         { // resize
2354             const int maxSpans = (ymax - ymin) * numRects;
2355             if (maxSpans > allocated) {
2356                 m_spans = (QSpan *)::realloc(m_spans, maxSpans * sizeof(QSpan));
2357                 Q_CHECK_PTR(m_spans);
2358                 allocated = maxSpans;
2359             }
2360         }
2361
2362         int y = 0;
2363         int firstInBand = 0;
2364         count = 0;
2365         while (firstInBand < numRects) {
2366             const int currMinY = rects.at(firstInBand).y();
2367             const int currMaxY = currMinY + rects.at(firstInBand).height();
2368
2369             while (y < currMinY) {
2370                 m_clipLines[y].spans = 0;
2371                 m_clipLines[y].count = 0;
2372                 ++y;
2373             }
2374
2375             int lastInBand = firstInBand;
2376             while (lastInBand + 1 < numRects && rects.at(lastInBand+1).top() == y)
2377                 ++lastInBand;
2378
2379             while (y < currMaxY) {
2380
2381                 m_clipLines[y].spans = m_spans + count;
2382                 m_clipLines[y].count = lastInBand - firstInBand + 1;
2383
2384                 for (int r = firstInBand; r <= lastInBand; ++r) {
2385                     const QRect &currRect = rects.at(r);
2386                     QSpan *span = m_spans + count;
2387                     span->x = currRect.x();
2388                     span->len = currRect.width();
2389                     span->y = y;
2390                     span->coverage = 255;
2391                     ++count;
2392                 }
2393                 ++y;
2394             }
2395
2396             firstInBand = lastInBand + 1;
2397         }
2398
2399         Q_ASSERT(count <= allocated);
2400
2401         while (y < clipSpanHeight) {
2402             m_clipLines[y].spans = 0;
2403             m_clipLines[y].count = 0;
2404             ++y;
2405         }
2406
2407     }
2408 }
2409
2410 void QClipData::fixup()
2411 {
2412     Q_ASSERT(m_spans);
2413
2414     if (count == 0) {
2415         ymin = ymax = xmin = xmax = 0;
2416         return;
2417     }
2418
2419     int y = -1;
2420     ymin = m_spans[0].y;
2421     ymax = m_spans[count-1].y + 1;
2422     xmin = INT_MAX;
2423     xmax = 0;
2424
2425     const int firstLeft = m_spans[0].x;
2426     const int firstRight = m_spans[0].x + m_spans[0].len;
2427     bool isRect = true;
2428
2429     for (int i = 0; i < count; ++i) {
2430         QT_FT_Span_& span = m_spans[i];
2431
2432         if (span.y != y) {
2433             if (span.y != y + 1 && y != -1)
2434                 isRect = false;
2435             y = span.y;
2436             m_clipLines[y].spans = &span;
2437             m_clipLines[y].count = 1;
2438         } else
2439             ++m_clipLines[y].count;
2440
2441         const int spanLeft = span.x;
2442         const int spanRight = spanLeft + span.len;
2443
2444         if (spanLeft < xmin)
2445             xmin = spanLeft;
2446
2447         if (spanRight > xmax)
2448             xmax = spanRight;
2449
2450         if (spanLeft != firstLeft || spanRight != firstRight)
2451             isRect = false;
2452     }
2453
2454     if (isRect) {
2455         hasRectClip = true;
2456         clipRect.setRect(xmin, ymin, xmax - xmin, ymax - ymin);
2457     }
2458 }
2459
2460 /*
2461     Convert \a rect to clip spans.
2462  */
2463 void QClipData::setClipRect(const QRect &rect)
2464 {
2465     if (hasRectClip && rect == clipRect)
2466         return;
2467
2468 //    qDebug() << "setClipRect" << clipSpanHeight << count << allocated << rect;
2469     hasRectClip = true;
2470     hasRegionClip = false;
2471     clipRect = rect;
2472
2473     xmin = rect.x();
2474     xmax = rect.x() + rect.width();
2475     ymin = qMin(rect.y(), clipSpanHeight);
2476     ymax = qMin(rect.y() + rect.height(), clipSpanHeight);
2477
2478     if (m_spans) {
2479         free(m_spans);
2480         m_spans = 0;
2481     }
2482
2483 //    qDebug() << xmin << xmax << ymin << ymax;
2484 }
2485
2486 /*
2487     Convert \a region to clip spans.
2488  */
2489 void QClipData::setClipRegion(const QRegion &region)
2490 {
2491     if (region.rectCount() == 1) {
2492         setClipRect(region.rects().at(0));
2493         return;
2494     }
2495
2496     hasRegionClip = true;
2497     hasRectClip = false;
2498     clipRegion = region;
2499
2500     { // set bounding rect
2501         const QRect rect = region.boundingRect();
2502         xmin = rect.x();
2503         xmax = rect.x() + rect.width();
2504         ymin = rect.y();
2505         ymax = rect.y() + rect.height();
2506     }
2507
2508     if (m_spans) {
2509         free(m_spans);
2510         m_spans = 0;
2511     }
2512
2513 }
2514
2515 /*!
2516     \internal
2517     spans must be sorted on y
2518 */
2519 static const QSpan *qt_intersect_spans(const QClipData *clip, int *currentClip,
2520                                        const QSpan *spans, const QSpan *end,
2521                                        QSpan **outSpans, int available)
2522 {
2523     const_cast<QClipData *>(clip)->initialize();
2524
2525     QSpan *out = *outSpans;
2526
2527     const QSpan *clipSpans = clip->m_spans + *currentClip;
2528     const QSpan *clipEnd = clip->m_spans + clip->count;
2529
2530     while (available && spans < end ) {
2531         if (clipSpans >= clipEnd) {
2532             spans = end;
2533             break;
2534         }
2535         if (clipSpans->y > spans->y) {
2536             ++spans;
2537             continue;
2538         }
2539         if (spans->y != clipSpans->y) {
2540             if (spans->y < clip->count && clip->m_clipLines[spans->y].spans)
2541                 clipSpans = clip->m_clipLines[spans->y].spans;
2542             else
2543                 ++clipSpans;
2544             continue;
2545         }
2546         Q_ASSERT(spans->y == clipSpans->y);
2547
2548         int sx1 = spans->x;
2549         int sx2 = sx1 + spans->len;
2550         int cx1 = clipSpans->x;
2551         int cx2 = cx1 + clipSpans->len;
2552
2553         if (cx1 < sx1 && cx2 < sx1) {
2554             ++clipSpans;
2555             continue;
2556         } else if (sx1 < cx1 && sx2 < cx1) {
2557             ++spans;
2558             continue;
2559         }
2560         int x = qMax(sx1, cx1);
2561         int len = qMin(sx2, cx2) - x;
2562         if (len) {
2563             out->x = qMax(sx1, cx1);
2564             out->len = qMin(sx2, cx2) - out->x;
2565             out->y = spans->y;
2566             out->coverage = qt_div_255(spans->coverage * clipSpans->coverage);
2567             ++out;
2568             --available;
2569         }
2570         if (sx2 < cx2) {
2571             ++spans;
2572         } else {
2573             ++clipSpans;
2574         }
2575     }
2576
2577     *outSpans = out;
2578     *currentClip = clipSpans - clip->m_spans;
2579     return spans;
2580 }
2581
2582 static void qt_span_fill_clipped(int spanCount, const QSpan *spans, void *userData)
2583 {
2584 //     qDebug() << "qt_span_fill_clipped" << spanCount;
2585     QSpanData *fillData = reinterpret_cast<QSpanData *>(userData);
2586
2587     Q_ASSERT(fillData->blend && fillData->unclipped_blend);
2588
2589     const int NSPANS = 256;
2590     QSpan cspans[NSPANS];
2591     int currentClip = 0;
2592     const QSpan *end = spans + spanCount;
2593     while (spans < end) {
2594         QSpan *clipped = cspans;
2595         spans = qt_intersect_spans(fillData->clip, &currentClip, spans, end, &clipped, NSPANS);
2596 //         qDebug() << "processed " << spanCount - (end - spans) << "clipped" << clipped-cspans
2597 //                  << "span:" << cspans->x << cspans->y << cspans->len << spans->coverage;
2598
2599         if (clipped - cspans)
2600             fillData->unclipped_blend(clipped - cspans, cspans, fillData);
2601     }
2602 }
2603
2604 /*
2605     \internal
2606     Clip spans to \a{clip}-rectangle.
2607     Returns number of unclipped spans
2608 */
2609 static int qt_intersect_spans(QT_FT_Span *spans, int numSpans,
2610                               const QRect &clip)
2611 {
2612     const short minx = clip.left();
2613     const short miny = clip.top();
2614     const short maxx = clip.right();
2615     const short maxy = clip.bottom();
2616
2617     int n = 0;
2618     for (int i = 0; i < numSpans; ++i) {
2619         if (spans[i].y > maxy)
2620             break;
2621         if (spans[i].y < miny
2622             || spans[i].x > maxx
2623             || spans[i].x + spans[i].len <= minx) {
2624             continue;
2625         }
2626         if (spans[i].x < minx) {
2627             spans[n].len = qMin(spans[i].len - (minx - spans[i].x), maxx - minx + 1);
2628             spans[n].x = minx;
2629         } else {
2630             spans[n].x = spans[i].x;
2631             spans[n].len = qMin(spans[i].len, ushort(maxx - spans[n].x + 1));
2632         }
2633         if (spans[n].len == 0)
2634             continue;
2635         spans[n].y = spans[i].y;
2636         spans[n].coverage = spans[i].coverage;
2637         ++n;
2638     }
2639     return n;
2640 }
2641
2642
2643 static void qt_span_fill_clipRect(int count, const QSpan *spans,
2644                                   void *userData)
2645 {
2646     QSpanData *fillData = reinterpret_cast<QSpanData *>(userData);
2647     Q_ASSERT(fillData->blend && fillData->unclipped_blend);
2648
2649     Q_ASSERT(fillData->clip);
2650     Q_ASSERT(!fillData->clip->clipRect.isEmpty());
2651
2652     // hw: check if this const_cast<> is safe!!!
2653     count = qt_intersect_spans(const_cast<QSpan*>(spans), count,
2654                                fillData->clip->clipRect);
2655     if (count > 0)
2656         fillData->unclipped_blend(count, spans, fillData);
2657 }
2658
2659 static void qt_span_clip(int count, const QSpan *spans, void *userData)
2660 {
2661     ClipData *clipData = reinterpret_cast<ClipData *>(userData);
2662
2663 //     qDebug() << " qt_span_clip: " << count << clipData->operation;
2664 //     for (int i = 0; i < qMin(count, 10); ++i) {
2665 //         qDebug() << "    " << spans[i].x << spans[i].y << spans[i].len << spans[i].coverage;
2666 //     }
2667
2668     switch (clipData->operation) {
2669
2670     case Qt::IntersectClip:
2671         {
2672             QClipData *newClip = clipData->newClip;
2673             newClip->initialize();
2674
2675             int currentClip = 0;
2676             const QSpan *end = spans + count;
2677             while (spans < end) {
2678                 QSpan *newspans = newClip->m_spans + newClip->count;
2679                 spans = qt_intersect_spans(clipData->oldClip, &currentClip, spans, end,
2680                                            &newspans, newClip->allocated - newClip->count);
2681                 newClip->count = newspans - newClip->m_spans;
2682                 if (spans < end) {
2683                     newClip->m_spans = (QSpan *)::realloc(newClip->m_spans, newClip->allocated*2*sizeof(QSpan));
2684                     Q_CHECK_PTR(newClip->m_spans);
2685                     newClip->allocated *= 2;
2686                 }
2687             }
2688         }
2689         break;
2690
2691     case Qt::UniteClip:
2692     case Qt::ReplaceClip:
2693         clipData->newClip->appendSpans(spans, count);
2694         break;
2695     case Qt::NoClip:
2696         break;
2697     }
2698 }
2699
2700 #ifndef QT_NO_DEBUG
2701 QImage QRasterBuffer::bufferImage() const
2702 {
2703     QImage image(m_width, m_height, QImage::Format_ARGB32_Premultiplied);
2704
2705     for (int y = 0; y < m_height; ++y) {
2706         const uint *span = (const uint *)this->scanLine(y);
2707
2708         for (int x=0; x<m_width; ++x) {
2709             image.setPixel(x, y, span[x]);
2710         }
2711     }
2712     return image;
2713 }
2714 #endif
2715
2716 void QSpanData::init(QRasterBuffer *rb, const QRasterPaintEngine *pe)
2717 {
2718     rasterBuffer = rb;
2719     type = None;
2720     txop = QTransform::TxNone;
2721     bilinear = false;
2722     m11 = m22 = m33 = 1.;
2723     m12 = m13 = m21 = m23 = dx = dy = 0.0;
2724     clip = pe ? pe->d_func()->clip() : 0;
2725 }
2726
2727 Q_GUI_EXPORT extern QImage qt_imageForBrush(int brushStyle);
2728
2729 void QSpanData::setup(const QBrush &brush, int alpha, QPainter::CompositionMode compositionMode)
2730 {
2731     Qt::BrushStyle brushStyle = brush.style();
2732     switch (brushStyle) {
2733         case Qt::SolidPattern: {
2734             type = Solid;
2735             const QColor c = brush.color();
2736             const QRgb rgba = c.rgba();
2737             solid.color = PREMUL(ARGB_COMBINE_ALPHA(rgba, alpha));
2738             if ((solid.color & 0xff000000) == 0
2739                 && compositionMode == QPainter::CompositionMode_SourceOver) {
2740                 type = None;
2741             }
2742             break;
2743         }
2744
2745         case Qt::LinearGradientPattern: {
2746             type = LinearGradient;
2747             const QLinearGradient *g = static_cast<const QLinearGradient *>(brush.gradient());
2748             gradient.alphaColor = !brush.isOpaque() || alpha != 256;
2749             gradient.generateGradientColorTable(*g, alpha);
2750             gradient.spread = g->spread();
2751
2752             QLinearGradientData &linearData = gradient.linear;
2753
2754             linearData.origin.x = g->start().x();
2755             linearData.origin.y = g->start().y();
2756             linearData.end.x = g->finalStop().x();
2757             linearData.end.y = g->finalStop().y();
2758             break;
2759         }
2760
2761         case Qt::RadialGradientPattern: {
2762             type = RadialGradient;
2763             const QRadialGradient *g = static_cast<const QRadialGradient *>(brush.gradient());
2764             gradient.alphaColor = !brush.isOpaque() || alpha != 256;
2765             gradient.generateGradientColorTable(*g, alpha);
2766             gradient.spread = g->spread();
2767
2768             QRadialGradientData &radialData = gradient.radial;
2769
2770             QPointF center = g->center();
2771             radialData.center.x = center.x();
2772             radialData.center.y = center.y();
2773             radialData.center.radius = g->centerRadius();
2774             QPointF focal = g->focalPoint();
2775             radialData.focal.x = focal.x();
2776             radialData.focal.y = focal.y();
2777             radialData.focal.radius = g->focalRadius();
2778             break;
2779         }
2780
2781         case Qt::Dense1Pattern:
2782         case Qt::Dense2Pattern:
2783         case Qt::Dense3Pattern:
2784         case Qt::Dense4Pattern:
2785         case Qt::Dense5Pattern:
2786         case Qt::Dense6Pattern:
2787         case Qt::Dense7Pattern:
2788         case Qt::HorPattern:
2789         case Qt::VerPattern:
2790         case Qt::CrossPattern:
2791         case Qt::BDiagPattern:
2792         case Qt::FDiagPattern:
2793         case Qt::DiagCrossPattern: {
2794             type = Texture;
2795             if (!tempImage)
2796                 tempImage = new QImage();
2797             *tempImage = rasterBuffer->colorizeBitmap(qt_imageForBrush(brushStyle), brush.color());
2798             initTexture(tempImage, alpha, QTextureData::Tiled);
2799             break;
2800         }
2801
2802         case Qt::TexturePattern: {
2803             type = Texture;
2804             if (!tempImage)
2805                 tempImage = new QImage();
2806
2807             if (qHasPixmapTexture(brush) && brush.texture().isQBitmap())
2808                 *tempImage = rasterBuffer->colorizeBitmap(brush.textureImage(), brush.color());
2809             else
2810                 *tempImage = brush.textureImage();
2811             initTexture(tempImage, alpha, QTextureData::Tiled, tempImage->rect());
2812             break;
2813         }
2814
2815         case Qt::NoBrush: {
2816             type = None;
2817             break;
2818         }
2819     }
2820     adjustSpanMethods();
2821 }
2822
2823 void QSpanData::adjustSpanMethods()
2824 {
2825     fillRect = 0;
2826
2827     switch(type) {
2828     case None:
2829         unclipped_blend = 0;
2830         break;
2831     case Solid:
2832         unclipped_blend = rasterBuffer->drawHelper->blendColor;
2833         fillRect = rasterBuffer->drawHelper->fillRect;
2834         break;
2835     case LinearGradient:
2836     case RadialGradient:
2837         unclipped_blend = rasterBuffer->drawHelper->blendGradient;
2838         break;
2839     case Texture:
2840         unclipped_blend = qBlendTexture;
2841         if (!texture.imageData)
2842             unclipped_blend = 0;
2843
2844         break;
2845     }
2846     // setup clipping
2847     if (!unclipped_blend) {
2848         blend = 0;
2849     } else if (!clip) {
2850         blend = unclipped_blend;
2851     } else if (clip->hasRectClip) {
2852         blend = clip->clipRect.isEmpty() ? 0 : qt_span_fill_clipRect;
2853     } else {
2854         blend = qt_span_fill_clipped;
2855     }
2856 }
2857
2858 void QSpanData::setupMatrix(const QTransform &matrix, bool bilin)
2859 {
2860     // make sure we round off correctly in qdrawhelper.cpp
2861     static const qreal delta = 1.0 / 65536;
2862     static const QTransform deltam = QTransform::fromTranslate(delta, delta);
2863
2864     QTransform inv = (deltam * matrix).inverted();
2865     m11 = inv.m11();
2866     m12 = inv.m12();
2867     m13 = inv.m13();
2868     m21 = inv.m21();
2869     m22 = inv.m22();
2870     m23 = inv.m23();
2871     m33 = inv.m33();
2872     dx = inv.dx();
2873     dy = inv.dy();
2874     txop = inv.type();
2875     bilinear = bilin;
2876
2877     adjustSpanMethods();
2878 }
2879
2880 void QSpanData::initTexture(const QImage *image, int alpha, QTextureData::Type _type, const QRect &sourceRect)
2881 {
2882     const QImageData *d = image->d;
2883     if (!d || d->height == 0) {
2884         texture.imageData = 0;
2885         texture.width = 0;
2886         texture.height = 0;
2887         texture.x1 = 0;
2888         texture.y1 = 0;
2889         texture.x2 = 0;
2890         texture.y2 = 0;
2891         texture.bytesPerLine = 0;
2892         texture.format = QImage::Format_Invalid;
2893         texture.mono0 = -1;
2894         texture.mono1 = -1;
2895         texture.hasAlpha = alpha != 256;
2896     } else {
2897         texture.imageData = d->data;
2898         texture.width = d->width;
2899         texture.height = d->height;
2900
2901         if (sourceRect.isNull()) {
2902             texture.x1 = 0;
2903             texture.y1 = 0;
2904             texture.x2 = texture.width;
2905             texture.y2 = texture.height;
2906         } else {
2907             texture.x1 = sourceRect.x();
2908             texture.y1 = sourceRect.y();
2909             texture.x2 = qMin(texture.x1 + sourceRect.width(), d->width);
2910             texture.y2 = qMin(texture.y1 + sourceRect.height(), d->height);
2911         }
2912
2913         texture.bytesPerLine = d->bytes_per_line;
2914
2915         texture.format = d->format;
2916         if (d->depth == 1) {
2917             texture.mono0 = d->mono0;
2918             texture.mono1 = d->mono1;
2919         } else {
2920             texture.mono0 = -1;
2921             texture.mono1 = -1;
2922         }
2923         texture.hasAlpha = image->hasAlphaChannel() || alpha != 256;
2924     }
2925     texture.const_alpha = alpha;
2926     texture.type = _type;
2927
2928     adjustSpanMethods();
2929 }
2930
2931 /*!
2932     \fn void QRasterPaintEngine::drawPoints(const QPoint *points, int pointCount)
2933     \overload
2934
2935     Draws the first \a pointCount points in the buffer \a points
2936
2937     The default implementation converts the first \a pointCount QPoints in \a points
2938     to QPointFs and calls the floating point version of drawPoints.
2939 */
2940
2941 /*!
2942     \fn void QRasterPaintEngine::drawEllipse(const QRect &rect)
2943     \overload
2944
2945     Reimplement this function to draw the largest ellipse that can be
2946     contained within rectangle \a rect.
2947 */
2948
2949 #ifdef QT_DEBUG_DRAW
2950 void dumpClip(int width, int height, const QClipData *clip)
2951 {
2952     QImage clipImg(width, height, QImage::Format_ARGB32_Premultiplied);
2953     clipImg.fill(0xffff0000);
2954
2955     int x0 = width;
2956     int x1 = 0;
2957     int y0 = height;
2958     int y1 = 0;
2959
2960     ((QClipData *) clip)->spans(); // Force allocation of the spans structure...
2961
2962     for (int i = 0; i < clip->count; ++i) {
2963         const QSpan *span = ((QClipData *) clip)->spans() + i;
2964         for (int j = 0; j < span->len; ++j)
2965             clipImg.setPixel(span->x + j, span->y, 0xffffff00);
2966         x0 = qMin(x0, int(span->x));
2967         x1 = qMax(x1, int(span->x + span->len - 1));
2968
2969         y0 = qMin(y0, int(span->y));
2970         y1 = qMax(y1, int(span->y));
2971     }
2972
2973     static int counter = 0;
2974
2975     Q_ASSERT(y0 >= 0);
2976     Q_ASSERT(x0 >= 0);
2977     Q_ASSERT(y1 >= 0);
2978     Q_ASSERT(x1 >= 0);
2979
2980     fprintf(stderr,"clip %d: %d %d - %d %d\n", counter, x0, y0, x1, y1);
2981     clipImg.save(QString::fromLatin1("clip-%0.png").arg(counter++));
2982 }
2983 #endif
2984
2985
2986 QT_END_NAMESPACE
2987
2988
2989
2990
2991