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