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