Make QPoint have the same layout on all platforms
[profile/ivi/qtbase.git] / src / gui / painting / qpaintengineex.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
6 **
7 ** This file is part of the QtGui module of the Qt Toolkit.
8 **
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 **
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 **
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
29 **
30 ** Other Usage
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qpaintengineex_p.h"
43 #include "qpainter_p.h"
44 #include "qstroker_p.h"
45 #include "qbezier_p.h"
46 #include <private/qpainterpath_p.h>
47 #include <private/qfontengine_p.h>
48 #include <private/qstatictext_p.h>
49
50 #include <qvarlengtharray.h>
51 #include <qdebug.h>
52
53
54 QT_BEGIN_NAMESPACE
55
56 /*******************************************************************************
57  *
58  * class QVectorPath
59  *
60  */
61 QVectorPath::~QVectorPath()
62 {
63     if (m_hints & ShouldUseCacheHint) {
64         CacheEntry *e = m_cache;
65         while (e) {
66             if (e->data)
67                 e->cleanup(e->engine, e->data);
68             CacheEntry *n = e->next;
69             delete e;
70             e = n;
71         }
72     }
73 }
74
75
76 QRectF QVectorPath::controlPointRect() const
77 {
78     if (m_hints & ControlPointRect)
79         return QRectF(QPointF(m_cp_rect.x1, m_cp_rect.y1), QPointF(m_cp_rect.x2, m_cp_rect.y2));
80
81     if (m_count == 0) {
82         m_cp_rect.x1 = m_cp_rect.x2 = m_cp_rect.y1 = m_cp_rect.y2 = 0;
83         m_hints |= ControlPointRect;
84         return QRectF(QPointF(m_cp_rect.x1, m_cp_rect.y1), QPointF(m_cp_rect.x2, m_cp_rect.y2));
85     }
86     Q_ASSERT(m_points && m_count > 0);
87
88     const qreal *pts = m_points;
89     m_cp_rect.x1 = m_cp_rect.x2 = *pts;
90     ++pts;
91     m_cp_rect.y1 = m_cp_rect.y2 = *pts;
92     ++pts;
93
94     const qreal *epts = m_points + (m_count << 1);
95     while (pts < epts) {
96         qreal x = *pts;
97         if (x < m_cp_rect.x1) m_cp_rect.x1 = x;
98         else if (x > m_cp_rect.x2) m_cp_rect.x2 = x;
99         ++pts;
100
101         qreal y = *pts;
102         if (y < m_cp_rect.y1) m_cp_rect.y1 = y;
103         else if (y > m_cp_rect.y2) m_cp_rect.y2 = y;
104         ++pts;
105     }
106
107     m_hints |= ControlPointRect;
108     return QRectF(QPointF(m_cp_rect.x1, m_cp_rect.y1), QPointF(m_cp_rect.x2, m_cp_rect.y2));
109 }
110
111
112 QVectorPath::CacheEntry *QVectorPath::addCacheData(QPaintEngineEx *engine, void *data,
113                                                    qvectorpath_cache_cleanup cleanup) const{
114     Q_ASSERT(!lookupCacheData(engine));
115     if ((m_hints & IsCachedHint) == 0) {
116         m_cache = 0;
117         m_hints |= IsCachedHint;
118     }
119     CacheEntry *e = new CacheEntry;
120     e->engine = engine;
121     e->data = data;
122     e->cleanup = cleanup;
123     e->next = m_cache;
124     m_cache = e;
125     return m_cache;
126 }
127
128
129 const QVectorPath &qtVectorPathForPath(const QPainterPath &path)
130 {
131     Q_ASSERT(path.d_func());
132     return path.d_func()->vectorPath();
133 }
134
135 #ifndef QT_NO_DEBUG_STREAM
136 QDebug Q_GUI_EXPORT &operator<<(QDebug &s, const QVectorPath &path)
137 {
138     QRectF rf = path.controlPointRect();
139     s << "QVectorPath(size:" << path.elementCount()
140       << " hints:" << hex << path.hints()
141       << rf << ')';
142     return s;
143 }
144 #endif
145
146 /*******************************************************************************
147  *
148  * class QPaintEngineExPrivate:
149  *
150  */
151
152
153 struct StrokeHandler {
154     StrokeHandler(int reserve) : pts(reserve), types(reserve) {}
155     QDataBuffer<qreal> pts;
156     QDataBuffer<QPainterPath::ElementType> types;
157 };
158
159
160 QPaintEngineExPrivate::QPaintEngineExPrivate()
161     : dasher(&stroker),
162       strokeHandler(0),
163       activeStroker(0),
164       strokerPen(Qt::NoPen)
165 {
166 }
167
168
169 QPaintEngineExPrivate::~QPaintEngineExPrivate()
170 {
171     delete strokeHandler;
172 }
173
174
175 void QPaintEngineExPrivate::replayClipOperations()
176 {
177     Q_Q(QPaintEngineEx);
178
179     QPainter *p = q->painter();
180     if (!p || !p->d_ptr)
181         return;
182
183     QList<QPainterClipInfo> clipInfo = p->d_ptr->state->clipInfo;
184
185     QTransform transform = q->state()->matrix;
186
187     for (int i = 0; i <  clipInfo.size(); ++i) {
188         const QPainterClipInfo &info = clipInfo.at(i);
189
190         if (info.matrix != q->state()->matrix) {
191             q->state()->matrix = info.matrix;
192             q->transformChanged();
193         }
194
195         switch (info.clipType) {
196         case QPainterClipInfo::RegionClip:
197             q->clip(info.region, info.operation);
198             break;
199         case QPainterClipInfo::PathClip:
200             q->clip(info.path, info.operation);
201             break;
202         case QPainterClipInfo::RectClip:
203             q->clip(info.rect, info.operation);
204             break;
205         case QPainterClipInfo::RectFClip: {
206             qreal right = info.rectf.x() + info.rectf.width();
207             qreal bottom = info.rectf.y() + info.rectf.height();
208             qreal pts[] = { info.rectf.x(), info.rectf.y(),
209                             right, info.rectf.y(),
210                             right, bottom,
211                             info.rectf.x(), bottom };
212             QVectorPath vp(pts, 4, 0, QVectorPath::RectangleHint);
213             q->clip(vp, info.operation);
214             break;
215             }
216         }
217     }
218
219     if (transform != q->state()->matrix) {
220         q->state()->matrix = transform;
221         q->transformChanged();
222     }
223 }
224
225
226 bool QPaintEngineExPrivate::hasClipOperations() const
227 {
228     Q_Q(const QPaintEngineEx);
229
230     QPainter *p = q->painter();
231     if (!p || !p->d_ptr)
232         return false;
233
234     QList<QPainterClipInfo> clipInfo = p->d_ptr->state->clipInfo;
235
236     return !clipInfo.isEmpty();
237 }
238
239 /*******************************************************************************
240  *
241  * class QPaintEngineEx:
242  *
243  */
244
245 static QPainterPath::ElementType qpaintengineex_ellipse_types[] = {
246     QPainterPath::MoveToElement,
247     QPainterPath::CurveToElement,
248     QPainterPath::CurveToDataElement,
249     QPainterPath::CurveToDataElement,
250
251     QPainterPath::CurveToElement,
252     QPainterPath::CurveToDataElement,
253     QPainterPath::CurveToDataElement,
254
255     QPainterPath::CurveToElement,
256     QPainterPath::CurveToDataElement,
257     QPainterPath::CurveToDataElement,
258
259     QPainterPath::CurveToElement,
260     QPainterPath::CurveToDataElement,
261     QPainterPath::CurveToDataElement
262 };
263
264 static QPainterPath::ElementType qpaintengineex_line_types_16[] = {
265     QPainterPath::MoveToElement, QPainterPath::LineToElement,
266     QPainterPath::MoveToElement, QPainterPath::LineToElement,
267     QPainterPath::MoveToElement, QPainterPath::LineToElement,
268     QPainterPath::MoveToElement, QPainterPath::LineToElement,
269     QPainterPath::MoveToElement, QPainterPath::LineToElement,
270     QPainterPath::MoveToElement, QPainterPath::LineToElement,
271     QPainterPath::MoveToElement, QPainterPath::LineToElement,
272     QPainterPath::MoveToElement, QPainterPath::LineToElement,
273     QPainterPath::MoveToElement, QPainterPath::LineToElement,
274     QPainterPath::MoveToElement, QPainterPath::LineToElement,
275     QPainterPath::MoveToElement, QPainterPath::LineToElement,
276     QPainterPath::MoveToElement, QPainterPath::LineToElement,
277     QPainterPath::MoveToElement, QPainterPath::LineToElement,
278     QPainterPath::MoveToElement, QPainterPath::LineToElement,
279     QPainterPath::MoveToElement, QPainterPath::LineToElement,
280     QPainterPath::MoveToElement, QPainterPath::LineToElement
281 };
282
283 static QPainterPath::ElementType qpaintengineex_rect4_types_32[] = {
284     QPainterPath::MoveToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, // 1
285     QPainterPath::MoveToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, // 2
286     QPainterPath::MoveToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, // 3
287     QPainterPath::MoveToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, // 4
288     QPainterPath::MoveToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, // 5
289     QPainterPath::MoveToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, // 6
290     QPainterPath::MoveToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, // 7
291     QPainterPath::MoveToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, // 8
292     QPainterPath::MoveToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, // 9
293     QPainterPath::MoveToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, // 10
294     QPainterPath::MoveToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, // 11
295     QPainterPath::MoveToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, // 12
296     QPainterPath::MoveToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, // 13
297     QPainterPath::MoveToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, // 14
298     QPainterPath::MoveToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, // 15
299     QPainterPath::MoveToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, // 16
300     QPainterPath::MoveToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, // 17
301     QPainterPath::MoveToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, // 18
302     QPainterPath::MoveToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, // 19
303     QPainterPath::MoveToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, // 20
304     QPainterPath::MoveToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, // 21
305     QPainterPath::MoveToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, // 22
306     QPainterPath::MoveToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, // 23
307     QPainterPath::MoveToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, // 24
308     QPainterPath::MoveToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, // 25
309     QPainterPath::MoveToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, // 26
310     QPainterPath::MoveToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, // 27
311     QPainterPath::MoveToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, // 28
312     QPainterPath::MoveToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, // 29
313     QPainterPath::MoveToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, // 30
314     QPainterPath::MoveToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, // 31
315     QPainterPath::MoveToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, // 32
316 };
317
318
319 static QPainterPath::ElementType qpaintengineex_roundedrect_types[] = {
320     QPainterPath::MoveToElement,
321     QPainterPath::LineToElement,
322     QPainterPath::CurveToElement,
323     QPainterPath::CurveToDataElement,
324     QPainterPath::CurveToDataElement,
325     QPainterPath::LineToElement,
326     QPainterPath::CurveToElement,
327     QPainterPath::CurveToDataElement,
328     QPainterPath::CurveToDataElement,
329     QPainterPath::LineToElement,
330     QPainterPath::CurveToElement,
331     QPainterPath::CurveToDataElement,
332     QPainterPath::CurveToDataElement,
333     QPainterPath::LineToElement,
334     QPainterPath::CurveToElement,
335     QPainterPath::CurveToDataElement,
336     QPainterPath::CurveToDataElement
337 };
338
339
340
341 static void qpaintengineex_moveTo(qreal x, qreal y, void *data) {
342     ((StrokeHandler *) data)->pts.add(x);
343     ((StrokeHandler *) data)->pts.add(y);
344     ((StrokeHandler *) data)->types.add(QPainterPath::MoveToElement);
345 }
346
347 static void qpaintengineex_lineTo(qreal x, qreal y, void *data) {
348     ((StrokeHandler *) data)->pts.add(x);
349     ((StrokeHandler *) data)->pts.add(y);
350     ((StrokeHandler *) data)->types.add(QPainterPath::LineToElement);
351 }
352
353 static void qpaintengineex_cubicTo(qreal c1x, qreal c1y, qreal c2x, qreal c2y, qreal ex, qreal ey, void *data) {
354     ((StrokeHandler *) data)->pts.add(c1x);
355     ((StrokeHandler *) data)->pts.add(c1y);
356     ((StrokeHandler *) data)->types.add(QPainterPath::CurveToElement);
357
358     ((StrokeHandler *) data)->pts.add(c2x);
359     ((StrokeHandler *) data)->pts.add(c2y);
360     ((StrokeHandler *) data)->types.add(QPainterPath::CurveToDataElement);
361
362     ((StrokeHandler *) data)->pts.add(ex);
363     ((StrokeHandler *) data)->pts.add(ey);
364     ((StrokeHandler *) data)->types.add(QPainterPath::CurveToDataElement);
365 }
366
367 QPaintEngineEx::QPaintEngineEx()
368     : QPaintEngine(*new QPaintEngineExPrivate, AllFeatures)
369 {
370     extended = true;
371 }
372
373 QPaintEngineEx::QPaintEngineEx(QPaintEngineExPrivate &data)
374     : QPaintEngine(data, AllFeatures)
375 {
376     extended = true;
377 }
378
379 QPainterState *QPaintEngineEx::createState(QPainterState *orig) const
380 {
381     if (!orig)
382         return new QPainterState;
383     return new QPainterState(orig);
384 }
385
386 Q_GUI_EXPORT extern bool qt_scaleForTransform(const QTransform &transform, qreal *scale); // qtransform.cpp
387
388 void QPaintEngineEx::stroke(const QVectorPath &path, const QPen &pen)
389 {
390 #ifdef QT_DEBUG_DRAW
391     qDebug() << "QPaintEngineEx::stroke()" << pen;
392 #endif
393
394     Q_D(QPaintEngineEx);
395
396     if (path.isEmpty())
397         return;
398
399     if (!d->strokeHandler) {
400         d->strokeHandler = new StrokeHandler(path.elementCount()+4);
401         d->stroker.setMoveToHook(qpaintengineex_moveTo);
402         d->stroker.setLineToHook(qpaintengineex_lineTo);
403         d->stroker.setCubicToHook(qpaintengineex_cubicTo);
404     }
405
406     if (!qpen_fast_equals(pen, d->strokerPen)) {
407         d->strokerPen = pen;
408         d->stroker.setJoinStyle(pen.joinStyle());
409         d->stroker.setCapStyle(pen.capStyle());
410         d->stroker.setMiterLimit(pen.miterLimit());
411         qreal penWidth = pen.widthF();
412         if (penWidth == 0)
413             d->stroker.setStrokeWidth(1);
414         else
415             d->stroker.setStrokeWidth(penWidth);
416
417         Qt::PenStyle style = pen.style();
418         if (style == Qt::SolidLine) {
419             d->activeStroker = &d->stroker;
420         } else if (style == Qt::NoPen) {
421             d->activeStroker = 0;
422         } else {
423             d->dasher.setDashPattern(pen.dashPattern());
424             d->dasher.setDashOffset(pen.dashOffset());
425             d->activeStroker = &d->dasher;
426         }
427     }
428
429     if (!d->activeStroker) {
430         return;
431     }
432
433     if (pen.style() > Qt::SolidLine) {
434         if (pen.isCosmetic()) {
435             d->activeStroker->setClipRect(d->exDeviceRect);
436         } else {
437             QRectF clipRect = state()->matrix.inverted().mapRect(QRectF(d->exDeviceRect));
438             d->activeStroker->setClipRect(clipRect);
439         }
440     }
441
442     const QPainterPath::ElementType *types = path.elements();
443     const qreal *points = path.points();
444     int pointCount = path.elementCount();
445
446     const qreal *lastPoint = points + (pointCount<<1);
447
448     d->strokeHandler->types.reset();
449     d->strokeHandler->pts.reset();
450
451     // Some engines might decide to optimize for the non-shape hint later on...
452     uint flags = QVectorPath::WindingFill;
453
454     if (path.elementCount() > 2)
455         flags |= QVectorPath::NonConvexShapeMask;
456
457     if (d->stroker.capStyle() == Qt::RoundCap || d->stroker.joinStyle() == Qt::RoundJoin)
458         flags |= QVectorPath::CurvedShapeMask;
459
460     // ### Perspective Xforms are currently not supported...
461     if (!pen.isCosmetic()) {
462         // We include cosmetic pens in this case to avoid having to
463         // change the current transform. Normal transformed,
464         // non-cosmetic pens will be transformed as part of fill
465         // later, so they are also covered here..
466         d->activeStroker->setCurveThresholdFromTransform(state()->matrix);
467         d->activeStroker->begin(d->strokeHandler);
468         if (types) {
469             while (points < lastPoint) {
470                 switch (*types) {
471                 case QPainterPath::MoveToElement:
472                     d->activeStroker->moveTo(points[0], points[1]);
473                     points += 2;
474                     ++types;
475                     break;
476                 case QPainterPath::LineToElement:
477                     d->activeStroker->lineTo(points[0], points[1]);
478                     points += 2;
479                     ++types;
480                     break;
481                 case QPainterPath::CurveToElement:
482                     d->activeStroker->cubicTo(points[0], points[1],
483                                               points[2], points[3],
484                                               points[4], points[5]);
485                     points += 6;
486                     types += 3;
487                     flags |= QVectorPath::CurvedShapeMask;
488                     break;
489                 default:
490                     break;
491                 }
492             }
493             if (path.hasImplicitClose())
494                 d->activeStroker->lineTo(path.points()[0], path.points()[1]);
495
496         } else {
497             d->activeStroker->moveTo(points[0], points[1]);
498             points += 2;
499             while (points < lastPoint) {
500                 d->activeStroker->lineTo(points[0], points[1]);
501                 points += 2;
502             }
503             if (path.hasImplicitClose())
504                 d->activeStroker->lineTo(path.points()[0], path.points()[1]);
505         }
506         d->activeStroker->end();
507
508         if (!d->strokeHandler->types.size()) // an empty path...
509             return;
510
511         QVectorPath strokePath(d->strokeHandler->pts.data(),
512                                d->strokeHandler->types.size(),
513                                d->strokeHandler->types.data(),
514                                flags);
515         fill(strokePath, pen.brush());
516     } else {
517         // For cosmetic pens we need a bit of trickery... We to process xform the input points
518         if (state()->matrix.type() >= QTransform::TxProject) {
519             QPainterPath painterPath = state()->matrix.map(path.convertToPainterPath());
520             d->activeStroker->strokePath(painterPath, d->strokeHandler, QTransform());
521         } else {
522             d->activeStroker->setCurveThresholdFromTransform(QTransform());
523             d->activeStroker->begin(d->strokeHandler);
524             if (types) {
525                 while (points < lastPoint) {
526                     switch (*types) {
527                     case QPainterPath::MoveToElement: {
528                         QPointF pt = (*(QPointF *) points) * state()->matrix;
529                         d->activeStroker->moveTo(pt.x(), pt.y());
530                         points += 2;
531                         ++types;
532                         break;
533                     }
534                     case QPainterPath::LineToElement: {
535                         QPointF pt = (*(QPointF *) points) * state()->matrix;
536                         d->activeStroker->lineTo(pt.x(), pt.y());
537                         points += 2;
538                         ++types;
539                         break;
540                     }
541                     case QPainterPath::CurveToElement: {
542                         QPointF c1 = ((QPointF *) points)[0] * state()->matrix;
543                         QPointF c2 = ((QPointF *) points)[1] * state()->matrix;
544                         QPointF e =  ((QPointF *) points)[2] * state()->matrix;
545                         d->activeStroker->cubicTo(c1.x(), c1.y(), c2.x(), c2.y(), e.x(), e.y());
546                         points += 6;
547                         types += 3;
548                         flags |= QVectorPath::CurvedShapeMask;
549                         break;
550                     }
551                     default:
552                         break;
553                     }
554                 }
555                 if (path.hasImplicitClose()) {
556                     QPointF pt = * ((QPointF *) path.points()) * state()->matrix;
557                     d->activeStroker->lineTo(pt.x(), pt.y());
558                 }
559
560             } else {
561                 QPointF p = ((QPointF *)points)[0] * state()->matrix;
562                 d->activeStroker->moveTo(p.x(), p.y());
563                 points += 2;
564                 while (points < lastPoint) {
565                     QPointF p = ((QPointF *)points)[0] * state()->matrix;
566                     d->activeStroker->lineTo(p.x(), p.y());
567                     points += 2;
568                 }
569                 if (path.hasImplicitClose())
570                     d->activeStroker->lineTo(p.x(), p.y());
571             }
572             d->activeStroker->end();
573         }
574
575         QVectorPath strokePath(d->strokeHandler->pts.data(),
576                                d->strokeHandler->types.size(),
577                                d->strokeHandler->types.data(),
578                                flags);
579
580         QTransform xform = state()->matrix;
581         state()->matrix = QTransform();
582         transformChanged();
583
584         QBrush brush = pen.brush();
585         if (qbrush_style(brush) != Qt::SolidPattern)
586             brush.setTransform(brush.transform() * xform);
587
588         fill(strokePath, brush);
589
590         state()->matrix = xform;
591         transformChanged();
592     }
593 }
594
595 void QPaintEngineEx::draw(const QVectorPath &path)
596 {
597     const QBrush &brush = state()->brush;
598     if (qbrush_style(brush) != Qt::NoBrush)
599         fill(path, brush);
600
601     const QPen &pen = state()->pen;
602     if (qpen_style(pen) != Qt::NoPen && qbrush_style(qpen_brush(pen)) != Qt::NoBrush)
603         stroke(path, pen);
604 }
605
606
607 void QPaintEngineEx::clip(const QRect &r, Qt::ClipOperation op)
608 {
609     qreal right = r.x() + r.width();
610     qreal bottom = r.y() + r.height();
611     qreal pts[] = { qreal(r.x()), qreal(r.y()),
612                     right, qreal(r.y()),
613                     right, bottom,
614                     qreal(r.x()), bottom,
615                     qreal(r.x()), qreal(r.y()) };
616     QVectorPath vp(pts, 5, 0, QVectorPath::RectangleHint);
617     clip(vp, op);
618 }
619
620 void QPaintEngineEx::clip(const QRegion &region, Qt::ClipOperation op)
621 {
622     if (region.rectCount() == 1)
623         clip(region.boundingRect(), op);
624
625     QVector<QRect> rects = region.rects();
626     if (rects.size() <= 32) {
627         qreal pts[2*32*4];
628         int pos = 0;
629         for (QVector<QRect>::const_iterator i = rects.constBegin(); i != rects.constEnd(); ++i) {
630             qreal x1 = i->x();
631             qreal y1 = i->y();
632             qreal x2 = i->x() + i->width();
633             qreal y2 = i->y() + i->height();
634
635             pts[pos++] = x1;
636             pts[pos++] = y1;
637
638             pts[pos++] = x2;
639             pts[pos++] = y1;
640
641             pts[pos++] = x2;
642             pts[pos++] = y2;
643
644             pts[pos++] = x1;
645             pts[pos++] = y2;
646         }
647         QVectorPath vp(pts, rects.size() * 4, qpaintengineex_rect4_types_32);
648         clip(vp, op);
649     } else {
650         QVarLengthArray<qreal> pts(rects.size() * 2 * 4);
651         QVarLengthArray<QPainterPath::ElementType> types(rects.size() * 4);
652         int ppos = 0;
653         int tpos = 0;
654
655         for (QVector<QRect>::const_iterator i = rects.constBegin(); i != rects.constEnd(); ++i) {
656             qreal x1 = i->x();
657             qreal y1 = i->y();
658             qreal x2 = i->x() + i->width();
659             qreal y2 = i->y() + i->height();
660
661             pts[ppos++] = x1;
662             pts[ppos++] = y1;
663
664             pts[ppos++] = x2;
665             pts[ppos++] = y1;
666
667             pts[ppos++] = x2;
668             pts[ppos++] = y2;
669
670             pts[ppos++] = x1;
671             pts[ppos++] = y2;
672
673             types[tpos++] = QPainterPath::MoveToElement;
674             types[tpos++] = QPainterPath::LineToElement;
675             types[tpos++] = QPainterPath::LineToElement;
676             types[tpos++] = QPainterPath::LineToElement;
677         }
678
679         QVectorPath vp(pts.data(), rects.size() * 4, types.data());
680         clip(vp, op);
681     }
682
683 }
684
685 void QPaintEngineEx::clip(const QPainterPath &path, Qt::ClipOperation op)
686 {
687     if (path.isEmpty()) {
688         QVectorPath vp(0, 0);
689         clip(vp, op);
690     } else {
691         clip(qtVectorPathForPath(path), op);
692     }
693 }
694
695 void QPaintEngineEx::fillRect(const QRectF &r, const QBrush &brush)
696 {
697     qreal pts[] = { r.x(), r.y(), r.x() + r.width(), r.y(),
698                     r.x() + r.width(), r.y() + r.height(), r.x(), r.y() + r.height() };
699     QVectorPath vp(pts, 4, 0, QVectorPath::RectangleHint);
700     fill(vp, brush);
701 }
702
703 void QPaintEngineEx::fillRect(const QRectF &r, const QColor &color)
704 {
705     fillRect(r, QBrush(color));
706 }
707
708 void QPaintEngineEx::drawRects(const QRect *rects, int rectCount)
709 {
710     for (int i=0; i<rectCount; ++i) {
711         const QRect &r = rects[i];
712         // ### Is there a one off here?
713         qreal right = r.x() + r.width();
714         qreal bottom = r.y() + r.height();
715         qreal pts[] = { qreal(r.x()), qreal(r.y()),
716                         right, qreal(r.y()),
717                         right, bottom,
718                         qreal(r.x()), bottom,
719                         qreal(r.x()), qreal(r.y()) };
720         QVectorPath vp(pts, 5, 0, QVectorPath::RectangleHint);
721         draw(vp);
722     }
723 }
724
725 void QPaintEngineEx::drawRects(const QRectF *rects, int rectCount)
726 {
727     for (int i=0; i<rectCount; ++i) {
728         const QRectF &r = rects[i];
729         qreal right = r.x() + r.width();
730         qreal bottom = r.y() + r.height();
731         qreal pts[] = { r.x(), r.y(),
732                         right, r.y(),
733                         right, bottom,
734                         r.x(), bottom,
735                         r.x(), r.y() };
736         QVectorPath vp(pts, 5, 0, QVectorPath::RectangleHint);
737         draw(vp);
738     }
739 }
740
741
742 void QPaintEngineEx::drawRoundedRect(const QRectF &rect, qreal xRadius, qreal yRadius,
743                                      Qt::SizeMode mode)
744 {
745     qreal x1 = rect.left();
746     qreal x2 = rect.right();
747     qreal y1 = rect.top();
748     qreal y2 = rect.bottom();
749
750     if (mode == Qt::RelativeSize) {
751         xRadius = xRadius * rect.width() / 200.;
752         yRadius = yRadius * rect.height() / 200.;
753     }
754
755     xRadius = qMin(xRadius, rect.width() / 2);
756     yRadius = qMin(yRadius, rect.height() / 2);
757
758     qreal pts[] = {
759         x1 + xRadius, y1,                   // MoveTo
760         x2 - xRadius, y1,                   // LineTo
761         x2 - (1 - KAPPA) * xRadius, y1,     // CurveTo
762         x2, y1 + (1 - KAPPA) * yRadius,
763         x2, y1 + yRadius,
764         x2, y2 - yRadius,                   // LineTo
765         x2, y2 - (1 - KAPPA) * yRadius,     // CurveTo
766         x2 - (1 - KAPPA) * xRadius, y2,
767         x2 - xRadius, y2,
768         x1 + xRadius, y2,                   // LineTo
769         x1 + (1 - KAPPA) * xRadius, y2,           // CurveTo
770         x1, y2 - (1 - KAPPA) * yRadius,
771         x1, y2 - yRadius,
772         x1, y1 + yRadius,                   // LineTo
773         x1, y1 + (1 - KAPPA) * yRadius,           // CurveTo
774         x1 + (1 - KAPPA) * xRadius, y1,
775         x1 + xRadius, y1
776     };
777
778     QVectorPath path(pts, 17, qpaintengineex_roundedrect_types, QVectorPath::RoundedRectHint);
779     draw(path);
780 }
781
782
783
784 void QPaintEngineEx::drawLines(const QLine *lines, int lineCount)
785 {
786     int elementCount = lineCount << 1;
787     while (elementCount > 0) {
788         int count = qMin(elementCount, 32);
789
790         qreal pts[64];
791         int count2 = count<<1;
792         for (int i=0; i<count2; ++i)
793             pts[i] = ((int *) lines)[i];
794
795         QVectorPath path(pts, count, qpaintengineex_line_types_16, QVectorPath::LinesHint);
796         stroke(path, state()->pen);
797
798         elementCount -= 32;
799         lines += 16;
800     }
801 }
802
803 void QPaintEngineEx::drawLines(const QLineF *lines, int lineCount)
804 {
805     int elementCount = lineCount << 1;
806     while (elementCount > 0) {
807         int count = qMin(elementCount, 32);
808
809         QVectorPath path((qreal *) lines, count, qpaintengineex_line_types_16,
810                          QVectorPath::LinesHint);
811         stroke(path, state()->pen);
812
813         elementCount -= 32;
814         lines += 16;
815     }
816 }
817
818 void QPaintEngineEx::drawEllipse(const QRectF &r)
819 {
820     qreal pts[26]; // QPointF[13] without constructors...
821     union {
822         qreal *ptr;
823         QPointF *points;
824     } x;
825     x.ptr = pts;
826
827     int point_count = 0;
828     x.points[0] = qt_curves_for_arc(r, 0, -360, x.points + 1, &point_count);
829     QVectorPath vp((qreal *) pts, point_count + 1, qpaintengineex_ellipse_types, QVectorPath::EllipseHint);
830     draw(vp);
831 }
832
833 void QPaintEngineEx::drawEllipse(const QRect &r)
834 {
835     drawEllipse(QRectF(r));
836 }
837
838 void QPaintEngineEx::drawPath(const QPainterPath &path)
839 {
840     if (!path.isEmpty())
841         draw(qtVectorPathForPath(path));
842 }
843
844
845 void QPaintEngineEx::drawPoints(const QPointF *points, int pointCount)
846 {
847     QPen pen = state()->pen;
848     if (pen.capStyle() == Qt::FlatCap)
849         pen.setCapStyle(Qt::SquareCap);
850
851     if (pen.brush().isOpaque()) {
852         while (pointCount > 0) {
853             int count = qMin(pointCount, 16);
854             qreal pts[64];
855             int oset = -1;
856             for (int i=0; i<count; ++i) {
857                 pts[++oset] = points[i].x();
858                 pts[++oset] = points[i].y();
859                 pts[++oset] = points[i].x() + 1/63.;
860                 pts[++oset] = points[i].y();
861             }
862             QVectorPath path(pts, count * 2, qpaintengineex_line_types_16, QVectorPath::LinesHint);
863             stroke(path, pen);
864             pointCount -= 16;
865             points += 16;
866         }
867     } else {
868         for (int i=0; i<pointCount; ++i) {
869             qreal pts[] = { points[i].x(), points[i].y(), points[i].x() + 1/63., points[i].y() };
870             QVectorPath path(pts, 2, 0);
871             stroke(path, pen);
872         }
873     }
874 }
875
876 void QPaintEngineEx::drawPoints(const QPoint *points, int pointCount)
877 {
878     QPen pen = state()->pen;
879     if (pen.capStyle() == Qt::FlatCap)
880         pen.setCapStyle(Qt::SquareCap);
881
882     if (pen.brush().isOpaque()) {
883         while (pointCount > 0) {
884             int count = qMin(pointCount, 16);
885             qreal pts[64];
886             int oset = -1;
887             for (int i=0; i<count; ++i) {
888                 pts[++oset] = points[i].x();
889                 pts[++oset] = points[i].y();
890                 pts[++oset] = points[i].x() + 1/63.;
891                 pts[++oset] = points[i].y();
892             }
893             QVectorPath path(pts, count * 2, qpaintengineex_line_types_16, QVectorPath::LinesHint);
894             stroke(path, pen);
895             pointCount -= 16;
896             points += 16;
897         }
898     } else {
899         for (int i=0; i<pointCount; ++i) {
900             qreal pts[] = { qreal(points[i].x()), qreal(points[i].y()),
901                             qreal(points[i].x() +1/63.), qreal(points[i].y()) };
902             QVectorPath path(pts, 2, 0);
903             stroke(path, pen);
904         }
905     }
906 }
907
908
909 void QPaintEngineEx::drawPolygon(const QPointF *points, int pointCount, PolygonDrawMode mode)
910 {
911     QVectorPath path((qreal *) points, pointCount, 0, QVectorPath::polygonFlags(mode));
912
913     if (mode == PolylineMode)
914         stroke(path, state()->pen);
915     else
916         draw(path);
917 }
918
919 void QPaintEngineEx::drawPolygon(const QPoint *points, int pointCount, PolygonDrawMode mode)
920 {
921     int count = pointCount<<1;
922     QVarLengthArray<qreal> pts(count);
923
924 #ifdef Q_WS_MAC
925     for (int i=0; i<count; i+=2) {
926         pts[i] = ((int *) points)[i+1];
927         pts[i+1] = ((int *) points)[i];
928     }
929 #else
930     for (int i=0; i<count; ++i)
931         pts[i] = ((int *) points)[i];
932 #endif
933
934     QVectorPath path(pts.data(), pointCount, 0, QVectorPath::polygonFlags(mode));
935
936     if (mode == PolylineMode)
937         stroke(path, state()->pen);
938     else
939         draw(path);
940
941 }
942
943 void QPaintEngineEx::drawPixmap(const QPointF &pos, const QPixmap &pm)
944 {
945     drawPixmap(QRectF(pos, pm.size()), pm, pm.rect());
946 }
947
948 void QPaintEngineEx::drawImage(const QPointF &pos, const QImage &image)
949 {
950     drawImage(QRectF(pos, image.size()), image, image.rect());
951 }
952
953 void QPaintEngineEx::drawTiledPixmap(const QRectF &r, const QPixmap &pixmap, const QPointF &s)
954 {
955     QBrush brush(state()->pen.color(), pixmap);
956     QTransform xform = QTransform::fromTranslate(r.x() - s.x(), r.y() - s.y());
957     brush.setTransform(xform);
958
959     qreal pts[] = { r.x(), r.y(),
960                     r.x() + r.width(), r.y(),
961                     r.x() + r.width(), r.y() + r.height(),
962                     r.x(), r.y() + r.height() };
963
964     QVectorPath path(pts, 4, 0, QVectorPath::RectangleHint);
965     fill(path, brush);
966 }
967
968 void QPaintEngineEx::drawPixmapFragments(const QPainter::PixmapFragment *fragments, int fragmentCount,
969                                          const QPixmap &pixmap, QPainter::PixmapFragmentHints /*hints*/)
970 {
971     if (pixmap.isNull())
972         return;
973
974     qreal oldOpacity = state()->opacity;
975     QTransform oldTransform = state()->matrix;
976
977     for (int i = 0; i < fragmentCount; ++i) {
978         QTransform transform = oldTransform;
979         transform.translate(fragments[i].x, fragments[i].y);
980         transform.rotate(fragments[i].rotation);
981         state()->opacity = oldOpacity * fragments[i].opacity;
982         state()->matrix = transform;
983         opacityChanged();
984         transformChanged();
985
986         qreal w = fragments[i].scaleX * fragments[i].width;
987         qreal h = fragments[i].scaleY * fragments[i].height;
988         QRectF sourceRect(fragments[i].sourceLeft, fragments[i].sourceTop,
989                           fragments[i].width, fragments[i].height);
990         drawPixmap(QRectF(-0.5 * w, -0.5 * h, w, h), pixmap, sourceRect);
991     }
992
993     state()->opacity = oldOpacity;
994     state()->matrix = oldTransform;
995     opacityChanged();
996     transformChanged();
997 }
998
999 void QPaintEngineEx::setState(QPainterState *s)
1000 {
1001     QPaintEngine::state = s;
1002 }
1003
1004
1005 void QPaintEngineEx::updateState(const QPaintEngineState &)
1006 {
1007     // do nothing...
1008 }
1009
1010 Q_GUI_EXPORT QPainterPath qt_painterPathFromVectorPath(const QVectorPath &path)
1011 {
1012     const qreal *points = path.points();
1013     const QPainterPath::ElementType *types = path.elements();
1014
1015     QPainterPath p;
1016     if (types) {
1017         int id = 0;
1018         for (int i=0; i<path.elementCount(); ++i) {
1019             switch(types[i]) {
1020             case QPainterPath::MoveToElement:
1021                 p.moveTo(QPointF(points[id], points[id+1]));
1022                 id+=2;
1023                 break;
1024             case QPainterPath::LineToElement:
1025                 p.lineTo(QPointF(points[id], points[id+1]));
1026                 id+=2;
1027                 break;
1028             case QPainterPath::CurveToElement: {
1029                 QPointF p1(points[id], points[id+1]);
1030                 QPointF p2(points[id+2], points[id+3]);
1031                 QPointF p3(points[id+4], points[id+5]);
1032                 p.cubicTo(p1, p2, p3);
1033                 id+=6;
1034                 break;
1035             }
1036             case QPainterPath::CurveToDataElement:
1037                 ;
1038                 break;
1039             }
1040         }
1041     } else {
1042         p.moveTo(QPointF(points[0], points[1]));
1043         int id = 2;
1044         for (int i=1; i<path.elementCount(); ++i) {
1045             p.lineTo(QPointF(points[id], points[id+1]));
1046             id+=2;
1047         }
1048     }
1049     if (path.hints() & QVectorPath::WindingFill)
1050         p.setFillRule(Qt::WindingFill);
1051
1052     return p;
1053 }
1054
1055 void QPaintEngineEx::drawStaticTextItem(QStaticTextItem *staticTextItem)
1056 {
1057     QPainterPath path;
1058 #ifndef Q_WS_MAC
1059     path.setFillRule(Qt::WindingFill);
1060 #endif
1061
1062     if (staticTextItem->numGlyphs == 0)
1063         return;
1064
1065     QFontEngine *fontEngine = staticTextItem->fontEngine();
1066     fontEngine->addGlyphsToPath(staticTextItem->glyphs, staticTextItem->glyphPositions,
1067                                 staticTextItem->numGlyphs, &path, 0);
1068     if (!path.isEmpty()) {
1069         QPainterState *s = state();
1070         QPainter::RenderHints oldHints = s->renderHints;
1071         bool changedHints = false;
1072         if (bool(oldHints & QPainter::TextAntialiasing)
1073             && !bool(fontEngine->fontDef.styleStrategy & QFont::NoAntialias)
1074             && !bool(oldHints & QPainter::Antialiasing)) {
1075             s->renderHints |= QPainter::Antialiasing;
1076             renderHintsChanged();
1077             changedHints = true;
1078         }
1079
1080         fill(qtVectorPathForPath(path), s->pen.color());
1081
1082         if (changedHints) {
1083             s->renderHints = oldHints;
1084             renderHintsChanged();
1085         }
1086     }
1087 }
1088
1089 bool QPaintEngineEx::supportsTransformations(qreal pixelSize, const QTransform &m) const
1090 {
1091     Q_UNUSED(pixelSize);
1092
1093     if (!m.isAffine())
1094         return true;
1095
1096     return false;
1097 }
1098
1099 QT_END_NAMESPACE