src/openvg/qpaintengine_vg.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 QtOpenVG 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 "qpaintengine_vg_p.h"
       
    43 #include "qpixmapdata_vg_p.h"
       
    44 #include "qpixmapfilter_vg_p.h"
       
    45 #include "qvgcompositionhelper_p.h"
       
    46 #if !defined(QT_NO_EGL)
       
    47 #include <QtGui/private/qegl_p.h>
       
    48 #include "qwindowsurface_vgegl_p.h"
       
    49 #endif
       
    50 #include <QtCore/qvarlengtharray.h>
       
    51 #include <QtGui/private/qdrawhelper_p.h>
       
    52 #include <QtGui/private/qtextureglyphcache_p.h>
       
    53 #include <QtGui/private/qtextengine_p.h>
       
    54 #include <QtGui/private/qfontengine_p.h>
       
    55 #include <QtGui/private/qpainterpath_p.h>
       
    56 #include <QDebug>
       
    57 #include <QSet>
       
    58 
       
    59 QT_BEGIN_NAMESPACE
       
    60 
       
    61 // vgDrawGlyphs() only exists in OpenVG 1.1 and higher.
       
    62 #if !defined(OPENVG_VERSION_1_1) && !defined(QVG_NO_DRAW_GLYPHS)
       
    63 #define QVG_NO_DRAW_GLYPHS 1
       
    64 #endif
       
    65 
       
    66 // vgRenderToMask() only exists in OpenVG 1.1 and higher.
       
    67 // Also, disable masking completely if we are using the scissor to clip.
       
    68 #if !defined(OPENVG_VERSION_1_1) && !defined(QVG_NO_RENDER_TO_MASK)
       
    69 #define QVG_NO_RENDER_TO_MASK 1
       
    70 #endif
       
    71 #if defined(QVG_SCISSOR_CLIP) && !defined(QVG_NO_RENDER_TO_MASK)
       
    72 #define QVG_NO_RENDER_TO_MASK 1
       
    73 #endif
       
    74 
       
    75 #if !defined(QVG_NO_DRAW_GLYPHS)
       
    76 
       
    77 extern int qt_defaultDpiX();
       
    78 extern int qt_defaultDpiY();
       
    79 
       
    80 class QVGPaintEnginePrivate;
       
    81 
       
    82 class QVGFontGlyphCache
       
    83 {
       
    84 public:
       
    85     QVGFontGlyphCache();
       
    86     ~QVGFontGlyphCache();
       
    87 
       
    88     void cacheGlyphs(QVGPaintEnginePrivate *d,
       
    89                      const QTextItemInt &ti,
       
    90                      const QVarLengthArray<glyph_t> &glyphs);
       
    91     void setScaleFromText(const QTextItemInt &ti);
       
    92 
       
    93     VGFont font;
       
    94     VGfloat scaleX;
       
    95     VGfloat scaleY;
       
    96     
       
    97     uint cachedGlyphsMask[256 / 32];
       
    98     QSet<glyph_t> cachedGlyphs;
       
    99 };
       
   100 
       
   101 typedef QHash<QFontEngine*, QVGFontGlyphCache*> QVGFontCache;
       
   102 
       
   103 #endif
       
   104 
       
   105 class QVGFontEngineCleaner : public QObject
       
   106 {
       
   107     Q_OBJECT
       
   108 public:
       
   109     QVGFontEngineCleaner(QVGPaintEnginePrivate *d);
       
   110     ~QVGFontEngineCleaner();
       
   111 
       
   112 public slots:
       
   113     void fontEngineDestroyed();
       
   114 
       
   115 private:
       
   116     QVGPaintEnginePrivate *d_ptr;
       
   117 };
       
   118 
       
   119 class QVGPaintEnginePrivate : public QPaintEngineExPrivate
       
   120 {
       
   121 public:
       
   122     QVGPaintEnginePrivate();
       
   123     ~QVGPaintEnginePrivate();
       
   124 
       
   125     void init();
       
   126     void initObjects();
       
   127     void destroy();
       
   128     void setTransform(VGMatrixMode mode, const QTransform& transform);
       
   129     void updateTransform(QPaintDevice *pdev);
       
   130     void draw(VGPath path, const QPen& pen, const QBrush& brush, VGint rule = VG_EVEN_ODD);
       
   131     void stroke(VGPath path, const QPen& pen);
       
   132     void fill(VGPath path, const QBrush& brush, VGint rule = VG_EVEN_ODD);
       
   133     VGPath vectorPathToVGPath(const QVectorPath& path);
       
   134     VGPath painterPathToVGPath(const QPainterPath& path);
       
   135     VGPath roundedRectPath(const QRectF &rect, qreal xRadius, qreal yRadius, Qt::SizeMode mode);
       
   136     VGPaintType setBrush
       
   137         (VGPaint paint, const QBrush& brush, VGMatrixMode mode,
       
   138          VGPaintType prevPaintType);
       
   139     void setPenParams(const QPen& pen);
       
   140     void setBrushTransform(const QBrush& brush, VGMatrixMode mode);
       
   141     void setupColorRamp(const QGradient *grad, VGPaint paint);
       
   142     void setImageOptions();
       
   143 #if !defined(QVG_SCISSOR_CLIP)
       
   144     void ensureMask(QVGPaintEngine *engine, int width, int height);
       
   145     void modifyMask
       
   146         (QVGPaintEngine *engine, VGMaskOperation op, const QRegion& region);
       
   147     void modifyMask
       
   148         (QVGPaintEngine *engine, VGMaskOperation op, const QRect& rect);
       
   149 #endif
       
   150 
       
   151     VGint maxScissorRects;  // Maximum scissor rectangles for clipping.
       
   152 
       
   153     VGPaint penPaint;       // Paint for currently active pen.
       
   154     VGPaint brushPaint;     // Paint for currently active brush.
       
   155     VGPaint opacityPaint;   // Paint for drawing images with opacity.
       
   156     VGPaint fillPaint;      // Current fill paint that is active.
       
   157 
       
   158     QPen currentPen;        // Current pen set in "penPaint".
       
   159     QBrush currentBrush;    // Current brush set in "brushPaint".
       
   160 
       
   161     bool forcePenChange;    // Force a pen change, even if the same.
       
   162     bool forceBrushChange;  // Force a brush change, even if the same.
       
   163 
       
   164     VGPaintType penType;    // Type of the last pen that was set.
       
   165     VGPaintType brushType;  // Type of the last brush that was set.
       
   166 
       
   167     QPointF brushOrigin;    // Current brush origin.
       
   168 
       
   169     VGint fillRule;         // Last fill rule that was set.
       
   170 
       
   171     qreal opacity;          // Current drawing opacity.
       
   172     qreal paintOpacity;     // Opacity in opacityPaint.
       
   173 
       
   174 #if !defined(QVG_NO_MODIFY_PATH)
       
   175     VGPath rectPath;        // Cached path for quick drawing of rectangles.
       
   176     VGPath linePath;        // Cached path for quick drawing of lines.
       
   177     VGPath roundRectPath;   // Cached path for quick drawing of rounded rects.
       
   178 #endif
       
   179 
       
   180     QTransform transform;   // Currently active transform.
       
   181     bool simpleTransform;   // True if the transform is simple (non-projective).
       
   182     qreal penScale;         // Pen scaling factor from "transform".
       
   183 
       
   184     QTransform pathTransform;  // Calculated VG path transformation.
       
   185     QTransform imageTransform; // Calculated VG image transformation.
       
   186     bool pathTransformSet;  // True if path transform set in the VG context.
       
   187 
       
   188     bool maskValid;         // True if vgMask() contains valid data.
       
   189     bool maskIsSet;         // True if mask would be fully set if it was valid.
       
   190     bool rawVG;             // True if processing a raw VG escape.
       
   191 
       
   192     QRect maskRect;         // Rectangle version of mask if it is simple.
       
   193 
       
   194     QTransform penTransform;   // Transform for the pen.
       
   195     QTransform brushTransform; // Transform for the brush.
       
   196 
       
   197     VGMatrixMode matrixMode;    // Last matrix mode that was set.
       
   198     VGImageMode imageMode;      // Last image mode that was set.
       
   199 
       
   200     QRegion scissorRegion;  // Currently active scissor region.
       
   201     bool scissorActive;     // True if scissor region is active.
       
   202 
       
   203     QPaintEngine::DirtyFlags dirty;
       
   204 
       
   205     QColor clearColor;      // Last clear color that was set.
       
   206     VGfloat clearOpacity;   // Opacity during the last clear.
       
   207 
       
   208     VGBlendMode blendMode;  // Active blend mode.
       
   209     VGRenderingQuality renderingQuality; // Active rendering quality.
       
   210     VGImageQuality imageQuality;    // Active image quality.
       
   211 
       
   212 #if !defined(QVG_NO_DRAW_GLYPHS)
       
   213     QVGFontCache fontCache;
       
   214     QVGFontEngineCleaner *fontEngineCleaner;
       
   215 #endif
       
   216 
       
   217     QScopedPointer<QPixmapFilter> convolutionFilter;
       
   218     QScopedPointer<QPixmapFilter> colorizeFilter;
       
   219     QScopedPointer<QPixmapFilter> dropShadowFilter;
       
   220     QScopedPointer<QPixmapFilter> blurFilter;
       
   221 
       
   222     // Ensure that the path transform is properly set in the VG context
       
   223     // before we perform a vgDrawPath() operation.
       
   224     inline void ensurePathTransform()
       
   225     {
       
   226         if (!pathTransformSet) {
       
   227             setTransform(VG_MATRIX_PATH_USER_TO_SURFACE, pathTransform);
       
   228             pathTransformSet = true;
       
   229         }
       
   230     }
       
   231 
       
   232     // Ensure that a specific pen has been set into penPaint.
       
   233     inline void ensurePen(const QPen& pen) {
       
   234         if (forcePenChange || pen != currentPen) {
       
   235             currentPen = pen;
       
   236             forcePenChange = false;
       
   237             penType = setBrush
       
   238                 (penPaint, pen.brush(),
       
   239                  VG_MATRIX_STROKE_PAINT_TO_USER, penType);
       
   240             setPenParams(pen);
       
   241         }
       
   242     }
       
   243 
       
   244     // Ensure that a specific brush has been set into brushPaint.
       
   245     inline void ensureBrush(const QBrush& brush) {
       
   246         if (forceBrushChange || brush != currentBrush) {
       
   247             currentBrush = brush;
       
   248             forceBrushChange = false;
       
   249             brushType = setBrush
       
   250                 (brushPaint, brush, VG_MATRIX_FILL_PAINT_TO_USER, brushType);
       
   251         }
       
   252         if (fillPaint != brushPaint) {
       
   253             vgSetPaint(brushPaint, VG_FILL_PATH);
       
   254             fillPaint = brushPaint;
       
   255         }
       
   256     }
       
   257 
       
   258     // Set various modes, but only if different.
       
   259     inline void setImageMode(VGImageMode mode);
       
   260     inline void setRenderingQuality(VGRenderingQuality mode);
       
   261     inline void setImageQuality(VGImageQuality mode);
       
   262     inline void setBlendMode(VGBlendMode mode);
       
   263     inline void setFillRule(VGint mode);
       
   264 
       
   265     // Clear all lazily-set modes.
       
   266     void clearModes();
       
   267 };
       
   268 
       
   269 inline void QVGPaintEnginePrivate::setImageMode(VGImageMode mode)
       
   270 {
       
   271     if (imageMode != mode) {
       
   272         imageMode = mode;
       
   273         vgSeti(VG_IMAGE_MODE, mode);
       
   274     }
       
   275 }
       
   276 
       
   277 inline void QVGPaintEnginePrivate::setRenderingQuality(VGRenderingQuality mode)
       
   278 {
       
   279     if (renderingQuality != mode) {
       
   280         vgSeti(VG_RENDERING_QUALITY, mode);
       
   281         renderingQuality = mode;
       
   282     }
       
   283 }
       
   284 
       
   285 inline void QVGPaintEnginePrivate::setImageQuality(VGImageQuality mode)
       
   286 {
       
   287     if (imageQuality != mode) {
       
   288         vgSeti(VG_IMAGE_QUALITY, mode);
       
   289         imageQuality = mode;
       
   290     }
       
   291 }
       
   292 
       
   293 inline void QVGPaintEnginePrivate::setBlendMode(VGBlendMode mode)
       
   294 {
       
   295     if (blendMode != mode) {
       
   296         vgSeti(VG_BLEND_MODE, mode);
       
   297         blendMode = mode;
       
   298     }
       
   299 }
       
   300 
       
   301 inline void QVGPaintEnginePrivate::setFillRule(VGint mode)
       
   302 {
       
   303     if (fillRule != mode) {
       
   304         fillRule = mode;
       
   305         vgSeti(VG_FILL_RULE, mode);
       
   306     }
       
   307 }
       
   308 
       
   309 void QVGPaintEnginePrivate::clearModes()
       
   310 {
       
   311     matrixMode = (VGMatrixMode)0;
       
   312     imageMode = (VGImageMode)0;
       
   313     blendMode = (VGBlendMode)0;
       
   314     renderingQuality = (VGRenderingQuality)0;
       
   315     imageQuality = (VGImageQuality)0;
       
   316 }
       
   317 
       
   318 QVGPaintEnginePrivate::QVGPaintEnginePrivate()
       
   319 {
       
   320     init();
       
   321 }
       
   322 
       
   323 void QVGPaintEnginePrivate::init()
       
   324 {
       
   325     maxScissorRects = 0;
       
   326 
       
   327     penPaint = 0;
       
   328     brushPaint = 0;
       
   329     opacityPaint = 0;
       
   330     fillPaint = 0;
       
   331 
       
   332     forcePenChange = true;
       
   333     forceBrushChange = true;
       
   334     penType = (VGPaintType)0;
       
   335     brushType = (VGPaintType)0;
       
   336 
       
   337     brushOrigin = QPointF(0.0f, 0.0f);
       
   338 
       
   339     fillRule = 0;
       
   340 
       
   341     opacity = 1.0;
       
   342     paintOpacity = 1.0f;
       
   343 
       
   344 #if !defined(QVG_NO_MODIFY_PATH)
       
   345     rectPath = 0;
       
   346     linePath = 0;
       
   347     roundRectPath = 0;
       
   348 #endif
       
   349 
       
   350     simpleTransform = true;
       
   351     pathTransformSet = false;
       
   352     penScale = 1.0;
       
   353 
       
   354     maskValid = false;
       
   355     maskIsSet = false;
       
   356     rawVG = false;
       
   357 
       
   358     scissorActive = false;
       
   359 
       
   360     dirty = 0;
       
   361 
       
   362     clearOpacity = 1.0f;
       
   363 
       
   364 #if !defined(QVG_NO_DRAW_GLYPHS)
       
   365     fontEngineCleaner = 0;
       
   366 #endif
       
   367 
       
   368     clearModes();
       
   369 }
       
   370 
       
   371 QVGPaintEnginePrivate::~QVGPaintEnginePrivate()
       
   372 {
       
   373     destroy();
       
   374 }
       
   375 
       
   376 void QVGPaintEnginePrivate::initObjects()
       
   377 {
       
   378     maxScissorRects = vgGeti(VG_MAX_SCISSOR_RECTS);
       
   379 
       
   380     penPaint = vgCreatePaint();
       
   381     vgSetParameteri(penPaint, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR);
       
   382     vgSetPaint(penPaint, VG_STROKE_PATH);
       
   383 
       
   384     vgSeti(VG_MATRIX_MODE, VG_MATRIX_STROKE_PAINT_TO_USER);
       
   385     vgLoadIdentity();
       
   386 
       
   387     brushPaint = vgCreatePaint();
       
   388     vgSetParameteri(brushPaint, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR);
       
   389     vgSetPaint(brushPaint, VG_FILL_PATH);
       
   390     fillPaint = brushPaint;
       
   391 
       
   392     vgSeti(VG_MATRIX_MODE, VG_MATRIX_FILL_PAINT_TO_USER);
       
   393     vgLoadIdentity();
       
   394     matrixMode = VG_MATRIX_FILL_PAINT_TO_USER;
       
   395 
       
   396     opacityPaint = vgCreatePaint();
       
   397     vgSetParameteri(opacityPaint, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR);
       
   398     VGfloat values[4];
       
   399     values[0] = 1.0f;
       
   400     values[1] = 1.0f;
       
   401     values[2] = 1.0f;
       
   402     values[3] = paintOpacity;
       
   403     vgSetParameterfv(opacityPaint, VG_PAINT_COLOR, 4, values);
       
   404 
       
   405 #if !defined(QVG_NO_MODIFY_PATH)
       
   406     // Create a dummy path for rectangle drawing, which we can
       
   407     // modify later with vgModifyPathCoords().  This should be
       
   408     // faster than constantly creating and destroying paths.
       
   409     rectPath = vgCreatePath(VG_PATH_FORMAT_STANDARD,
       
   410                             VG_PATH_DATATYPE_F,
       
   411                             1.0f, // scale
       
   412                             0.0f, // bias
       
   413                             5,    // segmentCapacityHint
       
   414                             8,    // coordCapacityHint
       
   415                             VG_PATH_CAPABILITY_ALL);
       
   416     static VGubyte const segments[5] = {
       
   417         VG_MOVE_TO_ABS,
       
   418         VG_LINE_TO_ABS,
       
   419         VG_LINE_TO_ABS,
       
   420         VG_LINE_TO_ABS,
       
   421         VG_CLOSE_PATH
       
   422     };
       
   423     VGfloat coords[8];
       
   424     coords[0] = 0.0f;
       
   425     coords[1] = 0.0f;
       
   426     coords[2] = 100.0f;
       
   427     coords[3] = coords[1];
       
   428     coords[4] = coords[2];
       
   429     coords[5] = 100.0f;
       
   430     coords[6] = coords[0];
       
   431     coords[7] = coords[5];
       
   432     vgAppendPathData(rectPath, 5, segments, coords);
       
   433 
       
   434     // Create a dummy line drawing path as well.
       
   435     linePath = vgCreatePath(VG_PATH_FORMAT_STANDARD,
       
   436                             VG_PATH_DATATYPE_F,
       
   437                             1.0f, // scale
       
   438                             0.0f, // bias
       
   439                             2,    // segmentCapacityHint
       
   440                             4,    // coordCapacityHint
       
   441                             VG_PATH_CAPABILITY_ALL);
       
   442     vgAppendPathData(linePath, 2, segments, coords);
       
   443 #endif
       
   444 }
       
   445 
       
   446 void QVGPaintEnginePrivate::destroy()
       
   447 {
       
   448     if (penPaint)
       
   449         vgDestroyPaint(penPaint);
       
   450     if (brushPaint)
       
   451         vgDestroyPaint(brushPaint);
       
   452     if (opacityPaint)
       
   453         vgDestroyPaint(opacityPaint);
       
   454 
       
   455 #if !defined(QVG_NO_MODIFY_PATH)
       
   456     if (rectPath)
       
   457         vgDestroyPath(rectPath);
       
   458     if (linePath)
       
   459         vgDestroyPath(linePath);
       
   460     if (roundRectPath)
       
   461         vgDestroyPath(roundRectPath);
       
   462 #endif
       
   463 
       
   464 #if !defined(QVG_NO_DRAW_GLYPHS)
       
   465     QVGFontCache::Iterator it;
       
   466     for (it = fontCache.begin(); it != fontCache.end(); ++it)
       
   467         delete it.value();
       
   468     fontCache.clear();
       
   469     delete fontEngineCleaner;
       
   470 #endif
       
   471 }
       
   472 
       
   473 // Set a specific VG transformation matrix in the current VG context.
       
   474 void QVGPaintEnginePrivate::setTransform
       
   475         (VGMatrixMode mode, const QTransform& transform)
       
   476 {
       
   477     VGfloat mat[9];
       
   478     if (mode != matrixMode) {
       
   479         vgSeti(VG_MATRIX_MODE, mode);
       
   480         matrixMode = mode;
       
   481     }
       
   482     mat[0] = transform.m11();
       
   483     mat[1] = transform.m12();
       
   484     mat[2] = transform.m13();
       
   485     mat[3] = transform.m21();
       
   486     mat[4] = transform.m22();
       
   487     mat[5] = transform.m23();
       
   488     mat[6] = transform.m31();
       
   489     mat[7] = transform.m32();
       
   490     mat[8] = transform.m33();
       
   491     vgLoadMatrix(mat);
       
   492 }
       
   493 
       
   494 extern bool qt_scaleForTransform(const QTransform &transform, qreal *scale);
       
   495 
       
   496 void QVGPaintEnginePrivate::updateTransform(QPaintDevice *pdev)
       
   497 {
       
   498     VGfloat devh = pdev->height() - 1;
       
   499 
       
   500     // Construct the VG transform by combining the Qt transform with
       
   501     // the following viewport transformation:
       
   502     //        | 1  0  0   |   | 1 0  0.5 |   | 1  0     0.5      |
       
   503     //        | 0 -1 devh | * | 0 1 -0.5 | = | 0 -1 (0.5 + devh) |
       
   504     //        | 0  0  1   |   | 0 0   1  |   | 0  0      1       |
       
   505     // The full VG transform is effectively:
       
   506     //      1. Apply the user's transformation matrix.
       
   507     //      2. Translate by (0.5, -0.5) to correct for Qt and VG putting
       
   508     //         the centre of the pixel at different positions.
       
   509     //      3. Flip the co-ordinate system upside down.
       
   510     QTransform viewport(1.0f, 0.0f, 0.0f,
       
   511                         0.0f, -1.0f, 0.0f,
       
   512                         0.5f, devh + 0.5f, 1.0f);
       
   513 
       
   514     // The image transform is always the full transformation,
       
   515     // because it can be projective.
       
   516     imageTransform = transform * viewport;
       
   517 
       
   518     // Determine if the transformation is projective.
       
   519     bool projective = (imageTransform.m13() != 0.0f ||
       
   520                        imageTransform.m23() != 0.0f ||
       
   521                        imageTransform.m33() != 1.0f);
       
   522     if (projective) {
       
   523         // The engine cannot do projective path transforms for us,
       
   524         // so we will have to convert the co-ordinates ourselves.
       
   525         // Change the matrix to just the viewport transformation.
       
   526         pathTransform = viewport;
       
   527         simpleTransform = false;
       
   528     } else {
       
   529         pathTransform = imageTransform;
       
   530         simpleTransform = true;
       
   531     }
       
   532     pathTransformSet = false;
       
   533 
       
   534     // Calculate the scaling factor to use for turning cosmetic pens
       
   535     // into ordinary non-cosmetic pens.
       
   536     qt_scaleForTransform(transform, &penScale);
       
   537 }
       
   538 
       
   539 VGPath QVGPaintEnginePrivate::vectorPathToVGPath(const QVectorPath& path)
       
   540 {
       
   541     int count = path.elementCount();
       
   542     const qreal *points = path.points();
       
   543     const QPainterPath::ElementType *elements = path.elements();
       
   544 
       
   545     VGPath vgpath = vgCreatePath(VG_PATH_FORMAT_STANDARD,
       
   546                                  VG_PATH_DATATYPE_F,
       
   547                                  1.0f,        // scale
       
   548                                  0.0f,        // bias
       
   549                                  count + 1,   // segmentCapacityHint
       
   550                                  count * 2,   // coordCapacityHint
       
   551                                  VG_PATH_CAPABILITY_ALL);
       
   552 
       
   553     // Size is sufficient segments for drawRoundedRect() paths.
       
   554     QVarLengthArray<VGubyte, 20> segments;
       
   555 
       
   556     if (sizeof(qreal) == sizeof(VGfloat) && elements && simpleTransform) {
       
   557         // If Qt was compiled with qreal the same size as VGfloat,
       
   558         // then convert the segment types and use the incoming
       
   559         // points array directly.
       
   560         for (int i = 0; i < count; ++i) {
       
   561             switch (elements[i]) {
       
   562 
       
   563             case QPainterPath::MoveToElement:
       
   564                 segments.append(VG_MOVE_TO_ABS); break;
       
   565 
       
   566             case QPainterPath::LineToElement:
       
   567                 segments.append(VG_LINE_TO_ABS); break;
       
   568 
       
   569             case QPainterPath::CurveToElement:
       
   570                 segments.append(VG_CUBIC_TO_ABS); break;
       
   571 
       
   572             case QPainterPath::CurveToDataElement: break;
       
   573 
       
   574             }
       
   575         }
       
   576         if (path.hasImplicitClose())
       
   577             segments.append(VG_CLOSE_PATH);
       
   578 
       
   579         vgAppendPathData(vgpath, segments.count(), segments.constData(),
       
   580                          reinterpret_cast<const VGfloat *>(points));
       
   581 
       
   582         return vgpath;
       
   583     }
       
   584 
       
   585     // Sizes chosen so that drawRoundedRect() paths fit in these arrays.
       
   586     QVarLengthArray<VGfloat, 48> coords;
       
   587 
       
   588     int curvePos = 0;
       
   589     QPointF temp;
       
   590 
       
   591     if (elements && simpleTransform) {
       
   592         // Convert the members of the element array.
       
   593         for (int i = 0; i < count; ++i) {
       
   594             switch (elements[i]) {
       
   595 
       
   596             case QPainterPath::MoveToElement:
       
   597             {
       
   598                 coords.append(points[0]);
       
   599                 coords.append(points[1]);
       
   600                 segments.append(VG_MOVE_TO_ABS);
       
   601             }
       
   602             break;
       
   603 
       
   604             case QPainterPath::LineToElement:
       
   605             {
       
   606                 coords.append(points[0]);
       
   607                 coords.append(points[1]);
       
   608                 segments.append(VG_LINE_TO_ABS);
       
   609             }
       
   610             break;
       
   611 
       
   612             case QPainterPath::CurveToElement:
       
   613             {
       
   614                 coords.append(points[0]);
       
   615                 coords.append(points[1]);
       
   616                 curvePos = 2;
       
   617             }
       
   618             break;
       
   619 
       
   620             case QPainterPath::CurveToDataElement:
       
   621             {
       
   622                 coords.append(points[0]);
       
   623                 coords.append(points[1]);
       
   624                 curvePos += 2;
       
   625                 if (curvePos == 6) {
       
   626                     curvePos = 0;
       
   627                     segments.append(VG_CUBIC_TO_ABS);
       
   628                 }
       
   629             }
       
   630             break;
       
   631 
       
   632             }
       
   633             points += 2;
       
   634         }
       
   635     } else if (elements && !simpleTransform) {
       
   636         // Convert the members of the element array after applying the
       
   637         // current transform to the path locally.
       
   638         for (int i = 0; i < count; ++i) {
       
   639             switch (elements[i]) {
       
   640 
       
   641             case QPainterPath::MoveToElement:
       
   642             {
       
   643                 temp = transform.map(QPointF(points[0], points[1]));
       
   644                 coords.append(temp.x());
       
   645                 coords.append(temp.y());
       
   646                 segments.append(VG_MOVE_TO_ABS);
       
   647             }
       
   648             break;
       
   649 
       
   650             case QPainterPath::LineToElement:
       
   651             {
       
   652                 temp = transform.map(QPointF(points[0], points[1]));
       
   653                 coords.append(temp.x());
       
   654                 coords.append(temp.y());
       
   655                 segments.append(VG_LINE_TO_ABS);
       
   656             }
       
   657             break;
       
   658 
       
   659             case QPainterPath::CurveToElement:
       
   660             {
       
   661                 temp = transform.map(QPointF(points[0], points[1]));
       
   662                 coords.append(temp.x());
       
   663                 coords.append(temp.y());
       
   664                 curvePos = 2;
       
   665             }
       
   666             break;
       
   667 
       
   668             case QPainterPath::CurveToDataElement:
       
   669             {
       
   670                 temp = transform.map(QPointF(points[0], points[1]));
       
   671                 coords.append(temp.x());
       
   672                 coords.append(temp.y());
       
   673                 curvePos += 2;
       
   674                 if (curvePos == 6) {
       
   675                     curvePos = 0;
       
   676                     segments.append(VG_CUBIC_TO_ABS);
       
   677                 }
       
   678             }
       
   679             break;
       
   680 
       
   681             }
       
   682             points += 2;
       
   683         }
       
   684     } else if (count > 0 && simpleTransform) {
       
   685         // If there is no element array, then the path is assumed
       
   686         // to be a MoveTo followed by several LineTo's.
       
   687         coords.append(points[0]);
       
   688         coords.append(points[1]);
       
   689         segments.append(VG_MOVE_TO_ABS);
       
   690         while (count > 1) {
       
   691             points += 2;
       
   692             coords.append(points[0]);
       
   693             coords.append(points[1]);
       
   694             segments.append(VG_LINE_TO_ABS);
       
   695             --count;
       
   696         }
       
   697     } else if (count > 0 && !simpleTransform) {
       
   698         // Convert a simple path, and apply the transform locally.
       
   699         temp = transform.map(QPointF(points[0], points[1]));
       
   700         coords.append(temp.x());
       
   701         coords.append(temp.y());
       
   702         segments.append(VG_MOVE_TO_ABS);
       
   703         while (count > 1) {
       
   704             points += 2;
       
   705             temp = transform.map(QPointF(points[0], points[1]));
       
   706             coords.append(temp.x());
       
   707             coords.append(temp.y());
       
   708             segments.append(VG_LINE_TO_ABS);
       
   709             --count;
       
   710         }
       
   711     }
       
   712 
       
   713     // Close the path if specified.
       
   714     if (path.hasImplicitClose())
       
   715         segments.append(VG_CLOSE_PATH);
       
   716 
       
   717     vgAppendPathData(vgpath, segments.count(),
       
   718                      segments.constData(), coords.constData());
       
   719 
       
   720     return vgpath;
       
   721 }
       
   722 
       
   723 VGPath QVGPaintEnginePrivate::painterPathToVGPath(const QPainterPath& path)
       
   724 {
       
   725     int count = path.elementCount();
       
   726 
       
   727     VGPath vgpath = vgCreatePath(VG_PATH_FORMAT_STANDARD,
       
   728                                  VG_PATH_DATATYPE_F,
       
   729                                  1.0f,        // scale
       
   730                                  0.0f,        // bias
       
   731                                  count + 1,   // segmentCapacityHint
       
   732                                  count * 2,   // coordCapacityHint
       
   733                                  VG_PATH_CAPABILITY_ALL);
       
   734 
       
   735     if (count == 0)
       
   736         return vgpath;
       
   737 
       
   738     const QPainterPath::Element *elements = &(path.elementAt(0));
       
   739 
       
   740     // Sizes chosen so that drawRoundedRect() paths fit in these arrays.
       
   741     QVarLengthArray<VGfloat, 48> coords;
       
   742     QVarLengthArray<VGubyte, 20> segments;
       
   743 
       
   744     int curvePos = 0;
       
   745     QPointF temp;
       
   746 
       
   747     // Keep track of the start and end of each sub-path.  QPainterPath
       
   748     // does not have an "implicit close" flag like QVectorPath does.
       
   749     // We therefore have to detect closed paths by looking for a LineTo
       
   750     // element that connects back to the initial MoveTo element.
       
   751     qreal startx = 0.0;
       
   752     qreal starty = 0.0;
       
   753     qreal endx = 0.0;
       
   754     qreal endy = 0.0;
       
   755     bool haveStart = false;
       
   756     bool haveEnd = false;
       
   757 
       
   758     if (simpleTransform) {
       
   759         // Convert the members of the element array.
       
   760         for (int i = 0; i < count; ++i) {
       
   761             switch (elements[i].type) {
       
   762 
       
   763             case QPainterPath::MoveToElement:
       
   764             {
       
   765                 if (haveStart && haveEnd && startx == endx && starty == endy) {
       
   766                     // Implicitly close the previous sub-path.
       
   767                     segments.append(VG_CLOSE_PATH);
       
   768                 }
       
   769                 startx = elements[i].x;
       
   770                 starty = elements[i].y;
       
   771                 coords.append(startx);
       
   772                 coords.append(starty);
       
   773                 haveStart = true;
       
   774                 haveEnd = false;
       
   775                 segments.append(VG_MOVE_TO_ABS);
       
   776             }
       
   777             break;
       
   778 
       
   779             case QPainterPath::LineToElement:
       
   780             {
       
   781                 endx = elements[i].x;
       
   782                 endy = elements[i].y;
       
   783                 coords.append(endx);
       
   784                 coords.append(endy);
       
   785                 haveEnd = true;
       
   786                 segments.append(VG_LINE_TO_ABS);
       
   787             }
       
   788             break;
       
   789 
       
   790             case QPainterPath::CurveToElement:
       
   791             {
       
   792                 coords.append(elements[i].x);
       
   793                 coords.append(elements[i].y);
       
   794                 haveEnd = false;
       
   795                 curvePos = 2;
       
   796             }
       
   797             break;
       
   798 
       
   799             case QPainterPath::CurveToDataElement:
       
   800             {
       
   801                 coords.append(elements[i].x);
       
   802                 coords.append(elements[i].y);
       
   803                 haveEnd = false;
       
   804                 curvePos += 2;
       
   805                 if (curvePos == 6) {
       
   806                     curvePos = 0;
       
   807                     segments.append(VG_CUBIC_TO_ABS);
       
   808                 }
       
   809             }
       
   810             break;
       
   811 
       
   812             }
       
   813         }
       
   814     } else {
       
   815         // Convert the members of the element array after applying the
       
   816         // current transform to the path locally.
       
   817         for (int i = 0; i < count; ++i) {
       
   818             switch (elements[i].type) {
       
   819 
       
   820             case QPainterPath::MoveToElement:
       
   821             {
       
   822                 if (haveStart && haveEnd && startx == endx && starty == endy) {
       
   823                     // Implicitly close the previous sub-path.
       
   824                     segments.append(VG_CLOSE_PATH);
       
   825                 }
       
   826                 temp = transform.map(QPointF(elements[i].x, elements[i].y));
       
   827                 startx = temp.x();
       
   828                 starty = temp.y();
       
   829                 coords.append(startx);
       
   830                 coords.append(starty);
       
   831                 haveStart = true;
       
   832                 haveEnd = false;
       
   833                 segments.append(VG_MOVE_TO_ABS);
       
   834             }
       
   835             break;
       
   836 
       
   837             case QPainterPath::LineToElement:
       
   838             {
       
   839                 temp = transform.map(QPointF(elements[i].x, elements[i].y));
       
   840                 endx = temp.x();
       
   841                 endy = temp.y();
       
   842                 coords.append(endx);
       
   843                 coords.append(endy);
       
   844                 haveEnd = true;
       
   845                 segments.append(VG_LINE_TO_ABS);
       
   846             }
       
   847             break;
       
   848 
       
   849             case QPainterPath::CurveToElement:
       
   850             {
       
   851                 temp = transform.map(QPointF(elements[i].x, elements[i].y));
       
   852                 coords.append(temp.x());
       
   853                 coords.append(temp.y());
       
   854                 haveEnd = false;
       
   855                 curvePos = 2;
       
   856             }
       
   857             break;
       
   858 
       
   859             case QPainterPath::CurveToDataElement:
       
   860             {
       
   861                 temp = transform.map(QPointF(elements[i].x, elements[i].y));
       
   862                 coords.append(temp.x());
       
   863                 coords.append(temp.y());
       
   864                 haveEnd = false;
       
   865                 curvePos += 2;
       
   866                 if (curvePos == 6) {
       
   867                     curvePos = 0;
       
   868                     segments.append(VG_CUBIC_TO_ABS);
       
   869                 }
       
   870             }
       
   871             break;
       
   872 
       
   873             }
       
   874         }
       
   875     }
       
   876 
       
   877     if (haveStart && haveEnd && startx == endx && starty == endy) {
       
   878         // Implicitly close the last sub-path.
       
   879         segments.append(VG_CLOSE_PATH);
       
   880     }
       
   881 
       
   882     vgAppendPathData(vgpath, segments.count(),
       
   883                      segments.constData(), coords.constData());
       
   884 
       
   885     return vgpath;
       
   886 }
       
   887 
       
   888 VGPath QVGPaintEnginePrivate::roundedRectPath(const QRectF &rect, qreal xRadius, qreal yRadius, Qt::SizeMode mode)
       
   889 {
       
   890     static VGubyte roundedrect_types[] = {
       
   891         VG_MOVE_TO_ABS,
       
   892         VG_LINE_TO_ABS,
       
   893         VG_CUBIC_TO_ABS,
       
   894         VG_LINE_TO_ABS,
       
   895         VG_CUBIC_TO_ABS,
       
   896         VG_LINE_TO_ABS,
       
   897         VG_CUBIC_TO_ABS,
       
   898         VG_LINE_TO_ABS,
       
   899         VG_CUBIC_TO_ABS,
       
   900         VG_CLOSE_PATH
       
   901     };
       
   902 
       
   903     qreal x1 = rect.left();
       
   904     qreal x2 = rect.right();
       
   905     qreal y1 = rect.top();
       
   906     qreal y2 = rect.bottom();
       
   907 
       
   908     if (mode == Qt::RelativeSize) {
       
   909         xRadius = xRadius * rect.width() / 200.;
       
   910         yRadius = yRadius * rect.height() / 200.;
       
   911     }
       
   912 
       
   913     xRadius = qMin(xRadius, rect.width() / 2);
       
   914     yRadius = qMin(yRadius, rect.height() / 2);
       
   915 
       
   916     VGfloat pts[] = {
       
   917         x1 + xRadius, y1,                   // MoveTo
       
   918         x2 - xRadius, y1,                   // LineTo
       
   919         x2 - (1 - KAPPA) * xRadius, y1,     // CurveTo
       
   920         x2, y1 + (1 - KAPPA) * yRadius,
       
   921         x2, y1 + yRadius,
       
   922         x2, y2 - yRadius,                   // LineTo
       
   923         x2, y2 - (1 - KAPPA) * yRadius,     // CurveTo
       
   924         x2 - (1 - KAPPA) * xRadius, y2,
       
   925         x2 - xRadius, y2,
       
   926         x1 + xRadius, y2,                   // LineTo
       
   927         x1 + (1 - KAPPA) * xRadius, y2,     // CurveTo
       
   928         x1, y2 - (1 - KAPPA) * yRadius,
       
   929         x1, y2 - yRadius,
       
   930         x1, y1 + yRadius,                   // LineTo
       
   931         x1, y1 + KAPPA * yRadius,           // CurveTo
       
   932         x1 + (1 - KAPPA) * xRadius, y1,
       
   933         x1 + xRadius, y1
       
   934     };
       
   935 
       
   936 #if !defined(QVG_NO_MODIFY_PATH)
       
   937     VGPath vgpath = roundRectPath;
       
   938     if (!vgpath) {
       
   939         vgpath = vgCreatePath(VG_PATH_FORMAT_STANDARD,
       
   940                               VG_PATH_DATATYPE_F,
       
   941                               1.0f,        // scale
       
   942                               0.0f,        // bias
       
   943                               10,          // segmentCapacityHint
       
   944                               17 * 2,      // coordCapacityHint
       
   945                               VG_PATH_CAPABILITY_ALL);
       
   946         vgAppendPathData(vgpath, 10, roundedrect_types, pts);
       
   947         roundRectPath = vgpath;
       
   948     } else {
       
   949         vgModifyPathCoords(vgpath, 0, 9, pts);
       
   950     }
       
   951 #else
       
   952     VGPath vgpath = vgCreatePath(VG_PATH_FORMAT_STANDARD,
       
   953                                  VG_PATH_DATATYPE_F,
       
   954                                  1.0f,        // scale
       
   955                                  0.0f,        // bias
       
   956                                  10,          // segmentCapacityHint
       
   957                                  17 * 2,      // coordCapacityHint
       
   958                                  VG_PATH_CAPABILITY_ALL);
       
   959     vgAppendPathData(vgpath, 10, roundedrect_types, pts);
       
   960 #endif
       
   961 
       
   962     return vgpath;
       
   963 }
       
   964 
       
   965 extern QImage qt_imageForBrush(int style, bool invert);
       
   966 
       
   967 static QImage colorizeBitmap(const QImage &image, const QColor &color)
       
   968 {
       
   969     QImage sourceImage = image.convertToFormat(QImage::Format_MonoLSB);
       
   970     QImage dest = QImage(sourceImage.size(), QImage::Format_ARGB32_Premultiplied);
       
   971 
       
   972     QRgb fg = PREMUL(color.rgba());
       
   973     QRgb bg = 0;
       
   974 
       
   975     int height = sourceImage.height();
       
   976     int width = sourceImage.width();
       
   977     for (int y=0; y<height; ++y) {
       
   978         uchar *source = sourceImage.scanLine(y);
       
   979         QRgb *target = reinterpret_cast<QRgb *>(dest.scanLine(y));
       
   980         for (int x=0; x < width; ++x)
       
   981             target[x] = (source[x>>3] >> (x&7)) & 1 ? fg : bg;
       
   982     }
       
   983     return dest;
       
   984 }
       
   985 
       
   986 static VGImage toVGImage
       
   987     (const QImage & image, Qt::ImageConversionFlags flags = Qt::AutoColor)
       
   988 {
       
   989     QImage img(image);
       
   990 
       
   991     VGImageFormat format;
       
   992     switch (img.format()) {
       
   993     case QImage::Format_Mono:
       
   994         img = image.convertToFormat(QImage::Format_MonoLSB, flags);
       
   995         format = VG_BW_1;
       
   996         break;
       
   997     case QImage::Format_MonoLSB:
       
   998         format = VG_BW_1;
       
   999         break;
       
  1000     case QImage::Format_RGB32:
       
  1001         format = VG_sXRGB_8888;
       
  1002         break;
       
  1003     case QImage::Format_ARGB32:
       
  1004         format = VG_sARGB_8888;
       
  1005         break;
       
  1006     case QImage::Format_ARGB32_Premultiplied:
       
  1007         format = VG_sARGB_8888_PRE;
       
  1008         break;
       
  1009     case QImage::Format_RGB16:
       
  1010         format = VG_sRGB_565;
       
  1011         break;
       
  1012     default:
       
  1013         // Convert everything else into ARGB32_Premultiplied.
       
  1014         img = image.convertToFormat(QImage::Format_ARGB32_Premultiplied, flags);
       
  1015         format = VG_sARGB_8888_PRE;
       
  1016         break;
       
  1017     }
       
  1018 
       
  1019     const uchar *pixels = img.bits();
       
  1020 
       
  1021     VGImage vgImg = vgCreateImage
       
  1022         (format, img.width(), img.height(), VG_IMAGE_QUALITY_FASTER);
       
  1023     vgImageSubData
       
  1024         (vgImg, pixels, img.bytesPerLine(), format, 0, 0,
       
  1025          img.width(), img.height());
       
  1026 
       
  1027     return vgImg;
       
  1028 }
       
  1029 
       
  1030 static VGImage toVGImageSubRect
       
  1031     (const QImage & image, const QRect& sr,
       
  1032      Qt::ImageConversionFlags flags = Qt::AutoColor)
       
  1033 {
       
  1034     QImage img(image);
       
  1035 
       
  1036     VGImageFormat format;
       
  1037     int bpp = 4;
       
  1038 
       
  1039     switch (img.format()) {
       
  1040     case QImage::Format_Mono:
       
  1041     case QImage::Format_MonoLSB:
       
  1042         return VG_INVALID_HANDLE;
       
  1043     case QImage::Format_RGB32:
       
  1044         format = VG_sXRGB_8888;
       
  1045         break;
       
  1046     case QImage::Format_ARGB32:
       
  1047         format = VG_sARGB_8888;
       
  1048         break;
       
  1049     case QImage::Format_ARGB32_Premultiplied:
       
  1050         format = VG_sARGB_8888_PRE;
       
  1051         break;
       
  1052     case QImage::Format_RGB16:
       
  1053         format = VG_sRGB_565;
       
  1054         bpp = 2;
       
  1055         break;
       
  1056     default:
       
  1057         // Convert everything else into ARGB32_Premultiplied.
       
  1058         img = image.convertToFormat(QImage::Format_ARGB32_Premultiplied, flags);
       
  1059         format = VG_sARGB_8888_PRE;
       
  1060         break;
       
  1061     }
       
  1062 
       
  1063     const uchar *pixels = img.bits() + bpp * sr.x() +
       
  1064                           img.bytesPerLine() * sr.y();
       
  1065 
       
  1066     VGImage vgImg = vgCreateImage
       
  1067         (format, sr.width(), sr.height(), VG_IMAGE_QUALITY_FASTER);
       
  1068     vgImageSubData
       
  1069         (vgImg, pixels, img.bytesPerLine(), format, 0, 0,
       
  1070          sr.width(), sr.height());
       
  1071 
       
  1072     return vgImg;
       
  1073 }
       
  1074 
       
  1075 static VGImage toVGImageWithOpacity(const QImage & image, qreal opacity)
       
  1076 {
       
  1077     QImage img(image.size(), QImage::Format_ARGB32_Premultiplied);
       
  1078     img.fill(0);
       
  1079     QPainter painter;
       
  1080     painter.begin(&img);
       
  1081     painter.setOpacity(opacity);
       
  1082     painter.drawImage(0, 0, image);
       
  1083     painter.end();
       
  1084 
       
  1085     const uchar *pixels = img.bits();
       
  1086 
       
  1087     VGImage vgImg = vgCreateImage
       
  1088         (VG_sARGB_8888_PRE, img.width(), img.height(), VG_IMAGE_QUALITY_FASTER);
       
  1089     vgImageSubData
       
  1090         (vgImg, pixels, img.bytesPerLine(), VG_sARGB_8888_PRE, 0, 0,
       
  1091          img.width(), img.height());
       
  1092 
       
  1093     return vgImg;
       
  1094 }
       
  1095 
       
  1096 static VGImage toVGImageWithOpacitySubRect
       
  1097     (const QImage & image, qreal opacity, const QRect& sr)
       
  1098 {
       
  1099     QImage img(sr.size(), QImage::Format_ARGB32_Premultiplied);
       
  1100     img.fill(0);
       
  1101     QPainter painter;
       
  1102     painter.begin(&img);
       
  1103     painter.setOpacity(opacity);
       
  1104     painter.drawImage(QPoint(0, 0), image, sr);
       
  1105     painter.end();
       
  1106 
       
  1107     const uchar *pixels = img.bits();
       
  1108 
       
  1109     VGImage vgImg = vgCreateImage
       
  1110         (VG_sARGB_8888_PRE, img.width(), img.height(), VG_IMAGE_QUALITY_FASTER);
       
  1111     vgImageSubData
       
  1112         (vgImg, pixels, img.bytesPerLine(), VG_sARGB_8888_PRE, 0, 0,
       
  1113          img.width(), img.height());
       
  1114 
       
  1115     return vgImg;
       
  1116 }
       
  1117 
       
  1118 VGPaintType QVGPaintEnginePrivate::setBrush
       
  1119         (VGPaint paint, const QBrush& brush, VGMatrixMode mode,
       
  1120          VGPaintType prevType)
       
  1121 {
       
  1122     VGfloat values[5];
       
  1123     setBrushTransform(brush, mode);
       
  1124 
       
  1125     // Reset the paint pattern on the brush, which will discard
       
  1126     // the previous VGImage if one was set.
       
  1127     if (prevType == VG_PAINT_TYPE_PATTERN || prevType == (VGPaintType)0)
       
  1128         vgPaintPattern(paint, VG_INVALID_HANDLE);
       
  1129 
       
  1130     switch (brush.style()) {
       
  1131 
       
  1132     case Qt::SolidPattern: {
       
  1133         // The brush is a solid color.
       
  1134         QColor color(brush.color());
       
  1135         values[0] = color.redF();
       
  1136         values[1] = color.greenF();
       
  1137         values[2] = color.blueF();
       
  1138         values[3] = color.alphaF() * opacity;
       
  1139         if (prevType != VG_PAINT_TYPE_COLOR)
       
  1140             vgSetParameteri(paint, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR);
       
  1141         vgSetParameterfv(paint, VG_PAINT_COLOR, 4, values);
       
  1142         return VG_PAINT_TYPE_COLOR;
       
  1143     }
       
  1144 
       
  1145     case Qt::LinearGradientPattern: {
       
  1146         // The brush is a linear gradient.
       
  1147         Q_ASSERT(brush.gradient()->type() == QGradient::LinearGradient);
       
  1148         const QLinearGradient *grad =
       
  1149             static_cast<const QLinearGradient*>(brush.gradient());
       
  1150         values[0] = grad->start().x();
       
  1151         values[1] = grad->start().y();
       
  1152         values[2] = grad->finalStop().x();
       
  1153         values[3] = grad->finalStop().y();
       
  1154         if (prevType != VG_PAINT_TYPE_LINEAR_GRADIENT)
       
  1155             vgSetParameteri(paint, VG_PAINT_TYPE, VG_PAINT_TYPE_LINEAR_GRADIENT);
       
  1156         vgSetParameterfv(paint, VG_PAINT_LINEAR_GRADIENT, 4, values);
       
  1157         setupColorRamp(grad, paint);
       
  1158         return VG_PAINT_TYPE_LINEAR_GRADIENT;
       
  1159     }
       
  1160 
       
  1161     case Qt::RadialGradientPattern: {
       
  1162         // The brush is a radial gradient.
       
  1163         Q_ASSERT(brush.gradient()->type() == QGradient::RadialGradient);
       
  1164         const QRadialGradient *grad =
       
  1165             static_cast<const QRadialGradient*>(brush.gradient());
       
  1166         values[0] = grad->center().x();
       
  1167         values[1] = grad->center().y();
       
  1168         values[2] = grad->focalPoint().x();
       
  1169         values[3] = grad->focalPoint().y();
       
  1170         values[4] = grad->radius();
       
  1171         if (prevType != VG_PAINT_TYPE_RADIAL_GRADIENT)
       
  1172             vgSetParameteri(paint, VG_PAINT_TYPE, VG_PAINT_TYPE_RADIAL_GRADIENT);
       
  1173         vgSetParameterfv(paint, VG_PAINT_RADIAL_GRADIENT, 5, values);
       
  1174         setupColorRamp(grad, paint);
       
  1175         return VG_PAINT_TYPE_RADIAL_GRADIENT;
       
  1176     }
       
  1177 
       
  1178     case Qt::TexturePattern: {
       
  1179         // The brush is a texture specified by a QPixmap/QImage.
       
  1180         QPixmapData *pd = brush.texture().pixmapData();
       
  1181         VGImage vgImg;
       
  1182         bool deref = false;
       
  1183         if (pd->pixelType() == QPixmapData::BitmapType) {
       
  1184             // Colorize bitmaps using the brush color and opacity.
       
  1185             QColor color = brush.color();
       
  1186             if (opacity != 1.0)
       
  1187                 color.setAlphaF(color.alphaF() * opacity);
       
  1188             QImage image = colorizeBitmap(*(pd->buffer()), color);
       
  1189             vgImg = toVGImage(image);
       
  1190             deref = true;
       
  1191         } else if (opacity == 1.0) {
       
  1192             if (pd->classId() == QPixmapData::OpenVGClass) {
       
  1193                 QVGPixmapData *vgpd = static_cast<QVGPixmapData *>(pd);
       
  1194                 vgImg = vgpd->toVGImage();
       
  1195             } else {
       
  1196                 vgImg = toVGImage(*(pd->buffer()));
       
  1197                 deref = true;
       
  1198             }
       
  1199         } else if (pd->classId() == QPixmapData::OpenVGClass) {
       
  1200             QVGPixmapData *vgpd = static_cast<QVGPixmapData *>(pd);
       
  1201             vgImg = vgpd->toVGImage(opacity);
       
  1202         } else {
       
  1203             vgImg = toVGImageWithOpacity(*(pd->buffer()), opacity);
       
  1204             deref = true;
       
  1205         }
       
  1206         if (vgImg == VG_INVALID_HANDLE)
       
  1207             break;
       
  1208         if (prevType != VG_PAINT_TYPE_PATTERN)
       
  1209             vgSetParameteri(paint, VG_PAINT_TYPE, VG_PAINT_TYPE_PATTERN);
       
  1210         vgSetParameteri(paint, VG_PAINT_PATTERN_TILING_MODE, VG_TILE_REPEAT);
       
  1211         vgPaintPattern(paint, vgImg);
       
  1212         if (deref)
       
  1213             vgDestroyImage(vgImg); // Will be valid until pattern is destroyed.
       
  1214         return VG_PAINT_TYPE_PATTERN;
       
  1215     }
       
  1216 
       
  1217     case Qt::ConicalGradientPattern: {
       
  1218         // Convert conical gradients into the first stop color.
       
  1219         qWarning() << "QVGPaintEnginePrivate::setBrush: conical gradients are not supported by OpenVG";
       
  1220         Q_ASSERT(brush.gradient()->type() == QGradient::ConicalGradient);
       
  1221         const QConicalGradient *grad =
       
  1222             static_cast<const QConicalGradient*>(brush.gradient());
       
  1223         const QGradientStops stops = grad->stops();
       
  1224         QColor color;
       
  1225         if (stops.size() > 0)
       
  1226             color = stops[0].second;
       
  1227         values[0] = color.redF();
       
  1228         values[1] = color.greenF();
       
  1229         values[2] = color.blueF();
       
  1230         values[3] = color.alphaF() * opacity;
       
  1231         if (prevType != VG_PAINT_TYPE_COLOR)
       
  1232             vgSetParameteri(paint, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR);
       
  1233         vgSetParameterfv(paint, VG_PAINT_COLOR, 4, values);
       
  1234         return VG_PAINT_TYPE_COLOR;
       
  1235     }
       
  1236 
       
  1237     case Qt::Dense1Pattern:
       
  1238     case Qt::Dense2Pattern:
       
  1239     case Qt::Dense3Pattern:
       
  1240     case Qt::Dense4Pattern:
       
  1241     case Qt::Dense5Pattern:
       
  1242     case Qt::Dense6Pattern:
       
  1243     case Qt::Dense7Pattern:
       
  1244     case Qt::HorPattern:
       
  1245     case Qt::VerPattern:
       
  1246     case Qt::CrossPattern:
       
  1247     case Qt::BDiagPattern:
       
  1248     case Qt::FDiagPattern:
       
  1249     case Qt::DiagCrossPattern: {
       
  1250         // The brush is a traditional dotted or cross-hatched pattern brush.
       
  1251         QColor color = brush.color();
       
  1252         if (opacity != 1.0)
       
  1253             color.setAlphaF(color.alphaF() * opacity);
       
  1254         QImage image = colorizeBitmap
       
  1255             (qt_imageForBrush(brush.style(), true), color);
       
  1256         VGImage vgImg = toVGImage(image);
       
  1257         if (prevType != VG_PAINT_TYPE_PATTERN)
       
  1258             vgSetParameteri(paint, VG_PAINT_TYPE, VG_PAINT_TYPE_PATTERN);
       
  1259         vgSetParameteri(paint, VG_PAINT_PATTERN_TILING_MODE, VG_TILE_REPEAT);
       
  1260         vgPaintPattern(paint, vgImg);
       
  1261         vgDestroyImage(vgImg); // Will stay valid until pattern is destroyed.
       
  1262         return VG_PAINT_TYPE_PATTERN;
       
  1263     }
       
  1264 
       
  1265     default: break;
       
  1266     }
       
  1267     return (VGPaintType)0;
       
  1268 }
       
  1269 
       
  1270 void QVGPaintEnginePrivate::setPenParams(const QPen& pen)
       
  1271 {
       
  1272     // Note: OpenVG does not support zero-width or cosmetic pens,
       
  1273     // so we have to simulate cosmetic pens by reversing the scale.
       
  1274     VGfloat width = pen.widthF();
       
  1275     if (width <= 0.0f)
       
  1276         width = 1.0f;
       
  1277     if (pen.isCosmetic()) {
       
  1278         if (penScale != 1.0 && penScale != 0.0)
       
  1279             width /= penScale;
       
  1280     }
       
  1281     vgSetf(VG_STROKE_LINE_WIDTH, width);
       
  1282 
       
  1283     if (pen.capStyle() == Qt::FlatCap)
       
  1284         vgSetf(VG_STROKE_CAP_STYLE, VG_CAP_BUTT);
       
  1285     else if (pen.capStyle() == Qt::SquareCap)
       
  1286         vgSetf(VG_STROKE_CAP_STYLE, VG_CAP_SQUARE);
       
  1287     else
       
  1288         vgSetf(VG_STROKE_CAP_STYLE, VG_CAP_ROUND);
       
  1289 
       
  1290     if (pen.joinStyle() == Qt::MiterJoin) {
       
  1291         vgSetf(VG_STROKE_JOIN_STYLE, VG_JOIN_MITER);
       
  1292         vgSetf(VG_STROKE_MITER_LIMIT, pen.miterLimit());
       
  1293     } else if (pen.joinStyle() == Qt::BevelJoin) {
       
  1294         vgSetf(VG_STROKE_JOIN_STYLE, VG_JOIN_BEVEL);
       
  1295     } else {
       
  1296         vgSetf(VG_STROKE_JOIN_STYLE, VG_JOIN_ROUND);
       
  1297     }
       
  1298 
       
  1299     if (pen.style() == Qt::SolidLine) {
       
  1300         vgSetfv(VG_STROKE_DASH_PATTERN, 0, NULL);
       
  1301     } else {
       
  1302         const QVector<qreal> dashPattern = pen.dashPattern();
       
  1303         QVector<VGfloat> currentDashPattern(dashPattern.count());
       
  1304         for (int i = 0; i < dashPattern.count(); ++i)
       
  1305             currentDashPattern[i] = dashPattern[i] * width;
       
  1306         vgSetfv(VG_STROKE_DASH_PATTERN, currentDashPattern.count(), currentDashPattern.data());
       
  1307         vgSetf(VG_STROKE_DASH_PHASE, pen.dashOffset());
       
  1308         vgSetf(VG_STROKE_DASH_PHASE_RESET, VG_FALSE);
       
  1309     }
       
  1310 }
       
  1311 
       
  1312 void QVGPaintEnginePrivate::setBrushTransform
       
  1313         (const QBrush& brush, VGMatrixMode mode)
       
  1314 {
       
  1315     // Compute the new brush transformation matrix.
       
  1316     QTransform transform(brush.transform());
       
  1317     if (brushOrigin.x() != 0.0f || brushOrigin.y() != 0.0f)
       
  1318         transform.translate(brushOrigin.x(), brushOrigin.y());
       
  1319 
       
  1320     // Bail out if the matrix is the same as last time, to avoid
       
  1321     // updating the VG context state unless absolutely necessary.
       
  1322     // Most applications won't have a brush transformation set,
       
  1323     // which will leave the VG setting at its default of identity.
       
  1324     // Always change the transform if coming out of raw VG mode.
       
  1325     if (mode == VG_MATRIX_FILL_PAINT_TO_USER) {
       
  1326         if (!rawVG && transform == brushTransform)
       
  1327             return;
       
  1328         brushTransform = transform;
       
  1329     } else {
       
  1330         if (!rawVG && transform == penTransform)
       
  1331             return;
       
  1332         penTransform = transform;
       
  1333     }
       
  1334 
       
  1335     // Set the brush transformation matrix.
       
  1336     if (mode != matrixMode) {
       
  1337         vgSeti(VG_MATRIX_MODE, mode);
       
  1338         matrixMode = mode;
       
  1339     }
       
  1340     if (transform.isIdentity()) {
       
  1341         vgLoadIdentity();
       
  1342     } else {
       
  1343         VGfloat mat[9];
       
  1344         mat[0] = transform.m11();
       
  1345         mat[1] = transform.m12();
       
  1346         mat[2] = transform.m13();
       
  1347         mat[3] = transform.m21();
       
  1348         mat[4] = transform.m22();
       
  1349         mat[5] = transform.m23();
       
  1350         mat[6] = transform.m31();
       
  1351         mat[7] = transform.m32();
       
  1352         mat[8] = transform.m33();
       
  1353         vgLoadMatrix(mat);
       
  1354     }
       
  1355 }
       
  1356 
       
  1357 void QVGPaintEnginePrivate::setupColorRamp(const QGradient *grad, VGPaint paint)
       
  1358 {
       
  1359     QGradient::Spread spread = grad->spread();
       
  1360     VGColorRampSpreadMode spreadMode;
       
  1361     if (spread == QGradient::ReflectSpread)
       
  1362         spreadMode = VG_COLOR_RAMP_SPREAD_REFLECT;
       
  1363     else if (spread == QGradient::RepeatSpread)
       
  1364         spreadMode = VG_COLOR_RAMP_SPREAD_REPEAT;
       
  1365     else
       
  1366         spreadMode = VG_COLOR_RAMP_SPREAD_PAD;
       
  1367 
       
  1368     const QGradientStops stops = grad->stops();
       
  1369     int n = 5*stops.size();
       
  1370     QVector<VGfloat> fill_stops(n);
       
  1371 
       
  1372     for (int i = 0; i < stops.size(); ++i ) {
       
  1373         QColor col = stops[i].second;
       
  1374         fill_stops[i*5] = stops[i].first;
       
  1375         fill_stops[i*5 + 1] = col.redF();
       
  1376         fill_stops[i*5 + 2] = col.greenF();
       
  1377         fill_stops[i*5 + 3] = col.blueF();
       
  1378         fill_stops[i*5 + 4] = col.alphaF() * opacity;
       
  1379     }
       
  1380 
       
  1381     vgSetParameteri(paint, VG_PAINT_COLOR_RAMP_SPREAD_MODE, spreadMode);
       
  1382     vgSetParameteri(paint, VG_PAINT_COLOR_RAMP_PREMULTIPLIED, VG_FALSE);
       
  1383     vgSetParameterfv(paint, VG_PAINT_COLOR_RAMP_STOPS, n, fill_stops.data());
       
  1384 }
       
  1385 
       
  1386 QVGPainterState::QVGPainterState(QVGPainterState& other)
       
  1387     : QPainterState(other),
       
  1388       isNew(true), clipRegion(other.clipRegion),
       
  1389       savedDirty(0)
       
  1390 {
       
  1391 }
       
  1392 
       
  1393 QVGPainterState::QVGPainterState()
       
  1394     : isNew(true), savedDirty(0)
       
  1395 {
       
  1396 }
       
  1397 
       
  1398 QVGPainterState::~QVGPainterState()
       
  1399 {
       
  1400 }
       
  1401 
       
  1402 QVGPaintEngine::QVGPaintEngine()
       
  1403     : QPaintEngineEx(*new QVGPaintEnginePrivate)
       
  1404 {
       
  1405 }
       
  1406 
       
  1407 QVGPaintEngine::QVGPaintEngine(QVGPaintEnginePrivate &data)
       
  1408     : QPaintEngineEx(data)
       
  1409 {
       
  1410 }
       
  1411 
       
  1412 QVGPaintEngine::~QVGPaintEngine()
       
  1413 {
       
  1414 }
       
  1415 
       
  1416 QPainterState *QVGPaintEngine::createState(QPainterState *orig) const
       
  1417 {
       
  1418     if (!orig) {
       
  1419         return new QVGPainterState();
       
  1420     } else {
       
  1421         Q_D(const QVGPaintEngine);
       
  1422         QVGPaintEnginePrivate *d2 = const_cast<QVGPaintEnginePrivate*>(d);
       
  1423         QVGPainterState *origState = static_cast<QVGPainterState *>(orig);
       
  1424         origState->savedDirty = d2->dirty;
       
  1425         d2->dirty = 0;
       
  1426         return new QVGPainterState(*origState);
       
  1427     }
       
  1428 }
       
  1429 
       
  1430 void QVGPaintEnginePrivate::draw
       
  1431     (VGPath path, const QPen& pen, const QBrush& brush, VGint rule)
       
  1432 {
       
  1433     VGbitfield mode = 0;
       
  1434     if (pen.style() != Qt::NoPen) {
       
  1435         ensurePen(pen);
       
  1436         mode |= VG_STROKE_PATH;
       
  1437     }
       
  1438     if (brush.style() != Qt::NoBrush) {
       
  1439         ensureBrush(brush);
       
  1440         setFillRule(rule);
       
  1441         mode |= VG_FILL_PATH;
       
  1442     }
       
  1443     if (mode != 0) {
       
  1444         ensurePathTransform();
       
  1445         vgDrawPath(path, mode);
       
  1446     }
       
  1447 }
       
  1448 
       
  1449 void QVGPaintEnginePrivate::stroke(VGPath path, const QPen& pen)
       
  1450 {
       
  1451     if (pen.style() == Qt::NoPen)
       
  1452         return;
       
  1453     ensurePen(pen);
       
  1454     ensurePathTransform();
       
  1455     vgDrawPath(path, VG_STROKE_PATH);
       
  1456 }
       
  1457 
       
  1458 void QVGPaintEnginePrivate::fill(VGPath path, const QBrush& brush, VGint rule)
       
  1459 {
       
  1460     if (brush.style() == Qt::NoBrush)
       
  1461         return;
       
  1462     ensureBrush(brush);
       
  1463     setFillRule(rule);
       
  1464     ensurePathTransform();
       
  1465     vgDrawPath(path, VG_FILL_PATH);
       
  1466 }
       
  1467 
       
  1468 bool QVGPaintEngine::begin(QPaintDevice *pdev)
       
  1469 {
       
  1470     Q_UNUSED(pdev);
       
  1471     Q_D(QVGPaintEngine);
       
  1472 
       
  1473     // Initialize the VG painting objects if we haven't done it yet.
       
  1474     if (!d->penPaint)
       
  1475         d->initObjects();
       
  1476 
       
  1477     // The initial clip region is the entire device area.
       
  1478     QVGPainterState *s = state();
       
  1479     s->clipRegion = defaultClipRegion();
       
  1480 
       
  1481     // Initialize the VG state for this paint operation.
       
  1482     restoreState(QPaintEngine::AllDirty);
       
  1483     d->dirty = 0;
       
  1484     d->rawVG = false;
       
  1485     return true;
       
  1486 }
       
  1487 
       
  1488 bool QVGPaintEngine::end()
       
  1489 {
       
  1490     return true;
       
  1491 }
       
  1492 
       
  1493 void QVGPaintEngine::draw(const QVectorPath &path)
       
  1494 {
       
  1495     Q_D(QVGPaintEngine);
       
  1496     QVGPainterState *s = state();
       
  1497     VGPath vgpath = d->vectorPathToVGPath(path);
       
  1498     if (!path.hasWindingFill())
       
  1499         d->draw(vgpath, s->pen, s->brush, VG_EVEN_ODD);
       
  1500     else
       
  1501         d->draw(vgpath, s->pen, s->brush, VG_NON_ZERO);
       
  1502     vgDestroyPath(vgpath);
       
  1503 }
       
  1504 
       
  1505 void QVGPaintEngine::fill(const QVectorPath &path, const QBrush &brush)
       
  1506 {
       
  1507     Q_D(QVGPaintEngine);
       
  1508     VGPath vgpath = d->vectorPathToVGPath(path);
       
  1509     if (!path.hasWindingFill())
       
  1510         d->fill(vgpath, brush, VG_EVEN_ODD);
       
  1511     else
       
  1512         d->fill(vgpath, brush, VG_NON_ZERO);
       
  1513     vgDestroyPath(vgpath);
       
  1514 }
       
  1515 
       
  1516 void QVGPaintEngine::stroke(const QVectorPath &path, const QPen &pen)
       
  1517 {
       
  1518     Q_D(QVGPaintEngine);
       
  1519     VGPath vgpath = d->vectorPathToVGPath(path);
       
  1520     d->stroke(vgpath, pen);
       
  1521     vgDestroyPath(vgpath);
       
  1522 }
       
  1523 
       
  1524 // Determine if a co-ordinate transform is simple enough to allow
       
  1525 // rectangle-based clipping with vgMask().  Simple transforms most
       
  1526 // often result from origin translations.
       
  1527 static inline bool clipTransformIsSimple(const QTransform& transform)
       
  1528 {
       
  1529     QTransform::TransformationType type = transform.type();
       
  1530     return (type == QTransform::TxNone || type == QTransform::TxTranslate);
       
  1531 }
       
  1532 
       
  1533 #if defined(QVG_SCISSOR_CLIP)
       
  1534 
       
  1535 void QVGPaintEngine::clip(const QVectorPath &path, Qt::ClipOperation op)
       
  1536 {
       
  1537     Q_D(QVGPaintEngine);
       
  1538     QVGPainterState *s = state();
       
  1539 
       
  1540     d->dirty |= QPaintEngine::DirtyClipRegion;
       
  1541 
       
  1542     if (op == Qt::NoClip) {
       
  1543         s->clipRegion = defaultClipRegion();
       
  1544         updateScissor();
       
  1545         return;
       
  1546     }
       
  1547 
       
  1548     // We aren't using masking, so handle simple QRectF's only.
       
  1549     if (path.shape() == QVectorPath::RectangleHint &&
       
  1550             path.elementCount() == 4 && clipTransformIsSimple(d->transform)) {
       
  1551         // Clipping region that resulted from QPainter::setClipRect(QRectF).
       
  1552         // Convert it into a QRect and apply.
       
  1553         const qreal *points = path.points();
       
  1554         QRectF rect(points[0], points[1], points[2] - points[0],
       
  1555                     points[5] - points[1]);
       
  1556         clip(rect.toRect(), op);
       
  1557     } else {
       
  1558         // The best we can do is clip to the bounding rectangle
       
  1559         // of all control points.
       
  1560         clip(path.controlPointRect().toRect(), op);
       
  1561     }
       
  1562 }
       
  1563 
       
  1564 void QVGPaintEngine::clip(const QRect &rect, Qt::ClipOperation op)
       
  1565 {
       
  1566     Q_D(QVGPaintEngine);
       
  1567     QVGPainterState *s = state();
       
  1568 
       
  1569     d->dirty |= QPaintEngine::DirtyClipRegion;
       
  1570 
       
  1571     // If we have a non-simple transform, then use path-based clipping.
       
  1572     if (op != Qt::NoClip && !clipTransformIsSimple(d->transform)) {
       
  1573         QPaintEngineEx::clip(rect, op);
       
  1574         return;
       
  1575     }
       
  1576 
       
  1577     switch (op) {
       
  1578         case Qt::NoClip:
       
  1579         {
       
  1580             s->clipRegion = defaultClipRegion();
       
  1581         }
       
  1582         break;
       
  1583 
       
  1584         case Qt::ReplaceClip:
       
  1585         {
       
  1586             s->clipRegion = d->transform.map(QRegion(rect));
       
  1587         }
       
  1588         break;
       
  1589 
       
  1590         case Qt::IntersectClip:
       
  1591         {
       
  1592             s->clipRegion = s->clipRegion.intersect(d->transform.map(QRegion(rect)));
       
  1593         }
       
  1594         break;
       
  1595 
       
  1596         case Qt::UniteClip:
       
  1597         {
       
  1598             s->clipRegion = s->clipRegion.unite(d->transform.map(QRegion(rect)));
       
  1599         }
       
  1600         break;
       
  1601     }
       
  1602 
       
  1603     updateScissor();
       
  1604 }
       
  1605 
       
  1606 void QVGPaintEngine::clip(const QRegion &region, Qt::ClipOperation op)
       
  1607 {
       
  1608     Q_D(QVGPaintEngine);
       
  1609     QVGPainterState *s = state();
       
  1610 
       
  1611     d->dirty |= QPaintEngine::DirtyClipRegion;
       
  1612 
       
  1613     // If we have a non-simple transform, then use path-based clipping.
       
  1614     if (op != Qt::NoClip && !clipTransformIsSimple(d->transform)) {
       
  1615         QPaintEngineEx::clip(region, op);
       
  1616         return;
       
  1617     }
       
  1618 
       
  1619     switch (op) {
       
  1620         case Qt::NoClip:
       
  1621         {
       
  1622             s->clipRegion = defaultClipRegion();
       
  1623         }
       
  1624         break;
       
  1625 
       
  1626         case Qt::ReplaceClip:
       
  1627         {
       
  1628             s->clipRegion = d->transform.map(region);
       
  1629         }
       
  1630         break;
       
  1631 
       
  1632         case Qt::IntersectClip:
       
  1633         {
       
  1634             s->clipRegion = s->clipRegion.intersect(d->transform.map(region));
       
  1635         }
       
  1636         break;
       
  1637 
       
  1638         case Qt::UniteClip:
       
  1639         {
       
  1640             s->clipRegion = s->clipRegion.unite(d->transform.map(region));
       
  1641         }
       
  1642         break;
       
  1643     }
       
  1644 
       
  1645     updateScissor();
       
  1646 }
       
  1647 
       
  1648 void QVGPaintEngine::clip(const QPainterPath &path, Qt::ClipOperation op)
       
  1649 {
       
  1650     QPaintEngineEx::clip(path, op);
       
  1651 }
       
  1652 
       
  1653 #else // !QVG_SCISSOR_CLIP
       
  1654 
       
  1655 void QVGPaintEngine::clip(const QVectorPath &path, Qt::ClipOperation op)
       
  1656 {
       
  1657     Q_D(QVGPaintEngine);
       
  1658 
       
  1659     d->dirty |= QPaintEngine::DirtyClipRegion;
       
  1660 
       
  1661     if (op == Qt::NoClip) {
       
  1662         d->maskValid = false;
       
  1663         d->maskIsSet = true;
       
  1664         d->maskRect = QRect();
       
  1665         vgSeti(VG_MASKING, VG_FALSE);
       
  1666         return;
       
  1667     }
       
  1668 
       
  1669 #if defined(QVG_NO_RENDER_TO_MASK)
       
  1670     // We don't have vgRenderToMask(), so handle simple QRectF's only.
       
  1671     if (path.shape() == QVectorPath::RectangleHint &&
       
  1672             path.elementCount() == 4 && clipTransformIsSimple(d->transform)) {
       
  1673         // Clipping region that resulted from QPainter::setClipRect(QRectF).
       
  1674         // Convert it into a QRect and apply.
       
  1675         const qreal *points = path.points();
       
  1676         QRectF rect(points[0], points[1], points[2] - points[0],
       
  1677                     points[5] - points[1]);
       
  1678         clip(rect.toRect(), op);
       
  1679     }
       
  1680 #else
       
  1681     QPaintDevice *pdev = paintDevice();
       
  1682     int width = pdev->width();
       
  1683     int height = pdev->height();
       
  1684 
       
  1685     if (op == Qt::ReplaceClip) {
       
  1686         vgMask(VG_INVALID_HANDLE, VG_CLEAR_MASK, 0, 0, width, height);
       
  1687         d->maskRect = QRect();
       
  1688     } else if (!d->maskValid) {
       
  1689         d->ensureMask(this, width, height);
       
  1690     }
       
  1691 
       
  1692     d->ensurePathTransform();
       
  1693     VGPath vgpath = d->vectorPathToVGPath(path);
       
  1694     switch (op) {
       
  1695         case Qt::ReplaceClip:
       
  1696         case Qt::UniteClip:
       
  1697             vgRenderToMask(vgpath, VG_FILL_PATH, VG_UNION_MASK);
       
  1698             break;
       
  1699 
       
  1700         case Qt::IntersectClip:
       
  1701             vgRenderToMask(vgpath, VG_FILL_PATH, VG_INTERSECT_MASK);
       
  1702             break;
       
  1703 
       
  1704         default: break;
       
  1705     }
       
  1706     vgDestroyPath(vgpath);
       
  1707 
       
  1708     vgSeti(VG_MASKING, VG_TRUE);
       
  1709     d->maskValid = true;
       
  1710     d->maskIsSet = false;
       
  1711 #endif
       
  1712 }
       
  1713 
       
  1714 void QVGPaintEngine::clip(const QRect &rect, Qt::ClipOperation op)
       
  1715 {
       
  1716     Q_D(QVGPaintEngine);
       
  1717 
       
  1718     d->dirty |= QPaintEngine::DirtyClipRegion;
       
  1719 
       
  1720     // If we have a non-simple transform, then use path-based clipping.
       
  1721     if (op != Qt::NoClip && !clipTransformIsSimple(d->transform)) {
       
  1722         QPaintEngineEx::clip(rect, op);
       
  1723         return;
       
  1724     }
       
  1725 
       
  1726     switch (op) {
       
  1727         case Qt::NoClip:
       
  1728         {
       
  1729             d->maskValid = false;
       
  1730             d->maskIsSet = true;
       
  1731             d->maskRect = QRect();
       
  1732             vgSeti(VG_MASKING, VG_FALSE);
       
  1733         }
       
  1734         break;
       
  1735 
       
  1736         case Qt::ReplaceClip:
       
  1737         {
       
  1738             QRect r = d->transform.mapRect(rect);
       
  1739             if (isDefaultClipRect(r)) {
       
  1740                 // Replacing the clip with a full-window region is the
       
  1741                 // same as turning off clipping.
       
  1742                 if (d->maskValid)
       
  1743                     vgSeti(VG_MASKING, VG_FALSE);
       
  1744                 d->maskValid = false;
       
  1745                 d->maskIsSet = true;
       
  1746                 d->maskRect = QRect();
       
  1747             } else {
       
  1748                 // Special case: if the intersection of the system
       
  1749                 // clip and "r" is a single rectangle, then use the
       
  1750                 // scissor for clipping.  We try to avoid allocating a
       
  1751                 // QRegion copy on the heap for the test if we can.
       
  1752                 QRegion clip = d->systemClip; // Reference-counted, no alloc.
       
  1753                 QRect clipRect;
       
  1754                 if (clip.numRects() == 1) {
       
  1755                     clipRect = clip.boundingRect().intersected(r);
       
  1756                 } else if (clip.isEmpty()) {
       
  1757                     clipRect = r;
       
  1758                 } else {
       
  1759                     clip = clip.intersect(r);
       
  1760                     if (clip.numRects() != 1) {
       
  1761                         d->maskValid = false;
       
  1762                         d->maskIsSet = false;
       
  1763                         d->maskRect = QRect();
       
  1764                         d->modifyMask(this, VG_FILL_MASK, r);
       
  1765                         break;
       
  1766                     }
       
  1767                     clipRect = clip.boundingRect();
       
  1768                 }
       
  1769                 d->maskValid = false;
       
  1770                 d->maskIsSet = false;
       
  1771                 d->maskRect = clipRect;
       
  1772                 vgSeti(VG_MASKING, VG_FALSE);
       
  1773                 updateScissor();
       
  1774             }
       
  1775         }
       
  1776         break;
       
  1777 
       
  1778         case Qt::IntersectClip:
       
  1779         {
       
  1780             QRect r = d->transform.mapRect(rect);
       
  1781             if (d->maskIsSet && isDefaultClipRect(r)) {
       
  1782                 // Intersecting a full-window clip with a full-window
       
  1783                 // region is the same as turning off clipping.
       
  1784                 if (d->maskValid)
       
  1785                     vgSeti(VG_MASKING, VG_FALSE);
       
  1786                 d->maskValid = false;
       
  1787                 d->maskIsSet = true;
       
  1788                 d->maskRect = QRect();
       
  1789             } else {
       
  1790                 d->modifyMask(this, VG_INTERSECT_MASK, r);
       
  1791             }
       
  1792         }
       
  1793         break;
       
  1794 
       
  1795         case Qt::UniteClip:
       
  1796         {
       
  1797             // If we already have a full-window clip, then uniting a
       
  1798             // region with it will do nothing.  Otherwise union.
       
  1799             if (!(d->maskIsSet))
       
  1800                 d->modifyMask(this, VG_UNION_MASK, d->transform.mapRect(rect));
       
  1801         }
       
  1802         break;
       
  1803     }
       
  1804 }
       
  1805 
       
  1806 void QVGPaintEngine::clip(const QRegion &region, Qt::ClipOperation op)
       
  1807 {
       
  1808     Q_D(QVGPaintEngine);
       
  1809 
       
  1810     // Use the QRect case if the region consists of a single rectangle.
       
  1811     if (region.numRects() == 1) {
       
  1812         clip(region.boundingRect(), op);
       
  1813         return;
       
  1814     }
       
  1815 
       
  1816     d->dirty |= QPaintEngine::DirtyClipRegion;
       
  1817 
       
  1818     // If we have a non-simple transform, then use path-based clipping.
       
  1819     if (op != Qt::NoClip && !clipTransformIsSimple(d->transform)) {
       
  1820         QPaintEngineEx::clip(region, op);
       
  1821         return;
       
  1822     }
       
  1823 
       
  1824     switch (op) {
       
  1825         case Qt::NoClip:
       
  1826         {
       
  1827             d->maskValid = false;
       
  1828             d->maskIsSet = true;
       
  1829             d->maskRect = QRect();
       
  1830             vgSeti(VG_MASKING, VG_FALSE);
       
  1831         }
       
  1832         break;
       
  1833 
       
  1834         case Qt::ReplaceClip:
       
  1835         {
       
  1836             QRegion r = d->transform.map(region);
       
  1837             if (isDefaultClipRegion(r)) {
       
  1838                 // Replacing the clip with a full-window region is the
       
  1839                 // same as turning off clipping.
       
  1840                 if (d->maskValid)
       
  1841                     vgSeti(VG_MASKING, VG_FALSE);
       
  1842                 d->maskValid = false;
       
  1843                 d->maskIsSet = true;
       
  1844                 d->maskRect = QRect();
       
  1845             } else {
       
  1846                 // Special case: if the intersection of the system
       
  1847                 // clip and the region is a single rectangle, then
       
  1848                 // use the scissor for clipping.
       
  1849                 QRegion clip = d->systemClip;
       
  1850                 if (clip.isEmpty())
       
  1851                     clip = r;
       
  1852                 else
       
  1853                     clip = clip.intersect(r);
       
  1854                 if (clip.numRects() == 1) {
       
  1855                     d->maskValid = false;
       
  1856                     d->maskIsSet = false;
       
  1857                     d->maskRect = clip.boundingRect();
       
  1858                     vgSeti(VG_MASKING, VG_FALSE);
       
  1859                     updateScissor();
       
  1860                 } else {
       
  1861                     d->maskValid = false;
       
  1862                     d->maskIsSet = false;
       
  1863                     d->maskRect = QRect();
       
  1864                     d->modifyMask(this, VG_FILL_MASK, r);
       
  1865                 }
       
  1866             }
       
  1867         }
       
  1868         break;
       
  1869 
       
  1870         case Qt::IntersectClip:
       
  1871         {
       
  1872             if (region.numRects() != 1) {
       
  1873                 // If there is more than one rectangle, then intersecting
       
  1874                 // the rectangles one by one in modifyMask() will not give
       
  1875                 // the desired result.  So fall back to path-based clipping.
       
  1876                 QPaintEngineEx::clip(region, op);
       
  1877                 return;
       
  1878             }
       
  1879             QRegion r = d->transform.map(region);
       
  1880             if (d->maskIsSet && isDefaultClipRegion(r)) {
       
  1881                 // Intersecting a full-window clip with a full-window
       
  1882                 // region is the same as turning off clipping.
       
  1883                 if (d->maskValid)
       
  1884                     vgSeti(VG_MASKING, VG_FALSE);
       
  1885                 d->maskValid = false;
       
  1886                 d->maskIsSet = true;
       
  1887                 d->maskRect = QRect();
       
  1888             } else {
       
  1889                 d->modifyMask(this, VG_INTERSECT_MASK, r);
       
  1890             }
       
  1891         }
       
  1892         break;
       
  1893 
       
  1894         case Qt::UniteClip:
       
  1895         {
       
  1896             // If we already have a full-window clip, then uniting a
       
  1897             // region with it will do nothing.  Otherwise union.
       
  1898             if (!(d->maskIsSet))
       
  1899                 d->modifyMask(this, VG_UNION_MASK, d->transform.map(region));
       
  1900         }
       
  1901         break;
       
  1902     }
       
  1903 }
       
  1904 
       
  1905 #if !defined(QVG_NO_RENDER_TO_MASK)
       
  1906 
       
  1907 // Copied from qpathclipper.cpp.
       
  1908 static bool qt_vg_pathToRect(const QPainterPath &path, QRectF *rect)
       
  1909 {
       
  1910     if (path.elementCount() != 5)
       
  1911         return false;
       
  1912 
       
  1913     const bool mightBeRect = path.elementAt(0).isMoveTo()
       
  1914         && path.elementAt(1).isLineTo()
       
  1915         && path.elementAt(2).isLineTo()
       
  1916         && path.elementAt(3).isLineTo()
       
  1917         && path.elementAt(4).isLineTo();
       
  1918 
       
  1919     if (!mightBeRect)
       
  1920         return false;
       
  1921 
       
  1922     const qreal x1 = path.elementAt(0).x;
       
  1923     const qreal y1 = path.elementAt(0).y;
       
  1924 
       
  1925     const qreal x2 = path.elementAt(1).x;
       
  1926     const qreal y2 = path.elementAt(2).y;
       
  1927 
       
  1928     if (path.elementAt(1).y != y1)
       
  1929         return false;
       
  1930 
       
  1931     if (path.elementAt(2).x != x2)
       
  1932         return false;
       
  1933 
       
  1934     if (path.elementAt(3).x != x1 || path.elementAt(3).y != y2)
       
  1935         return false;
       
  1936 
       
  1937     if (path.elementAt(4).x != x1 || path.elementAt(4).y != y1)
       
  1938         return false;
       
  1939 
       
  1940     if (rect)
       
  1941         *rect = QRectF(QPointF(x1, y1), QPointF(x2, y2));
       
  1942 
       
  1943     return true;
       
  1944 }
       
  1945 
       
  1946 #endif
       
  1947 
       
  1948 void QVGPaintEngine::clip(const QPainterPath &path, Qt::ClipOperation op)
       
  1949 {
       
  1950 #if !defined(QVG_NO_RENDER_TO_MASK)
       
  1951     Q_D(QVGPaintEngine);
       
  1952 
       
  1953     // If the path is a simple rectangle, then use clip(QRect) instead.
       
  1954     QRectF simpleRect;
       
  1955     if (qt_vg_pathToRect(path, &simpleRect)) {
       
  1956         clip(simpleRect.toRect(), op);
       
  1957         return;
       
  1958     }
       
  1959 
       
  1960     d->dirty |= QPaintEngine::DirtyClipRegion;
       
  1961 
       
  1962     if (op == Qt::NoClip) {
       
  1963         d->maskValid = false;
       
  1964         d->maskIsSet = true;
       
  1965         d->maskRect = QRect();
       
  1966         vgSeti(VG_MASKING, VG_FALSE);
       
  1967         return;
       
  1968     }
       
  1969 
       
  1970     QPaintDevice *pdev = paintDevice();
       
  1971     int width = pdev->width();
       
  1972     int height = pdev->height();
       
  1973 
       
  1974     if (op == Qt::ReplaceClip) {
       
  1975         vgMask(VG_INVALID_HANDLE, VG_CLEAR_MASK, 0, 0, width, height);
       
  1976         d->maskRect = QRect();
       
  1977     } else if (!d->maskValid) {
       
  1978         d->ensureMask(this, width, height);
       
  1979     }
       
  1980 
       
  1981     d->ensurePathTransform();
       
  1982     VGPath vgpath = d->painterPathToVGPath(path);
       
  1983     switch (op) {
       
  1984         case Qt::ReplaceClip:
       
  1985         case Qt::UniteClip:
       
  1986             vgRenderToMask(vgpath, VG_FILL_PATH, VG_UNION_MASK);
       
  1987             break;
       
  1988 
       
  1989         case Qt::IntersectClip:
       
  1990             vgRenderToMask(vgpath, VG_FILL_PATH, VG_INTERSECT_MASK);
       
  1991             break;
       
  1992 
       
  1993         default: break;
       
  1994     }
       
  1995     vgDestroyPath(vgpath);
       
  1996 
       
  1997     vgSeti(VG_MASKING, VG_TRUE);
       
  1998     d->maskValid = true;
       
  1999     d->maskIsSet = false;
       
  2000 #else
       
  2001     QPaintEngineEx::clip(path, op);
       
  2002 #endif
       
  2003 }
       
  2004 
       
  2005 void QVGPaintEnginePrivate::ensureMask
       
  2006         (QVGPaintEngine *engine, int width, int height)
       
  2007 {
       
  2008     if (maskIsSet) {
       
  2009         vgMask(VG_INVALID_HANDLE, VG_FILL_MASK, 0, 0, width, height);
       
  2010         maskRect = QRect();
       
  2011     } else {
       
  2012         vgMask(VG_INVALID_HANDLE, VG_CLEAR_MASK, 0, 0, width, height);
       
  2013         if (maskRect.isValid()) {
       
  2014             vgMask(VG_INVALID_HANDLE, VG_FILL_MASK,
       
  2015                    maskRect.x(), height - maskRect.y() - maskRect.height(),
       
  2016                    maskRect.width(), maskRect.height());
       
  2017             maskRect = QRect();
       
  2018             engine->updateScissor();
       
  2019         }
       
  2020     }
       
  2021 }
       
  2022 
       
  2023 void QVGPaintEnginePrivate::modifyMask
       
  2024         (QVGPaintEngine *engine, VGMaskOperation op, const QRegion& region)
       
  2025 {
       
  2026     QPaintDevice *pdev = engine->paintDevice();
       
  2027     int width = pdev->width();
       
  2028     int height = pdev->height();
       
  2029 
       
  2030     if (!maskValid)
       
  2031         ensureMask(engine, width, height);
       
  2032 
       
  2033     QVector<QRect> rects = region.rects();
       
  2034     for (int i = 0; i < rects.size(); ++i) {
       
  2035         vgMask(VG_INVALID_HANDLE, op,
       
  2036                rects[i].x(), height - rects[i].y() - rects[i].height(),
       
  2037                rects[i].width(), rects[i].height());
       
  2038     }
       
  2039 
       
  2040     vgSeti(VG_MASKING, VG_TRUE);
       
  2041     maskValid = true;
       
  2042     maskIsSet = false;
       
  2043 }
       
  2044 
       
  2045 void QVGPaintEnginePrivate::modifyMask
       
  2046         (QVGPaintEngine *engine, VGMaskOperation op, const QRect& rect)
       
  2047 {
       
  2048     QPaintDevice *pdev = engine->paintDevice();
       
  2049     int width = pdev->width();
       
  2050     int height = pdev->height();
       
  2051 
       
  2052     if (!maskValid)
       
  2053         ensureMask(engine, width, height);
       
  2054 
       
  2055     if (rect.isValid()) {
       
  2056         vgMask(VG_INVALID_HANDLE, op,
       
  2057                rect.x(), height - rect.y() - rect.height(),
       
  2058                rect.width(), rect.height());
       
  2059     }
       
  2060 
       
  2061     vgSeti(VG_MASKING, VG_TRUE);
       
  2062     maskValid = true;
       
  2063     maskIsSet = false;
       
  2064 }
       
  2065 
       
  2066 #endif // !QVG_SCISSOR_CLIP
       
  2067 
       
  2068 void QVGPaintEngine::updateScissor()
       
  2069 {
       
  2070     Q_D(QVGPaintEngine);
       
  2071 
       
  2072     QRegion region = d->systemClip;
       
  2073 
       
  2074 #if defined(QVG_SCISSOR_CLIP)
       
  2075     // Using the scissor to do clipping, so combine the systemClip
       
  2076     // with the current painting clipRegion.
       
  2077     QVGPainterState *s = state();
       
  2078     if (s->clipEnabled) {
       
  2079         if (region.isEmpty())
       
  2080             region = s->clipRegion;
       
  2081         else
       
  2082             region = region.intersect(s->clipRegion);
       
  2083         if (isDefaultClipRegion(region)) {
       
  2084             // The scissor region is the entire drawing surface,
       
  2085             // so there is no point doing any scissoring.
       
  2086             vgSeti(VG_SCISSORING, VG_FALSE);
       
  2087             d->scissorActive = false;
       
  2088             return;
       
  2089         }
       
  2090     } else
       
  2091 #endif
       
  2092     {
       
  2093 #if !defined(QVG_SCISSOR_CLIP)
       
  2094         // Combine the system clip with the simple mask rectangle.
       
  2095         if (!d->maskRect.isNull()) {
       
  2096             if (region.isEmpty())
       
  2097                 region = d->maskRect;
       
  2098             else
       
  2099                 region = region.intersect(d->maskRect);
       
  2100             if (isDefaultClipRegion(region)) {
       
  2101                 // The scissor region is the entire drawing surface,
       
  2102                 // so there is no point doing any scissoring.
       
  2103                 vgSeti(VG_SCISSORING, VG_FALSE);
       
  2104                 d->scissorActive = false;
       
  2105                 return;
       
  2106             }
       
  2107         } else
       
  2108 #endif
       
  2109 
       
  2110         // Disable the scissor completely if the system clip is empty.
       
  2111         if (region.isEmpty()) {
       
  2112             vgSeti(VG_SCISSORING, VG_FALSE);
       
  2113             d->scissorActive = false;
       
  2114             return;
       
  2115         }
       
  2116     }
       
  2117 
       
  2118     if (d->scissorActive && region == d->scissorRegion)
       
  2119         return;
       
  2120 
       
  2121     QVector<QRect> rects = region.rects();
       
  2122     int count = rects.count();
       
  2123     if (count > d->maxScissorRects)
       
  2124         count = d->maxScissorRects;
       
  2125     QVarLengthArray<VGint> params(count * 4);
       
  2126     int height = paintDevice()->height();
       
  2127     for (int i = 0; i < count; ++i) {
       
  2128         params[i * 4 + 0] = rects[i].x();
       
  2129         params[i * 4 + 1] = height - rects[i].y() - rects[i].height();
       
  2130         params[i * 4 + 2] = rects[i].width();
       
  2131         params[i * 4 + 3] = rects[i].height();
       
  2132     }
       
  2133 
       
  2134     vgSetiv(VG_SCISSOR_RECTS, count * 4, params.data());
       
  2135     vgSeti(VG_SCISSORING, VG_TRUE);
       
  2136     d->scissorActive = true;
       
  2137     d->scissorRegion = region;
       
  2138 }
       
  2139 
       
  2140 QRegion QVGPaintEngine::defaultClipRegion()
       
  2141 {
       
  2142     // The default clip region for a paint device is the whole drawing area.
       
  2143     QPaintDevice *pdev = paintDevice();
       
  2144     return QRegion(0, 0, pdev->width(), pdev->height());
       
  2145 }
       
  2146 
       
  2147 bool QVGPaintEngine::isDefaultClipRegion(const QRegion& region)
       
  2148 {
       
  2149     if (region.numRects() != 1)
       
  2150         return false;
       
  2151 
       
  2152     QPaintDevice *pdev = paintDevice();
       
  2153     int width = pdev->width();
       
  2154     int height = pdev->height();
       
  2155 
       
  2156     QRect rect = region.boundingRect();
       
  2157     return (rect.x() == 0 && rect.y() == 0 &&
       
  2158             rect.width() == width && rect.height() == height);
       
  2159 }
       
  2160 
       
  2161 bool QVGPaintEngine::isDefaultClipRect(const QRect& rect)
       
  2162 {
       
  2163     QPaintDevice *pdev = paintDevice();
       
  2164     int width = pdev->width();
       
  2165     int height = pdev->height();
       
  2166 
       
  2167     return (rect.x() == 0 && rect.y() == 0 &&
       
  2168             rect.width() == width && rect.height() == height);
       
  2169 }
       
  2170 
       
  2171 void QVGPaintEngine::clipEnabledChanged()
       
  2172 {
       
  2173 #if defined(QVG_SCISSOR_CLIP)
       
  2174     updateScissor();
       
  2175 #else
       
  2176     Q_D(QVGPaintEngine);
       
  2177     QVGPainterState *s = state();
       
  2178     d->dirty |= QPaintEngine::DirtyClipEnabled;
       
  2179     if (s->clipEnabled && s->clipOperation != Qt::NoClip) {
       
  2180         // Replay the entire clip stack to put the mask into the right state.
       
  2181         d->maskValid = false;
       
  2182         d->maskIsSet = true;
       
  2183         d->maskRect = QRect();
       
  2184         s->clipRegion = defaultClipRegion();
       
  2185         d->replayClipOperations();
       
  2186         d->transform = s->transform();
       
  2187         d->updateTransform(paintDevice());
       
  2188     } else {
       
  2189         vgSeti(VG_MASKING, VG_FALSE);
       
  2190         d->maskValid = false;
       
  2191         d->maskIsSet = false;
       
  2192         d->maskRect = QRect();
       
  2193     }
       
  2194 #endif
       
  2195 }
       
  2196 
       
  2197 void QVGPaintEngine::penChanged()
       
  2198 {
       
  2199     Q_D(QVGPaintEngine);
       
  2200     d->dirty |= QPaintEngine::DirtyPen;
       
  2201 }
       
  2202 
       
  2203 void QVGPaintEngine::brushChanged()
       
  2204 {
       
  2205     Q_D(QVGPaintEngine);
       
  2206     d->dirty |= QPaintEngine::DirtyBrush;
       
  2207 }
       
  2208 
       
  2209 void QVGPaintEngine::brushOriginChanged()
       
  2210 {
       
  2211     Q_D(QVGPaintEngine);
       
  2212     d->dirty |= QPaintEngine::DirtyBrushOrigin;
       
  2213     d->brushOrigin = state()->brushOrigin;
       
  2214     d->forcePenChange = true;
       
  2215     d->forceBrushChange = true;
       
  2216 }
       
  2217 
       
  2218 void QVGPaintEngine::opacityChanged()
       
  2219 {
       
  2220     Q_D(QVGPaintEngine);
       
  2221     d->dirty |= QPaintEngine::DirtyOpacity;
       
  2222     d->opacity = state()->opacity;
       
  2223     d->forcePenChange = true;
       
  2224     d->forceBrushChange = true;
       
  2225 }
       
  2226 
       
  2227 void QVGPaintEngine::compositionModeChanged()
       
  2228 {
       
  2229     Q_D(QVGPaintEngine);
       
  2230     d->dirty |= QPaintEngine::DirtyCompositionMode;
       
  2231 
       
  2232     VGBlendMode vgMode = VG_BLEND_SRC_OVER;
       
  2233 
       
  2234     switch (state()->composition_mode) {
       
  2235     case QPainter::CompositionMode_SourceOver:
       
  2236         vgMode = VG_BLEND_SRC_OVER;
       
  2237         break;
       
  2238     case QPainter::CompositionMode_DestinationOver:
       
  2239         vgMode = VG_BLEND_DST_OVER;
       
  2240         break;
       
  2241     case QPainter::CompositionMode_Source:
       
  2242         vgMode = VG_BLEND_SRC;
       
  2243         break;
       
  2244     case QPainter::CompositionMode_SourceIn:
       
  2245         vgMode = VG_BLEND_SRC_IN;
       
  2246         break;
       
  2247     case QPainter::CompositionMode_DestinationIn:
       
  2248         vgMode = VG_BLEND_DST_IN;
       
  2249         break;
       
  2250     case QPainter::CompositionMode_Plus:
       
  2251         vgMode = VG_BLEND_ADDITIVE;
       
  2252         break;
       
  2253     case QPainter::CompositionMode_Multiply:
       
  2254         vgMode = VG_BLEND_MULTIPLY;
       
  2255         break;
       
  2256     case QPainter::CompositionMode_Screen:
       
  2257         vgMode = VG_BLEND_SCREEN;
       
  2258         break;
       
  2259     case QPainter::CompositionMode_Darken:
       
  2260         vgMode = VG_BLEND_DARKEN;
       
  2261         break;
       
  2262     case QPainter::CompositionMode_Lighten:
       
  2263         vgMode = VG_BLEND_LIGHTEN;
       
  2264         break;
       
  2265     default:
       
  2266         qWarning() << "QVGPaintEngine::compositionModeChanged unsupported mode" << state()->composition_mode;
       
  2267         break;  // Fall back to VG_BLEND_SRC_OVER.
       
  2268     }
       
  2269 
       
  2270     d->setBlendMode(vgMode);
       
  2271 }
       
  2272 
       
  2273 void QVGPaintEngine::renderHintsChanged()
       
  2274 {
       
  2275     Q_D(QVGPaintEngine);
       
  2276     d->dirty |= QPaintEngine::DirtyHints;
       
  2277 
       
  2278     QPainter::RenderHints hints = state()->renderHints;
       
  2279 
       
  2280     VGRenderingQuality rq =
       
  2281             (hints & QPainter::Antialiasing)
       
  2282                 ? VG_RENDERING_QUALITY_BETTER
       
  2283                 : VG_RENDERING_QUALITY_NONANTIALIASED;
       
  2284     VGImageQuality iq =
       
  2285             (hints & QPainter::SmoothPixmapTransform)
       
  2286                 ? VG_IMAGE_QUALITY_BETTER
       
  2287                 : VG_IMAGE_QUALITY_NONANTIALIASED;
       
  2288 
       
  2289     d->setRenderingQuality(rq);
       
  2290     d->setImageQuality(iq);
       
  2291 }
       
  2292 
       
  2293 void QVGPaintEngine::transformChanged()
       
  2294 {
       
  2295     Q_D(QVGPaintEngine);
       
  2296     QVGPainterState *s = state();
       
  2297     d->dirty |= QPaintEngine::DirtyTransform;
       
  2298     d->transform = s->transform();
       
  2299     qreal oldPenScale = d->penScale;
       
  2300     d->updateTransform(paintDevice());
       
  2301     if (d->penScale != oldPenScale)
       
  2302         d->forcePenChange = true;
       
  2303 }
       
  2304 
       
  2305 bool QVGPaintEngine::clearRect(const QRectF &rect, const QColor &color)
       
  2306 {
       
  2307     Q_D(QVGPaintEngine);
       
  2308     QVGPainterState *s = state();
       
  2309     if (!s->clipEnabled || s->clipOperation == Qt::NoClip) {
       
  2310         // The transform will either be identity or a simple translation,
       
  2311         // so do a simpler version of "r = d->transform.map(rect).toRect()".
       
  2312         QRect r = QRect(qRound(rect.x() + d->transform.dx()),
       
  2313                         qRound(rect.y() + d->transform.dy()),
       
  2314                         qRound(rect.width()),
       
  2315                         qRound(rect.height()));
       
  2316         int height = paintDevice()->height();
       
  2317         if (d->clearColor != color || d->clearOpacity != s->opacity) {
       
  2318             VGfloat values[4];
       
  2319             values[0] = color.redF();
       
  2320             values[1] = color.greenF();
       
  2321             values[2] = color.blueF();
       
  2322             values[3] = color.alphaF() * s->opacity;
       
  2323             vgSetfv(VG_CLEAR_COLOR, 4, values);
       
  2324             d->clearColor = color;
       
  2325             d->clearOpacity = s->opacity;
       
  2326         }
       
  2327         vgClear(r.x(), height - r.y() - r.height(),
       
  2328                 r.width(), r.height());
       
  2329         return true;
       
  2330     }
       
  2331     return false;
       
  2332 }
       
  2333 
       
  2334 void QVGPaintEngine::fillRect(const QRectF &rect, const QBrush &brush)
       
  2335 {
       
  2336     Q_D(QVGPaintEngine);
       
  2337 
       
  2338     if (brush.style() == Qt::NoBrush)
       
  2339         return;
       
  2340 
       
  2341     // Check to see if we can use vgClear() for faster filling.
       
  2342     if (brush.style() == Qt::SolidPattern &&
       
  2343             clipTransformIsSimple(d->transform) && d->opacity == 1.0f &&
       
  2344             clearRect(rect, brush.color())) {
       
  2345         return;
       
  2346     }
       
  2347 
       
  2348 #if !defined(QVG_NO_MODIFY_PATH)
       
  2349     VGfloat coords[8];
       
  2350     if (d->simpleTransform) {
       
  2351         coords[0] = rect.x();
       
  2352         coords[1] = rect.y();
       
  2353         coords[2] = rect.x() + rect.width();
       
  2354         coords[3] = coords[1];
       
  2355         coords[4] = coords[2];
       
  2356         coords[5] = rect.y() + rect.height();
       
  2357         coords[6] = coords[0];
       
  2358         coords[7] = coords[5];
       
  2359     } else {
       
  2360         QPointF tl = d->transform.map(rect.topLeft());
       
  2361         QPointF tr = d->transform.map(rect.topRight());
       
  2362         QPointF bl = d->transform.map(rect.bottomLeft());
       
  2363         QPointF br = d->transform.map(rect.bottomRight());
       
  2364         coords[0] = tl.x();
       
  2365         coords[1] = tl.y();
       
  2366         coords[2] = tr.x();
       
  2367         coords[3] = tr.y();
       
  2368         coords[4] = br.x();
       
  2369         coords[5] = br.y();
       
  2370         coords[6] = bl.x();
       
  2371         coords[7] = bl.y();
       
  2372     }
       
  2373     vgModifyPathCoords(d->rectPath, 0, 4, coords);
       
  2374     d->fill(d->rectPath, brush);
       
  2375 #else
       
  2376     QPaintEngineEx::fillRect(rect, brush);
       
  2377 #endif
       
  2378 }
       
  2379 
       
  2380 void QVGPaintEngine::fillRect(const QRectF &rect, const QColor &color)
       
  2381 {
       
  2382     Q_D(QVGPaintEngine);
       
  2383 
       
  2384     // Check to see if we can use vgClear() for faster filling.
       
  2385     if (clipTransformIsSimple(d->transform) && d->opacity == 1.0f &&
       
  2386             clearRect(rect, color)) {
       
  2387         return;
       
  2388     }
       
  2389 
       
  2390 #if !defined(QVG_NO_MODIFY_PATH)
       
  2391     VGfloat coords[8];
       
  2392     if (d->simpleTransform) {
       
  2393         coords[0] = rect.x();
       
  2394         coords[1] = rect.y();
       
  2395         coords[2] = rect.x() + rect.width();
       
  2396         coords[3] = coords[1];
       
  2397         coords[4] = coords[2];
       
  2398         coords[5] = rect.y() + rect.height();
       
  2399         coords[6] = coords[0];
       
  2400         coords[7] = coords[5];
       
  2401     } else {
       
  2402         QPointF tl = d->transform.map(rect.topLeft());
       
  2403         QPointF tr = d->transform.map(rect.topRight());
       
  2404         QPointF bl = d->transform.map(rect.bottomLeft());
       
  2405         QPointF br = d->transform.map(rect.bottomRight());
       
  2406         coords[0] = tl.x();
       
  2407         coords[1] = tl.y();
       
  2408         coords[2] = tr.x();
       
  2409         coords[3] = tr.y();
       
  2410         coords[4] = br.x();
       
  2411         coords[5] = br.y();
       
  2412         coords[6] = bl.x();
       
  2413         coords[7] = bl.y();
       
  2414     }
       
  2415     vgModifyPathCoords(d->rectPath, 0, 4, coords);
       
  2416     d->fill(d->rectPath, QBrush(color));
       
  2417 #else
       
  2418     QPaintEngineEx::fillRect(rect, QBrush(color));
       
  2419 #endif
       
  2420 }
       
  2421 
       
  2422 void QVGPaintEngine::drawRoundedRect(const QRectF &rect, qreal xrad, qreal yrad, Qt::SizeMode mode)
       
  2423 {
       
  2424     Q_D(QVGPaintEngine);
       
  2425     if (d->simpleTransform) {
       
  2426         QVGPainterState *s = state();
       
  2427         VGPath vgpath = d->roundedRectPath(rect, xrad, yrad, mode);
       
  2428         d->draw(vgpath, s->pen, s->brush);
       
  2429 #if defined(QVG_NO_MODIFY_PATH)
       
  2430         vgDestroyPath(vgpath);
       
  2431 #endif
       
  2432     } else {
       
  2433         QPaintEngineEx::drawRoundedRect(rect, xrad, yrad, mode);
       
  2434     }
       
  2435 }
       
  2436 
       
  2437 void QVGPaintEngine::drawRects(const QRect *rects, int rectCount)
       
  2438 {
       
  2439 #if !defined(QVG_NO_MODIFY_PATH)
       
  2440     Q_D(QVGPaintEngine);
       
  2441     QVGPainterState *s = state();
       
  2442     for (int i = 0; i < rectCount; ++i, ++rects) {
       
  2443         VGfloat coords[8];
       
  2444         if (d->simpleTransform) {
       
  2445             coords[0] = rects->x();
       
  2446             coords[1] = rects->y();
       
  2447             coords[2] = rects->x() + rects->width();
       
  2448             coords[3] = coords[1];
       
  2449             coords[4] = coords[2];
       
  2450             coords[5] = rects->y() + rects->height();
       
  2451             coords[6] = coords[0];
       
  2452             coords[7] = coords[5];
       
  2453         } else {
       
  2454             QPointF tl = d->transform.map(QPointF(rects->x(), rects->y()));
       
  2455             QPointF tr = d->transform.map(QPointF(rects->x() + rects->width(),
       
  2456                                                   rects->y()));
       
  2457             QPointF bl = d->transform.map(QPointF(rects->x(),
       
  2458                                                   rects->y() + rects->height()));
       
  2459             QPointF br = d->transform.map(QPointF(rects->x() + rects->width(),
       
  2460                                                   rects->y() + rects->height()));
       
  2461             coords[0] = tl.x();
       
  2462             coords[1] = tl.y();
       
  2463             coords[2] = tr.x();
       
  2464             coords[3] = tr.y();
       
  2465             coords[4] = br.x();
       
  2466             coords[5] = br.y();
       
  2467             coords[6] = bl.x();
       
  2468             coords[7] = bl.y();
       
  2469         }
       
  2470         vgModifyPathCoords(d->rectPath, 0, 4, coords);
       
  2471         d->draw(d->rectPath, s->pen, s->brush);
       
  2472     }
       
  2473 #else
       
  2474     QPaintEngineEx::drawRects(rects, rectCount);
       
  2475 #endif
       
  2476 }
       
  2477 
       
  2478 void QVGPaintEngine::drawRects(const QRectF *rects, int rectCount)
       
  2479 {
       
  2480 #if !defined(QVG_NO_MODIFY_PATH)
       
  2481     Q_D(QVGPaintEngine);
       
  2482     QVGPainterState *s = state();
       
  2483     for (int i = 0; i < rectCount; ++i, ++rects) {
       
  2484         VGfloat coords[8];
       
  2485         if (d->simpleTransform) {
       
  2486             coords[0] = rects->x();
       
  2487             coords[1] = rects->y();
       
  2488             coords[2] = rects->x() + rects->width();
       
  2489             coords[3] = coords[1];
       
  2490             coords[4] = coords[2];
       
  2491             coords[5] = rects->y() + rects->height();
       
  2492             coords[6] = coords[0];
       
  2493             coords[7] = coords[5];
       
  2494         } else {
       
  2495             QPointF tl = d->transform.map(rects->topLeft());
       
  2496             QPointF tr = d->transform.map(rects->topRight());
       
  2497             QPointF bl = d->transform.map(rects->bottomLeft());
       
  2498             QPointF br = d->transform.map(rects->bottomRight());
       
  2499             coords[0] = tl.x();
       
  2500             coords[1] = tl.y();
       
  2501             coords[2] = tr.x();
       
  2502             coords[3] = tr.y();
       
  2503             coords[4] = br.x();
       
  2504             coords[5] = br.y();
       
  2505             coords[6] = bl.x();
       
  2506             coords[7] = bl.y();
       
  2507         }
       
  2508         vgModifyPathCoords(d->rectPath, 0, 4, coords);
       
  2509         d->draw(d->rectPath, s->pen, s->brush);
       
  2510     }
       
  2511 #else
       
  2512     QPaintEngineEx::drawRects(rects, rectCount);
       
  2513 #endif
       
  2514 }
       
  2515 
       
  2516 void QVGPaintEngine::drawLines(const QLine *lines, int lineCount)
       
  2517 {
       
  2518 #if !defined(QVG_NO_MODIFY_PATH)
       
  2519     Q_D(QVGPaintEngine);
       
  2520     QVGPainterState *s = state();
       
  2521     for (int i = 0; i < lineCount; ++i, ++lines) {
       
  2522         VGfloat coords[4];
       
  2523         if (d->simpleTransform) {
       
  2524             coords[0] = lines->x1();
       
  2525             coords[1] = lines->y1();
       
  2526             coords[2] = lines->x2();
       
  2527             coords[3] = lines->y2();
       
  2528         } else {
       
  2529             QPointF p1 = d->transform.map(QPointF(lines->x1(), lines->y1()));
       
  2530             QPointF p2 = d->transform.map(QPointF(lines->x2(), lines->y2()));
       
  2531             coords[0] = p1.x();
       
  2532             coords[1] = p1.y();
       
  2533             coords[2] = p2.x();
       
  2534             coords[3] = p2.y();
       
  2535         }
       
  2536         vgModifyPathCoords(d->linePath, 0, 2, coords);
       
  2537         d->stroke(d->linePath, s->pen);
       
  2538     }
       
  2539 #else
       
  2540     QPaintEngineEx::drawLines(lines, lineCount);
       
  2541 #endif
       
  2542 }
       
  2543 
       
  2544 void QVGPaintEngine::drawLines(const QLineF *lines, int lineCount)
       
  2545 {
       
  2546 #if !defined(QVG_NO_MODIFY_PATH)
       
  2547     Q_D(QVGPaintEngine);
       
  2548     QVGPainterState *s = state();
       
  2549     for (int i = 0; i < lineCount; ++i, ++lines) {
       
  2550         VGfloat coords[4];
       
  2551         if (d->simpleTransform) {
       
  2552             coords[0] = lines->x1();
       
  2553             coords[1] = lines->y1();
       
  2554             coords[2] = lines->x2();
       
  2555             coords[3] = lines->y2();
       
  2556         } else {
       
  2557             QPointF p1 = d->transform.map(lines->p1());
       
  2558             QPointF p2 = d->transform.map(lines->p2());
       
  2559             coords[0] = p1.x();
       
  2560             coords[1] = p1.y();
       
  2561             coords[2] = p2.x();
       
  2562             coords[3] = p2.y();
       
  2563         }
       
  2564         vgModifyPathCoords(d->linePath, 0, 2, coords);
       
  2565         d->stroke(d->linePath, s->pen);
       
  2566     }
       
  2567 #else
       
  2568     QPaintEngineEx::drawLines(lines, lineCount);
       
  2569 #endif
       
  2570 }
       
  2571 
       
  2572 void QVGPaintEngine::drawEllipse(const QRectF &r)
       
  2573 {
       
  2574     // Based on the description of vguEllipse() in the OpenVG specification.
       
  2575     // We don't use vguEllipse(), to avoid unnecessary library dependencies.
       
  2576     Q_D(QVGPaintEngine);
       
  2577     if (d->simpleTransform) {
       
  2578         QVGPainterState *s = state();
       
  2579         VGPath path = vgCreatePath(VG_PATH_FORMAT_STANDARD,
       
  2580                                    VG_PATH_DATATYPE_F,
       
  2581                                    1.0f, // scale
       
  2582                                    0.0f, // bias
       
  2583                                    4,    // segmentCapacityHint
       
  2584                                    12,   // coordCapacityHint
       
  2585                                    VG_PATH_CAPABILITY_ALL);
       
  2586         static VGubyte segments[4] = {
       
  2587             VG_MOVE_TO_ABS,
       
  2588             VG_SCCWARC_TO_REL,
       
  2589             VG_SCCWARC_TO_REL,
       
  2590             VG_CLOSE_PATH
       
  2591         };
       
  2592         VGfloat coords[12];
       
  2593         VGfloat halfwid = r.width() / 2;
       
  2594         VGfloat halfht = r.height() / 2;
       
  2595         coords[0]  = r.x() + r.width();
       
  2596         coords[1]  = r.y() + halfht;
       
  2597         coords[2]  = halfwid;
       
  2598         coords[3]  = halfht;
       
  2599         coords[4]  = 0.0f;
       
  2600         coords[5]  = -r.width();
       
  2601         coords[6]  = 0.0f;
       
  2602         coords[7]  = halfwid;
       
  2603         coords[8]  = halfht;
       
  2604         coords[9]  = 0.0f;
       
  2605         coords[10] = r.width();
       
  2606         coords[11] = 0.0f;
       
  2607         vgAppendPathData(path, 4, segments, coords);
       
  2608         d->draw(path, s->pen, s->brush);
       
  2609         vgDestroyPath(path);
       
  2610     } else {
       
  2611         // The projective transform version of an ellipse is difficult.
       
  2612         // Generate a QVectorPath containing cubic curves and transform that.
       
  2613         QPaintEngineEx::drawEllipse(r);
       
  2614     }
       
  2615 }
       
  2616 
       
  2617 void QVGPaintEngine::drawEllipse(const QRect &r)
       
  2618 {
       
  2619     drawEllipse(QRectF(r));
       
  2620 }
       
  2621 
       
  2622 void QVGPaintEngine::drawPath(const QPainterPath &path)
       
  2623 {
       
  2624     // Shortcut past the QPainterPath -> QVectorPath conversion,
       
  2625     // converting the QPainterPath directly into a VGPath.
       
  2626     Q_D(QVGPaintEngine);
       
  2627     QVGPainterState *s = state();
       
  2628     VGPath vgpath = d->painterPathToVGPath(path);
       
  2629     if (path.fillRule() == Qt::OddEvenFill)
       
  2630         d->draw(vgpath, s->pen, s->brush, VG_EVEN_ODD);
       
  2631     else
       
  2632         d->draw(vgpath, s->pen, s->brush, VG_NON_ZERO);
       
  2633     vgDestroyPath(vgpath);
       
  2634 }
       
  2635 
       
  2636 void QVGPaintEngine::drawPoints(const QPointF *points, int pointCount)
       
  2637 {
       
  2638 #if !defined(QVG_NO_MODIFY_PATH)
       
  2639     Q_D(QVGPaintEngine);
       
  2640 
       
  2641     // Set up a new pen if necessary.
       
  2642     QPen pen = state()->pen;
       
  2643     if (pen.style() == Qt::NoPen)
       
  2644         return;
       
  2645     if (pen.capStyle() == Qt::FlatCap)
       
  2646         pen.setCapStyle(Qt::SquareCap);
       
  2647 
       
  2648     for (int i = 0; i < pointCount; ++i, ++points) {
       
  2649         VGfloat coords[4];
       
  2650         if (d->simpleTransform) {
       
  2651             coords[0] = points->x();
       
  2652             coords[1] = points->y();
       
  2653             coords[2] = coords[0];
       
  2654             coords[3] = coords[1];
       
  2655         } else {
       
  2656             QPointF p = d->transform.map(*points);
       
  2657             coords[0] = p.x();
       
  2658             coords[1] = p.y();
       
  2659             coords[2] = coords[0];
       
  2660             coords[3] = coords[1];
       
  2661         }
       
  2662         vgModifyPathCoords(d->linePath, 0, 2, coords);
       
  2663         d->stroke(d->linePath, pen);
       
  2664     }
       
  2665 #else
       
  2666     QPaintEngineEx::drawPoints(points, pointCount);
       
  2667 #endif
       
  2668 }
       
  2669 
       
  2670 void QVGPaintEngine::drawPoints(const QPoint *points, int pointCount)
       
  2671 {
       
  2672 #if !defined(QVG_NO_MODIFY_PATH)
       
  2673     Q_D(QVGPaintEngine);
       
  2674 
       
  2675     // Set up a new pen if necessary.
       
  2676     QPen pen = state()->pen;
       
  2677     if (pen.style() == Qt::NoPen)
       
  2678         return;
       
  2679     if (pen.capStyle() == Qt::FlatCap)
       
  2680         pen.setCapStyle(Qt::SquareCap);
       
  2681 
       
  2682     for (int i = 0; i < pointCount; ++i, ++points) {
       
  2683         VGfloat coords[4];
       
  2684         if (d->simpleTransform) {
       
  2685             coords[0] = points->x();
       
  2686             coords[1] = points->y();
       
  2687             coords[2] = coords[0];
       
  2688             coords[3] = coords[1];
       
  2689         } else {
       
  2690             QPointF p = d->transform.map(QPointF(*points));
       
  2691             coords[0] = p.x();
       
  2692             coords[1] = p.y();
       
  2693             coords[2] = coords[0];
       
  2694             coords[3] = coords[1];
       
  2695         }
       
  2696         vgModifyPathCoords(d->linePath, 0, 2, coords);
       
  2697         d->stroke(d->linePath, pen);
       
  2698     }
       
  2699 #else
       
  2700     QPaintEngineEx::drawPoints(points, pointCount);
       
  2701 #endif
       
  2702 }
       
  2703 
       
  2704 void QVGPaintEngine::drawPolygon(const QPointF *points, int pointCount, PolygonDrawMode mode)
       
  2705 {
       
  2706     Q_D(QVGPaintEngine);
       
  2707     QVGPainterState *s = state();
       
  2708     VGPath path = vgCreatePath(VG_PATH_FORMAT_STANDARD,
       
  2709                                VG_PATH_DATATYPE_F,
       
  2710                                1.0f,             // scale
       
  2711                                0.0f,             // bias
       
  2712                                pointCount + 1,   // segmentCapacityHint
       
  2713                                pointCount * 2,   // coordCapacityHint
       
  2714                                VG_PATH_CAPABILITY_ALL);
       
  2715     QVarLengthArray<VGfloat, 16> coords;
       
  2716     QVarLengthArray<VGubyte, 10> segments;
       
  2717     for (int i = 0; i < pointCount; ++i, ++points) {
       
  2718         if (d->simpleTransform) {
       
  2719             coords.append(points->x());
       
  2720             coords.append(points->y());
       
  2721         } else {
       
  2722             QPointF temp = d->transform.map(*points);
       
  2723             coords.append(temp.x());
       
  2724             coords.append(temp.y());
       
  2725         }
       
  2726         if (i == 0)
       
  2727             segments.append(VG_MOVE_TO_ABS);
       
  2728         else
       
  2729             segments.append(VG_LINE_TO_ABS);
       
  2730     }
       
  2731     if (mode != QPaintEngine::PolylineMode)
       
  2732         segments.append(VG_CLOSE_PATH);
       
  2733     vgAppendPathData(path, segments.count(),
       
  2734                      segments.constData(), coords.constData());
       
  2735     switch (mode) {
       
  2736         case QPaintEngine::WindingMode:
       
  2737             d->draw(path, s->pen, s->brush, VG_NON_ZERO);
       
  2738             break;
       
  2739 
       
  2740         case QPaintEngine::PolylineMode:
       
  2741             d->stroke(path, s->pen);
       
  2742             break;
       
  2743 
       
  2744         default:
       
  2745             d->draw(path, s->pen, s->brush, VG_EVEN_ODD);
       
  2746             break;
       
  2747     }
       
  2748     vgDestroyPath(path);
       
  2749 }
       
  2750 
       
  2751 void QVGPaintEngine::drawPolygon(const QPoint *points, int pointCount, PolygonDrawMode mode)
       
  2752 {
       
  2753     Q_D(QVGPaintEngine);
       
  2754     QVGPainterState *s = state();
       
  2755     VGPath path = vgCreatePath(VG_PATH_FORMAT_STANDARD,
       
  2756                                VG_PATH_DATATYPE_F,
       
  2757                                1.0f,             // scale
       
  2758                                0.0f,             // bias
       
  2759                                pointCount + 1,   // segmentCapacityHint
       
  2760                                pointCount * 2,   // coordCapacityHint
       
  2761                                VG_PATH_CAPABILITY_ALL);
       
  2762     QVarLengthArray<VGfloat, 16> coords;
       
  2763     QVarLengthArray<VGubyte, 10> segments;
       
  2764     for (int i = 0; i < pointCount; ++i, ++points) {
       
  2765         if (d->simpleTransform) {
       
  2766             coords.append(points->x());
       
  2767             coords.append(points->y());
       
  2768         } else {
       
  2769             QPointF temp = d->transform.map(QPointF(*points));
       
  2770             coords.append(temp.x());
       
  2771             coords.append(temp.y());
       
  2772         }
       
  2773         if (i == 0)
       
  2774             segments.append(VG_MOVE_TO_ABS);
       
  2775         else
       
  2776             segments.append(VG_LINE_TO_ABS);
       
  2777     }
       
  2778     if (mode != QPaintEngine::PolylineMode)
       
  2779         segments.append(VG_CLOSE_PATH);
       
  2780     vgAppendPathData(path, segments.count(),
       
  2781                      segments.constData(), coords.constData());
       
  2782     switch (mode) {
       
  2783         case QPaintEngine::WindingMode:
       
  2784             d->draw(path, s->pen, s->brush, VG_NON_ZERO);
       
  2785             break;
       
  2786 
       
  2787         case QPaintEngine::PolylineMode:
       
  2788             d->stroke(path, s->pen);
       
  2789             break;
       
  2790 
       
  2791         default:
       
  2792             d->draw(path, s->pen, s->brush, VG_EVEN_ODD);
       
  2793             break;
       
  2794     }
       
  2795     vgDestroyPath(path);
       
  2796 }
       
  2797 
       
  2798 void QVGPaintEnginePrivate::setImageOptions()
       
  2799 {
       
  2800     if (opacity != 1.0f && simpleTransform) {
       
  2801         if (opacity != paintOpacity) {
       
  2802             VGfloat values[4];
       
  2803             values[0] = 1.0f;
       
  2804             values[1] = 1.0f;
       
  2805             values[2] = 1.0f;
       
  2806             values[3] = opacity;
       
  2807             vgSetParameterfv(opacityPaint, VG_PAINT_COLOR, 4, values);
       
  2808             paintOpacity = opacity;
       
  2809         }
       
  2810         if (fillPaint != opacityPaint) {
       
  2811             vgSetPaint(opacityPaint, VG_FILL_PATH);
       
  2812             fillPaint = opacityPaint;
       
  2813         }
       
  2814         setImageMode(VG_DRAW_IMAGE_MULTIPLY);
       
  2815     } else {
       
  2816         setImageMode(VG_DRAW_IMAGE_NORMAL);
       
  2817     }
       
  2818 }
       
  2819 
       
  2820 static void drawVGImage(QVGPaintEnginePrivate *d,
       
  2821                         const QRectF& r, VGImage vgImg,
       
  2822                         const QSize& imageSize, const QRectF& sr)
       
  2823 {
       
  2824     if (vgImg == VG_INVALID_HANDLE)
       
  2825         return;
       
  2826     VGImage child = VG_INVALID_HANDLE;
       
  2827 
       
  2828     if (sr.topLeft().isNull() && sr.size() == imageSize) {
       
  2829         child = vgImg;
       
  2830     } else {
       
  2831         QRect src = sr.toRect();
       
  2832 #if !defined(QT_SHIVAVG)
       
  2833         child = vgChildImage(vgImg, src.x(), src.y(), src.width(), src.height());
       
  2834 #else
       
  2835         child = vgImg;  // XXX: ShivaVG doesn't have vgChildImage().
       
  2836 #endif
       
  2837     }
       
  2838 
       
  2839     QTransform transform(d->imageTransform);
       
  2840     VGfloat scaleX = sr.width() == 0.0f ? 0.0f : r.width() / sr.width();
       
  2841     VGfloat scaleY = sr.height() == 0.0f ? 0.0f : r.height() / sr.height();
       
  2842     transform.translate(r.x(), r.y());
       
  2843     transform.scale(scaleX, scaleY);
       
  2844     d->setTransform(VG_MATRIX_IMAGE_USER_TO_SURFACE, transform);
       
  2845 
       
  2846     d->setImageOptions();
       
  2847     vgDrawImage(child);
       
  2848 
       
  2849     if(child != vgImg)
       
  2850         vgDestroyImage(child);
       
  2851 }
       
  2852 
       
  2853 static void drawVGImage(QVGPaintEnginePrivate *d,
       
  2854                         const QPointF& pos, VGImage vgImg)
       
  2855 {
       
  2856     if (vgImg == VG_INVALID_HANDLE)
       
  2857         return;
       
  2858 
       
  2859     QTransform transform(d->imageTransform);
       
  2860     transform.translate(pos.x(), pos.y());
       
  2861     d->setTransform(VG_MATRIX_IMAGE_USER_TO_SURFACE, transform);
       
  2862 
       
  2863     d->setImageOptions();
       
  2864     vgDrawImage(vgImg);
       
  2865 }
       
  2866 
       
  2867 // Used by qpixmapfilter_vg.cpp to draw filtered VGImage's.
       
  2868 void qt_vg_drawVGImage(QPainter *painter, const QPointF& pos, VGImage vgImg)
       
  2869 {
       
  2870     QVGPaintEngine *engine =
       
  2871         static_cast<QVGPaintEngine *>(painter->paintEngine());
       
  2872     drawVGImage(engine->vgPrivate(), pos, vgImg);
       
  2873 }
       
  2874 
       
  2875 // Used by qpixmapfilter_vg.cpp to draw filtered VGImage's as a stencil.
       
  2876 void qt_vg_drawVGImageStencil
       
  2877     (QPainter *painter, const QPointF& pos, VGImage vgImg, const QBrush& brush)
       
  2878 {
       
  2879     QVGPaintEngine *engine =
       
  2880         static_cast<QVGPaintEngine *>(painter->paintEngine());
       
  2881 
       
  2882     QVGPaintEnginePrivate *d = engine->vgPrivate();
       
  2883 
       
  2884     QTransform transform(d->imageTransform);
       
  2885     transform.translate(pos.x(), pos.y());
       
  2886     d->setTransform(VG_MATRIX_IMAGE_USER_TO_SURFACE, transform);
       
  2887 
       
  2888     d->ensureBrush(brush);
       
  2889     d->setImageMode(VG_DRAW_IMAGE_STENCIL);
       
  2890     vgDrawImage(vgImg);
       
  2891 }
       
  2892 
       
  2893 void QVGPaintEngine::drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr)
       
  2894 {
       
  2895     QPixmapData *pd = pm.pixmapData();
       
  2896     if (pd->classId() == QPixmapData::OpenVGClass) {
       
  2897         Q_D(QVGPaintEngine);
       
  2898         QVGPixmapData *vgpd = static_cast<QVGPixmapData *>(pd);
       
  2899         if (!vgpd->isValid())
       
  2900             return;
       
  2901         if (d->simpleTransform)
       
  2902             drawVGImage(d, r, vgpd->toVGImage(), vgpd->size(), sr);
       
  2903         else
       
  2904             drawVGImage(d, r, vgpd->toVGImage(d->opacity), vgpd->size(), sr);
       
  2905     } else {
       
  2906         drawImage(r, *(pd->buffer()), sr, Qt::AutoColor);
       
  2907     }
       
  2908 }
       
  2909 
       
  2910 void QVGPaintEngine::drawPixmap(const QPointF &pos, const QPixmap &pm)
       
  2911 {
       
  2912     QPixmapData *pd = pm.pixmapData();
       
  2913     if (pd->classId() == QPixmapData::OpenVGClass) {
       
  2914         Q_D(QVGPaintEngine);
       
  2915         QVGPixmapData *vgpd = static_cast<QVGPixmapData *>(pd);
       
  2916         if (!vgpd->isValid())
       
  2917             return;
       
  2918         if (d->simpleTransform)
       
  2919             drawVGImage(d, pos, vgpd->toVGImage());
       
  2920         else
       
  2921             drawVGImage(d, pos, vgpd->toVGImage(d->opacity));
       
  2922     } else {
       
  2923         drawImage(pos, *(pd->buffer()));
       
  2924     }
       
  2925 }
       
  2926 
       
  2927 void QVGPaintEngine::drawImage
       
  2928         (const QRectF &r, const QImage &image, const QRectF &sr,
       
  2929          Qt::ImageConversionFlags flags)
       
  2930 {
       
  2931     Q_D(QVGPaintEngine);
       
  2932     VGImage vgImg;
       
  2933     if (d->simpleTransform || d->opacity == 1.0f)
       
  2934         vgImg = toVGImageSubRect(image, sr.toRect(), flags);
       
  2935     else
       
  2936         vgImg = toVGImageWithOpacitySubRect(image, d->opacity, sr.toRect());
       
  2937     if (vgImg != VG_INVALID_HANDLE) {
       
  2938         if (r.size() == sr.size()) {
       
  2939             drawVGImage(d, r.topLeft(), vgImg);
       
  2940         } else {
       
  2941             drawVGImage(d, r, vgImg, sr.size().toSize(),
       
  2942                         QRectF(QPointF(0, 0), sr.size()));
       
  2943         }
       
  2944     } else {
       
  2945         // Monochrome images need to use the vgChildImage() path.
       
  2946         vgImg = toVGImage(image, flags);
       
  2947         drawVGImage(d, r, vgImg, image.size(), sr);
       
  2948     }
       
  2949     vgDestroyImage(vgImg);
       
  2950 }
       
  2951 
       
  2952 void QVGPaintEngine::drawImage(const QPointF &pos, const QImage &image)
       
  2953 {
       
  2954     Q_D(QVGPaintEngine);
       
  2955     VGImage vgImg;
       
  2956     if (d->simpleTransform || d->opacity == 1.0f)
       
  2957         vgImg = toVGImage(image);
       
  2958     else
       
  2959         vgImg = toVGImageWithOpacity(image, d->opacity);
       
  2960     drawVGImage(d, pos, vgImg);
       
  2961     vgDestroyImage(vgImg);
       
  2962 }
       
  2963 
       
  2964 void QVGPaintEngine::drawTiledPixmap
       
  2965         (const QRectF &r, const QPixmap &pixmap, const QPointF &s)
       
  2966 {
       
  2967     QBrush brush(state()->pen.color(), pixmap);
       
  2968     QTransform xform;
       
  2969     xform.translate(-s.x(), -s.y());
       
  2970     brush.setTransform(xform);
       
  2971     fillRect(r, brush);
       
  2972 }
       
  2973 
       
  2974 // Best performance will be achieved with QDrawPixmaps::OpaqueHint
       
  2975 // (i.e. no opacity), no rotation or scaling, and drawing the full
       
  2976 // pixmap rather than parts of the pixmap.  Even having just one of
       
  2977 // these conditions will improve performance.
       
  2978 void QVGPaintEngine::drawPixmaps
       
  2979     (const QDrawPixmaps::Data *drawingData, int dataCount,
       
  2980      const QPixmap &pixmap, QFlags<QDrawPixmaps::DrawingHint> hints)
       
  2981 {
       
  2982 #if !defined(QT_SHIVAVG)
       
  2983     Q_D(QVGPaintEngine);
       
  2984 
       
  2985     // If the pixmap is not VG, or the transformation is projective,
       
  2986     // then fall back to the default implementation.
       
  2987     QPixmapData *pd = pixmap.pixmapData();
       
  2988     if (pd->classId() != QPixmapData::OpenVGClass || !d->simpleTransform) {
       
  2989         QPaintEngineEx::drawPixmaps(drawingData, dataCount, pixmap, hints);
       
  2990         return;
       
  2991     }
       
  2992 
       
  2993     // Bail out if nothing to do.
       
  2994     if (dataCount <= 0)
       
  2995         return;
       
  2996 
       
  2997     // Bail out if we don't have a usable VGImage for the pixmap.
       
  2998     QVGPixmapData *vgpd = static_cast<QVGPixmapData *>(pd);
       
  2999     if (!vgpd->isValid())
       
  3000         return;
       
  3001     VGImage vgImg = vgpd->toVGImage();
       
  3002     if (vgImg == VG_INVALID_HANDLE)
       
  3003         return;
       
  3004 
       
  3005     // We cache the results of any vgChildImage() calls because the
       
  3006     // same child is very likely to be used over and over in particle
       
  3007     // systems.  However, performance is even better if vgChildImage()
       
  3008     // isn't needed at all, so use full source rects where possible.
       
  3009     QVarLengthArray<VGImage> cachedImages;
       
  3010     QVarLengthArray<QRect> cachedSources;
       
  3011 
       
  3012     // Select the opacity paint object.
       
  3013     if ((hints & QDrawPixmaps::OpaqueHint) != 0 && d->opacity == 1.0f) {
       
  3014         d->setImageMode(VG_DRAW_IMAGE_NORMAL);
       
  3015     }  else {
       
  3016         hints = 0;
       
  3017         if (d->fillPaint != d->opacityPaint) {
       
  3018             vgSetPaint(d->opacityPaint, VG_FILL_PATH);
       
  3019             d->fillPaint = d->opacityPaint;
       
  3020         }
       
  3021     }
       
  3022 
       
  3023     for (int i = 0; i < dataCount; ++i) {
       
  3024         QTransform transform(d->imageTransform);
       
  3025         transform.translate(drawingData[i].point.x(), drawingData[i].point.y());
       
  3026         transform.rotate(drawingData[i].rotation);
       
  3027 
       
  3028         VGImage child;
       
  3029         QSize imageSize = vgpd->size();
       
  3030         QRectF sr = drawingData[i].source;
       
  3031         if (sr.topLeft().isNull() && sr.size() == imageSize) {
       
  3032             child = vgImg;
       
  3033         } else {
       
  3034             // Look for a previous child with the same source rectangle
       
  3035             // to avoid constantly calling vgChildImage()/vgDestroyImage().
       
  3036             QRect src = sr.toRect();
       
  3037             int j;
       
  3038             for (j = 0; j < cachedSources.size(); ++j) {
       
  3039                 if (cachedSources[j] == src)
       
  3040                     break;
       
  3041             }
       
  3042             if (j < cachedSources.size()) {
       
  3043                 child = cachedImages[j];
       
  3044             } else {
       
  3045                 child = vgChildImage
       
  3046                     (vgImg, src.x(), src.y(), src.width(), src.height());
       
  3047                 cachedImages.append(child);
       
  3048                 cachedSources.append(src);
       
  3049             }
       
  3050         }
       
  3051 
       
  3052         VGfloat scaleX = drawingData[i].scaleX;
       
  3053         VGfloat scaleY = drawingData[i].scaleY;
       
  3054         transform.translate(-0.5 * scaleX * sr.width(),
       
  3055                             -0.5 * scaleY * sr.height());
       
  3056         transform.scale(scaleX, scaleY);
       
  3057         d->setTransform(VG_MATRIX_IMAGE_USER_TO_SURFACE, transform);
       
  3058 
       
  3059         if ((hints & QDrawPixmaps::OpaqueHint) == 0) {
       
  3060             qreal opacity = d->opacity * drawingData[i].opacity;
       
  3061             if (opacity != 1.0f) {
       
  3062                 if (d->paintOpacity != opacity) {
       
  3063                     VGfloat values[4];
       
  3064                     values[0] = 1.0f;
       
  3065                     values[1] = 1.0f;
       
  3066                     values[2] = 1.0f;
       
  3067                     values[3] = opacity;
       
  3068                     d->paintOpacity = opacity;
       
  3069                     vgSetParameterfv
       
  3070                         (d->opacityPaint, VG_PAINT_COLOR, 4, values);
       
  3071                 }
       
  3072                 d->setImageMode(VG_DRAW_IMAGE_MULTIPLY);
       
  3073             } else {
       
  3074                 d->setImageMode(VG_DRAW_IMAGE_NORMAL);
       
  3075             }
       
  3076         }
       
  3077 
       
  3078         vgDrawImage(child);
       
  3079     }
       
  3080 
       
  3081     // Destroy the cached child sub-images.
       
  3082     for (int i = 0; i < cachedImages.size(); ++i)
       
  3083         vgDestroyImage(cachedImages[i]);
       
  3084 #else
       
  3085     QPaintEngineEx::drawPixmaps(drawingData, dataCount, pixmap, hints);
       
  3086 #endif
       
  3087 }
       
  3088 
       
  3089 QVGFontEngineCleaner::QVGFontEngineCleaner(QVGPaintEnginePrivate *d)
       
  3090     : QObject(), d_ptr(d)
       
  3091 {
       
  3092 }
       
  3093 
       
  3094 QVGFontEngineCleaner::~QVGFontEngineCleaner()
       
  3095 {
       
  3096 }
       
  3097 
       
  3098 void QVGFontEngineCleaner::fontEngineDestroyed()
       
  3099 {
       
  3100 #if !defined(QVG_NO_DRAW_GLYPHS)
       
  3101     QFontEngine *engine = static_cast<QFontEngine *>(sender());
       
  3102     QVGFontCache::Iterator it = d_ptr->fontCache.find(engine);
       
  3103     if (it != d_ptr->fontCache.end()) {
       
  3104         delete it.value();
       
  3105         d_ptr->fontCache.erase(it);
       
  3106     }
       
  3107 #endif
       
  3108 }
       
  3109 
       
  3110 #if !defined(QVG_NO_DRAW_GLYPHS)
       
  3111 
       
  3112 QVGFontGlyphCache::QVGFontGlyphCache()
       
  3113 {
       
  3114     font = vgCreateFont(0);
       
  3115     scaleX = scaleY = 0.0;
       
  3116     memset(cachedGlyphsMask, 0, sizeof(cachedGlyphsMask));
       
  3117 }
       
  3118 
       
  3119 QVGFontGlyphCache::~QVGFontGlyphCache()
       
  3120 {
       
  3121     if (font != VG_INVALID_HANDLE)
       
  3122         vgDestroyFont(font);
       
  3123 }
       
  3124 
       
  3125 void QVGFontGlyphCache::setScaleFromText(const QTextItemInt &ti)
       
  3126 {
       
  3127     QFontInfo fi(ti.font());
       
  3128     qreal pixelSize = fi.pixelSize();
       
  3129     qreal emSquare = ti.fontEngine->properties().emSquare.toReal();
       
  3130     scaleX = scaleY = static_cast<VGfloat>(pixelSize / emSquare);
       
  3131 }
       
  3132 
       
  3133 void QVGFontGlyphCache::cacheGlyphs
       
  3134         (QVGPaintEnginePrivate *d, const QTextItemInt &ti,
       
  3135          const QVarLengthArray<glyph_t> &glyphs)
       
  3136 {
       
  3137     VGfloat origin[2];
       
  3138     VGfloat escapement[2];
       
  3139     const glyph_t *g = glyphs.constData();
       
  3140     int count = glyphs.size();
       
  3141     glyph_metrics_t metrics;
       
  3142     // Some Qt font engines don't set yoff in getUnscaledGlyph().
       
  3143     // Zero the metric structure so that everything has a default value.
       
  3144     memset(&metrics, 0, sizeof(metrics));
       
  3145     while (count-- > 0) {
       
  3146         // Skip this glyph if we have already cached it before.
       
  3147         glyph_t glyph = *g++;
       
  3148         if (glyph < 256) {
       
  3149             if ((cachedGlyphsMask[glyph / 32] & (1 << (glyph % 32))) != 0)
       
  3150                 continue;
       
  3151             cachedGlyphsMask[glyph / 32] |= (1 << (glyph % 32));
       
  3152         } else if (cachedGlyphs.contains(glyph)) {
       
  3153             continue;
       
  3154         } else {
       
  3155             cachedGlyphs.insert(glyph);
       
  3156         }
       
  3157 #if !defined(QVG_NO_IMAGE_GLYPHS)
       
  3158         Q_UNUSED(d);
       
  3159         QImage scaledImage = ti.fontEngine->alphaMapForGlyph(glyph);
       
  3160         VGImage vgImage = VG_INVALID_HANDLE;
       
  3161         metrics = ti.fontEngine->boundingBox(glyph);
       
  3162         if (!scaledImage.isNull()) {  // Not a space character
       
  3163             if (scaledImage.format() == QImage::Format_Indexed8) {
       
  3164                 vgImage = vgCreateImage(VG_A_8, scaledImage.width(), scaledImage.height(), VG_IMAGE_QUALITY_FASTER);
       
  3165                 vgImageSubData(vgImage, scaledImage.bits(), scaledImage.bytesPerLine(), VG_A_8, 0, 0, scaledImage.width(), scaledImage.height());
       
  3166             } else if (scaledImage.format() == QImage::Format_Mono) {
       
  3167                 QImage img = scaledImage.convertToFormat(QImage::Format_Indexed8);
       
  3168                 vgImage = vgCreateImage(VG_A_8, img.width(), img.height(), VG_IMAGE_QUALITY_FASTER);
       
  3169                 vgImageSubData(vgImage, img.bits(), img.bytesPerLine(), VG_A_8, 0, 0, img.width(), img.height());
       
  3170             } else {
       
  3171                 QImage img = scaledImage.convertToFormat(QImage::Format_ARGB32_Premultiplied);
       
  3172                 vgImage = vgCreateImage(VG_sARGB_8888_PRE, img.width(), img.height(), VG_IMAGE_QUALITY_FASTER);
       
  3173                 vgImageSubData(vgImage, img.bits(), img.bytesPerLine(), VG_sARGB_8888_PRE, 0, 0, img.width(), img.height());
       
  3174             }
       
  3175         }
       
  3176         origin[0] = -metrics.x.toReal() + 0.5f;
       
  3177         origin[1] = -metrics.y.toReal() + 0.5f;
       
  3178         escapement[0] = metrics.xoff.toReal();
       
  3179         escapement[1] = metrics.yoff.toReal();
       
  3180         vgSetGlyphToImage(font, glyph, vgImage, origin, escapement);
       
  3181         vgDestroyImage(vgImage);    // Reduce reference count.
       
  3182 #else
       
  3183         // Calculate the path for the glyph and cache it.
       
  3184         QPainterPath path;
       
  3185         ti.fontEngine->getUnscaledGlyph(glyph, &path, &metrics);
       
  3186         VGPath vgPath;
       
  3187         if (!path.isEmpty()) {
       
  3188             vgPath = d->painterPathToVGPath(path);
       
  3189         } else {
       
  3190             // Probably a "space" character with no visible outline.
       
  3191             vgPath = VG_INVALID_HANDLE;
       
  3192         }
       
  3193         origin[0] = 0;
       
  3194         origin[1] = 0;
       
  3195         escapement[0] = metrics.xoff.toReal();
       
  3196         escapement[1] = metrics.yoff.toReal();
       
  3197         vgSetGlyphToPath(font, glyph, vgPath, VG_FALSE, origin, escapement);
       
  3198         vgDestroyPath(vgPath);      // Reduce reference count.
       
  3199 #endif // !defined(QVG_NO_IMAGE_GLYPHS)
       
  3200     }
       
  3201 }
       
  3202 
       
  3203 #endif // !defined(QVG_NO_DRAW_GLYPHS)
       
  3204 
       
  3205 void QVGPaintEngine::drawTextItem(const QPointF &p, const QTextItem &textItem)
       
  3206 {
       
  3207 #if !defined(QVG_NO_DRAW_GLYPHS)
       
  3208     Q_D(QVGPaintEngine);
       
  3209     const QTextItemInt &ti = static_cast<const QTextItemInt &>(textItem);
       
  3210 
       
  3211     // If we are not using a simple transform, then fall back
       
  3212     // to the default Qt path stroking algorithm.
       
  3213     if (!d->simpleTransform) {
       
  3214         QPaintEngineEx::drawTextItem(p, textItem);
       
  3215         return;
       
  3216     }
       
  3217  
       
  3218     // Get the glyphs and positions associated with the text item.
       
  3219     QVarLengthArray<QFixedPoint> positions;
       
  3220     QVarLengthArray<glyph_t> glyphs;
       
  3221     QTransform matrix = d->transform;
       
  3222     matrix.translate(p.x(), p.y());
       
  3223     ti.fontEngine->getGlyphPositions
       
  3224         (ti.glyphs, matrix, ti.flags, glyphs, positions);
       
  3225 
       
  3226     // Find the glyph cache for this font.
       
  3227     QVGFontCache::ConstIterator it = d->fontCache.constFind(ti.fontEngine);
       
  3228     QVGFontGlyphCache *glyphCache;
       
  3229     if (it != d->fontCache.constEnd()) {
       
  3230         glyphCache = it.value();
       
  3231     } else {
       
  3232         glyphCache = new QVGFontGlyphCache();
       
  3233         if (glyphCache->font == VG_INVALID_HANDLE) {
       
  3234             qWarning("QVGPaintEngine::drawTextItem: OpenVG fonts are not supported by the OpenVG engine");
       
  3235             delete glyphCache;
       
  3236             QPaintEngineEx::drawTextItem(p, textItem);
       
  3237             return;
       
  3238         }
       
  3239         glyphCache->setScaleFromText(ti);
       
  3240         d->fontCache.insert(ti.fontEngine, glyphCache);
       
  3241         if (!d->fontEngineCleaner)
       
  3242             d->fontEngineCleaner = new QVGFontEngineCleaner(d);
       
  3243         QObject::connect(ti.fontEngine, SIGNAL(destroyed()),
       
  3244                          d->fontEngineCleaner, SLOT(fontEngineDestroyed()));
       
  3245     }
       
  3246 
       
  3247     // Set the transformation to use for drawing the current glyphs.
       
  3248     QTransform glyphTransform(d->pathTransform);
       
  3249     glyphTransform.translate(p.x(), p.y());
       
  3250 #if defined(QVG_NO_IMAGE_GLYPHS)
       
  3251     glyphTransform.scale(glyphCache->scaleX, glyphCache->scaleY);
       
  3252 #endif
       
  3253     d->setTransform(VG_MATRIX_GLYPH_USER_TO_SURFACE, glyphTransform);
       
  3254 
       
  3255     // Add the glyphs from the text item into the glyph cache.
       
  3256     glyphCache->cacheGlyphs(d, ti, glyphs);
       
  3257 
       
  3258     // Set the glyph drawing origin.
       
  3259     VGfloat origin[2];
       
  3260     origin[0] = 0;
       
  3261     origin[1] = 0;
       
  3262     vgSetfv(VG_GLYPH_ORIGIN, 2, origin);
       
  3263 
       
  3264     // Fast anti-aliasing for paths, better for images.
       
  3265 #if !defined(QVG_NO_IMAGE_GLYPHS)
       
  3266     d->setImageQuality(VG_IMAGE_QUALITY_BETTER);
       
  3267     d->setImageMode(VG_DRAW_IMAGE_STENCIL);
       
  3268 #else
       
  3269     d->setRenderingQuality(VG_RENDERING_QUALITY_FASTER);
       
  3270 #endif
       
  3271 
       
  3272     // Draw the glyphs.  We need to fill with the brush associated with
       
  3273     // the Qt pen, not the Qt brush.
       
  3274     d->ensureBrush(state()->pen.brush());
       
  3275     vgDrawGlyphs(glyphCache->font, glyphs.size(), (VGuint*)glyphs.data(),
       
  3276                  NULL, NULL, VG_FILL_PATH, VG_TRUE);
       
  3277 #else
       
  3278     // OpenGL 1.0 does not have support for VGFont and glyphs,
       
  3279     // so fall back to the default Qt path stroking algorithm.
       
  3280     QPaintEngineEx::drawTextItem(p, textItem);
       
  3281 #endif
       
  3282 }
       
  3283 
       
  3284 void QVGPaintEngine::setState(QPainterState *s)
       
  3285 {
       
  3286     Q_D(QVGPaintEngine);
       
  3287     QPaintEngineEx::setState(s);
       
  3288     QVGPainterState *ps = static_cast<QVGPainterState *>(s);
       
  3289     if (ps->isNew) {
       
  3290         // Newly created state object.  The call to setState()
       
  3291         // will either be followed by a call to begin(), or we are
       
  3292         // setting the state as part of a save().
       
  3293         ps->isNew = false;
       
  3294     } else {
       
  3295         // This state object was set as part of a restore().
       
  3296         restoreState(d->dirty);
       
  3297         d->dirty = ps->savedDirty;
       
  3298     }
       
  3299 }
       
  3300 
       
  3301 void QVGPaintEngine::beginNativePainting()
       
  3302 {
       
  3303     Q_D(QVGPaintEngine);
       
  3304 
       
  3305     // About to enter raw VG mode: flush pending changes and make
       
  3306     // sure that all matrices are set to the current transformation.
       
  3307     QVGPainterState *s = this->state();
       
  3308     d->ensurePen(s->pen);
       
  3309     d->ensureBrush(s->brush);
       
  3310     d->ensurePathTransform();
       
  3311     d->setTransform(VG_MATRIX_IMAGE_USER_TO_SURFACE, d->imageTransform);
       
  3312 #if !defined(QVG_NO_DRAW_GLYPHS)
       
  3313     d->setTransform(VG_MATRIX_GLYPH_USER_TO_SURFACE, d->pathTransform);
       
  3314 #endif
       
  3315     d->rawVG = true;
       
  3316 }
       
  3317 
       
  3318 void QVGPaintEngine::endNativePainting()
       
  3319 {
       
  3320     Q_D(QVGPaintEngine);
       
  3321     // Exiting raw VG mode: force all state values to be
       
  3322     // explicitly set on the VG engine to undo any changes
       
  3323     // that were made by the raw VG function calls.
       
  3324     QPaintEngine::DirtyFlags dirty = d->dirty;
       
  3325     d->clearModes();
       
  3326     d->forcePenChange = true;
       
  3327     d->forceBrushChange = true;
       
  3328     d->penType = (VGPaintType)0;
       
  3329     d->brushType = (VGPaintType)0;
       
  3330     d->clearColor = QColor();
       
  3331     d->fillPaint = d->brushPaint;
       
  3332     restoreState(QPaintEngine::AllDirty);
       
  3333     d->dirty = dirty;
       
  3334     d->rawVG = false;
       
  3335     vgSetPaint(d->penPaint, VG_STROKE_PATH);
       
  3336     vgSetPaint(d->brushPaint, VG_FILL_PATH);
       
  3337 }
       
  3338 
       
  3339 QPixmapFilter *QVGPaintEngine::pixmapFilter(int type, const QPixmapFilter *prototype)
       
  3340 {
       
  3341 #if !defined(QT_SHIVAVG)
       
  3342     Q_D(QVGPaintEngine);
       
  3343     switch (type) {
       
  3344         case QPixmapFilter::ConvolutionFilter:
       
  3345             if (!d->convolutionFilter)
       
  3346                 d->convolutionFilter.reset(new QVGPixmapConvolutionFilter);
       
  3347             return d->convolutionFilter.data();
       
  3348         case QPixmapFilter::ColorizeFilter:
       
  3349             if (!d->colorizeFilter)
       
  3350                 d->colorizeFilter.reset(new QVGPixmapColorizeFilter);
       
  3351             return d->colorizeFilter.data();
       
  3352         case QPixmapFilter::DropShadowFilter:
       
  3353             if (!d->dropShadowFilter)
       
  3354                 d->dropShadowFilter.reset(new QVGPixmapDropShadowFilter);
       
  3355             return d->dropShadowFilter.data();
       
  3356         case QPixmapFilter::BlurFilter:
       
  3357             if (!d->blurFilter)
       
  3358                 d->blurFilter.reset(new QVGPixmapBlurFilter);
       
  3359             return d->blurFilter.data();
       
  3360         default: break;
       
  3361     }
       
  3362 #endif
       
  3363     return QPaintEngineEx::pixmapFilter(type, prototype);
       
  3364 }
       
  3365 
       
  3366 void QVGPaintEngine::restoreState(QPaintEngine::DirtyFlags dirty)
       
  3367 {
       
  3368     Q_D(QVGPaintEngine);
       
  3369 
       
  3370     // Restore the pen, brush, and other settings.
       
  3371     if ((dirty & QPaintEngine::DirtyBrushOrigin) != 0)
       
  3372         brushOriginChanged();
       
  3373     d->fillRule = 0;
       
  3374     if ((dirty & QPaintEngine::DirtyOpacity) != 0)
       
  3375         opacityChanged();
       
  3376     if ((dirty & QPaintEngine::DirtyTransform) != 0)
       
  3377         transformChanged();
       
  3378     if ((dirty & QPaintEngine::DirtyCompositionMode) != 0)
       
  3379         compositionModeChanged();
       
  3380     if ((dirty & QPaintEngine::DirtyHints) != 0)
       
  3381         renderHintsChanged();
       
  3382     if ((dirty & (QPaintEngine::DirtyClipRegion |
       
  3383                   QPaintEngine::DirtyClipPath |
       
  3384                   QPaintEngine::DirtyClipEnabled)) != 0) {
       
  3385         d->maskValid = false;
       
  3386         d->maskIsSet = false;
       
  3387         d->maskRect = QRect();
       
  3388         clipEnabledChanged();
       
  3389     }
       
  3390 
       
  3391 #if defined(QVG_SCISSOR_CLIP)
       
  3392     if ((dirty & (QPaintEngine::DirtyClipRegion |
       
  3393                   QPaintEngine::DirtyClipPath |
       
  3394                   QPaintEngine::DirtyClipEnabled)) == 0) {
       
  3395         updateScissor();
       
  3396     }
       
  3397 #else
       
  3398     updateScissor();
       
  3399 #endif
       
  3400 }
       
  3401 
       
  3402 #if !defined(QVG_NO_SINGLE_CONTEXT) && !defined(QT_NO_EGL)
       
  3403 
       
  3404 QVGCompositionHelper::QVGCompositionHelper()
       
  3405 {
       
  3406     d = qt_vg_create_paint_engine()->vgPrivate();
       
  3407 }
       
  3408 
       
  3409 QVGCompositionHelper::~QVGCompositionHelper()
       
  3410 {
       
  3411 }
       
  3412 
       
  3413 void QVGCompositionHelper::startCompositing(const QSize& screenSize)
       
  3414 {
       
  3415     this->screenSize = screenSize;
       
  3416     clearScissor();
       
  3417     d->setBlendMode(VG_BLEND_SRC_OVER);
       
  3418 }
       
  3419 
       
  3420 void QVGCompositionHelper::endCompositing()
       
  3421 {
       
  3422     clearScissor();
       
  3423 }
       
  3424 
       
  3425 void QVGCompositionHelper::blitWindow
       
  3426     (QVGEGLWindowSurfacePrivate *surface, const QRect& rect,
       
  3427      const QPoint& topLeft, int opacity)
       
  3428 {
       
  3429     // Get the VGImage that is acting as a back buffer for the window.
       
  3430     VGImage image = surface->surfaceImage();
       
  3431     if (image == VG_INVALID_HANDLE)
       
  3432         return;
       
  3433     QSize imageSize = surface->surfaceSize();
       
  3434 
       
  3435     // Determine which sub rectangle of the window to draw.
       
  3436     QRect sr = rect.translated(-topLeft);
       
  3437 
       
  3438     if (opacity >= 255) {
       
  3439         // Fully opaque: use vgSetPixels() to directly copy the sub-region.
       
  3440         int y = screenSize.height() - (rect.bottom() + 1);
       
  3441         vgSetPixels(rect.x(), y, image, sr.x(),
       
  3442                     imageSize.height() - (sr.y() + sr.height()),
       
  3443                     sr.width(), sr.height());
       
  3444     } else {
       
  3445         // Extract the child image that we want to draw.
       
  3446         VGImage child;
       
  3447         if (sr.topLeft().isNull() && sr.size() == imageSize)
       
  3448             child = image;
       
  3449         else {
       
  3450             child = vgChildImage
       
  3451                 (image, sr.x(), imageSize.height() - (sr.y() + sr.height()),
       
  3452                  sr.width(), sr.height());
       
  3453         }
       
  3454 
       
  3455         // Set the image transform.
       
  3456         QTransform transform;
       
  3457         int y = screenSize.height() - (rect.bottom() + 1);
       
  3458         transform.translate(rect.x() + 0.5f, y + 0.5f);
       
  3459         d->setTransform(VG_MATRIX_IMAGE_USER_TO_SURFACE, transform);
       
  3460 
       
  3461         // Enable opacity for image drawing if necessary.
       
  3462         if (opacity < 255) {
       
  3463             if (opacity != d->paintOpacity) {
       
  3464                 VGfloat values[4];
       
  3465                 values[0] = 1.0f;
       
  3466                 values[1] = 1.0f;
       
  3467                 values[2] = 1.0f;
       
  3468                 values[3] = ((VGfloat)opacity) / 255.0f;
       
  3469                 vgSetParameterfv(d->opacityPaint, VG_PAINT_COLOR, 4, values);
       
  3470                 d->paintOpacity = values[3];
       
  3471             }
       
  3472             if (d->fillPaint != d->opacityPaint) {
       
  3473                 vgSetPaint(d->opacityPaint, VG_FILL_PATH);
       
  3474                 d->fillPaint = d->opacityPaint;
       
  3475             }
       
  3476             d->setImageMode(VG_DRAW_IMAGE_MULTIPLY);
       
  3477         } else {
       
  3478             d->setImageMode(VG_DRAW_IMAGE_NORMAL);
       
  3479         }
       
  3480 
       
  3481         // Draw the child image.
       
  3482         vgDrawImage(child);
       
  3483 
       
  3484         // Destroy the child image.
       
  3485         if(child != image)
       
  3486             vgDestroyImage(child);
       
  3487     }
       
  3488 }
       
  3489 
       
  3490 static void fillBackgroundRect(const QRect& rect, QVGPaintEnginePrivate *d)
       
  3491 {
       
  3492     VGfloat coords[8];
       
  3493     coords[0] = rect.x();
       
  3494     coords[1] = rect.y();
       
  3495     coords[2] = rect.x() + rect.width();
       
  3496     coords[3] = coords[1];
       
  3497     coords[4] = coords[2];
       
  3498     coords[5] = rect.y() + rect.height();
       
  3499     coords[6] = coords[0];
       
  3500     coords[7] = coords[5];
       
  3501 #if !defined(QVG_NO_MODIFY_PATH)
       
  3502     vgModifyPathCoords(d->rectPath, 0, 4, coords);
       
  3503     vgDrawPath(d->rectPath, VG_FILL_PATH);
       
  3504 #else
       
  3505     Q_UNUSED(d);
       
  3506     VGPath rectPath = vgCreatePath
       
  3507             (VG_PATH_FORMAT_STANDARD,
       
  3508              VG_PATH_DATATYPE_F,
       
  3509              1.0f, // scale
       
  3510              0.0f, // bias
       
  3511              5,    // segmentCapacityHint
       
  3512              8,    // coordCapacityHint
       
  3513              VG_PATH_CAPABILITY_ALL);
       
  3514     static VGubyte const segments[5] = {
       
  3515         VG_MOVE_TO_ABS,
       
  3516         VG_LINE_TO_ABS,
       
  3517         VG_LINE_TO_ABS,
       
  3518         VG_LINE_TO_ABS,
       
  3519         VG_CLOSE_PATH
       
  3520     };
       
  3521     vgAppendPathData(rectPath, 5, segments, coords);
       
  3522     vgDrawPath(rectPath, VG_FILL_PATH);
       
  3523     vgDestroyPath(rectPath);
       
  3524 #endif
       
  3525 }
       
  3526 
       
  3527 void QVGCompositionHelper::fillBackground
       
  3528     (const QRegion& region, const QBrush& brush)
       
  3529 {
       
  3530     // Set the path transform to the default viewport transformation.
       
  3531     VGfloat devh = screenSize.height() - 1;
       
  3532     QTransform viewport(1.0f, 0.0f, 0.0f,
       
  3533                         0.0f, -1.0f, 0.0f,
       
  3534                         0.5f, devh + 0.5f, 1.0f);
       
  3535     d->setTransform(VG_MATRIX_PATH_USER_TO_SURFACE, viewport);
       
  3536 
       
  3537     // Set the brush to use to fill the background.
       
  3538     d->ensureBrush(brush);
       
  3539     d->setFillRule(VG_EVEN_ODD);
       
  3540 
       
  3541     if (region.numRects() == 1) {
       
  3542         fillBackgroundRect(region.boundingRect(), d);
       
  3543     } else {
       
  3544         const QVector<QRect> rects = region.rects();
       
  3545         for (int i = 0; i < rects.size(); ++i)
       
  3546             fillBackgroundRect(rects.at(i), d);
       
  3547     }
       
  3548 
       
  3549     // We will need to reset the path transform during the next paint.
       
  3550     d->pathTransformSet = false;
       
  3551 }
       
  3552 
       
  3553 void QVGCompositionHelper::drawCursorImage
       
  3554     (const QImage& image, const QPoint& offset)
       
  3555 {
       
  3556     QImage img = image.convertToFormat(QImage::Format_ARGB32_Premultiplied);
       
  3557 
       
  3558     VGImage vgImg = vgCreateImage
       
  3559         (VG_sARGB_8888_PRE, img.width(), img.height(),
       
  3560          VG_IMAGE_QUALITY_FASTER);
       
  3561     vgImageSubData
       
  3562         (vgImg, img.bits() + img.bytesPerLine() * (img.height() - 1),
       
  3563          -(img.bytesPerLine()), VG_sARGB_8888_PRE, 0, 0,
       
  3564          img.width(), img.height());
       
  3565 
       
  3566     QTransform transform;
       
  3567     int y = screenSize.height() - (offset.y() + img.height());
       
  3568     transform.translate(offset.x() + 0.5f, y + 0.5f);
       
  3569     d->setTransform(VG_MATRIX_IMAGE_USER_TO_SURFACE, transform);
       
  3570 
       
  3571     d->setImageMode(VG_DRAW_IMAGE_NORMAL);
       
  3572     vgDrawImage(vgImg);
       
  3573 
       
  3574     vgDestroyImage(vgImg);
       
  3575 }
       
  3576 
       
  3577 void QVGCompositionHelper::drawCursorPixmap
       
  3578     (const QPixmap& pixmap, const QPoint& offset)
       
  3579 {
       
  3580     QPixmapData *pd = pixmap.pixmapData();
       
  3581     if (pd->classId() == QPixmapData::OpenVGClass) {
       
  3582         QVGPixmapData *vgpd = static_cast<QVGPixmapData *>(pd);
       
  3583         if (vgpd->isValid()) {
       
  3584             VGfloat devh = screenSize.height() - 1;
       
  3585             QTransform transform(1.0f, 0.0f, 0.0f,
       
  3586                                  0.0f, -1.0f, 0.0f,
       
  3587                                  0.5f, devh + 0.5f, 1.0f);
       
  3588             transform.translate(offset.x(), offset.y());
       
  3589             d->setTransform(VG_MATRIX_IMAGE_USER_TO_SURFACE, transform);
       
  3590 
       
  3591             d->setImageMode(VG_DRAW_IMAGE_NORMAL);
       
  3592             vgDrawImage(vgpd->toVGImage());
       
  3593             return;
       
  3594         }
       
  3595     }
       
  3596 
       
  3597     drawCursorImage(pixmap.toImage(), offset);
       
  3598 }
       
  3599 
       
  3600 void QVGCompositionHelper::setScissor(const QRegion& region)
       
  3601 {
       
  3602     QVector<QRect> rects = region.rects();
       
  3603     int count = rects.count();
       
  3604     if (count > d->maxScissorRects)
       
  3605         count = d->maxScissorRects;
       
  3606     QVarLengthArray<VGint> params(count * 4);
       
  3607     int height = screenSize.height();
       
  3608     for (int i = 0; i < count; ++i) {
       
  3609         params[i * 4 + 0] = rects[i].x();
       
  3610         params[i * 4 + 1] = height - rects[i].y() - rects[i].height();
       
  3611         params[i * 4 + 2] = rects[i].width();
       
  3612         params[i * 4 + 3] = rects[i].height();
       
  3613     }
       
  3614 
       
  3615     vgSetiv(VG_SCISSOR_RECTS, count * 4, params.data());
       
  3616     vgSeti(VG_SCISSORING, VG_TRUE);
       
  3617     d->scissorActive = true;
       
  3618     d->scissorRegion = region;
       
  3619 }
       
  3620 
       
  3621 void QVGCompositionHelper::clearScissor()
       
  3622 {
       
  3623     if (d->scissorActive) {
       
  3624         vgSeti(VG_SCISSORING, VG_FALSE);
       
  3625         d->scissorActive = false;
       
  3626     }
       
  3627 }
       
  3628 
       
  3629 #endif // !QVG_NO_SINGLE_CONTEXT && !QT_NO_EGL
       
  3630 
       
  3631 VGImageFormat qt_vg_image_to_vg_format(QImage::Format format)
       
  3632 {
       
  3633     switch (format) {
       
  3634         case QImage::Format_MonoLSB:
       
  3635             return VG_BW_1;
       
  3636         case QImage::Format_ARGB32_Premultiplied:
       
  3637             return VG_sARGB_8888_PRE;
       
  3638         case QImage::Format_RGB32:
       
  3639             return VG_sXRGB_8888;
       
  3640         case QImage::Format_ARGB32:
       
  3641             return VG_sARGB_8888;
       
  3642         case QImage::Format_RGB16:
       
  3643             return VG_sRGB_565;
       
  3644         case QImage::Format_ARGB4444_Premultiplied:
       
  3645             return VG_sARGB_4444;
       
  3646         default: break;
       
  3647     }
       
  3648     return VG_sARGB_8888;   // XXX
       
  3649 }
       
  3650 
       
  3651 QT_END_NAMESPACE
       
  3652 
       
  3653 #include "qpaintengine_vg.moc"