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