Qt 4.8
qpaintengine_vg.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
5 **
6 ** This file is part of the QtOpenVG module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia. For licensing terms and
14 ** conditions see http://qt.digia.com/licensing. For further information
15 ** use the contact form at http://qt.digia.com/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights. These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file. Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 
42 #include "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 
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 
81 
82 typedef QHash<QFontEngine*, QVGFontGlyphCache*> QVGFontCache;
83 
84 #endif
85 
87 {
88  Q_OBJECT
89 public:
92 
93 public slots:
94  void fontEngineDestroyed();
95 
96 private:
98 };
99 
101 {
103 public:
104  // Extra blending modes from VG_KHR_advanced_blending extension.
105  // Use the QT_VG prefix to avoid conflicts with any definitions
106  // that may come in via <VG/vgext.h>.
108  QT_VG_BLEND_OVERLAY_KHR = 0x2010,
109  QT_VG_BLEND_HARDLIGHT_KHR = 0x2011,
110  QT_VG_BLEND_SOFTLIGHT_SVG_KHR = 0x2012,
111  QT_VG_BLEND_SOFTLIGHT_KHR = 0x2013,
112  QT_VG_BLEND_COLORDODGE_KHR = 0x2014,
113  QT_VG_BLEND_COLORBURN_KHR = 0x2015,
114  QT_VG_BLEND_DIFFERENCE_KHR = 0x2016,
115  QT_VG_BLEND_SUBTRACT_KHR = 0x2017,
116  QT_VG_BLEND_INVERT_KHR = 0x2018,
117  QT_VG_BLEND_EXCLUSION_KHR = 0x2019,
118  QT_VG_BLEND_LINEARDODGE_KHR = 0x201a,
119  QT_VG_BLEND_LINEARBURN_KHR = 0x201b,
120  QT_VG_BLEND_VIVIDLIGHT_KHR = 0x201c,
121  QT_VG_BLEND_LINEARLIGHT_KHR = 0x201d,
122  QT_VG_BLEND_PINLIGHT_KHR = 0x201e,
123  QT_VG_BLEND_HARDMIX_KHR = 0x201f,
124  QT_VG_BLEND_CLEAR_KHR = 0x2020,
125  QT_VG_BLEND_DST_KHR = 0x2021,
126  QT_VG_BLEND_SRC_OUT_KHR = 0x2022,
127  QT_VG_BLEND_DST_OUT_KHR = 0x2023,
128  QT_VG_BLEND_SRC_ATOP_KHR = 0x2024,
129  QT_VG_BLEND_DST_ATOP_KHR = 0x2025,
130  QT_VG_BLEND_XOR_KHR = 0x2026
131  };
132 
135 
136  void init();
137  void initObjects();
138  void destroy();
139  void setTransform(VGMatrixMode mode, const QTransform& transform);
140  void updateTransform(QPaintDevice *pdev);
141  void draw(VGPath path, const QPen& pen, const QBrush& brush, VGint rule = VG_EVEN_ODD);
142  void stroke(VGPath path, const QPen& pen);
143  void fill(VGPath path, const QBrush& brush, VGint rule = VG_EVEN_ODD);
144  VGPath vectorPathToVGPath(const QVectorPath& path);
145  VGPath painterPathToVGPath(const QPainterPath& path);
146  VGPath roundedRectPath(const QRectF &rect, qreal xRadius, qreal yRadius, Qt::SizeMode mode);
147  VGPaintType setBrush
148  (VGPaint paint, const QBrush& brush, VGMatrixMode mode,
149  VGPaintType prevPaintType);
150  void setPenParams(const QPen& pen);
151  void setBrushTransform(const QBrush& brush, VGMatrixMode mode);
152  void setupColorRamp(const QGradient *grad, VGPaint paint);
153  void setImageOptions();
154  void systemStateChanged();
155 #if !defined(QVG_SCISSOR_CLIP)
156  void ensureMask(QVGPaintEngine *engine, int width, int height);
157  void modifyMask
158  (QVGPaintEngine *engine, VGMaskOperation op, const QRegion& region);
159  void modifyMask
160  (QVGPaintEngine *engine, VGMaskOperation op, const QRect& rect);
161 #endif
162 
163  VGint maxScissorRects; // Maximum scissor rectangles for clipping.
164 
165  VGPaint penPaint; // Paint for currently active pen.
166  VGPaint brushPaint; // Paint for currently active brush.
167  VGPaint opacityPaint; // Paint for drawing images with opacity.
168  VGPaint fillPaint; // Current fill paint that is active.
169 
170  QPen currentPen; // Current pen set in "penPaint".
171  QBrush currentBrush; // Current brush set in "brushPaint".
172 
173  bool forcePenChange; // Force a pen change, even if the same.
174  bool forceBrushChange; // Force a brush change, even if the same.
175 
176  bool hasExtendedRadialGradientPen; // Current pen's brush is extended radial gradient.
177  bool hasExtendedRadialGradientBrush; // Current brush is extended radial gradient.
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 
235 
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
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  inline bool needsEmulation(const QBrush &brush) const
282  {
284  return qt_isExtendedRadialGradient(brush);
285  }
286 
287  inline bool needsEmulation() const
288  {
289  return hasExtendedRadialGradientPen || hasExtendedRadialGradientBrush;
290  }
291 
292  inline bool needsPenEmulation() const
293  {
294  return hasExtendedRadialGradientPen;
295  }
296 
297  inline bool needsBrushEmulation() const
298  {
299  return hasExtendedRadialGradientBrush;
300  }
301 
302  // Set various modes, but only if different.
303  inline void setImageMode(VGImageMode mode);
304  inline void setRenderingQuality(VGRenderingQuality mode);
305  inline void setImageQuality(VGImageQuality mode);
306  inline void setBlendMode(VGBlendMode mode);
307  inline void setFillRule(VGint mode);
308 
309  // Clear all lazily-set modes.
310  void clearModes();
311 
312 private:
314 };
315 
316 inline void QVGPaintEnginePrivate::setImageMode(VGImageMode mode)
317 {
318  if (imageMode != mode) {
319  imageMode = mode;
320  vgSeti(VG_IMAGE_MODE, mode);
321  }
322 }
323 
324 inline void QVGPaintEnginePrivate::setRenderingQuality(VGRenderingQuality mode)
325 {
326  if (renderingQuality != mode) {
327  vgSeti(VG_RENDERING_QUALITY, mode);
328  renderingQuality = mode;
329  pathTransformSet = false; // need to tweak transform for aliased stroking
330  }
331 }
332 
333 inline void QVGPaintEnginePrivate::setImageQuality(VGImageQuality mode)
334 {
335  if (imageQuality != mode) {
336  vgSeti(VG_IMAGE_QUALITY, mode);
337  imageQuality = mode;
338  }
339 }
340 
341 inline void QVGPaintEnginePrivate::setBlendMode(VGBlendMode mode)
342 {
343  if (blendMode != mode) {
344  vgSeti(VG_BLEND_MODE, mode);
345  blendMode = mode;
346  }
347 }
348 
349 inline void QVGPaintEnginePrivate::setFillRule(VGint mode)
350 {
351  if (fillRule != mode) {
352  fillRule = mode;
353  vgSeti(VG_FILL_RULE, mode);
354  }
355 }
356 
358 {
359  matrixMode = (VGMatrixMode)0;
360  imageMode = (VGImageMode)0;
361  blendMode = (VGBlendMode)0;
362  renderingQuality = (VGRenderingQuality)0;
363  imageQuality = (VGImageQuality)0;
364 }
365 
367 {
368  init();
369 }
370 
372 {
373  maxScissorRects = 0;
374 
375  penPaint = 0;
376  brushPaint = 0;
377  opacityPaint = 0;
378  fillPaint = 0;
379 
380  forcePenChange = true;
381  forceBrushChange = true;
382 
385 
386  penType = (VGPaintType)0;
387  brushType = (VGPaintType)0;
388 
389  brushOrigin = QPointF(0.0f, 0.0f);
390 
391  fillRule = 0;
392 
393  opacity = 1.0;
394  paintOpacity = 1.0f;
395 
396 #if !defined(QVG_NO_MODIFY_PATH)
397  rectPath = 0;
398  linePath = 0;
399  roundRectPath = 0;
400 #endif
401 
402  simpleTransform = true;
403  pathTransformSet = false;
404  penScale = 1.0;
405 
406  maskValid = false;
407  maskIsSet = false;
408  scissorMask = false;
409  rawVG = false;
410 
411  scissorActive = false;
412  scissorDirty = false;
413 
414  dirty = 0;
415 
416  clearOpacity = 1.0f;
417 
418 #if !defined(QVG_NO_DRAW_GLYPHS)
419  fontEngineCleaner = 0;
420 #endif
421 
422  hasAdvancedBlending = false;
423 
424  clearModes();
425 }
426 
428 {
429  destroy();
430 }
431 
433 {
434  maxScissorRects = vgGeti(VG_MAX_SCISSOR_RECTS);
435 
436  penPaint = vgCreatePaint();
437  vgSetParameteri(penPaint, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR);
438  vgSetPaint(penPaint, VG_STROKE_PATH);
439 
440  vgSeti(VG_MATRIX_MODE, VG_MATRIX_STROKE_PAINT_TO_USER);
441  vgLoadIdentity();
442 
443  brushPaint = vgCreatePaint();
444  vgSetParameteri(brushPaint, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR);
445  vgSetPaint(brushPaint, VG_FILL_PATH);
447 
448  vgSeti(VG_MATRIX_MODE, VG_MATRIX_FILL_PAINT_TO_USER);
449  vgLoadIdentity();
450  matrixMode = VG_MATRIX_FILL_PAINT_TO_USER;
451 
452  opacityPaint = vgCreatePaint();
453  vgSetParameteri(opacityPaint, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR);
454  VGfloat values[4];
455  values[0] = 1.0f;
456  values[1] = 1.0f;
457  values[2] = 1.0f;
458  values[3] = paintOpacity;
459  vgSetParameterfv(opacityPaint, VG_PAINT_COLOR, 4, values);
460 
461 #if !defined(QVG_NO_MODIFY_PATH)
462  // Create a dummy path for rectangle drawing, which we can
463  // modify later with vgModifyPathCoords(). This should be
464  // faster than constantly creating and destroying paths.
465  rectPath = vgCreatePath(VG_PATH_FORMAT_STANDARD,
466  VG_PATH_DATATYPE_F,
467  1.0f, // scale
468  0.0f, // bias
469  5, // segmentCapacityHint
470  8, // coordCapacityHint
471  VG_PATH_CAPABILITY_ALL);
472  static VGubyte const segments[5] = {
473  VG_MOVE_TO_ABS,
474  VG_LINE_TO_ABS,
475  VG_LINE_TO_ABS,
476  VG_LINE_TO_ABS,
477  VG_CLOSE_PATH
478  };
479  VGfloat coords[8];
480  coords[0] = 0.0f;
481  coords[1] = 0.0f;
482  coords[2] = 100.0f;
483  coords[3] = coords[1];
484  coords[4] = coords[2];
485  coords[5] = 100.0f;
486  coords[6] = coords[0];
487  coords[7] = coords[5];
488  vgAppendPathData(rectPath, 5, segments, coords);
489 
490  // Create a dummy line drawing path as well.
491  linePath = vgCreatePath(VG_PATH_FORMAT_STANDARD,
492  VG_PATH_DATATYPE_F,
493  1.0f, // scale
494  0.0f, // bias
495  2, // segmentCapacityHint
496  4, // coordCapacityHint
497  VG_PATH_CAPABILITY_ALL);
498  vgAppendPathData(linePath, 2, segments, coords);
499 #endif
500 
501  const char *extensions = reinterpret_cast<const char *>(vgGetString(VG_EXTENSIONS));
502  if (extensions)
503  hasAdvancedBlending = strstr(extensions, "VG_KHR_advanced_blending") != 0;
504 }
505 
507 {
508  if (penPaint)
509  vgDestroyPaint(penPaint);
510  if (brushPaint)
511  vgDestroyPaint(brushPaint);
512  if (opacityPaint)
513  vgDestroyPaint(opacityPaint);
514 
515 #if !defined(QVG_NO_MODIFY_PATH)
516  if (rectPath)
517  vgDestroyPath(rectPath);
518  if (linePath)
519  vgDestroyPath(linePath);
520  if (roundRectPath)
521  vgDestroyPath(roundRectPath);
522 #endif
523 
524 #if !defined(QVG_NO_DRAW_GLYPHS)
525  QVGFontCache::Iterator it;
526  for (it = fontCache.begin(); it != fontCache.end(); ++it)
527  delete it.value();
528  fontCache.clear();
529  delete fontEngineCleaner;
530 #endif
531 }
532 
533 // Set a specific VG transformation matrix in the current VG context.
535  (VGMatrixMode mode, const QTransform& transform)
536 {
537  VGfloat mat[9];
538  if (mode != matrixMode) {
539  vgSeti(VG_MATRIX_MODE, mode);
540  matrixMode = mode;
541  }
542  mat[0] = transform.m11();
543  mat[1] = transform.m12();
544  mat[2] = transform.m13();
545  mat[3] = transform.m21();
546  mat[4] = transform.m22();
547  mat[5] = transform.m23();
548  mat[6] = transform.m31();
549  mat[7] = transform.m32();
550  mat[8] = transform.m33();
551  vgLoadMatrix(mat);
552 }
553 
554 Q_GUI_EXPORT bool qt_scaleForTransform(const QTransform &transform, qreal *scale);
555 
557 {
558  VGfloat devh = pdev->height();
559 
560  // Construct the VG transform by combining the Qt transform with
561  // the following viewport transformation:
562  // | 1 0 0 |
563  // | 0 -1 devh |
564  // | 0 0 1 |
565  // The full VG transform is effectively:
566  // 1. Apply the user's transformation matrix.
567  // 2. Flip the co-ordinate system upside down.
568  QTransform viewport(1.0f, 0.0f, 0.0f,
569  0.0f, -1.0f, 0.0f,
570  0.0f, devh, 1.0f);
571 
572  // Compute the path transform and determine if it is projective.
573  pathTransform = transform * viewport;
574  bool projective = (pathTransform.m13() != 0.0f ||
575  pathTransform.m23() != 0.0f ||
576  pathTransform.m33() != 1.0f);
577  if (projective) {
578  // The engine cannot do projective path transforms for us,
579  // so we will have to convert the co-ordinates ourselves.
580  // Change the matrix to just the viewport transformation.
581  pathTransform = viewport;
582  simpleTransform = false;
583  } else {
584  simpleTransform = true;
585  }
586  pathTransformSet = false;
587 
588  // The image transform is always the full transformation,
589  imageTransform = transform * viewport;
590 
591  // Calculate the scaling factor to use for turning cosmetic pens
592  // into ordinary non-cosmetic pens.
593  qt_scaleForTransform(transform, &penScale);
594 }
595 
597 {
598  int count = path.elementCount();
599  const qreal *points = path.points();
601 
602  VGPath vgpath = vgCreatePath(VG_PATH_FORMAT_STANDARD,
603  VG_PATH_DATATYPE_F,
604  1.0f, // scale
605  0.0f, // bias
606  count + 1, // segmentCapacityHint
607  count * 2, // coordCapacityHint
608  VG_PATH_CAPABILITY_ALL);
609 
610  // Size is sufficient segments for drawRoundedRect() paths.
612 
613  if (sizeof(qreal) == sizeof(VGfloat) && elements && simpleTransform) {
614  // If Qt was compiled with qreal the same size as VGfloat,
615  // then convert the segment types and use the incoming
616  // points array directly.
617  for (int i = 0; i < count; ++i) {
618  switch (elements[i]) {
619 
621  segments.append(VG_MOVE_TO_ABS); break;
622 
624  segments.append(VG_LINE_TO_ABS); break;
625 
627  segments.append(VG_CUBIC_TO_ABS); break;
628 
630 
631  }
632  }
633  if (path.hasImplicitClose())
634  segments.append(VG_CLOSE_PATH);
635 
636  vgAppendPathData(vgpath, segments.count(), segments.constData(),
637  reinterpret_cast<const VGfloat *>(points));
638 
639  return vgpath;
640  }
641 
642  // Sizes chosen so that drawRoundedRect() paths fit in these arrays.
644 
645  int curvePos = 0;
646  QPointF temp;
647 
648  if (elements && simpleTransform) {
649  // Convert the members of the element array.
650  for (int i = 0; i < count; ++i) {
651  switch (elements[i]) {
652 
654  {
655  coords.append(points[0]);
656  coords.append(points[1]);
657  segments.append(VG_MOVE_TO_ABS);
658  }
659  break;
660 
662  {
663  coords.append(points[0]);
664  coords.append(points[1]);
665  segments.append(VG_LINE_TO_ABS);
666  }
667  break;
668 
670  {
671  coords.append(points[0]);
672  coords.append(points[1]);
673  curvePos = 2;
674  }
675  break;
676 
678  {
679  coords.append(points[0]);
680  coords.append(points[1]);
681  curvePos += 2;
682  if (curvePos == 6) {
683  curvePos = 0;
684  segments.append(VG_CUBIC_TO_ABS);
685  }
686  }
687  break;
688 
689  }
690  points += 2;
691  }
692  } else if (elements && !simpleTransform) {
693  // Convert the members of the element array after applying the
694  // current transform to the path locally.
695  for (int i = 0; i < count; ++i) {
696  switch (elements[i]) {
697 
699  {
700  temp = transform.map(QPointF(points[0], points[1]));
701  coords.append(temp.x());
702  coords.append(temp.y());
703  segments.append(VG_MOVE_TO_ABS);
704  }
705  break;
706 
708  {
709  temp = transform.map(QPointF(points[0], points[1]));
710  coords.append(temp.x());
711  coords.append(temp.y());
712  segments.append(VG_LINE_TO_ABS);
713  }
714  break;
715 
717  {
718  temp = transform.map(QPointF(points[0], points[1]));
719  coords.append(temp.x());
720  coords.append(temp.y());
721  curvePos = 2;
722  }
723  break;
724 
726  {
727  temp = transform.map(QPointF(points[0], points[1]));
728  coords.append(temp.x());
729  coords.append(temp.y());
730  curvePos += 2;
731  if (curvePos == 6) {
732  curvePos = 0;
733  segments.append(VG_CUBIC_TO_ABS);
734  }
735  }
736  break;
737 
738  }
739  points += 2;
740  }
741  } else if (count > 0 && simpleTransform) {
742  // If there is no element array, then the path is assumed
743  // to be a MoveTo followed by several LineTo's.
744  coords.append(points[0]);
745  coords.append(points[1]);
746  segments.append(VG_MOVE_TO_ABS);
747  while (count > 1) {
748  points += 2;
749  coords.append(points[0]);
750  coords.append(points[1]);
751  segments.append(VG_LINE_TO_ABS);
752  --count;
753  }
754  } else if (count > 0 && !simpleTransform) {
755  // Convert a simple path, and apply the transform locally.
756  temp = transform.map(QPointF(points[0], points[1]));
757  coords.append(temp.x());
758  coords.append(temp.y());
759  segments.append(VG_MOVE_TO_ABS);
760  while (count > 1) {
761  points += 2;
762  temp = transform.map(QPointF(points[0], points[1]));
763  coords.append(temp.x());
764  coords.append(temp.y());
765  segments.append(VG_LINE_TO_ABS);
766  --count;
767  }
768  }
769 
770  // Close the path if specified.
771  if (path.hasImplicitClose())
772  segments.append(VG_CLOSE_PATH);
773 
774  vgAppendPathData(vgpath, segments.count(),
775  segments.constData(), coords.constData());
776 
777  return vgpath;
778 }
779 
781 {
782  int count = path.elementCount();
783 
784  VGPath vgpath = vgCreatePath(VG_PATH_FORMAT_STANDARD,
785  VG_PATH_DATATYPE_F,
786  1.0f, // scale
787  0.0f, // bias
788  count + 1, // segmentCapacityHint
789  count * 2, // coordCapacityHint
790  VG_PATH_CAPABILITY_ALL);
791 
792  if (count == 0)
793  return vgpath;
794 
795  const QPainterPath::Element *elements = &(path.elementAt(0));
796 
797  // Sizes chosen so that drawRoundedRect() paths fit in these arrays.
800 
801  int curvePos = 0;
802  QPointF temp;
803 
804  // Keep track of the start and end of each sub-path. QPainterPath
805  // does not have an "implicit close" flag like QVectorPath does.
806  // We therefore have to detect closed paths by looking for a LineTo
807  // element that connects back to the initial MoveTo element.
808  qreal startx = 0.0;
809  qreal starty = 0.0;
810  qreal endx = 0.0;
811  qreal endy = 0.0;
812  bool haveStart = false;
813  bool haveEnd = false;
814 
815  if (simpleTransform) {
816  // Convert the members of the element array.
817  for (int i = 0; i < count; ++i) {
818  switch (elements[i].type) {
819 
821  {
822  if (haveStart && haveEnd && startx == endx && starty == endy) {
823  // Implicitly close the previous sub-path.
824  segments.append(VG_CLOSE_PATH);
825  }
826  startx = elements[i].x;
827  starty = elements[i].y;
828  coords.append(startx);
829  coords.append(starty);
830  haveStart = true;
831  haveEnd = false;
832  segments.append(VG_MOVE_TO_ABS);
833  }
834  break;
835 
837  {
838  endx = elements[i].x;
839  endy = elements[i].y;
840  coords.append(endx);
841  coords.append(endy);
842  haveEnd = true;
843  segments.append(VG_LINE_TO_ABS);
844  }
845  break;
846 
848  {
849  coords.append(elements[i].x);
850  coords.append(elements[i].y);
851  haveEnd = false;
852  curvePos = 2;
853  }
854  break;
855 
857  {
858  coords.append(elements[i].x);
859  coords.append(elements[i].y);
860  haveEnd = false;
861  curvePos += 2;
862  if (curvePos == 6) {
863  curvePos = 0;
864  segments.append(VG_CUBIC_TO_ABS);
865  }
866  }
867  break;
868 
869  }
870  }
871  } else {
872  // Convert the members of the element array after applying the
873  // current transform to the path locally.
874  for (int i = 0; i < count; ++i) {
875  switch (elements[i].type) {
876 
878  {
879  if (haveStart && haveEnd && startx == endx && starty == endy) {
880  // Implicitly close the previous sub-path.
881  segments.append(VG_CLOSE_PATH);
882  }
883  temp = transform.map(QPointF(elements[i].x, elements[i].y));
884  startx = temp.x();
885  starty = temp.y();
886  coords.append(startx);
887  coords.append(starty);
888  haveStart = true;
889  haveEnd = false;
890  segments.append(VG_MOVE_TO_ABS);
891  }
892  break;
893 
895  {
896  temp = transform.map(QPointF(elements[i].x, elements[i].y));
897  endx = temp.x();
898  endy = temp.y();
899  coords.append(endx);
900  coords.append(endy);
901  haveEnd = true;
902  segments.append(VG_LINE_TO_ABS);
903  }
904  break;
905 
907  {
908  temp = transform.map(QPointF(elements[i].x, elements[i].y));
909  coords.append(temp.x());
910  coords.append(temp.y());
911  haveEnd = false;
912  curvePos = 2;
913  }
914  break;
915 
917  {
918  temp = transform.map(QPointF(elements[i].x, elements[i].y));
919  coords.append(temp.x());
920  coords.append(temp.y());
921  haveEnd = false;
922  curvePos += 2;
923  if (curvePos == 6) {
924  curvePos = 0;
925  segments.append(VG_CUBIC_TO_ABS);
926  }
927  }
928  break;
929 
930  }
931  }
932  }
933 
934  if (haveStart && haveEnd && startx == endx && starty == endy) {
935  // Implicitly close the last sub-path.
936  segments.append(VG_CLOSE_PATH);
937  }
938 
939  vgAppendPathData(vgpath, segments.count(),
940  segments.constData(), coords.constData());
941 
942  return vgpath;
943 }
944 
945 VGPath QVGPaintEnginePrivate::roundedRectPath(const QRectF &rect, qreal xRadius, qreal yRadius, Qt::SizeMode mode)
946 {
947  static VGubyte roundedrect_types[] = {
948  VG_MOVE_TO_ABS,
949  VG_LINE_TO_ABS,
950  VG_CUBIC_TO_ABS,
951  VG_LINE_TO_ABS,
952  VG_CUBIC_TO_ABS,
953  VG_LINE_TO_ABS,
954  VG_CUBIC_TO_ABS,
955  VG_LINE_TO_ABS,
956  VG_CUBIC_TO_ABS,
957  VG_CLOSE_PATH
958  };
959 
960  qreal x1 = rect.left();
961  qreal x2 = rect.right();
962  qreal y1 = rect.top();
963  qreal y2 = rect.bottom();
964 
965  if (mode == Qt::RelativeSize) {
966  xRadius = xRadius * rect.width() / 200.;
967  yRadius = yRadius * rect.height() / 200.;
968  }
969 
970  xRadius = qMin(xRadius, rect.width() / 2);
971  yRadius = qMin(yRadius, rect.height() / 2);
972 
973  VGfloat pts[] = {
974  x1 + xRadius, y1, // MoveTo
975  x2 - xRadius, y1, // LineTo
976  x2 - (1 - KAPPA) * xRadius, y1, // CurveTo
977  x2, y1 + (1 - KAPPA) * yRadius,
978  x2, y1 + yRadius,
979  x2, y2 - yRadius, // LineTo
980  x2, y2 - (1 - KAPPA) * yRadius, // CurveTo
981  x2 - (1 - KAPPA) * xRadius, y2,
982  x2 - xRadius, y2,
983  x1 + xRadius, y2, // LineTo
984  x1 + (1 - KAPPA) * xRadius, y2, // CurveTo
985  x1, y2 - (1 - KAPPA) * yRadius,
986  x1, y2 - yRadius,
987  x1, y1 + yRadius, // LineTo
988  x1, y1 + (1 - KAPPA) * yRadius, // CurveTo
989  x1 + (1 - KAPPA) * xRadius, y1,
990  x1 + xRadius, y1
991  };
992 
993 #if !defined(QVG_NO_MODIFY_PATH)
994  VGPath vgpath = roundRectPath;
995  if (!vgpath) {
996  vgpath = vgCreatePath(VG_PATH_FORMAT_STANDARD,
997  VG_PATH_DATATYPE_F,
998  1.0f, // scale
999  0.0f, // bias
1000  10, // segmentCapacityHint
1001  17 * 2, // coordCapacityHint
1002  VG_PATH_CAPABILITY_ALL);
1003  vgAppendPathData(vgpath, 10, roundedrect_types, pts);
1004  roundRectPath = vgpath;
1005  } else {
1006  vgModifyPathCoords(vgpath, 0, 9, pts);
1007  }
1008 #else
1009  VGPath vgpath = vgCreatePath(VG_PATH_FORMAT_STANDARD,
1010  VG_PATH_DATATYPE_F,
1011  1.0f, // scale
1012  0.0f, // bias
1013  10, // segmentCapacityHint
1014  17 * 2, // coordCapacityHint
1015  VG_PATH_CAPABILITY_ALL);
1016  vgAppendPathData(vgpath, 10, roundedrect_types, pts);
1017 #endif
1018 
1019  return vgpath;
1020 }
1021 
1022 Q_GUI_EXPORT QImage qt_imageForBrush(int style, bool invert);
1023 
1024 static QImage colorizeBitmap(const QImage &image, const QColor &color)
1025 {
1026  QImage sourceImage = image.convertToFormat(QImage::Format_MonoLSB);
1027  QImage dest = QImage(sourceImage.size(), QImage::Format_ARGB32_Premultiplied);
1028 
1029  QRgb fg = PREMUL(color.rgba());
1030  QRgb bg = 0;
1031 
1032  int height = sourceImage.height();
1033  int width = sourceImage.width();
1034  for (int y=0; y<height; ++y) {
1035  const uchar *source = sourceImage.constScanLine(y);
1036  QRgb *target = reinterpret_cast<QRgb *>(dest.scanLine(y));
1037  for (int x=0; x < width; ++x)
1038  target[x] = (source[x>>3] >> (x&7)) & 1 ? fg : bg;
1039  }
1040  return dest;
1041 }
1042 
1043 static VGImage toVGImage
1044  (const QImage & image, Qt::ImageConversionFlags flags = Qt::AutoColor)
1045 {
1046  QImage img(image);
1047 
1048  VGImageFormat format;
1049  switch (img.format()) {
1050  case QImage::Format_Mono:
1051  img = image.convertToFormat(QImage::Format_MonoLSB, flags);
1052  img.invertPixels();
1053  format = VG_BW_1;
1054  break;
1056  img.invertPixels();
1057  format = VG_BW_1;
1058  break;
1059  case QImage::Format_RGB32:
1060  format = VG_sXRGB_8888;
1061  break;
1062  case QImage::Format_ARGB32:
1063  format = VG_sARGB_8888;
1064  break;
1066  format = VG_sARGB_8888_PRE;
1067  break;
1068  case QImage::Format_RGB16:
1069  format = VG_sRGB_565;
1070  break;
1071  default:
1072  // Convert everything else into ARGB32_Premultiplied.
1074  format = VG_sARGB_8888_PRE;
1075  break;
1076  }
1077 
1078  const uchar *pixels = img.constBits();
1079 
1080  VGImage vgImg = QVGImagePool::instance()->createPermanentImage
1081  (format, img.width(), img.height(), VG_IMAGE_QUALITY_FASTER);
1082  vgImageSubData
1083  (vgImg, pixels, img.bytesPerLine(), format, 0, 0,
1084  img.width(), img.height());
1085 
1086  return vgImg;
1087 }
1088 
1089 static VGImage toVGImageSubRect
1090  (const QImage & image, const QRect& sr,
1091  Qt::ImageConversionFlags flags = Qt::AutoColor)
1092 {
1093  QImage img(image);
1094 
1095  VGImageFormat format;
1096  int bpp = 4;
1097 
1098  switch (img.format()) {
1099  case QImage::Format_Mono:
1101  return VG_INVALID_HANDLE;
1102  case QImage::Format_RGB32:
1103  format = VG_sXRGB_8888;
1104  break;
1105  case QImage::Format_ARGB32:
1106  format = VG_sARGB_8888;
1107  break;
1109  format = VG_sARGB_8888_PRE;
1110  break;
1111  case QImage::Format_RGB16:
1112  format = VG_sRGB_565;
1113  bpp = 2;
1114  break;
1115  default:
1116  // Convert everything else into ARGB32_Premultiplied.
1118  format = VG_sARGB_8888_PRE;
1119  break;
1120  }
1121 
1122  const uchar *pixels = img.constBits() + bpp * sr.x() +
1123  img.bytesPerLine() * sr.y();
1124 
1125  VGImage vgImg = QVGImagePool::instance()->createPermanentImage
1126  (format, sr.width(), sr.height(), VG_IMAGE_QUALITY_FASTER);
1127  vgImageSubData
1128  (vgImg, pixels, img.bytesPerLine(), format, 0, 0,
1129  sr.width(), sr.height());
1130 
1131  return vgImg;
1132 }
1133 
1134 static VGImage toVGImageWithOpacity(const QImage & image, qreal opacity)
1135 {
1137  img.fill(0);
1138  QPainter painter;
1139  painter.begin(&img);
1140  painter.setOpacity(opacity);
1141  painter.drawImage(0, 0, image);
1142  painter.end();
1143 
1144  const uchar *pixels = img.constBits();
1145 
1146  VGImage vgImg = QVGImagePool::instance()->createPermanentImage
1147  (VG_sARGB_8888_PRE, img.width(), img.height(), VG_IMAGE_QUALITY_FASTER);
1148  vgImageSubData
1149  (vgImg, pixels, img.bytesPerLine(), VG_sARGB_8888_PRE, 0, 0,
1150  img.width(), img.height());
1151 
1152  return vgImg;
1153 }
1154 
1155 static VGImage toVGImageWithOpacitySubRect
1156  (const QImage & image, qreal opacity, const QRect& sr)
1157 {
1159  img.fill(0);
1160  QPainter painter;
1161  painter.begin(&img);
1162  painter.setOpacity(opacity);
1163  painter.drawImage(QPoint(0, 0), image, sr);
1164  painter.end();
1165 
1166  const uchar *pixels = img.constBits();
1167 
1168  VGImage vgImg = QVGImagePool::instance()->createPermanentImage
1169  (VG_sARGB_8888_PRE, img.width(), img.height(), VG_IMAGE_QUALITY_FASTER);
1170  vgImageSubData
1171  (vgImg, pixels, img.bytesPerLine(), VG_sARGB_8888_PRE, 0, 0,
1172  img.width(), img.height());
1173 
1174  return vgImg;
1175 }
1176 
1178  (VGPaint paint, const QBrush& brush, VGMatrixMode mode,
1179  VGPaintType prevType)
1180 {
1181  VGfloat values[5];
1182  setBrushTransform(brush, mode);
1183 
1184  // Reset the paint pattern on the brush, which will discard
1185  // the previous VGImage if one was set.
1186  if (prevType == VG_PAINT_TYPE_PATTERN || prevType == (VGPaintType)0)
1187  vgPaintPattern(paint, VG_INVALID_HANDLE);
1188 
1189  switch (brush.style()) {
1190 
1191  case Qt::SolidPattern: {
1192  // The brush is a solid color.
1193  QColor color(brush.color());
1194  values[0] = color.redF();
1195  values[1] = color.greenF();
1196  values[2] = color.blueF();
1197  values[3] = color.alphaF() * opacity;
1198  if (prevType != VG_PAINT_TYPE_COLOR)
1199  vgSetParameteri(paint, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR);
1200  vgSetParameterfv(paint, VG_PAINT_COLOR, 4, values);
1201  return VG_PAINT_TYPE_COLOR;
1202  }
1203 
1205  // The brush is a linear gradient.
1207  const QLinearGradient *grad =
1208  static_cast<const QLinearGradient*>(brush.gradient());
1209  values[0] = grad->start().x();
1210  values[1] = grad->start().y();
1211  values[2] = grad->finalStop().x();
1212  values[3] = grad->finalStop().y();
1213  if (prevType != VG_PAINT_TYPE_LINEAR_GRADIENT)
1214  vgSetParameteri(paint, VG_PAINT_TYPE, VG_PAINT_TYPE_LINEAR_GRADIENT);
1215  vgSetParameterfv(paint, VG_PAINT_LINEAR_GRADIENT, 4, values);
1216  setupColorRamp(grad, paint);
1217  return VG_PAINT_TYPE_LINEAR_GRADIENT;
1218  }
1219 
1221  // The brush is a radial gradient.
1223  const QRadialGradient *grad =
1224  static_cast<const QRadialGradient*>(brush.gradient());
1225  values[0] = grad->center().x();
1226  values[1] = grad->center().y();
1227  values[2] = grad->focalPoint().x();
1228  values[3] = grad->focalPoint().y();
1229  values[4] = grad->radius();
1230  if (prevType != VG_PAINT_TYPE_RADIAL_GRADIENT)
1231  vgSetParameteri(paint, VG_PAINT_TYPE, VG_PAINT_TYPE_RADIAL_GRADIENT);
1232  vgSetParameterfv(paint, VG_PAINT_RADIAL_GRADIENT, 5, values);
1233  setupColorRamp(grad, paint);
1234  return VG_PAINT_TYPE_RADIAL_GRADIENT;
1235  }
1236 
1237  case Qt::TexturePattern: {
1238  // The brush is a texture specified by a QPixmap/QImage.
1239  QPixmapData *pd = brush.texture().pixmapData();
1240  if (!pd)
1241  break; // null QPixmap
1242  VGImage vgImg;
1243  bool deref = false;
1244  if (pd->pixelType() == QPixmapData::BitmapType) {
1245  // Colorize bitmaps using the brush color and opacity.
1246  QColor color = brush.color();
1247  if (opacity != 1.0)
1248  color.setAlphaF(color.alphaF() * opacity);
1249  QImage image = colorizeBitmap(*(pd->buffer()), color);
1250  vgImg = toVGImage(image);
1251  deref = true;
1252  } else if (opacity == 1.0) {
1253  if (pd->classId() == QPixmapData::OpenVGClass) {
1254  QVGPixmapData *vgpd = static_cast<QVGPixmapData *>(pd);
1255  vgImg = vgpd->toVGImage();
1256 
1257  // We don't want the pool to reclaim this image
1258  // because we cannot predict when the paint object
1259  // will stop using it. Replacing the image with
1260  // new data will make the paint object invalid.
1261  vgpd->detachImageFromPool();
1262  } else {
1263  vgImg = toVGImage(*(pd->buffer()));
1264  deref = true;
1265  }
1266  } else if (pd->classId() == QPixmapData::OpenVGClass) {
1267  QVGPixmapData *vgpd = static_cast<QVGPixmapData *>(pd);
1268  vgImg = vgpd->toVGImage(opacity);
1269  vgpd->detachImageFromPool();
1270  } else {
1271  vgImg = toVGImageWithOpacity(*(pd->buffer()), opacity);
1272  deref = true;
1273  }
1274  if (vgImg == VG_INVALID_HANDLE)
1275  break;
1276  if (prevType != VG_PAINT_TYPE_PATTERN)
1277  vgSetParameteri(paint, VG_PAINT_TYPE, VG_PAINT_TYPE_PATTERN);
1278  vgSetParameteri(paint, VG_PAINT_PATTERN_TILING_MODE, VG_TILE_REPEAT);
1279  vgPaintPattern(paint, vgImg);
1280  if (deref)
1281  vgDestroyImage(vgImg); // Will be valid until pattern is destroyed.
1282  return VG_PAINT_TYPE_PATTERN;
1283  }
1284 
1286  // Convert conical gradients into the first stop color.
1287  qWarning() << "QVGPaintEnginePrivate::setBrush: conical gradients are not supported by OpenVG";
1289  const QConicalGradient *grad =
1290  static_cast<const QConicalGradient*>(brush.gradient());
1291  const QGradientStops stops = grad->stops();
1292  QColor color;
1293  if (stops.size() > 0)
1294  color = stops[0].second;
1295  values[0] = color.redF();
1296  values[1] = color.greenF();
1297  values[2] = color.blueF();
1298  values[3] = color.alphaF() * opacity;
1299  if (prevType != VG_PAINT_TYPE_COLOR)
1300  vgSetParameteri(paint, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR);
1301  vgSetParameterfv(paint, VG_PAINT_COLOR, 4, values);
1302  return VG_PAINT_TYPE_COLOR;
1303  }
1304 
1305  case Qt::Dense1Pattern:
1306  case Qt::Dense2Pattern:
1307  case Qt::Dense3Pattern:
1308  case Qt::Dense4Pattern:
1309  case Qt::Dense5Pattern:
1310  case Qt::Dense6Pattern:
1311  case Qt::Dense7Pattern:
1312  case Qt::HorPattern:
1313  case Qt::VerPattern:
1314  case Qt::CrossPattern:
1315  case Qt::BDiagPattern:
1316  case Qt::FDiagPattern:
1317  case Qt::DiagCrossPattern: {
1318  // The brush is a traditional dotted or cross-hatched pattern brush.
1319  QColor color = brush.color();
1320  if (opacity != 1.0)
1321  color.setAlphaF(color.alphaF() * opacity);
1322  QImage image = colorizeBitmap
1323  (qt_imageForBrush(brush.style(), true), color);
1324  VGImage vgImg = toVGImage(image);
1325  if (prevType != VG_PAINT_TYPE_PATTERN)
1326  vgSetParameteri(paint, VG_PAINT_TYPE, VG_PAINT_TYPE_PATTERN);
1327  vgSetParameteri(paint, VG_PAINT_PATTERN_TILING_MODE, VG_TILE_REPEAT);
1328  vgPaintPattern(paint, vgImg);
1329  vgDestroyImage(vgImg); // Will stay valid until pattern is destroyed.
1330  return VG_PAINT_TYPE_PATTERN;
1331  }
1332 
1333  default: break;
1334  }
1335  return (VGPaintType)0;
1336 }
1337 
1339 {
1340  // Note: OpenVG does not support zero-width or cosmetic pens,
1341  // so we have to simulate cosmetic pens by reversing the scale.
1342  VGfloat width = pen.widthF();
1343  if (width <= 0.0f)
1344  width = 1.0f;
1345  if (pen.isCosmetic()) {
1346  if (penScale != 1.0 && penScale != 0.0)
1347  width /= penScale;
1348  }
1349  vgSetf(VG_STROKE_LINE_WIDTH, width);
1350 
1351  if (pen.capStyle() == Qt::FlatCap)
1352  vgSetf(VG_STROKE_CAP_STYLE, VG_CAP_BUTT);
1353  else if (pen.capStyle() == Qt::SquareCap)
1354  vgSetf(VG_STROKE_CAP_STYLE, VG_CAP_SQUARE);
1355  else
1356  vgSetf(VG_STROKE_CAP_STYLE, VG_CAP_ROUND);
1357 
1358  if (pen.joinStyle() == Qt::MiterJoin) {
1359  vgSetf(VG_STROKE_JOIN_STYLE, VG_JOIN_MITER);
1360  vgSetf(VG_STROKE_MITER_LIMIT, pen.miterLimit());
1361  } else if (pen.joinStyle() == Qt::BevelJoin) {
1362  vgSetf(VG_STROKE_JOIN_STYLE, VG_JOIN_BEVEL);
1363  } else {
1364  vgSetf(VG_STROKE_JOIN_STYLE, VG_JOIN_ROUND);
1365  }
1366 
1367  if (pen.style() == Qt::SolidLine) {
1368  vgSetfv(VG_STROKE_DASH_PATTERN, 0, NULL);
1369  } else {
1370  const QVector<qreal> dashPattern = pen.dashPattern();
1371  QVector<VGfloat> currentDashPattern(dashPattern.count());
1372  for (int i = 0; i < dashPattern.count(); ++i)
1373  currentDashPattern[i] = dashPattern[i] * width;
1374  vgSetfv(VG_STROKE_DASH_PATTERN, currentDashPattern.count(), currentDashPattern.data());
1375  vgSetf(VG_STROKE_DASH_PHASE, pen.dashOffset());
1376  vgSetf(VG_STROKE_DASH_PHASE_RESET, VG_FALSE);
1377  }
1378 }
1379 
1381  (const QBrush& brush, VGMatrixMode mode)
1382 {
1383  // Compute the new brush transformation matrix.
1384  QTransform transform(brush.transform());
1385  if (brushOrigin.x() != 0.0f || brushOrigin.y() != 0.0f)
1386  transform.translate(brushOrigin.x(), brushOrigin.y());
1387 
1388  // Bail out if the matrix is the same as last time, to avoid
1389  // updating the VG context state unless absolutely necessary.
1390  // Most applications won't have a brush transformation set,
1391  // which will leave the VG setting at its default of identity.
1392  // Always change the transform if coming out of raw VG mode.
1393  if (mode == VG_MATRIX_FILL_PAINT_TO_USER) {
1394  if (!rawVG && transform == brushTransform)
1395  return;
1397  } else {
1398  if (!rawVG && transform == penTransform)
1399  return;
1401  }
1402 
1403  // Set the brush transformation matrix.
1404  if (mode != matrixMode) {
1405  vgSeti(VG_MATRIX_MODE, mode);
1406  matrixMode = mode;
1407  }
1408  if (transform.isIdentity()) {
1409  vgLoadIdentity();
1410  } else {
1411  VGfloat mat[9];
1412  mat[0] = transform.m11();
1413  mat[1] = transform.m12();
1414  mat[2] = transform.m13();
1415  mat[3] = transform.m21();
1416  mat[4] = transform.m22();
1417  mat[5] = transform.m23();
1418  mat[6] = transform.m31();
1419  mat[7] = transform.m32();
1420  mat[8] = transform.m33();
1421  vgLoadMatrix(mat);
1422  }
1423 }
1424 
1425 void QVGPaintEnginePrivate::setupColorRamp(const QGradient *grad, VGPaint paint)
1426 {
1427  QGradient::Spread spread = grad->spread();
1428  VGColorRampSpreadMode spreadMode;
1429  if (spread == QGradient::ReflectSpread)
1430  spreadMode = VG_COLOR_RAMP_SPREAD_REFLECT;
1431  else if (spread == QGradient::RepeatSpread)
1432  spreadMode = VG_COLOR_RAMP_SPREAD_REPEAT;
1433  else
1434  spreadMode = VG_COLOR_RAMP_SPREAD_PAD;
1435 
1436  const QGradientStops stops = grad->stops();
1437  int n = 5*stops.size();
1438  QVector<VGfloat> fill_stops(n);
1439 
1440  for (int i = 0; i < stops.size(); ++i ) {
1441  QColor col = stops[i].second;
1442  fill_stops[i*5] = stops[i].first;
1443  fill_stops[i*5 + 1] = col.redF();
1444  fill_stops[i*5 + 2] = col.greenF();
1445  fill_stops[i*5 + 3] = col.blueF();
1446  fill_stops[i*5 + 4] = col.alphaF() * opacity;
1447  }
1448 
1449  vgSetParameteri(paint, VG_PAINT_COLOR_RAMP_SPREAD_MODE, spreadMode);
1450  vgSetParameteri(paint, VG_PAINT_COLOR_RAMP_PREMULTIPLIED, VG_FALSE);
1451  vgSetParameterfv(paint, VG_PAINT_COLOR_RAMP_STOPS, n, fill_stops.data());
1452 }
1453 
1455  : QPainterState(other),
1456  isNew(true), clipRegion(other.clipRegion),
1457  savedDirty(0)
1458 {
1459 }
1460 
1462  : isNew(true), savedDirty(0)
1463 {
1464 }
1465 
1467 {
1468 }
1469 
1472 {
1473 }
1474 
1476  : QPaintEngineEx(data)
1477 {
1478 }
1479 
1481 {
1482 }
1483 
1485 {
1486  if (!orig) {
1487  return new QVGPainterState();
1488  } else {
1489  Q_D(const QVGPaintEngine);
1490  QVGPaintEnginePrivate *d2 = const_cast<QVGPaintEnginePrivate*>(d);
1491  QVGPainterState *origState = static_cast<QVGPainterState *>(orig);
1492  origState->savedDirty = d2->dirty;
1493  d2->dirty = 0;
1494  return new QVGPainterState(*origState);
1495  }
1496 }
1497 
1499  (VGPath path, const QPen& pen, const QBrush& brush, VGint rule)
1500 {
1501  VGbitfield mode = 0;
1502  if (qpen_style(pen) != Qt::NoPen && qbrush_style(qpen_brush(pen)) != Qt::NoBrush) {
1503  ensurePen(pen);
1504  mode |= VG_STROKE_PATH;
1505  }
1506  if (brush.style() != Qt::NoBrush) {
1507  ensureBrush(brush);
1508  setFillRule(rule);
1509  mode |= VG_FILL_PATH;
1510  }
1511  if (mode != 0) {
1512  ensurePathTransform();
1513  vgDrawPath(path, mode);
1514  }
1515 }
1516 
1517 void QVGPaintEnginePrivate::stroke(VGPath path, const QPen& pen)
1518 {
1519  if (pen.style() == Qt::NoPen)
1520  return;
1521  ensurePen(pen);
1522  ensurePathTransform();
1523  vgDrawPath(path, VG_STROKE_PATH);
1524 }
1525 
1526 void QVGPaintEnginePrivate::fill(VGPath path, const QBrush& brush, VGint rule)
1527 {
1528  if (brush.style() == Qt::NoBrush)
1529  return;
1530  ensureBrush(brush);
1531  setFillRule(rule);
1532  QPen savedPen = currentPen;
1533  currentPen = Qt::NoPen;
1534  ensurePathTransform();
1535  currentPen = savedPen;
1536  vgDrawPath(path, VG_FILL_PATH);
1537 }
1538 
1540 {
1541  Q_UNUSED(pdev);
1543 
1544  // Initialize the VG painting objects if we haven't done it yet.
1545  if (!d->penPaint)
1546  d->initObjects();
1547 
1548  // The initial clip region is the entire device area.
1549  QVGPainterState *s = state();
1551 
1552  // Initialize the VG state for this paint operation.
1554  d->dirty = 0;
1555  d->rawVG = false;
1556  return true;
1557 }
1558 
1560 {
1561  vgSeti(VG_SCISSORING, VG_FALSE);
1562  vgSeti(VG_MASKING, VG_FALSE);
1563  return true;
1564 }
1565 
1567 {
1569  if (d->needsEmulation()) {
1570  QPaintEngineEx::draw(path);
1571  return;
1572  }
1573  QVGPainterState *s = state();
1574  VGPath vgpath = d->vectorPathToVGPath(path);
1575  if (!path.hasWindingFill())
1576  d->draw(vgpath, s->pen, s->brush, VG_EVEN_ODD);
1577  else
1578  d->draw(vgpath, s->pen, s->brush, VG_NON_ZERO);
1579  vgDestroyPath(vgpath);
1580 }
1581 
1583 
1584 void QVGPaintEngine::fill(const QVectorPath &path, const QBrush &brush)
1585 {
1587  if (d->needsEmulation(brush)) {
1588  QPainter *p = painter();
1589  QBrush oldBrush = p->brush();
1590  p->setBrush(brush);
1592  p->setBrush(oldBrush);
1593  return;
1594  }
1595  VGPath vgpath = d->vectorPathToVGPath(path);
1596  if (!path.hasWindingFill())
1597  d->fill(vgpath, brush, VG_EVEN_ODD);
1598  else
1599  d->fill(vgpath, brush, VG_NON_ZERO);
1600  vgDestroyPath(vgpath);
1601 }
1602 
1603 void QVGPaintEngine::stroke(const QVectorPath &path, const QPen &pen)
1604 {
1606  if (d->needsEmulation(pen.brush())) {
1607  QPaintEngineEx::stroke(path, pen);
1608  return;
1609  }
1610  VGPath vgpath = d->vectorPathToVGPath(path);
1611  d->stroke(vgpath, pen);
1612  vgDestroyPath(vgpath);
1613 }
1614 
1615 // Determine if a co-ordinate transform is simple enough to allow
1616 // rectangle-based clipping with vgMask(). Simple transforms most
1617 // often result from origin translations.
1618 static inline bool clipTransformIsSimple(const QTransform& transform)
1619 {
1621  if (type == QTransform::TxNone || type == QTransform::TxTranslate)
1622  return true;
1623  if (type == QTransform::TxRotate) {
1624  // Check for 0, 90, 180, and 270 degree rotations.
1625  // (0 might happen after 4 rotations of 90 degrees).
1626  qreal m11 = transform.m11();
1627  qreal m12 = transform.m12();
1628  qreal m21 = transform.m21();
1629  qreal m22 = transform.m22();
1630  if (m11 == 0.0f && m22 == 0.0f) {
1631  if (m12 == 1.0f && m21 == -1.0f)
1632  return true; // 90 degrees.
1633  else if (m12 == -1.0f && m21 == 1.0f)
1634  return true; // 270 degrees.
1635  } else if (m12 == 0.0f && m21 == 0.0f) {
1636  if (m11 == -1.0f && m22 == -1.0f)
1637  return true; // 180 degrees.
1638  else if (m11 == 1.0f && m22 == 1.0f)
1639  return true; // 0 degrees.
1640  }
1641  }
1642  return false;
1643 }
1644 
1645 #if defined(QVG_SCISSOR_CLIP)
1646 
1648 {
1650  QVGPainterState *s = state();
1651 
1652  d->dirty |= QPaintEngine::DirtyClipRegion;
1653 
1654  if (op == Qt::NoClip) {
1656  updateScissor();
1657  return;
1658  }
1659 
1660  // We aren't using masking, so handle simple QRectF's only.
1661  if (path.shape() == QVectorPath::RectangleHint &&
1662  path.elementCount() == 4 && clipTransformIsSimple(d->transform)) {
1663  // Clipping region that resulted from QPainter::setClipRect(QRectF).
1664  // Convert it into a QRect and apply.
1665  const qreal *points = path.points();
1666  QRectF rect(points[0], points[1], points[2] - points[0],
1667  points[5] - points[1]);
1668  clip(rect.toRect(), op);
1669  return;
1670  }
1671 
1672  // Try converting the path into a QRegion that tightly follows
1673  // the outline of the path we want to clip with.
1674  QRegion region;
1675  if (!path.isEmpty())
1677 
1678  switch (op) {
1679  case Qt::NoClip:
1680  {
1681  region = defaultClipRegion();
1682  }
1683  break;
1684 
1685  case Qt::ReplaceClip:
1686  {
1687  region = d->transform.map(region);
1688  }
1689  break;
1690 
1691  case Qt::IntersectClip:
1692  {
1693  region = s->clipRegion.intersect(d->transform.map(region));
1694  }
1695  break;
1696 
1697  case Qt::UniteClip:
1698  {
1699  region = s->clipRegion.unite(d->transform.map(region));
1700  }
1701  break;
1702  }
1703  if (region.numRects() <= d->maxScissorRects) {
1704  // We haven't reached the maximum scissor count yet, so we can
1705  // still make use of this region.
1706  s->clipRegion = region;
1707  updateScissor();
1708  return;
1709  }
1710 
1711  // The best we can do is clip to the bounding rectangle
1712  // of all control points.
1713  clip(path.controlPointRect().toRect(), op);
1714 }
1715 
1716 void QVGPaintEngine::clip(const QRect &rect, Qt::ClipOperation op)
1717 {
1719  QVGPainterState *s = state();
1720 
1721  d->dirty |= QPaintEngine::DirtyClipRegion;
1722 
1723  switch (op) {
1724  case Qt::NoClip:
1725  {
1727  }
1728  break;
1729 
1730  case Qt::ReplaceClip:
1731  {
1732  s->clipRegion = d->transform.map(QRegion(rect));
1733  }
1734  break;
1735 
1736  case Qt::IntersectClip:
1737  {
1738  s->clipRegion = s->clipRegion.intersect(d->transform.map(QRegion(rect)));
1739  }
1740  break;
1741 
1742  case Qt::UniteClip:
1743  {
1744  s->clipRegion = s->clipRegion.unite(d->transform.map(QRegion(rect)));
1745  }
1746  break;
1747  }
1748 
1749  updateScissor();
1750 }
1751 
1752 void QVGPaintEngine::clip(const QRegion &region, Qt::ClipOperation op)
1753 {
1755  QVGPainterState *s = state();
1756 
1757  d->dirty |= QPaintEngine::DirtyClipRegion;
1758 
1759  switch (op) {
1760  case Qt::NoClip:
1761  {
1763  }
1764  break;
1765 
1766  case Qt::ReplaceClip:
1767  {
1768  s->clipRegion = d->transform.map(region);
1769  }
1770  break;
1771 
1772  case Qt::IntersectClip:
1773  {
1774  s->clipRegion = s->clipRegion.intersect(d->transform.map(region));
1775  }
1776  break;
1777 
1778  case Qt::UniteClip:
1779  {
1780  s->clipRegion = s->clipRegion.unite(d->transform.map(region));
1781  }
1782  break;
1783  }
1784 
1785  updateScissor();
1786 }
1787 
1789 {
1790  QPaintEngineEx::clip(path, op);
1791 }
1792 
1793 #else // !QVG_SCISSOR_CLIP
1794 
1796 {
1798 
1799  d->dirty |= QPaintEngine::DirtyClipRegion;
1800 
1801  if (op == Qt::NoClip) {
1802  d->maskValid = false;
1803  d->maskIsSet = true;
1804  d->scissorMask = false;
1805  d->maskRect = QRect();
1806  vgSeti(VG_MASKING, VG_FALSE);
1807  return;
1808  }
1809 
1810  // We don't have vgRenderToMask(), so handle simple QRectF's only.
1811  if (path.shape() == QVectorPath::RectangleHint &&
1812  path.elementCount() == 4 && clipTransformIsSimple(d->transform)) {
1813  // Clipping region that resulted from QPainter::setClipRect(QRectF).
1814  // Convert it into a QRect and apply.
1815  const qreal *points = path.points();
1816  QRectF rect(points[0], points[1], points[2] - points[0],
1817  points[5] - points[1]);
1818  clip(rect.toRect(), op);
1819  return;
1820  }
1821 
1822 #if !defined(QVG_NO_RENDER_TO_MASK)
1823  QPaintDevice *pdev = paintDevice();
1824  int width = pdev->width();
1825  int height = pdev->height();
1826 
1827  if (op == Qt::ReplaceClip) {
1828  vgMask(VG_INVALID_HANDLE, VG_CLEAR_MASK, 0, 0, width, height);
1829  d->maskRect = QRect();
1830  } else if (!d->maskValid) {
1831  d->ensureMask(this, width, height);
1832  }
1833 
1834  d->ensurePathTransform();
1835  VGPath vgpath = d->vectorPathToVGPath(path);
1836  switch (op) {
1837  case Qt::ReplaceClip:
1838  case Qt::UniteClip:
1839  vgRenderToMask(vgpath, VG_FILL_PATH, VG_UNION_MASK);
1840  break;
1841 
1842  case Qt::IntersectClip:
1843  vgRenderToMask(vgpath, VG_FILL_PATH, VG_INTERSECT_MASK);
1844  break;
1845 
1846  default: break;
1847  }
1848  vgDestroyPath(vgpath);
1849 
1850  vgSeti(VG_MASKING, VG_TRUE);
1851  d->maskValid = true;
1852  d->maskIsSet = false;
1853  d->scissorMask = false;
1854 #endif
1855 }
1856 
1858 {
1860 
1861  d->dirty |= QPaintEngine::DirtyClipRegion;
1862 
1863  // If we have a non-simple transform, then use path-based clipping.
1864  if (op != Qt::NoClip && !clipTransformIsSimple(d->transform)) {
1865  QPaintEngineEx::clip(rect, op);
1866  return;
1867  }
1868 
1869  switch (op) {
1870  case Qt::NoClip:
1871  {
1872  d->maskValid = false;
1873  d->maskIsSet = true;
1874  d->scissorMask = false;
1875  d->maskRect = QRect();
1876  vgSeti(VG_MASKING, VG_FALSE);
1877  }
1878  break;
1879 
1880  case Qt::ReplaceClip:
1881  {
1882  QRect r = d->transform.mapRect(rect);
1883  if (isDefaultClipRect(r)) {
1884  // Replacing the clip with a full-window region is the
1885  // same as turning off clipping.
1886  if (d->maskValid)
1887  vgSeti(VG_MASKING, VG_FALSE);
1888  d->maskValid = false;
1889  d->maskIsSet = true;
1890  d->scissorMask = false;
1891  d->maskRect = QRect();
1892  } else {
1893  // Special case: if the intersection of the system
1894  // clip and "r" is a single rectangle, then use the
1895  // scissor for clipping. We try to avoid allocating a
1896  // QRegion copy on the heap for the test if we can.
1897  QRegion clip = d->systemClip; // Reference-counted, no alloc.
1898  QRect clipRect;
1899  if (clip.rectCount() == 1) {
1900  clipRect = clip.boundingRect().intersected(r);
1901  } else if (clip.isEmpty()) {
1902  clipRect = r;
1903  } else {
1904  clip = clip.intersect(r);
1905  if (clip.rectCount() != 1) {
1906  d->maskValid = false;
1907  d->maskIsSet = false;
1908  d->scissorMask = false;
1909  d->maskRect = QRect();
1910  d->modifyMask(this, VG_FILL_MASK, r);
1911  break;
1912  }
1913  clipRect = clip.boundingRect();
1914  }
1915  d->maskValid = false;
1916  d->maskIsSet = false;
1917  d->scissorMask = true;
1918  d->maskRect = clipRect;
1919  vgSeti(VG_MASKING, VG_FALSE);
1920  updateScissor();
1921  }
1922  }
1923  break;
1924 
1925  case Qt::IntersectClip:
1926  {
1927  QRect r = d->transform.mapRect(rect);
1928  if (!d->maskValid) {
1929  // Mask has not been used yet, so intersect with
1930  // the previous scissor-based region in maskRect.
1931  if (d->scissorMask)
1932  r = r.intersect(d->maskRect);
1933  if (isDefaultClipRect(r)) {
1934  // The clip is the full window, so turn off clipping.
1935  d->maskIsSet = true;
1936  d->maskRect = QRect();
1937  } else {
1938  // Activate the scissor on a smaller maskRect.
1939  d->maskIsSet = false;
1940  d->maskRect = r;
1941  }
1942  d->scissorMask = true;
1943  updateScissor();
1944  } else if (d->maskIsSet && isDefaultClipRect(r)) {
1945  // Intersecting a full-window clip with a full-window
1946  // region is the same as turning off clipping.
1947  if (d->maskValid)
1948  vgSeti(VG_MASKING, VG_FALSE);
1949  d->maskValid = false;
1950  d->maskIsSet = true;
1951  d->scissorMask = false;
1952  d->maskRect = QRect();
1953  } else {
1954  d->modifyMask(this, VG_INTERSECT_MASK, r);
1955  }
1956  }
1957  break;
1958 
1959  case Qt::UniteClip:
1960  {
1961  // If we already have a full-window clip, then uniting a
1962  // region with it will do nothing. Otherwise union.
1963  if (!(d->maskIsSet))
1964  d->modifyMask(this, VG_UNION_MASK, d->transform.mapRect(rect));
1965  }
1966  break;
1967  }
1968 }
1969 
1971 {
1973 
1974  // Use the QRect case if the region consists of a single rectangle.
1975  if (region.rectCount() == 1) {
1976  clip(region.boundingRect(), op);
1977  return;
1978  }
1979 
1980  d->dirty |= QPaintEngine::DirtyClipRegion;
1981 
1982  // If we have a non-simple transform, then use path-based clipping.
1983  if (op != Qt::NoClip && !clipTransformIsSimple(d->transform)) {
1984  QPaintEngineEx::clip(region, op);
1985  return;
1986  }
1987 
1988  switch (op) {
1989  case Qt::NoClip:
1990  {
1991  d->maskValid = false;
1992  d->maskIsSet = true;
1993  d->scissorMask = false;
1994  d->maskRect = QRect();
1995  vgSeti(VG_MASKING, VG_FALSE);
1996  }
1997  break;
1998 
1999  case Qt::ReplaceClip:
2000  {
2001  QRegion r = d->transform.map(region);
2002  if (isDefaultClipRegion(r)) {
2003  // Replacing the clip with a full-window region is the
2004  // same as turning off clipping.
2005  if (d->maskValid)
2006  vgSeti(VG_MASKING, VG_FALSE);
2007  d->maskValid = false;
2008  d->maskIsSet = true;
2009  d->scissorMask = false;
2010  d->maskRect = QRect();
2011  } else {
2012  // Special case: if the intersection of the system
2013  // clip and the region is a single rectangle, then
2014  // use the scissor for clipping.
2015  QRegion clip = d->systemClip;
2016  if (clip.isEmpty())
2017  clip = r;
2018  else
2019  clip = clip.intersect(r);
2020  if (clip.rectCount() == 1) {
2021  d->maskValid = false;
2022  d->maskIsSet = false;
2023  d->scissorMask = true;
2024  d->maskRect = clip.boundingRect();
2025  vgSeti(VG_MASKING, VG_FALSE);
2026  updateScissor();
2027  } else {
2028  d->maskValid = false;
2029  d->maskIsSet = false;
2030  d->scissorMask = false;
2031  d->maskRect = QRect();
2032  d->modifyMask(this, VG_FILL_MASK, r);
2033  }
2034  }
2035  }
2036  break;
2037 
2038  case Qt::IntersectClip:
2039  {
2040  if (region.rectCount() != 1) {
2041  // If there is more than one rectangle, then intersecting
2042  // the rectangles one by one in modifyMask() will not give
2043  // the desired result. So fall back to path-based clipping.
2044  QPaintEngineEx::clip(region, op);
2045  return;
2046  }
2047  QRegion r = d->transform.map(region);
2048  if (d->maskIsSet && isDefaultClipRegion(r)) {
2049  // Intersecting a full-window clip with a full-window
2050  // region is the same as turning off clipping.
2051  if (d->maskValid)
2052  vgSeti(VG_MASKING, VG_FALSE);
2053  d->maskValid = false;
2054  d->maskIsSet = true;
2055  d->scissorMask = false;
2056  d->maskRect = QRect();
2057  } else {
2058  d->modifyMask(this, VG_INTERSECT_MASK, r);
2059  }
2060  }
2061  break;
2062 
2063  case Qt::UniteClip:
2064  {
2065  // If we already have a full-window clip, then uniting a
2066  // region with it will do nothing. Otherwise union.
2067  if (!(d->maskIsSet))
2068  d->modifyMask(this, VG_UNION_MASK, d->transform.map(region));
2069  }
2070  break;
2071  }
2072 }
2073 
2074 #if !defined(QVG_NO_RENDER_TO_MASK)
2075 
2076 // Copied from qpathclipper.cpp.
2077 static bool qt_vg_pathToRect(const QPainterPath &path, QRectF *rect)
2078 {
2079  if (path.elementCount() != 5)
2080  return false;
2081 
2082  const bool mightBeRect = path.elementAt(0).isMoveTo()
2083  && path.elementAt(1).isLineTo()
2084  && path.elementAt(2).isLineTo()
2085  && path.elementAt(3).isLineTo()
2086  && path.elementAt(4).isLineTo();
2087 
2088  if (!mightBeRect)
2089  return false;
2090 
2091  const qreal x1 = path.elementAt(0).x;
2092  const qreal y1 = path.elementAt(0).y;
2093 
2094  const qreal x2 = path.elementAt(1).x;
2095  const qreal y2 = path.elementAt(2).y;
2096 
2097  if (path.elementAt(1).y != y1)
2098  return false;
2099 
2100  if (path.elementAt(2).x != x2)
2101  return false;
2102 
2103  if (path.elementAt(3).x != x1 || path.elementAt(3).y != y2)
2104  return false;
2105 
2106  if (path.elementAt(4).x != x1 || path.elementAt(4).y != y1)
2107  return false;
2108 
2109  if (rect)
2110  *rect = QRectF(QPointF(x1, y1), QPointF(x2, y2));
2111 
2112  return true;
2113 }
2114 
2115 #endif
2116 
2118 {
2119 #if !defined(QVG_NO_RENDER_TO_MASK)
2121 
2122  // If the path is a simple rectangle, then use clip(QRect) instead.
2123  QRectF simpleRect;
2124  if (qt_vg_pathToRect(path, &simpleRect)) {
2125  clip(simpleRect.toRect(), op);
2126  return;
2127  }
2128 
2129  d->dirty |= QPaintEngine::DirtyClipRegion;
2130 
2131  if (op == Qt::NoClip) {
2132  d->maskValid = false;
2133  d->maskIsSet = true;
2134  d->scissorMask = false;
2135  d->maskRect = QRect();
2136  vgSeti(VG_MASKING, VG_FALSE);
2137  return;
2138  }
2139 
2140  QPaintDevice *pdev = paintDevice();
2141  int width = pdev->width();
2142  int height = pdev->height();
2143 
2144  if (op == Qt::ReplaceClip) {
2145  vgMask(VG_INVALID_HANDLE, VG_CLEAR_MASK, 0, 0, width, height);
2146  d->maskRect = QRect();
2147  } else if (!d->maskValid) {
2148  d->ensureMask(this, width, height);
2149  }
2150 
2151  d->ensurePathTransform();
2152  VGPath vgpath = d->painterPathToVGPath(path);
2153  switch (op) {
2154  case Qt::ReplaceClip:
2155  case Qt::UniteClip:
2156  vgRenderToMask(vgpath, VG_FILL_PATH, VG_UNION_MASK);
2157  break;
2158 
2159  case Qt::IntersectClip:
2160  vgRenderToMask(vgpath, VG_FILL_PATH, VG_INTERSECT_MASK);
2161  break;
2162 
2163  default: break;
2164  }
2165  vgDestroyPath(vgpath);
2166 
2167  vgSeti(VG_MASKING, VG_TRUE);
2168  d->maskValid = true;
2169  d->maskIsSet = false;
2170  d->scissorMask = false;
2171 #else
2172  QPaintEngineEx::clip(path, op);
2173 #endif
2174 }
2175 
2177  (QVGPaintEngine *engine, int width, int height)
2178 {
2179  scissorMask = false;
2180  if (maskIsSet) {
2181  vgMask(VG_INVALID_HANDLE, VG_FILL_MASK, 0, 0, width, height);
2182  maskRect = QRect();
2183  } else {
2184  vgMask(VG_INVALID_HANDLE, VG_CLEAR_MASK, 0, 0, width, height);
2185  if (maskRect.isValid()) {
2186  vgMask(VG_INVALID_HANDLE, VG_FILL_MASK,
2187  maskRect.x(), height - maskRect.y() - maskRect.height(),
2188  maskRect.width(), maskRect.height());
2189  maskRect = QRect();
2190  engine->updateScissor();
2191  }
2192  }
2193 }
2194 
2196  (QVGPaintEngine *engine, VGMaskOperation op, const QRegion& region)
2197 {
2198  QPaintDevice *pdev = engine->paintDevice();
2199  int width = pdev->width();
2200  int height = pdev->height();
2201 
2202  if (!maskValid)
2203  ensureMask(engine, width, height);
2204 
2205  QVector<QRect> rects = region.rects();
2206  for (int i = 0; i < rects.size(); ++i) {
2207  vgMask(VG_INVALID_HANDLE, op,
2208  rects[i].x(), height - rects[i].y() - rects[i].height(),
2209  rects[i].width(), rects[i].height());
2210  }
2211 
2212  vgSeti(VG_MASKING, VG_TRUE);
2213  maskValid = true;
2214  maskIsSet = false;
2215  scissorMask = false;
2216 }
2217 
2219  (QVGPaintEngine *engine, VGMaskOperation op, const QRect& rect)
2220 {
2221  QPaintDevice *pdev = engine->paintDevice();
2222  int width = pdev->width();
2223  int height = pdev->height();
2224 
2225  if (!maskValid)
2226  ensureMask(engine, width, height);
2227 
2228  if (rect.isValid()) {
2229  vgMask(VG_INVALID_HANDLE, op,
2230  rect.x(), height - rect.y() - rect.height(),
2231  rect.width(), rect.height());
2232  }
2233 
2234  vgSeti(VG_MASKING, VG_TRUE);
2235  maskValid = true;
2236  maskIsSet = false;
2237  scissorMask = false;
2238 }
2239 
2240 #endif // !QVG_SCISSOR_CLIP
2241 
2243 {
2245 
2246  QRegion region = d->systemClip;
2247 
2248 #if defined(QVG_SCISSOR_CLIP)
2249  // Using the scissor to do clipping, so combine the systemClip
2250  // with the current painting clipRegion.
2251 
2252  if (d->maskValid) {
2253  vgSeti(VG_MASKING, VG_FALSE);
2254  d->maskValid = false;
2255  }
2256 
2257  QVGPainterState *s = state();
2258  if (s->clipEnabled) {
2259  if (region.isEmpty())
2260  region = s->clipRegion;
2261  else
2262  region = region.intersect(s->clipRegion);
2263  if (isDefaultClipRegion(region)) {
2264  // The scissor region is the entire drawing surface,
2265  // so there is no point doing any scissoring.
2266  vgSeti(VG_SCISSORING, VG_FALSE);
2267  d->scissorActive = false;
2268  d->scissorDirty = false;
2269  return;
2270  }
2271  } else
2272 #endif
2273  {
2274 #if !defined(QVG_SCISSOR_CLIP)
2275  // Combine the system clip with the simple mask rectangle.
2276  if (d->scissorMask) {
2277  if (region.isEmpty())
2278  region = d->maskRect;
2279  else
2280  region = region.intersect(d->maskRect);
2281  if (isDefaultClipRegion(region)) {
2282  // The scissor region is the entire drawing surface,
2283  // so there is no point doing any scissoring.
2284  vgSeti(VG_SCISSORING, VG_FALSE);
2285  d->scissorActive = false;
2286  d->scissorDirty = false;
2287  return;
2288  }
2289  } else
2290 #endif
2291 
2292  // Disable the scissor completely if the system clip is empty.
2293  if (region.isEmpty()) {
2294  vgSeti(VG_SCISSORING, VG_FALSE);
2295  d->scissorActive = false;
2296  d->scissorDirty = false;
2297  return;
2298  }
2299  }
2300 
2301  if (d->scissorActive && region == d->scissorRegion && !d->scissorDirty)
2302  return;
2303 
2304  QVector<QRect> rects = region.rects();
2305  int count = rects.count();
2306  if (count > d->maxScissorRects) {
2307 #if !defined(QVG_SCISSOR_CLIP)
2308  count = d->maxScissorRects;
2309 #else
2310  // Use masking
2311  int width = paintDevice()->width();
2312  int height = paintDevice()->height();
2313  vgMask(VG_INVALID_HANDLE, VG_CLEAR_MASK,
2314  0, 0, width, height);
2315  for (int i = 0; i < rects.size(); ++i) {
2316  vgMask(VG_INVALID_HANDLE, VG_FILL_MASK,
2317  rects[i].x(), height - rects[i].y() - rects[i].height(),
2318  rects[i].width(), rects[i].height());
2319  }
2320 
2321  vgSeti(VG_SCISSORING, VG_FALSE);
2322  vgSeti(VG_MASKING, VG_TRUE);
2323  d->maskValid = true;
2324  d->maskIsSet = false;
2325  d->scissorMask = false;
2326  d->scissorActive = false;
2327  d->scissorDirty = false;
2328  d->scissorRegion = region;
2329  return;
2330 #endif
2331  }
2332 
2333  QVarLengthArray<VGint> params(count * 4);
2334  int height = paintDevice()->height();
2335  for (int i = 0; i < count; ++i) {
2336  params[i * 4 + 0] = rects[i].x();
2337  params[i * 4 + 1] = height - rects[i].y() - rects[i].height();
2338  params[i * 4 + 2] = rects[i].width();
2339  params[i * 4 + 3] = rects[i].height();
2340  }
2341 
2342  vgSetiv(VG_SCISSOR_RECTS, count * 4, params.data());
2343  vgSeti(VG_SCISSORING, VG_TRUE);
2344  d->scissorDirty = false;
2345  d->scissorActive = true;
2346  d->scissorRegion = region;
2347 }
2348 
2350 {
2351  // The default clip region for a paint device is the whole drawing area.
2352  QPaintDevice *pdev = paintDevice();
2353  return QRegion(0, 0, pdev->width(), pdev->height());
2354 }
2355 
2357 {
2358  if (region.rectCount() != 1)
2359  return false;
2360 
2361  QPaintDevice *pdev = paintDevice();
2362  int width = pdev->width();
2363  int height = pdev->height();
2364 
2365  QRect rect = region.boundingRect();
2366  return (rect.x() == 0 && rect.y() == 0 &&
2367  rect.width() == width && rect.height() == height);
2368 }
2369 
2371 {
2372  QPaintDevice *pdev = paintDevice();
2373  int width = pdev->width();
2374  int height = pdev->height();
2375 
2376  return (rect.x() == 0 && rect.y() == 0 &&
2377  rect.width() == width && rect.height() == height);
2378 }
2379 
2381 {
2382 #if defined(QVG_SCISSOR_CLIP)
2383  vgSeti(VG_MASKING, VG_FALSE); // disable mask fallback
2384  updateScissor();
2385 #else
2387  QVGPainterState *s = state();
2389  if (s->clipEnabled && s->clipOperation != Qt::NoClip) {
2390  // Replay the entire clip stack to put the mask into the right state.
2391  d->maskValid = false;
2392  d->maskIsSet = true;
2393  d->scissorMask = false;
2394  d->maskRect = QRect();
2396  d->replayClipOperations();
2397  d->transform = s->transform();
2398  d->updateTransform(paintDevice());
2399  } else {
2400  vgSeti(VG_MASKING, VG_FALSE);
2401  d->maskValid = false;
2402  d->maskIsSet = false;
2403  d->scissorMask = false;
2404  d->maskRect = QRect();
2405  }
2406 #endif
2407 }
2408 
2410 {
2412  d->dirty |= QPaintEngine::DirtyPen;
2413 
2414  d->hasExtendedRadialGradientPen =
2415  state()->pen.style() != Qt::NoPen && d->needsEmulation(state()->pen.brush());
2416 }
2417 
2419 {
2421  d->dirty |= QPaintEngine::DirtyBrush;
2422 
2423  d->hasExtendedRadialGradientPen = d->needsEmulation(state()->brush);
2424 }
2425 
2427 {
2430  d->brushOrigin = state()->brushOrigin;
2431  d->forcePenChange = true;
2432  d->forceBrushChange = true;
2433 }
2434 
2436 {
2438  d->dirty |= QPaintEngine::DirtyOpacity;
2439  d->opacity = state()->opacity;
2440  d->forcePenChange = true;
2441  d->forceBrushChange = true;
2442 }
2443 
2445 {
2448 
2449  VGint vgMode = VG_BLEND_SRC_OVER;
2450 
2451  switch (state()->composition_mode) {
2453  vgMode = VG_BLEND_SRC_OVER;
2454  break;
2456  vgMode = VG_BLEND_DST_OVER;
2457  break;
2459  vgMode = VG_BLEND_SRC;
2460  break;
2462  vgMode = VG_BLEND_SRC_IN;
2463  break;
2465  vgMode = VG_BLEND_DST_IN;
2466  break;
2468  vgMode = VG_BLEND_ADDITIVE;
2469  break;
2471  vgMode = VG_BLEND_MULTIPLY;
2472  break;
2474  vgMode = VG_BLEND_SCREEN;
2475  break;
2477  vgMode = VG_BLEND_DARKEN;
2478  break;
2480  vgMode = VG_BLEND_LIGHTEN;
2481  break;
2482  default:
2483  if (d->hasAdvancedBlending) {
2484  switch (state()->composition_mode) {
2487  break;
2490  break;
2493  break;
2496  break;
2499  break;
2502  break;
2505  break;
2508  break;
2511  break;
2514  break;
2517  break;
2520  break;
2521  default: break; // Fall back to VG_BLEND_SRC_OVER.
2522  }
2523  }
2524  if (vgMode == VG_BLEND_SRC_OVER)
2525  qWarning() << "QVGPaintEngine::compositionModeChanged unsupported mode" << state()->composition_mode;
2526  break;
2527  }
2528 
2529  d->setBlendMode(VGBlendMode(vgMode));
2530 }
2531 
2533 {
2535  d->dirty |= QPaintEngine::DirtyHints;
2536 
2537  QPainter::RenderHints hints = state()->renderHints;
2538 
2539  VGRenderingQuality rq =
2540  (hints & QPainter::Antialiasing)
2541  ? VG_RENDERING_QUALITY_BETTER
2542  : VG_RENDERING_QUALITY_NONANTIALIASED;
2543  VGImageQuality iq =
2545  ? VG_IMAGE_QUALITY_BETTER
2546  : VG_IMAGE_QUALITY_NONANTIALIASED;
2547 
2548  d->setRenderingQuality(rq);
2549  d->setImageQuality(iq);
2550 }
2551 
2553 {
2555  QVGPainterState *s = state();
2556  d->dirty |= QPaintEngine::DirtyTransform;
2557  d->transform = s->transform();
2558  qreal oldPenScale = d->penScale;
2559  d->updateTransform(paintDevice());
2560  if (d->penScale != oldPenScale)
2561  d->forcePenChange = true;
2562 }
2563 
2564 bool QVGPaintEngine::clearRect(const QRectF &rect, const QColor &color)
2565 {
2567  QVGPainterState *s = state();
2568  if (!s->clipEnabled || s->clipOperation == Qt::NoClip) {
2569  QRect r = d->transform.mapRect(rect).toRect();
2570  int height = paintDevice()->height();
2571  if (d->clearColor != color || d->clearOpacity != s->opacity) {
2572  VGfloat values[4];
2573  values[0] = color.redF();
2574  values[1] = color.greenF();
2575  values[2] = color.blueF();
2576  values[3] = color.alphaF() * s->opacity;
2577  vgSetfv(VG_CLEAR_COLOR, 4, values);
2578  d->clearColor = color;
2579  d->clearOpacity = s->opacity;
2580  }
2581  vgClear(r.x(), height - r.y() - r.height(),
2582  r.width(), r.height());
2583  return true;
2584  }
2585  return false;
2586 }
2587 
2588 void QVGPaintEngine::fillRect(const QRectF &rect, const QBrush &brush)
2589 {
2591 
2592  if (brush.style() == Qt::NoBrush)
2593  return;
2594 
2595  // Check to see if we can use vgClear() for faster filling.
2596  if (brush.style() == Qt::SolidPattern && brush.isOpaque() &&
2597  clipTransformIsSimple(d->transform) && d->opacity == 1.0f &&
2598  clearRect(rect, brush.color())) {
2599  return;
2600  }
2601 
2602  if (d->needsEmulation(brush)) {
2603  QPaintEngineEx::fillRect(rect, brush);
2604  return;
2605  }
2606 
2607 #if !defined(QVG_NO_MODIFY_PATH)
2608  VGfloat coords[8];
2609  if (d->simpleTransform) {
2610  coords[0] = rect.x();
2611  coords[1] = rect.y();
2612  coords[2] = rect.x() + rect.width();
2613  coords[3] = coords[1];
2614  coords[4] = coords[2];
2615  coords[5] = rect.y() + rect.height();
2616  coords[6] = coords[0];
2617  coords[7] = coords[5];
2618  } else {
2619  QPointF tl = d->transform.map(rect.topLeft());
2620  QPointF tr = d->transform.map(rect.topRight());
2621  QPointF bl = d->transform.map(rect.bottomLeft());
2622  QPointF br = d->transform.map(rect.bottomRight());
2623  coords[0] = tl.x();
2624  coords[1] = tl.y();
2625  coords[2] = tr.x();
2626  coords[3] = tr.y();
2627  coords[4] = br.x();
2628  coords[5] = br.y();
2629  coords[6] = bl.x();
2630  coords[7] = bl.y();
2631  }
2632  vgModifyPathCoords(d->rectPath, 0, 4, coords);
2633  d->fill(d->rectPath, brush);
2634 #else
2635  QPaintEngineEx::fillRect(rect, brush);
2636 #endif
2637 }
2638 
2639 void QVGPaintEngine::fillRect(const QRectF &rect, const QColor &color)
2640 {
2642 
2643  // Check to see if we can use vgClear() for faster filling.
2644  if (clipTransformIsSimple(d->transform) && d->opacity == 1.0f && color.alpha() == 255 &&
2645  clearRect(rect, color)) {
2646  return;
2647  }
2648 
2649 #if !defined(QVG_NO_MODIFY_PATH)
2650  VGfloat coords[8];
2651  if (d->simpleTransform) {
2652  coords[0] = rect.x();
2653  coords[1] = rect.y();
2654  coords[2] = rect.x() + rect.width();
2655  coords[3] = coords[1];
2656  coords[4] = coords[2];
2657  coords[5] = rect.y() + rect.height();
2658  coords[6] = coords[0];
2659  coords[7] = coords[5];
2660  } else {
2661  QPointF tl = d->transform.map(rect.topLeft());
2662  QPointF tr = d->transform.map(rect.topRight());
2663  QPointF bl = d->transform.map(rect.bottomLeft());
2664  QPointF br = d->transform.map(rect.bottomRight());
2665  coords[0] = tl.x();
2666  coords[1] = tl.y();
2667  coords[2] = tr.x();
2668  coords[3] = tr.y();
2669  coords[4] = br.x();
2670  coords[5] = br.y();
2671  coords[6] = bl.x();
2672  coords[7] = bl.y();
2673  }
2674  vgModifyPathCoords(d->rectPath, 0, 4, coords);
2675  d->fill(d->rectPath, QBrush(color));
2676 #else
2677  QPaintEngineEx::fillRect(rect, QBrush(color));
2678 #endif
2679 }
2680 
2682 {
2684  if (d->needsEmulation()) {
2685  QPaintEngineEx::drawRoundedRect(rect, xrad, yrad, mode);
2686  return;
2687  }
2688  if (d->simpleTransform) {
2689  QVGPainterState *s = state();
2690  VGPath vgpath = d->roundedRectPath(rect, xrad, yrad, mode);
2691  d->draw(vgpath, s->pen, s->brush);
2692 #if defined(QVG_NO_MODIFY_PATH)
2693  vgDestroyPath(vgpath);
2694 #endif
2695  } else {
2696  QPaintEngineEx::drawRoundedRect(rect, xrad, yrad, mode);
2697  }
2698 }
2699 
2700 void QVGPaintEngine::drawRects(const QRect *rects, int rectCount)
2701 {
2702 #if !defined(QVG_NO_MODIFY_PATH)
2704  if (d->needsEmulation()) {
2705  QPaintEngineEx::drawRects(rects, rectCount);
2706  return;
2707  }
2708  QVGPainterState *s = state();
2709  for (int i = 0; i < rectCount; ++i, ++rects) {
2710  VGfloat coords[8];
2711  if (d->simpleTransform) {
2712  coords[0] = rects->x();
2713  coords[1] = rects->y();
2714  coords[2] = rects->x() + rects->width();
2715  coords[3] = coords[1];
2716  coords[4] = coords[2];
2717  coords[5] = rects->y() + rects->height();
2718  coords[6] = coords[0];
2719  coords[7] = coords[5];
2720  } else {
2721  QPointF tl = d->transform.map(QPointF(rects->x(), rects->y()));
2722  QPointF tr = d->transform.map(QPointF(rects->x() + rects->width(),
2723  rects->y()));
2724  QPointF bl = d->transform.map(QPointF(rects->x(),
2725  rects->y() + rects->height()));
2726  QPointF br = d->transform.map(QPointF(rects->x() + rects->width(),
2727  rects->y() + rects->height()));
2728  coords[0] = tl.x();
2729  coords[1] = tl.y();
2730  coords[2] = tr.x();
2731  coords[3] = tr.y();
2732  coords[4] = br.x();
2733  coords[5] = br.y();
2734  coords[6] = bl.x();
2735  coords[7] = bl.y();
2736  }
2737  vgModifyPathCoords(d->rectPath, 0, 4, coords);
2738  d->draw(d->rectPath, s->pen, s->brush);
2739  }
2740 #else
2741  QPaintEngineEx::drawRects(rects, rectCount);
2742 #endif
2743 }
2744 
2745 void QVGPaintEngine::drawRects(const QRectF *rects, int rectCount)
2746 {
2747 #if !defined(QVG_NO_MODIFY_PATH)
2749  if (d->needsEmulation()) {
2750  QPaintEngineEx::drawRects(rects, rectCount);
2751  return;
2752  }
2753  QVGPainterState *s = state();
2754  for (int i = 0; i < rectCount; ++i, ++rects) {
2755  VGfloat coords[8];
2756  if (d->simpleTransform) {
2757  coords[0] = rects->x();
2758  coords[1] = rects->y();
2759  coords[2] = rects->x() + rects->width();
2760  coords[3] = coords[1];
2761  coords[4] = coords[2];
2762  coords[5] = rects->y() + rects->height();
2763  coords[6] = coords[0];
2764  coords[7] = coords[5];
2765  } else {
2766  QPointF tl = d->transform.map(rects->topLeft());
2767  QPointF tr = d->transform.map(rects->topRight());
2768  QPointF bl = d->transform.map(rects->bottomLeft());
2769  QPointF br = d->transform.map(rects->bottomRight());
2770  coords[0] = tl.x();
2771  coords[1] = tl.y();
2772  coords[2] = tr.x();
2773  coords[3] = tr.y();
2774  coords[4] = br.x();
2775  coords[5] = br.y();
2776  coords[6] = bl.x();
2777  coords[7] = bl.y();
2778  }
2779  vgModifyPathCoords(d->rectPath, 0, 4, coords);
2780  d->draw(d->rectPath, s->pen, s->brush);
2781  }
2782 #else
2783  QPaintEngineEx::drawRects(rects, rectCount);
2784 #endif
2785 }
2786 
2787 void QVGPaintEngine::drawLines(const QLine *lines, int lineCount)
2788 {
2789 #if !defined(QVG_NO_MODIFY_PATH)
2791  if (d->needsEmulation()) {
2792  QPaintEngineEx::drawLines(lines, lineCount);
2793  return;
2794  }
2795  QVGPainterState *s = state();
2796  for (int i = 0; i < lineCount; ++i, ++lines) {
2797  VGfloat coords[4];
2798  if (d->simpleTransform) {
2799  coords[0] = lines->x1();
2800  coords[1] = lines->y1();
2801  coords[2] = lines->x2();
2802  coords[3] = lines->y2();
2803  } else {
2804  QPointF p1 = d->transform.map(QPointF(lines->x1(), lines->y1()));
2805  QPointF p2 = d->transform.map(QPointF(lines->x2(), lines->y2()));
2806  coords[0] = p1.x();
2807  coords[1] = p1.y();
2808  coords[2] = p2.x();
2809  coords[3] = p2.y();
2810  }
2811  vgModifyPathCoords(d->linePath, 0, 2, coords);
2812  d->stroke(d->linePath, s->pen);
2813  }
2814 #else
2815  QPaintEngineEx::drawLines(lines, lineCount);
2816 #endif
2817 }
2818 
2819 void QVGPaintEngine::drawLines(const QLineF *lines, int lineCount)
2820 {
2821 #if !defined(QVG_NO_MODIFY_PATH)
2823  if (d->needsEmulation()) {
2824  QPaintEngineEx::drawLines(lines, lineCount);
2825  return;
2826  }
2827  QVGPainterState *s = state();
2828  for (int i = 0; i < lineCount; ++i, ++lines) {
2829  VGfloat coords[4];
2830  if (d->simpleTransform) {
2831  coords[0] = lines->x1();
2832  coords[1] = lines->y1();
2833  coords[2] = lines->x2();
2834  coords[3] = lines->y2();
2835  } else {
2836  QPointF p1 = d->transform.map(lines->p1());
2837  QPointF p2 = d->transform.map(lines->p2());
2838  coords[0] = p1.x();
2839  coords[1] = p1.y();
2840  coords[2] = p2.x();
2841  coords[3] = p2.y();
2842  }
2843  vgModifyPathCoords(d->linePath, 0, 2, coords);
2844  d->stroke(d->linePath, s->pen);
2845  }
2846 #else
2847  QPaintEngineEx::drawLines(lines, lineCount);
2848 #endif
2849 }
2850 
2852 {
2853  // Based on the description of vguEllipse() in the OpenVG specification.
2854  // We don't use vguEllipse(), to avoid unnecessary library dependencies.
2856  if (d->needsEmulation()) {
2858  return;
2859  }
2860  if (d->simpleTransform) {
2861  QVGPainterState *s = state();
2862  VGPath path = vgCreatePath(VG_PATH_FORMAT_STANDARD,
2863  VG_PATH_DATATYPE_F,
2864  1.0f, // scale
2865  0.0f, // bias
2866  4, // segmentCapacityHint
2867  12, // coordCapacityHint
2868  VG_PATH_CAPABILITY_ALL);
2869  static VGubyte segments[4] = {
2870  VG_MOVE_TO_ABS,
2871  VG_SCCWARC_TO_REL,
2872  VG_SCCWARC_TO_REL,
2873  VG_CLOSE_PATH
2874  };
2875  VGfloat coords[12];
2876  VGfloat halfwid = r.width() / 2;
2877  VGfloat halfht = r.height() / 2;
2878  coords[0] = r.x() + r.width();
2879  coords[1] = r.y() + halfht;
2880  coords[2] = halfwid;
2881  coords[3] = halfht;
2882  coords[4] = 0.0f;
2883  coords[5] = -r.width();
2884  coords[6] = 0.0f;
2885  coords[7] = halfwid;
2886  coords[8] = halfht;
2887  coords[9] = 0.0f;
2888  coords[10] = r.width();
2889  coords[11] = 0.0f;
2890  vgAppendPathData(path, 4, segments, coords);
2891  d->draw(path, s->pen, s->brush);
2892  vgDestroyPath(path);
2893  } else {
2894  // The projective transform version of an ellipse is difficult.
2895  // Generate a QVectorPath containing cubic curves and transform that.
2897  }
2898 }
2899 
2901 {
2902  drawEllipse(QRectF(r));
2903 }
2904 
2906 {
2907  // Shortcut past the QPainterPath -> QVectorPath conversion,
2908  // converting the QPainterPath directly into a VGPath.
2910  if (d->needsEmulation()) {
2912  return;
2913  }
2914  QVGPainterState *s = state();
2915  VGPath vgpath = d->painterPathToVGPath(path);
2916  if (path.fillRule() == Qt::OddEvenFill)
2917  d->draw(vgpath, s->pen, s->brush, VG_EVEN_ODD);
2918  else
2919  d->draw(vgpath, s->pen, s->brush, VG_NON_ZERO);
2920  vgDestroyPath(vgpath);
2921 }
2922 
2923 void QVGPaintEngine::drawPoints(const QPointF *points, int pointCount)
2924 {
2925 #if !defined(QVG_NO_MODIFY_PATH)
2927 
2928  if (d->needsPenEmulation()) {
2929  QPaintEngineEx::drawPoints(points, pointCount);
2930  return;
2931  }
2932 
2933  // Set up a new pen if necessary.
2934  QPen pen = state()->pen;
2935  if (pen.style() == Qt::NoPen)
2936  return;
2937  if (pen.capStyle() == Qt::FlatCap)
2939 
2940  for (int i = 0; i < pointCount; ++i, ++points) {
2941  VGfloat coords[4];
2942  if (d->simpleTransform) {
2943  coords[0] = points->x();
2944  coords[1] = points->y();
2945  coords[2] = coords[0];
2946  coords[3] = coords[1];
2947  } else {
2948  QPointF p = d->transform.map(*points);
2949  coords[0] = p.x();
2950  coords[1] = p.y();
2951  coords[2] = coords[0];
2952  coords[3] = coords[1];
2953  }
2954  vgModifyPathCoords(d->linePath, 0, 2, coords);
2955  d->stroke(d->linePath, pen);
2956  }
2957 #else
2958  QPaintEngineEx::drawPoints(points, pointCount);
2959 #endif
2960 }
2961 
2962 void QVGPaintEngine::drawPoints(const QPoint *points, int pointCount)
2963 {
2964 #if !defined(QVG_NO_MODIFY_PATH)
2966 
2967  if (d->needsEmulation()) {
2968  QPaintEngineEx::drawPoints(points, pointCount);
2969  return;
2970  }
2971 
2972  // Set up a new pen if necessary.
2973  QPen pen = state()->pen;
2974  if (pen.style() == Qt::NoPen)
2975  return;
2976  if (pen.capStyle() == Qt::FlatCap)
2978 
2979  for (int i = 0; i < pointCount; ++i, ++points) {
2980  VGfloat coords[4];
2981  if (d->simpleTransform) {
2982  coords[0] = points->x();
2983  coords[1] = points->y();
2984  coords[2] = coords[0];
2985  coords[3] = coords[1];
2986  } else {
2987  QPointF p = d->transform.map(QPointF(*points));
2988  coords[0] = p.x();
2989  coords[1] = p.y();
2990  coords[2] = coords[0];
2991  coords[3] = coords[1];
2992  }
2993  vgModifyPathCoords(d->linePath, 0, 2, coords);
2994  d->stroke(d->linePath, pen);
2995  }
2996 #else
2997  QPaintEngineEx::drawPoints(points, pointCount);
2998 #endif
2999 }
3000 
3001 void QVGPaintEngine::drawPolygon(const QPointF *points, int pointCount, PolygonDrawMode mode)
3002 {
3004 
3005  if (d->needsEmulation()) {
3006  QPaintEngineEx::drawPolygon(points, pointCount, mode);
3007  return;
3008  }
3009 
3010  QVGPainterState *s = state();
3011  VGPath path = vgCreatePath(VG_PATH_FORMAT_STANDARD,
3012  VG_PATH_DATATYPE_F,
3013  1.0f, // scale
3014  0.0f, // bias
3015  pointCount + 1, // segmentCapacityHint
3016  pointCount * 2, // coordCapacityHint
3017  VG_PATH_CAPABILITY_ALL);
3020  for (int i = 0; i < pointCount; ++i, ++points) {
3021  if (d->simpleTransform) {
3022  coords.append(points->x());
3023  coords.append(points->y());
3024  } else {
3025  QPointF temp = d->transform.map(*points);
3026  coords.append(temp.x());
3027  coords.append(temp.y());
3028  }
3029  if (i == 0)
3030  segments.append(VG_MOVE_TO_ABS);
3031  else
3032  segments.append(VG_LINE_TO_ABS);
3033  }
3034  if (mode != QPaintEngine::PolylineMode)
3035  segments.append(VG_CLOSE_PATH);
3036  vgAppendPathData(path, segments.count(),
3037  segments.constData(), coords.constData());
3038  switch (mode) {
3040  d->draw(path, s->pen, s->brush, VG_NON_ZERO);
3041  break;
3042 
3044  d->stroke(path, s->pen);
3045  break;
3046 
3047  default:
3048  d->draw(path, s->pen, s->brush, VG_EVEN_ODD);
3049  break;
3050  }
3051  vgDestroyPath(path);
3052 }
3053 
3054 void QVGPaintEngine::drawPolygon(const QPoint *points, int pointCount, PolygonDrawMode mode)
3055 {
3057 
3058  if (d->needsEmulation()) {
3059  QPaintEngineEx::drawPolygon(points, pointCount, mode);
3060  return;
3061  }
3062 
3063  QVGPainterState *s = state();
3064  VGPath path = vgCreatePath(VG_PATH_FORMAT_STANDARD,
3065  VG_PATH_DATATYPE_F,
3066  1.0f, // scale
3067  0.0f, // bias
3068  pointCount + 1, // segmentCapacityHint
3069  pointCount * 2, // coordCapacityHint
3070  VG_PATH_CAPABILITY_ALL);
3073  for (int i = 0; i < pointCount; ++i, ++points) {
3074  if (d->simpleTransform) {
3075  coords.append(points->x());
3076  coords.append(points->y());
3077  } else {
3078  QPointF temp = d->transform.map(QPointF(*points));
3079  coords.append(temp.x());
3080  coords.append(temp.y());
3081  }
3082  if (i == 0)
3083  segments.append(VG_MOVE_TO_ABS);
3084  else
3085  segments.append(VG_LINE_TO_ABS);
3086  }
3087  if (mode != QPaintEngine::PolylineMode)
3088  segments.append(VG_CLOSE_PATH);
3089  vgAppendPathData(path, segments.count(),
3090  segments.constData(), coords.constData());
3091  switch (mode) {
3093  d->draw(path, s->pen, s->brush, VG_NON_ZERO);
3094  break;
3095 
3097  d->stroke(path, s->pen);
3098  break;
3099 
3100  default:
3101  d->draw(path, s->pen, s->brush, VG_EVEN_ODD);
3102  break;
3103  }
3104  vgDestroyPath(path);
3105 }
3106 
3108 {
3109  if (opacity != 1.0f && simpleTransform) {
3110  if (opacity != paintOpacity) {
3111  VGfloat values[4];
3112  values[0] = 1.0f;
3113  values[1] = 1.0f;
3114  values[2] = 1.0f;
3115  values[3] = opacity;
3116  vgSetParameterfv(opacityPaint, VG_PAINT_COLOR, 4, values);
3117  paintOpacity = opacity;
3118  }
3119  if (fillPaint != opacityPaint) {
3120  vgSetPaint(opacityPaint, VG_FILL_PATH);
3121  fillPaint = opacityPaint;
3122  }
3123  setImageMode(VG_DRAW_IMAGE_MULTIPLY);
3124  } else {
3125  setImageMode(VG_DRAW_IMAGE_NORMAL);
3126  }
3127 }
3128 
3130 {
3131  q->updateScissor();
3132 }
3133 
3135  const QRectF& r, VGImage vgImg,
3136  const QSize& imageSize, const QRectF& sr)
3137 {
3138  if (vgImg == VG_INVALID_HANDLE)
3139  return;
3140  VGImage child = VG_INVALID_HANDLE;
3141 
3142  if (sr.topLeft().isNull() && sr.size() == imageSize) {
3143  child = vgImg;
3144  } else {
3145  QRect src = sr.toRect();
3146 #if !defined(QT_SHIVAVG)
3147  child = vgChildImage(vgImg, src.x(), src.y(), src.width(), src.height());
3148 #else
3149  child = vgImg; // XXX: ShivaVG doesn't have vgChildImage().
3150 #endif
3151  }
3152 
3153  QTransform transform(d->imageTransform);
3154  VGfloat scaleX = sr.width() == 0.0f ? 0.0f : r.width() / sr.width();
3155  VGfloat scaleY = sr.height() == 0.0f ? 0.0f : r.height() / sr.height();
3156  transform.translate(r.x(), r.y());
3157  transform.scale(scaleX, scaleY);
3158  d->setTransform(VG_MATRIX_IMAGE_USER_TO_SURFACE, transform);
3159 
3160  d->setImageOptions();
3161  vgDrawImage(child);
3162 
3163  if(child != vgImg)
3164  vgDestroyImage(child);
3165 }
3166 
3168  const QPointF& pos, VGImage vgImg)
3169 {
3170  if (vgImg == VG_INVALID_HANDLE)
3171  return;
3172 
3173  QTransform transform(d->imageTransform);
3174  transform.translate(pos.x(), pos.y());
3175  d->setTransform(VG_MATRIX_IMAGE_USER_TO_SURFACE, transform);
3176 
3177  d->setImageOptions();
3178  vgDrawImage(vgImg);
3179 }
3180 
3182  const QRectF &r,
3183  const QImage &image,
3184  const QRectF &sr = QRectF())
3185 {
3186  const int minTileSize = 16;
3187  int tileWidth = 512;
3188  int tileHeight = tileWidth;
3189 
3190  VGImageFormat tileFormat = qt_vg_image_to_vg_format(image.format());
3191  VGImage tile = VG_INVALID_HANDLE;
3193  while (tile == VG_INVALID_HANDLE && tileWidth >= minTileSize) {
3194  tile = pool->createPermanentImage(tileFormat, tileWidth, tileHeight,
3195  VG_IMAGE_QUALITY_FASTER);
3196  if (tile == VG_INVALID_HANDLE) {
3197  tileWidth /= 2;
3198  tileHeight /= 2;
3199  }
3200  }
3201  if (tile == VG_INVALID_HANDLE) {
3202  qWarning("drawImageTiled: Failed to create %dx%d tile, giving up", tileWidth, tileHeight);
3203  return;
3204  }
3205 
3206  VGfloat opacityMatrix[20] = {
3207  1.0f, 0.0f, 0.0f, 0.0f,
3208  0.0f, 1.0f, 0.0f, 0.0f,
3209  0.0f, 0.0f, 1.0f, 0.0f,
3210  0.0f, 0.0f, 0.0f, d->opacity,
3211  0.0f, 0.0f, 0.0f, 0.0f
3212  };
3213  VGImage tileWithOpacity = VG_INVALID_HANDLE;
3214  if (d->opacity != 1) {
3215  tileWithOpacity = pool->createPermanentImage(VG_sARGB_8888_PRE,
3216  tileWidth, tileHeight, VG_IMAGE_QUALITY_NONANTIALIASED);
3217  if (tileWithOpacity == VG_INVALID_HANDLE)
3218  qWarning("drawImageTiled: Failed to create extra tile, ignoring opacity");
3219  }
3220 
3221  QRect sourceRect = sr.toRect();
3222  if (sourceRect.isNull())
3223  sourceRect = QRect(0, 0, image.width(), image.height());
3224 
3225  VGfloat scaleX = r.width() / sourceRect.width();
3226  VGfloat scaleY = r.height() / sourceRect.height();
3227 
3228  d->setImageOptions();
3229  VGImageQuality oldImageQuality = d->imageQuality;
3230  VGRenderingQuality oldRenderingQuality = d->renderingQuality;
3231  d->setImageQuality(VG_IMAGE_QUALITY_NONANTIALIASED);
3232  d->setRenderingQuality(VG_RENDERING_QUALITY_NONANTIALIASED);
3233 
3234  for (int y = sourceRect.y(); y < sourceRect.height(); y += tileHeight) {
3235  int h = qMin(tileHeight, sourceRect.height() - y);
3236  if (h < 1)
3237  break;
3238  for (int x = sourceRect.x(); x < sourceRect.width(); x += tileWidth) {
3239  int w = qMin(tileWidth, sourceRect.width() - x);
3240  if (w < 1)
3241  break;
3242 
3243  int bytesPerPixel = image.depth() / 8;
3244  const uchar *sptr = image.constBits() + x * bytesPerPixel + y * image.bytesPerLine();
3245  vgImageSubData(tile, sptr, image.bytesPerLine(), tileFormat, 0, 0, w, h);
3246 
3247  QTransform transform(d->imageTransform);
3248  transform.translate(r.x() + x, r.y() + y);
3249  transform.scale(scaleX, scaleY);
3250  d->setTransform(VG_MATRIX_IMAGE_USER_TO_SURFACE, transform);
3251 
3252  VGImage actualTile = tile;
3253  if (tileWithOpacity != VG_INVALID_HANDLE) {
3254  vgColorMatrix(tileWithOpacity, actualTile, opacityMatrix);
3255  if (w < tileWidth || h < tileHeight)
3256  actualTile = vgChildImage(tileWithOpacity, 0, 0, w, h);
3257  else
3258  actualTile = tileWithOpacity;
3259  } else if (w < tileWidth || h < tileHeight) {
3260  actualTile = vgChildImage(tile, 0, 0, w, h);
3261  }
3262  vgDrawImage(actualTile);
3263 
3264  if (actualTile != tile && actualTile != tileWithOpacity)
3265  vgDestroyImage(actualTile);
3266  }
3267  }
3268 
3269  vgDestroyImage(tile);
3270  if (tileWithOpacity != VG_INVALID_HANDLE)
3271  vgDestroyImage(tileWithOpacity);
3272 
3273  d->setImageQuality(oldImageQuality);
3274  d->setRenderingQuality(oldRenderingQuality);
3275 }
3276 
3277 // Used by qpixmapfilter_vg.cpp to draw filtered VGImage's.
3278 void qt_vg_drawVGImage(QPainter *painter, const QPointF& pos, VGImage vgImg)
3279 {
3280  QVGPaintEngine *engine =
3281  static_cast<QVGPaintEngine *>(painter->paintEngine());
3282  drawVGImage(engine->vgPrivate(), pos, vgImg);
3283 }
3284 
3285 // Used by qpixmapfilter_vg.cpp to draw filtered VGImage's as a stencil.
3287  (QPainter *painter, const QPointF& pos, VGImage vgImg, const QBrush& brush)
3288 {
3289  QVGPaintEngine *engine =
3290  static_cast<QVGPaintEngine *>(painter->paintEngine());
3291 
3292  QVGPaintEnginePrivate *d = engine->vgPrivate();
3293 
3294  QTransform transform(d->imageTransform);
3295  transform.translate(pos.x(), pos.y());
3296  d->setTransform(VG_MATRIX_IMAGE_USER_TO_SURFACE, transform);
3297 
3298  d->ensureBrush(brush);
3299  d->setImageMode(VG_DRAW_IMAGE_STENCIL);
3300  vgDrawImage(vgImg);
3301 }
3302 
3304 {
3305  Q_D(const QVGPaintEngine);
3306 
3307  // qt_vg_image_to_vg_format returns VG_sARGB_8888 as
3308  // fallback case if no matching VG format is found.
3309  // If given image format is not Format_ARGB32 and returned
3310  // format is VG_sARGB_8888, it means that no match was
3311  // found. In that case vgWritePixels cannot be used.
3312  // Also 1-bit formats cannot be used directly either.
3313  if ((image.format() != QImage::Format_ARGB32
3314  && qt_vg_image_to_vg_format(image.format()) == VG_sARGB_8888)
3315  || image.depth() == 1) {
3316  return false;
3317  }
3318 
3319  // vgWritePixels ignores masking, blending and xforms so we can only use it if
3320  // ALL of the following conditions are true:
3321  // - It is a simple translate, or a scale of -1 on the y-axis (inverted)
3322  // - The opacity is totally opaque
3323  // - The composition mode is "source" OR "source over" provided the image is opaque
3324  return ( d->imageTransform.type() <= QTransform::TxScale
3325  && d->imageTransform.m11() == 1.0 && qAbs(d->imageTransform.m22()) == 1.0)
3326  && d->opacity == 1.0f
3327  && (d->blendMode == VG_BLEND_SRC || (d->blendMode == VG_BLEND_SRC_OVER &&
3328  !image.hasAlphaChannel()));
3329 }
3330 
3331 void QVGPaintEngine::drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr)
3332 {
3333  QPixmapData *pd = pm.pixmapData();
3334  if (!pd)
3335  return; // null QPixmap
3336  if (pd->classId() == QPixmapData::OpenVGClass) {
3338  QVGPixmapData *vgpd = static_cast<QVGPixmapData *>(pd);
3339  if (!vgpd->isValid())
3340  return;
3341  if (d->simpleTransform)
3342  drawVGImage(d, r, vgpd->toVGImage(), vgpd->size(), sr);
3343  else
3344  drawVGImage(d, r, vgpd->toVGImage(d->opacity), vgpd->size(), sr);
3345 
3346  if (vgpd->vgImage != VG_INVALID_HANDLE)
3347  return;
3348 
3349  vgpd->source.beginDataAccess();
3350  drawImage(r, vgpd->source.imageRef(), sr, Qt::AutoColor);
3351  vgpd->source.endDataAccess(true);
3352  } else {
3353  drawImage(r, *(pd->buffer()), sr, Qt::AutoColor);
3354  }
3355 }
3356 
3357 void QVGPaintEngine::drawPixmap(const QPointF &pos, const QPixmap &pm)
3358 {
3359  QPixmapData *pd = pm.pixmapData();
3360  if (!pd)
3361  return; // null QPixmap
3362  if (pd->classId() == QPixmapData::OpenVGClass) {
3364  QVGPixmapData *vgpd = static_cast<QVGPixmapData *>(pd);
3365  if (!vgpd->isValid())
3366  return;
3367  if (d->simpleTransform)
3368  drawVGImage(d, pos, vgpd->toVGImage());
3369  else
3370  drawVGImage(d, pos, vgpd->toVGImage(d->opacity));
3371 
3372  if (vgpd->vgImage != VG_INVALID_HANDLE)
3373  return;
3374 
3375  vgpd->source.beginDataAccess();
3376  drawImage(pos, vgpd->source.imageRef());
3377  vgpd->source.endDataAccess(true);
3378  } else {
3379  drawImage(pos, *(pd->buffer()));
3380  }
3381 }
3382 
3384  (const QRectF &r, const QImage &image, const QRectF &sr,
3385  Qt::ImageConversionFlags flags)
3386 {
3388  if (image.isNull())
3389  return;
3390  VGImage vgImg;
3391  if (d->simpleTransform || d->opacity == 1.0f)
3392  vgImg = toVGImageSubRect(image, sr.toRect(), flags);
3393  else
3394  vgImg = toVGImageWithOpacitySubRect(image, d->opacity, sr.toRect());
3395  if (vgImg != VG_INVALID_HANDLE) {
3396  if (r.size() == sr.size()) {
3397  drawVGImage(d, r.topLeft(), vgImg);
3398  } else {
3399  drawVGImage(d, r, vgImg, sr.size().toSize(),
3400  QRectF(QPointF(0, 0), sr.size()));
3401  }
3402  } else {
3403  if (canVgWritePixels(image) && (r.size() == sr.size()) && !flags) {
3404  // Optimization for straight blits, no blending
3405  int x = sr.x();
3406  int y = sr.y();
3407  int bpp = image.depth() >> 3; // bytes
3408  int offset = 0;
3409  int bpl = image.bytesPerLine();
3410  if (d->imageTransform.m22() < 0) {
3411  // inverted
3412  offset = ((y + sr.height()) * bpl) - ((image.width() - x) * bpp);
3413  bpl = -bpl;
3414  } else {
3415  offset = (y * bpl) + (x * bpp);
3416  }
3417  const uchar *bits = image.constBits() + offset;
3418 
3420  vgWritePixels(bits, bpl, qt_vg_image_to_vg_format(image.format()),
3421  mapped.x(), mapped.y() - sr.height(), r.width(), r.height());
3422  return;
3423  } else {
3424  // Monochrome images need to use the vgChildImage() path.
3425  vgImg = toVGImage(image, flags);
3426  if (vgImg == VG_INVALID_HANDLE)
3427  drawImageTiled(d, r, image, sr);
3428  else
3429  drawVGImage(d, r, vgImg, image.size(), sr);
3430  }
3431  }
3432  vgDestroyImage(vgImg);
3433 }
3434 
3435 void QVGPaintEngine::drawImage(const QPointF &pos, const QImage &image)
3436 {
3438  if (image.isNull())
3439  return;
3440  VGImage vgImg;
3441  if (canVgWritePixels(image)) {
3442  // Optimization for straight blits, no blending
3443  bool inverted = (d->imageTransform.m22() < 0);
3444  const uchar *bits = inverted ? image.constBits() + image.byteCount() - image.bytesPerLine() : image.constBits();
3445  int bpl = inverted ? -image.bytesPerLine() : image.bytesPerLine();
3446 
3447  QPointF mapped = d->imageTransform.map(pos);
3448  vgWritePixels(bits, bpl, qt_vg_image_to_vg_format(image.format()),
3449  mapped.x(), mapped.y() - image.height(), image.width(), image.height());
3450  return;
3451  } else if (d->simpleTransform || d->opacity == 1.0f) {
3452  vgImg = toVGImage(image);
3453  } else {
3454  vgImg = toVGImageWithOpacity(image, d->opacity);
3455  }
3456  if (vgImg == VG_INVALID_HANDLE)
3457  drawImageTiled(d, QRectF(pos, image.size()), image);
3458  else
3459  drawVGImage(d, pos, vgImg);
3460  vgDestroyImage(vgImg);
3461 }
3462 
3464  (const QRectF &r, const QPixmap &pixmap, const QPointF &s)
3465 {
3466  QBrush brush(state()->pen.color(), pixmap);
3467  QTransform xform = QTransform::fromTranslate(r.x() - s.x(), r.y() - s.y());
3468  brush.setTransform(xform);
3469  fillRect(r, brush);
3470 }
3471 
3472 // Best performance will be achieved with QDrawPixmaps::OpaqueHint
3473 // (i.e. no opacity), no rotation or scaling, and drawing the full
3474 // pixmap rather than parts of the pixmap. Even having just one of
3475 // these conditions will improve performance.
3476 void QVGPaintEngine::drawPixmapFragments(const QPainter::PixmapFragment *drawingData, int dataCount,
3477  const QPixmap &pixmap, QFlags<QPainter::PixmapFragmentHint> hints)
3478 {
3479 #if !defined(QT_SHIVAVG)
3481 
3482  // If the pixmap is not VG, or the transformation is projective,
3483  // then fall back to the default implementation.
3484  QPixmapData *pd = pixmap.pixmapData();
3485  if (!pd)
3486  return; // null QPixmap
3487  if (pd->classId() != QPixmapData::OpenVGClass || !d->simpleTransform) {
3488  QPaintEngineEx::drawPixmapFragments(drawingData, dataCount, pixmap, hints);
3489  return;
3490  }
3491 
3492  // Bail out if nothing to do.
3493  if (dataCount <= 0)
3494  return;
3495 
3496  // Bail out if we don't have a usable VGImage for the pixmap.
3497  QVGPixmapData *vgpd = static_cast<QVGPixmapData *>(pd);
3498  if (!vgpd->isValid())
3499  return;
3500  VGImage vgImg = vgpd->toVGImage();
3501  if (vgImg == VG_INVALID_HANDLE)
3502  return;
3503 
3504  // We cache the results of any vgChildImage() calls because the
3505  // same child is very likely to be used over and over in particle
3506  // systems. However, performance is even better if vgChildImage()
3507  // isn't needed at all, so use full source rects where possible.
3508  QVarLengthArray<VGImage> cachedImages;
3509  QVarLengthArray<QRect> cachedSources;
3510 
3511  // Select the opacity paint object.
3512  if ((hints & QPainter::OpaqueHint) != 0 && d->opacity == 1.0f) {
3513  d->setImageMode(VG_DRAW_IMAGE_NORMAL);
3514  } else {
3515  hints = 0;
3516  if (d->fillPaint != d->opacityPaint) {
3517  vgSetPaint(d->opacityPaint, VG_FILL_PATH);
3518  d->fillPaint = d->opacityPaint;
3519  }
3520  }
3521 
3522  for (int i = 0; i < dataCount; ++i) {
3523  QTransform transform(d->imageTransform);
3524  transform.translate(drawingData[i].x, drawingData[i].y);
3525  transform.rotate(drawingData[i].rotation);
3526 
3527  VGImage child;
3528  QSize imageSize = vgpd->size();
3529  QRectF sr(drawingData[i].sourceLeft, drawingData[i].sourceTop,
3530  drawingData[i].width, drawingData[i].height);
3531  if (sr.topLeft().isNull() && sr.size() == imageSize) {
3532  child = vgImg;
3533  } else {
3534  // Look for a previous child with the same source rectangle
3535  // to avoid constantly calling vgChildImage()/vgDestroyImage().
3536  QRect src = sr.toRect();
3537  int j;
3538  for (j = 0; j < cachedSources.size(); ++j) {
3539  if (cachedSources[j] == src)
3540  break;
3541  }
3542  if (j < cachedSources.size()) {
3543  child = cachedImages[j];
3544  } else {
3545  child = vgChildImage
3546  (vgImg, src.x(), src.y(), src.width(), src.height());
3547  cachedImages.append(child);
3548  cachedSources.append(src);
3549  }
3550  }
3551 
3552  VGfloat scaleX = drawingData[i].scaleX;
3553  VGfloat scaleY = drawingData[i].scaleY;
3554  transform.translate(-0.5 * scaleX * sr.width(),
3555  -0.5 * scaleY * sr.height());
3556  transform.scale(scaleX, scaleY);
3557  d->setTransform(VG_MATRIX_IMAGE_USER_TO_SURFACE, transform);
3558 
3559  if ((hints & QPainter::OpaqueHint) == 0) {
3560  qreal opacity = d->opacity * drawingData[i].opacity;
3561  if (opacity != 1.0f) {
3562  if (d->paintOpacity != opacity) {
3563  VGfloat values[4];
3564  values[0] = 1.0f;
3565  values[1] = 1.0f;
3566  values[2] = 1.0f;
3567  values[3] = opacity;
3568  d->paintOpacity = opacity;
3569  vgSetParameterfv
3570  (d->opacityPaint, VG_PAINT_COLOR, 4, values);
3571  }
3572  d->setImageMode(VG_DRAW_IMAGE_MULTIPLY);
3573  } else {
3574  d->setImageMode(VG_DRAW_IMAGE_NORMAL);
3575  }
3576  }
3577 
3578  vgDrawImage(child);
3579  }
3580 
3581  // Destroy the cached child sub-images.
3582  for (int i = 0; i < cachedImages.size(); ++i)
3583  vgDestroyImage(cachedImages[i]);
3584 #else
3585  QPaintEngineEx::drawPixmapFragments(drawingData, dataCount, pixmap, hints);
3586 #endif
3587 }
3588 
3590  : QObject(), d_ptr(d)
3591 {
3592 }
3593 
3595 {
3596 }
3597 
3599 {
3600 #if !defined(QVG_NO_DRAW_GLYPHS)
3601  QFontEngine *engine = static_cast<QFontEngine *>(sender());
3602  QVGFontCache::Iterator it = d_ptr->fontCache.find(engine);
3603  if (it != d_ptr->fontCache.end()) {
3604  delete it.value();
3605  d_ptr->fontCache.erase(it);
3606  }
3607 #endif
3608 }
3609 
3610 #if !defined(QVG_NO_DRAW_GLYPHS)
3611 
3612 QVGFontGlyphCache::QVGFontGlyphCache()
3613 {
3614  font = vgCreateFont(0);
3615  scaleX = scaleY = 0.0;
3616  invertedGlyphs = false;
3617  memset(cachedGlyphsMask, 0, sizeof(cachedGlyphsMask));
3618 }
3619 
3620 QVGFontGlyphCache::~QVGFontGlyphCache()
3621 {
3622  if (font != VG_INVALID_HANDLE)
3623  vgDestroyFont(font);
3624 }
3625 
3626 void QVGFontGlyphCache::setScaleFromText(const QFont &font, QFontEngine *fontEngine)
3627 {
3628  QFontInfo fi(font);
3629  qreal pixelSize = fi.pixelSize();
3630  qreal emSquare = fontEngine->properties().emSquare.toReal();
3631  scaleX = scaleY = static_cast<VGfloat>(pixelSize / emSquare);
3632 }
3633 
3634 void QVGFontGlyphCache::cacheGlyphs(QVGPaintEnginePrivate *d,
3635  QFontEngine *fontEngine,
3636  const glyph_t *g, int count)
3637 {
3638  VGfloat origin[2];
3639  VGfloat escapement[2];
3640  glyph_metrics_t metrics;
3641  // Some Qt font engines don't set yoff in getUnscaledGlyph().
3642  // Zero the metric structure so that everything has a default value.
3643  memset(&metrics, 0, sizeof(metrics));
3644  while (count-- > 0) {
3645  // Skip this glyph if we have already cached it before.
3646  glyph_t glyph = *g++;
3647  if (glyph < 256) {
3648  if ((cachedGlyphsMask[glyph / 32] & (1 << (glyph % 32))) != 0)
3649  continue;
3650  cachedGlyphsMask[glyph / 32] |= (1 << (glyph % 32));
3651  } else if (cachedGlyphs.contains(glyph)) {
3652  continue;
3653  } else {
3654  cachedGlyphs.insert(glyph);
3655  }
3656 #if !defined(QVG_NO_IMAGE_GLYPHS)
3657  Q_UNUSED(d);
3658  QImage scaledImage = fontEngine->alphaMapForGlyph(glyph);
3659  VGImage vgImage = VG_INVALID_HANDLE;
3660  metrics = fontEngine->boundingBox(glyph);
3661  if (!scaledImage.isNull()) { // Not a space character
3662  if (scaledImage.format() == QImage::Format_Indexed8) {
3663  vgImage = vgCreateImage(VG_A_8, scaledImage.width(), scaledImage.height(), VG_IMAGE_QUALITY_FASTER);
3664  vgImageSubData(vgImage, scaledImage.constBits(), scaledImage.bytesPerLine(), VG_A_8, 0, 0, scaledImage.width(), scaledImage.height());
3665  } else if (scaledImage.format() == QImage::Format_Mono) {
3666  QImage img = scaledImage.convertToFormat(QImage::Format_Indexed8);
3667  vgImage = vgCreateImage(VG_A_8, img.width(), img.height(), VG_IMAGE_QUALITY_FASTER);
3668  vgImageSubData(vgImage, img.constBits(), img.bytesPerLine(), VG_A_8, 0, 0, img.width(), img.height());
3669  } else {
3671  vgImage = vgCreateImage(VG_sARGB_8888_PRE, img.width(), img.height(), VG_IMAGE_QUALITY_FASTER);
3672  vgImageSubData(vgImage, img.constBits(), img.bytesPerLine(), VG_sARGB_8888_PRE, 0, 0, img.width(), img.height());
3673  }
3674  }
3675  origin[0] = -metrics.x.toReal();
3676  origin[1] = -metrics.y.toReal();
3677  escapement[0] = 0;
3678  escapement[1] = 0;
3679  vgSetGlyphToImage(font, glyph, vgImage, origin, escapement);
3680  vgDestroyImage(vgImage); // Reduce reference count.
3681 #else
3682  // Calculate the path for the glyph and cache it.
3683  QPainterPath path;
3684  fontEngine->getUnscaledGlyph(glyph, &path, &metrics);
3685  VGPath vgPath;
3686  if (!path.isEmpty()) {
3687  vgPath = d->painterPathToVGPath(path);
3688  } else {
3689  // Probably a "space" character with no visible outline.
3690  vgPath = VG_INVALID_HANDLE;
3691  }
3692  origin[0] = 0;
3693  origin[1] = 0;
3694  escapement[0] = 0;
3695  escapement[1] = 0;
3696  vgSetGlyphToPath(font, glyph, vgPath, VG_FALSE, origin, escapement);
3697  vgDestroyPath(vgPath); // Reduce reference count.
3698 #endif // !defined(QVG_NO_IMAGE_GLYPHS)
3699  }
3700 }
3701 
3702 #endif // !defined(QVG_NO_DRAW_GLYPHS)
3703 
3704 void QVGPaintEngine::drawTextItem(const QPointF &p, const QTextItem &textItem)
3705 {
3706 #if !defined(QVG_NO_DRAW_GLYPHS)
3708  const QTextItemInt &ti = static_cast<const QTextItemInt &>(textItem);
3709 
3710  // If we are not using a simple transform, then fall back
3711  // to the default Qt path stroking algorithm.
3712  if (!d->simpleTransform) {
3713  QPaintEngineEx::drawTextItem(p, textItem);
3714  return;
3715  }
3716 
3717  if (d->needsPenEmulation()) {
3718  QPaintEngineEx::drawTextItem(p, textItem);
3719  return;
3720  }
3721 
3722  // Get the glyphs and positions associated with the text item.
3724  QVarLengthArray<glyph_t> glyphs;
3725  QTransform matrix;
3726  ti.fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions);
3727 
3728  if (!drawCachedGlyphs(glyphs.size(), glyphs.data(), ti.font(), ti.fontEngine, p, positions.data()))
3729  QPaintEngineEx::drawTextItem(p, textItem);
3730 #else
3731  // OpenGL 1.0 does not have support for VGFont and glyphs,
3732  // so fall back to the default Qt path stroking algorithm.
3733  QPaintEngineEx::drawTextItem(p, textItem);
3734 #endif
3735 }
3736 
3738 {
3739  drawCachedGlyphs(textItem->numGlyphs, textItem->glyphs, textItem->font, textItem->fontEngine(),
3740  QPointF(0, 0), textItem->glyphPositions);
3741 }
3742 
3743  bool QVGPaintEngine::drawCachedGlyphs(int numGlyphs, const glyph_t *glyphs, const QFont &font,
3744  QFontEngine *fontEngine, const QPointF &p,
3745  const QFixedPoint *positions)
3746  {
3747 #if !defined(QVG_NO_DRAW_GLYPHS)
3749 
3750  // Find the glyph cache for this font.
3751  QVGFontCache::ConstIterator it = d->fontCache.constFind(fontEngine);
3752  QVGFontGlyphCache *glyphCache;
3753  if (it != d->fontCache.constEnd()) {
3754  glyphCache = it.value();
3755  } else {
3756 #ifdef Q_OS_SYMBIAN
3757  glyphCache = new QSymbianVGFontGlyphCache();
3758 #else
3759  glyphCache = new QVGFontGlyphCache();
3760 #endif
3761  if (glyphCache->font == VG_INVALID_HANDLE) {
3762  qWarning("QVGPaintEngine::drawTextItem: OpenVG fonts are not supported by the OpenVG engine");
3763  delete glyphCache;
3764  return false;
3765  }
3766  glyphCache->setScaleFromText(font, fontEngine);
3767  d->fontCache.insert(fontEngine, glyphCache);
3768  if (!d->fontEngineCleaner)
3769  d->fontEngineCleaner = new QVGFontEngineCleaner(d);
3770  QObject::connect(fontEngine, SIGNAL(destroyed()),
3771  d->fontEngineCleaner, SLOT(fontEngineDestroyed()));
3772  }
3773 
3774  // Set the transformation to use for drawing the current glyphs.
3775  QTransform glyphTransform(d->pathTransform);
3776  if (d->transform.type() <= QTransform::TxTranslate) {
3777  // Prevent blurriness of unscaled, unrotated text by forcing integer coordinates.
3778  glyphTransform.translate(
3779  floor(p.x() + glyphTransform.dx() + aliasedCoordinateDelta) - glyphTransform.dx(),
3780  floor(p.y() - glyphTransform.dy() + aliasedCoordinateDelta) + glyphTransform.dy());
3781  } else {
3782  glyphTransform.translate(p.x(), p.y());
3783  }
3784 #if defined(QVG_NO_IMAGE_GLYPHS)
3785  glyphTransform.scale(glyphCache->scaleX, glyphCache->scaleY);
3786 #endif
3787 
3788  // Some glyph caches can create the VGImage upright
3789  if (glyphCache->invertedGlyphs)
3790  glyphTransform.scale(1, -1);
3791 
3792  d->setTransform(VG_MATRIX_GLYPH_USER_TO_SURFACE, glyphTransform);
3793 
3794  // Add the glyphs from the text item into the glyph cache.
3795  glyphCache->cacheGlyphs(d, fontEngine, glyphs, numGlyphs);
3796 
3797  // Create the array of adjustments between glyphs
3798  QVarLengthArray<VGfloat> adjustments_x(numGlyphs);
3799  QVarLengthArray<VGfloat> adjustments_y(numGlyphs);
3800  for (int i = 1; i < numGlyphs; ++i) {
3801  adjustments_x[i-1] = (positions[i].x - positions[i-1].x).round().toReal();
3802  adjustments_y[i-1] = (positions[i].y - positions[i-1].y).round().toReal();
3803  }
3804 
3805  // Set the glyph drawing origin.
3806  VGfloat origin[2];
3807  origin[0] = positions[0].x.round().toReal();
3808  origin[1] = positions[0].y.round().toReal();
3809  vgSetfv(VG_GLYPH_ORIGIN, 2, origin);
3810 
3811  // Fast anti-aliasing for paths, better for images.
3812 #if !defined(QVG_NO_IMAGE_GLYPHS)
3813  d->setImageQuality(VG_IMAGE_QUALITY_BETTER);
3814  d->setImageMode(VG_DRAW_IMAGE_STENCIL);
3815 #else
3816  d->setRenderingQuality(VG_RENDERING_QUALITY_FASTER);
3817 #endif
3818 
3819  // Draw the glyphs. We need to fill with the brush associated with
3820  // the Qt pen, not the Qt brush.
3821  d->ensureBrush(state()->pen.brush());
3822  vgDrawGlyphs(glyphCache->font, numGlyphs, (VGuint*)glyphs,
3823  adjustments_x.data(), adjustments_y.data(), VG_FILL_PATH, VG_TRUE);
3824  return true;
3825 #else
3826  Q_UNUSED(numGlyphs);
3827  Q_UNUSED(glyphs);
3828  Q_UNUSED(font);
3829  Q_UNUSED(fontEngine);
3830  Q_UNUSED(p);
3831  Q_UNUSED(positions);
3832  return false;
3833 #endif
3834 }
3835 
3837 {
3840  QVGPainterState *ps = static_cast<QVGPainterState *>(s);
3841  if (ps->isNew) {
3842  // Newly created state object. The call to setState()
3843  // will either be followed by a call to begin(), or we are
3844  // setting the state as part of a save().
3845  ps->isNew = false;
3846  } else {
3847  // This state object was set as part of a restore().
3848  restoreState(d->dirty);
3849  d->dirty = ps->savedDirty;
3850  }
3851 }
3852 
3854 {
3856 
3857  // About to enter raw VG mode: flush pending changes and make
3858  // sure that all matrices are set to the current transformation.
3859  QVGPainterState *s = this->state();
3860  d->ensurePen(s->pen);
3861  d->ensureBrush(s->brush);
3862  d->ensurePathTransform();
3863  d->setTransform(VG_MATRIX_IMAGE_USER_TO_SURFACE, d->imageTransform);
3864 #if !defined(QVG_NO_DRAW_GLYPHS)
3865  d->setTransform(VG_MATRIX_GLYPH_USER_TO_SURFACE, d->pathTransform);
3866 #endif
3867  vgSeti(VG_SCISSORING, VG_FALSE);
3868  vgSeti(VG_MASKING, VG_FALSE);
3869  d->rawVG = true;
3870 }
3871 
3873 {
3875  // Exiting raw VG mode: force all state values to be
3876  // explicitly set on the VG engine to undo any changes
3877  // that were made by the raw VG function calls.
3878  QPaintEngine::DirtyFlags dirty = d->dirty;
3879  d->clearModes();
3880  d->forcePenChange = true;
3881  d->forceBrushChange = true;
3882  d->penType = (VGPaintType)0;
3883  d->brushType = (VGPaintType)0;
3884  d->clearColor = QColor();
3885  d->fillPaint = d->brushPaint;
3886  d->scissorDirty = true;
3887  restoreState(QPaintEngine::AllDirty);
3888  d->dirty = dirty;
3889  d->rawVG = false;
3890  vgSetPaint(d->penPaint, VG_STROKE_PATH);
3891  vgSetPaint(d->brushPaint, VG_FILL_PATH);
3892 }
3893 
3895 {
3896 #if !defined(QT_SHIVAVG)
3898  switch (type) {
3900  if (!d->convolutionFilter)
3902  return d->convolutionFilter.data();
3904  if (!d->colorizeFilter)
3906  return d->colorizeFilter.data();
3908  if (!d->dropShadowFilter)
3910  return d->dropShadowFilter.data();
3912  if (!d->blurFilter)
3914  return d->blurFilter.data();
3915  default: break;
3916  }
3917 #endif
3918  return QPaintEngineEx::pixmapFilter(type, prototype);
3919 }
3920 
3921 void QVGPaintEngine::restoreState(QPaintEngine::DirtyFlags dirty)
3922 {
3924 
3925  // Restore the pen, brush, and other settings.
3926  if ((dirty & QPaintEngine::DirtyBrushOrigin) != 0)
3927  brushOriginChanged();
3928  d->fillRule = 0;
3929  d->clearColor = QColor();
3930  if ((dirty & QPaintEngine::DirtyOpacity) != 0)
3931  opacityChanged();
3932  if ((dirty & QPaintEngine::DirtyTransform) != 0)
3933  transformChanged();
3934  if ((dirty & QPaintEngine::DirtyCompositionMode) != 0)
3935  compositionModeChanged();
3936  if ((dirty & QPaintEngine::DirtyHints) != 0)
3937  renderHintsChanged();
3938  if ((dirty & (QPaintEngine::DirtyClipRegion |
3941  d->maskValid = false;
3942  d->maskIsSet = false;
3943  d->scissorMask = false;
3944  d->maskRect = QRect();
3945  d->scissorDirty = true;
3946  clipEnabledChanged();
3947  }
3948 
3949 #if defined(QVG_SCISSOR_CLIP)
3950  if ((dirty & (QPaintEngine::DirtyClipRegion |
3953  updateScissor();
3954  }
3955 #else
3956  updateScissor();
3957 #endif
3958 }
3959 
3961  (const QRegion& region, const QColor& color, const QSize& surfaceSize)
3962 {
3964  if (d->clearColor != color || d->clearOpacity != 1.0f) {
3965  VGfloat values[4];
3966  values[0] = color.redF();
3967  values[1] = color.greenF();
3968  values[2] = color.blueF();
3969  values[3] = color.alphaF();
3970  vgSetfv(VG_CLEAR_COLOR, 4, values);
3971  d->clearColor = color;
3972  d->clearOpacity = 1.0f;
3973  }
3974  if (region.rectCount() == 1) {
3975  QRect r = region.boundingRect();
3976  vgClear(r.x(), surfaceSize.height() - r.y() - r.height(),
3977  r.width(), r.height());
3978  } else {
3979  const QVector<QRect> rects = region.rects();
3980  for (int i = 0; i < rects.size(); ++i) {
3981  QRect r = rects.at(i);
3982  vgClear(r.x(), surfaceSize.height() - r.y() - r.height(),
3983  r.width(), r.height());
3984  }
3985  }
3986 }
3987 
3988 #if !defined(QVG_NO_SINGLE_CONTEXT) && !defined(QT_NO_EGL)
3989 
3991 {
3993 }
3994 
3996 {
3997 }
3998 
4000 {
4001  this->screenSize = screenSize;
4002  clearScissor();
4003  d->setBlendMode(VG_BLEND_SRC_OVER);
4004 }
4005 
4007 {
4008  clearScissor();
4009 }
4010 
4012  (VGImage image, const QSize& imageSize,
4013  const QRect& rect, const QPoint& topLeft, int opacity)
4014 {
4015  if (image == VG_INVALID_HANDLE)
4016  return;
4017 
4018  // Determine which sub rectangle of the window to draw.
4019  QRect sr = rect.translated(-topLeft);
4020 
4021  if (opacity >= 255) {
4022  // Fully opaque: use vgSetPixels() to directly copy the sub-region.
4023  int y = screenSize.height() - (rect.bottom() + 1);
4024  vgSetPixels(rect.x(), y, image, sr.x(),
4025  imageSize.height() - (sr.y() + sr.height()),
4026  sr.width(), sr.height());
4027  } else {
4028  // Extract the child image that we want to draw.
4029  VGImage child;
4030  if (sr.topLeft().isNull() && sr.size() == imageSize)
4031  child = image;
4032  else {
4033  child = vgChildImage
4034  (image, sr.x(), imageSize.height() - (sr.y() + sr.height()),
4035  sr.width(), sr.height());
4036  }
4037 
4038  // Set the image transform.
4039  QTransform transform;
4040  int y = screenSize.height() - (rect.bottom() + 1);
4041  transform.translate(rect.x() - 0.5f, y - 0.5f);
4042  d->setTransform(VG_MATRIX_IMAGE_USER_TO_SURFACE, transform);
4043 
4044  // Enable opacity for image drawing if necessary.
4045  if (opacity != d->paintOpacity) {
4046  VGfloat values[4];
4047  values[0] = 1.0f;
4048  values[1] = 1.0f;
4049  values[2] = 1.0f;
4050  values[3] = ((VGfloat)opacity) / 255.0f;
4051  vgSetParameterfv(d->opacityPaint, VG_PAINT_COLOR, 4, values);
4052  d->paintOpacity = values[3];
4053  }
4054  if (d->fillPaint != d->opacityPaint) {
4055  vgSetPaint(d->opacityPaint, VG_FILL_PATH);
4056  d->fillPaint = d->opacityPaint;
4057  }
4058  d->setImageMode(VG_DRAW_IMAGE_MULTIPLY);
4059 
4060  // Draw the child image.
4061  vgDrawImage(child);
4062 
4063  // Destroy the child image.
4064  if(child != image)
4065  vgDestroyImage(child);
4066  }
4067 }
4068 
4069 static void fillBackgroundRect(const QRect& rect, QVGPaintEnginePrivate *d)
4070 {
4071  VGfloat coords[8];
4072  coords[0] = rect.x();
4073  coords[1] = rect.y();
4074  coords[2] = rect.x() + rect.width();
4075  coords[3] = coords[1];
4076  coords[4] = coords[2];
4077  coords[5] = rect.y() + rect.height();
4078  coords[6] = coords[0];
4079  coords[7] = coords[5];
4080 #if !defined(QVG_NO_MODIFY_PATH)
4081  vgModifyPathCoords(d->rectPath, 0, 4, coords);
4082  vgDrawPath(d->rectPath, VG_FILL_PATH);
4083 #else
4084  Q_UNUSED(d);
4085  VGPath rectPath = vgCreatePath
4086  (VG_PATH_FORMAT_STANDARD,
4087  VG_PATH_DATATYPE_F,
4088  1.0f, // scale
4089  0.0f, // bias
4090  5, // segmentCapacityHint
4091  8, // coordCapacityHint
4092  VG_PATH_CAPABILITY_ALL);
4093  static VGubyte const segments[5] = {
4094  VG_MOVE_TO_ABS,
4095  VG_LINE_TO_ABS,
4096  VG_LINE_TO_ABS,
4097  VG_LINE_TO_ABS,
4098  VG_CLOSE_PATH
4099  };
4100  vgAppendPathData(rectPath, 5, segments, coords);
4101  vgDrawPath(rectPath, VG_FILL_PATH);
4102  vgDestroyPath(rectPath);
4103 #endif
4104 }
4105 
4107  (const QRegion& region, const QBrush& brush)
4108 {
4109  if (brush.style() == Qt::SolidPattern) {
4110  // Use vgClear() to quickly fill the background.
4111  QColor color = brush.color();
4112  if (d->clearColor != color || d->clearOpacity != 1.0f) {
4113  VGfloat values[4];
4114  values[0] = color.redF();
4115  values[1] = color.greenF();
4116  values[2] = color.blueF();
4117  values[3] = color.alphaF();
4118  vgSetfv(VG_CLEAR_COLOR, 4, values);
4119  d->clearColor = color;
4120  d->clearOpacity = 1.0f;
4121  }
4122  if (region.rectCount() == 1) {
4123  QRect r = region.boundingRect();
4124  vgClear(r.x(), screenSize.height() - r.y() - r.height(),
4125  r.width(), r.height());
4126  } else {
4127  const QVector<QRect> rects = region.rects();
4128  for (int i = 0; i < rects.size(); ++i) {
4129  QRect r = rects.at(i);
4130  vgClear(r.x(), screenSize.height() - r.y() - r.height(),
4131  r.width(), r.height());
4132  }
4133  }
4134 
4135  } else {
4136  // Set the path transform to the default viewport transformation.
4137  VGfloat devh = screenSize.height();
4138  QTransform viewport(1.0f, 0.0f, 0.0f,
4139  0.0f, -1.0f, 0.0f,
4140  0.0f, devh, 1.0f);
4141  d->setTransform(VG_MATRIX_PATH_USER_TO_SURFACE, viewport);
4142 
4143  // Set the brush to use to fill the background.
4144  d->ensureBrush(brush);
4145  d->setFillRule(VG_EVEN_ODD);
4146 
4147  if (region.rectCount() == 1) {
4148  fillBackgroundRect(region.boundingRect(), d);
4149  } else {
4150  const QVector<QRect> rects = region.rects();
4151  for (int i = 0; i < rects.size(); ++i)
4152  fillBackgroundRect(rects.at(i), d);
4153  }
4154 
4155  // We will need to reset the path transform during the next paint.
4156  d->pathTransformSet = false;
4157  }
4158 }
4159 
4161  (const QPixmap& pixmap, const QPoint& offset)
4162 {
4163  VGImage vgImage = VG_INVALID_HANDLE;
4164 
4165  // Fetch the VGImage from the pixmap if possible.
4166  QPixmapData *pd = pixmap.pixmapData();
4167  if (!pd)
4168  return; // null QPixmap
4169  if (pd->classId() == QPixmapData::OpenVGClass) {
4170  QVGPixmapData *vgpd = static_cast<QVGPixmapData *>(pd);
4171  if (vgpd->isValid())
4172  vgImage = vgpd->toVGImage();
4173  }
4174 
4175  // Set the image transformation and modes.
4176  VGfloat devh = screenSize.height();
4177  QTransform transform(1.0f, 0.0f, 0.0f,
4178  0.0f, -1.0f, 0.0f,
4179  0.0f, devh, 1.0f);
4180  transform.translate(offset.x(), offset.y());
4181  d->setTransform(VG_MATRIX_IMAGE_USER_TO_SURFACE, transform);
4182  d->setImageMode(VG_DRAW_IMAGE_NORMAL);
4183 
4184  // Draw the VGImage.
4185  if (vgImage != VG_INVALID_HANDLE) {
4186  vgDrawImage(vgImage);
4187  } else {
4188  QImage img = pixmap.toImage().convertToFormat
4190 
4191  vgImage = vgCreateImage
4192  (VG_sARGB_8888_PRE, img.width(), img.height(),
4193  VG_IMAGE_QUALITY_FASTER);
4194  if (vgImage == VG_INVALID_HANDLE)
4195  return;
4196  vgImageSubData
4197  (vgImage, img.constBits() + img.bytesPerLine() * (img.height() - 1),
4198  -(img.bytesPerLine()), VG_sARGB_8888_PRE, 0, 0,
4199  img.width(), img.height());
4200 
4201  vgDrawImage(vgImage);
4202  vgDestroyImage(vgImage);
4203  }
4204 }
4205 
4207 {
4208  QVector<QRect> rects = region.rects();
4209  int count = rects.count();
4210  if (count > d->maxScissorRects)
4211  count = d->maxScissorRects;
4212  QVarLengthArray<VGint> params(count * 4);
4213  int height = screenSize.height();
4214  for (int i = 0; i < count; ++i) {
4215  params[i * 4 + 0] = rects[i].x();
4216  params[i * 4 + 1] = height - rects[i].y() - rects[i].height();
4217  params[i * 4 + 2] = rects[i].width();
4218  params[i * 4 + 3] = rects[i].height();
4219  }
4220 
4221  vgSetiv(VG_SCISSOR_RECTS, count * 4, params.data());
4222  vgSeti(VG_SCISSORING, VG_TRUE);
4223  d->scissorDirty = false;
4224  d->scissorActive = true;
4225  d->scissorRegion = region;
4226 }
4227 
4229 {
4230  if (d->scissorActive || d->scissorDirty) {
4231  vgSeti(VG_SCISSORING, VG_FALSE);
4232  d->scissorActive = false;
4233  d->scissorDirty = false;
4234  }
4235 }
4236 
4237 #endif // !QVG_NO_SINGLE_CONTEXT && !QT_NO_EGL
4238 
4240 {
4241  switch (format) {
4243  return VG_BW_1;
4245  return VG_sL_8;
4247  return VG_sARGB_8888_PRE;
4248  case QImage::Format_RGB32:
4249  return VG_sXRGB_8888;
4250  case QImage::Format_ARGB32:
4251  return VG_sARGB_8888;
4252  case QImage::Format_RGB16:
4253  return VG_sRGB_565;
4255  return VG_sARGB_4444;
4256  default:
4257  break;
4258  }
4259  return VG_sARGB_8888; // XXX
4260 }
4261 
4263 
4264 #include "qpaintengine_vg.moc"
virtual void drawPoints(const QPointF *points, int pointCount)
Draws the first pointCount points in the buffer points.
The QPainter class performs low-level painting on widgets and other paint devices.
Definition: qpainter.h:86
QSize size() const
The QColor class provides colors based on RGB, HSV or CMYK values.
Definition: qcolor.h:67
double d
Definition: qnumeric_p.h:62
QPointF bottomRight() const
Returns the position of the rectangle&#39;s bottom-right corner.
Definition: qrect.h:540
The QPainterPath::Element class specifies the position and type of a subpath.
Definition: qpainterpath.h:77
QFontEngine * fontEngine
const T * constData() const
void startCompositing(const QSize &screenSize)
QImage toImage() const
Converts the pixmap to a QImage.
Definition: qpixmap.cpp:542
bool isEmpty() const
Returns true if either there are no elements in this path, or if the only element is a MoveToElement;...
Definition: qpainterpath.h:392
ElementType
This enum describes the types of elements used to connect vertices in subpaths.
Definition: qpainterpath.h:70
QT_DEPRECATED int numRects() const
Returns the number of rectangles that will be returned in rects().
Definition: qregion.cpp:4456
qreal scaleY
the vertical scale of the target rectangle.
Definition: qpainter.h:112
Format
The following image formats are available in Qt.
Definition: qimage.h:91
qreal y() const
Returns the y-coordinate of the rectangle&#39;s top edge.
Definition: qrect.h:667
qreal dy() const
Returns the vertical translation factor.
Definition: qtransform.h:277
qreal right() const
Returns the x-coordinate of the rectangle&#39;s right edge.
Definition: qrect.h:527
qreal alphaF() const
Returns the alpha color component of this color.
Definition: qcolor.cpp:1106
unsigned int QRgb
Definition: qrgb.h:53
VGImageFormat qt_vg_image_to_vg_format(QImage::Format format)
bool isNull() const
Returns true if the rectangle is a null rectangle, otherwise returns false.
Definition: qrect.h:231
int type
Definition: qmetatype.cpp:239
double qreal
Definition: qglobal.h:1193
virtual QImage alphaMapForGlyph(glyph_t)
Q_DECL_CONSTEXPR const T & qMin(const T &a, const T &b)
Definition: qglobal.h:1215
#define QT_END_NAMESPACE
This macro expands to.
Definition: qglobal.h:90
const QColor & color() const
Returns the brush color.
Definition: qbrush.h:183
void stroke(VGPath path, const QPen &pen)
void drawEllipse(const QRectF &r)
Reimplement this function to draw the largest ellipse that can be contained within rectangle rect...
QFontEngine * fontEngine() const
QPaintDevice * paintDevice() const
Returns the device that this engine is painting on, if painting is active; otherwise returns 0...
int elementCount() const
virtual void drawPath(const QPainterPath &path)
The default implementation ignores the path and does nothing.
qreal m32() const
Returns the vertical translation factor.
Definition: qtransform.h:265
void setBrushTransform(const QBrush &brush, VGMatrixMode mode)
The QLine class provides a two-dimensional vector using integer precision.
Definition: qline.h:57
QPainter::RenderHints renderHints
Definition: qpainter_p.h:158
bool isEmpty() const
qreal greenF() const
Returns the green color component of this color.
Definition: qcolor.cpp:1241
VGPath painterPathToVGPath(const QPainterPath &path)
T * data() const
Returns the value of the pointer referenced by this object.
void beginDataAccess() const
const QGradient * gradient() const
Returns the gradient describing this brush.
Definition: qbrush.cpp:871
QPaintEngine::DirtyFlags savedDirty
QPainter::CompositionMode composition_mode
Definition: qpainter_p.h:174
#define it(className, varName)
Qt::BrushStyle qbrush_style(const QBrush &b)
Definition: qpainter_p.h:96
bool canVgWritePixels(const QImage &image) const
QSize toSize() const
Returns an integer based copy of this size.
Definition: qsize.h:355
QFixedPoint * glyphPositions
The QPainterPath class provides a container for painting operations, enabling graphical shapes to be ...
Definition: qpainterpath.h:67
int count(const T &t) const
Returns the number of occurrences of value in the vector.
Definition: qvector.h:742
VGImageQuality imageQuality
void setPenParams(const QPen &pen)
void setTransform(const QTransform &)
Sets matrix as an explicit transformation matrix on the current brush.
Definition: qbrush.cpp:968
qreal x2() const
Returns the x-coordinate of the line&#39;s end point.
Definition: qline.h:304
void setCapStyle(Qt::PenCapStyle pcs)
Sets the pen&#39;s cap style to the given style.
Definition: qpen.cpp:723
Qt::PenStyle style() const
Returns the pen style.
Definition: qpen.cpp:428
bool isDefaultClipRect(const QRect &rect)
QScopedPointer< QPixmapFilter > blurFilter
#define Q_GUI_EXPORT
Definition: qglobal.h:1450
QPointF p1() const
Returns the line&#39;s start point.
Definition: qline.h:314
bool isNull() const
Returns true if it is a null image, otherwise returns false.
Definition: qimage.cpp:1542
T & first()
Returns a reference to the first item in the vector.
Definition: qvector.h:260
qreal m21() const
Returns the horizontal shearing factor.
Definition: qtransform.h:249
int height() const
Definition: qpaintdevice.h:92
void fill(uint pixel)
Fills the entire image with the given pixelValue.
Definition: qimage.cpp:2032
virtual VGImage createPermanentImage(VGImageFormat format, VGint width, VGint height, VGbitfield allowedQuality)
RenderFlags flags
The QConicalGradient class is used in combination with QBrush to specify a conical gradient brush...
Definition: qbrush.h:329
QTransform transform() const
Returns the matrix in the current paint engine state.
Definition: qpainter.cpp:9377
static VGImage toVGImageWithOpacitySubRect(const QImage &image, qreal opacity, const QRect &sr)
qreal y2() const
Returns the y-coordinate of the line&#39;s end point.
Definition: qline.h:309
void drawPolygon(const QPointF *points, int pointCount, PolygonDrawMode mode)
Reimplement this virtual function to draw the polygon defined by the pointCount first points in point...
virtual void drawPixmapFragments(const QPainter::PixmapFragment *fragments, int fragmentCount, const QPixmap &pixmap, QPainter::PixmapFragmentHints hints)
void ensurePen(const QPen &pen)
#define SLOT(a)
Definition: qobjectdefs.h:226
The QPointF class defines a point in the plane using floating point precision.
Definition: qpoint.h:214
QRect intersect(const QRect &r) const
Use intersected(rectangle) instead.
Definition: qrect.h:476
qreal left() const
Returns the x-coordinate of the rectangle&#39;s left edge.
Definition: qrect.h:525
qreal m22() const
Returns the vertical scaling factor.
Definition: qtransform.h:253
void drawRoundedRect(const QRectF &rect, qreal xrad, qreal yrad, Qt::SizeMode mode)
VGPaintType setBrush(VGPaint paint, const QBrush &brush, VGMatrixMode mode, VGPaintType prevPaintType)
QPointF topLeft() const
Returns the position of the rectangle&#39;s top-left corner.
Definition: qrect.h:539
bool isLineTo() const
Returns true if the element is a line, otherwise returns false.
Definition: qpainterpath.h:84
static int bytesPerPixel(QImage::Format format)
int byteCount() const
Returns the number of bytes occupied by the image data.
Definition: qimage.cpp:1800
QColor color() const
Returns the color of this pen&#39;s brush.
Definition: qpen.cpp:771
QRect translated(int dx, int dy) const
Returns a copy of the rectangle that is translated dx along the x axis and dy along the y axis...
Definition: qrect.h:328
void qt_draw_helper(QPainterPrivate *p, const QPainterPath &path, QPainterPrivate::DrawOperation operation)
Definition: qpainter.cpp:9937
int width() const
Returns the width of the rectangle.
Definition: qrect.h:303
virtual uint flags() const
void qt_vg_drawVGImage(QPainter *painter, const QPointF &pos, VGImage vgImg)
QVGPaintEnginePrivate * d_ptr
bool hasAlphaChannel() const
Returns true if the image has a format that respects the alpha channel, otherwise returns false...
Definition: qimage.cpp:6495
static VGImage toVGImageWithOpacity(const QImage &image, qreal opacity)
virtual void draw(const QVectorPath &path)
int bytesPerLine() const
Returns the number of bytes per image scanline.
Definition: qimage.cpp:1812
QRect intersected(const QRect &other) const
Returns the intersection of this rectangle and the given rectangle.
Definition: qrect.h:481
QRect boundingRect() const
Returns the bounding rectangle of this region.
Definition: qregion.cpp:4363
QPointF bottomLeft() const
Returns the position of the rectangle&#39;s bottom-left corner.
Definition: qrect.h:542
QTransform & translate(qreal dx, qreal dy)
Moves the coordinate system dx along the x axis and dy along the y axis, and returns a reference to t...
Definition: qtransform.cpp:417
int height() const
Returns the height of the rectangle.
Definition: qrect.h:306
void setTransform(VGMatrixMode mode, const QTransform &transform)
The QRadialGradient class is used in combination with QBrush to specify a radial gradient brush...
Definition: qbrush.h:297
static QImage colorizeBitmap(const QImage &image, const QColor &color)
qreal y
the y coordinate of the element&#39;s position.
Definition: qpainterpath.h:80
int bottom() const
Returns the y-coordinate of the rectangle&#39;s bottom edge.
Definition: qrect.h:249
void drawLines(const QLine *lines, int lineCount)
The default implementation converts the first lineCount lines in lines to a QLineF and calls the floa...
qreal opacity
the opacity of the target rectangle, where 0.0 is fully transparent and 1.0 is fully opaque...
Definition: qpainter.h:114
The QHash class is a template class that provides a hash-table-based dictionary.
Definition: qdatastream.h:66
void clip(const QVectorPath &path, Qt::ClipOperation op)
Type type() const
Reimplement this function to return the paint engine Type.
Q_DECL_CONSTEXPR T qAbs(const T &t)
Definition: qglobal.h:1201
#define Q_ASSERT(cond)
Definition: qglobal.h:1823
The QObject class is the base class of all Qt objects.
Definition: qobject.h:111
TransformationType type() const
Returns the transformation type of this matrix.
Q_GUI_EXPORT QString extensions()
Definition: qegl.cpp:785
#define Q_D(Class)
Definition: qglobal.h:2482
QTransform transform() const
Returns the current transformation matrix for the brush.
Definition: qbrush.h:185
void setState(QPainterState *s)
The QPen class defines how a QPainter should draw lines and outlines of shapes.
Definition: qpen.h:64
QPolygon toPolygon() const
Creates and returns a QPolygon by converting each QPointF to a QPoint.
Definition: qpolygon.cpp:772
void drawTiledPixmap(const QRectF &r, const QPixmap &pixmap, const QPointF &s)
Reimplement this function to draw the pixmap in the given rect, starting at the given p...
void append(const T &t)
const QPainterPath::ElementType * elements() const
void endDataAccess(bool readOnly=false) const
int y1() const
Returns the y-coordinate of the line&#39;s start point.
Definition: qline.h:117
void setBlendMode(VGBlendMode mode)
void setRenderingQuality(VGRenderingQuality mode)
QVector< qreal > dashPattern() const
Returns the dash pattern of this pen.
Definition: qpen.cpp:466
void drawCursorPixmap(const QPixmap &pixmap, const QPoint &offset)
const QPainterPath::Element & elementAt(int i) const
Returns the element at the given index in the painter path.
Definition: qpainterpath.h:402
int rectCount() const
Returns the number of rectangles that will be returned in rects().
Definition: qregion.cpp:4461
Format format() const
Returns the format of the image.
Definition: qimage.cpp:2305
void stroke(const QVectorPath &path, const QPen &pen)
qreal x() const
Returns the x-coordinate of this point.
Definition: qpoint.h:282
QObject * sender() const
Returns a pointer to the object that sent the signal, if called in a slot activated by a signal; othe...
Definition: qobject.cpp:2327
virtual void fillRect(const QRectF &rect, const QBrush &brush)
bool begin(QPaintDevice *)
Begins painting the paint device and returns true if successful; otherwise returns false...
Definition: qpainter.cpp:1723
void setImageQuality(VGImageQuality mode)
void drawRects(const QRect *rects, int rectCount)
The default implementation converts the first rectCount rectangles in the buffer rects to a QRectF an...
Qt::ClipOperation clipOperation
Definition: qpainter_p.h:157
The QLineF class provides a two-dimensional vector using floating point precision.
Definition: qline.h:212
QFuture< T > mapped(const Sequence &sequence, MapFunction function)
Q_GUI_EXPORT QImage qt_imageForBrush(int style, bool invert)
Definition: qbrush.cpp:167
bool isIdentity() const
Returns true if the matrix is the identity matrix, otherwise returns false.
Definition: qtransform.h:204
void drawPath(const QPainterPath &path)
The default implementation ignores the path and does nothing.
QRectF controlPointRect() const
QGradientStops stops() const
Returns the stop points for this gradient.
Definition: qbrush.cpp:1520
virtual void stroke(const QVectorPath &path, const QPen &pen)
PixelType pixelType() const
QGlyphLayout glyphs
#define SIGNAL(a)
Definition: qobjectdefs.h:227
qreal m12() const
Returns the vertical shearing factor.
Definition: qtransform.h:241
bool clearRect(const QRectF &rect, const QColor &color)
QVGPaintEnginePrivate * vgPrivate()
unsigned char uchar
Definition: qglobal.h:994
void setScissor(const QRegion &region)
TransformationType
Definition: qtransform.h:68
QPainter * painter() const
Returns the paint engine&#39;s painter.
#define KAPPA
Definition: qbezier.cpp:370
#define QT_BEGIN_NAMESPACE
This macro expands to.
Definition: qglobal.h:89
int width() const
Definition: qpaintdevice.h:91
The QRectF class defines a rectangle in the plane using floating point precision. ...
Definition: qrect.h:511
QVGPaintEnginePrivate(QVGPaintEngine *q_ptr)
virtual QPixmapFilter * pixmapFilter(int, const QPixmapFilter *)
QFixed y
Definition: qfixed_p.h:191
virtual VGImage toVGImage()
void destroyed(QObject *=0)
This signal is emitted immediately before the object obj is destroyed, and can not be blocked...
QPolygonF toFillPolygon(const QMatrix &matrix=QMatrix()) const
This is an overloaded member function, provided for convenience. It differs from the above function o...
static float pixelSize(const QFontDef &request, int dpi)
Definition: qfont_win.cpp:80
QBrush qpen_brush(const QPen &p)
Definition: qpainter_p.h:87
bool isCosmetic() const
Returns true if the pen is cosmetic; otherwise returns false.
Definition: qpen.cpp:840
static bool connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
Creates a connection of the given type from the signal in the sender object to the method in the rece...
Definition: qobject.cpp:2580
bool needsBrushEmulation() const
QScopedPointer< QPixmapFilter > convolutionFilter
bool isEmpty() const
Returns true if the region is empty; otherwise returns false.
Definition: qregion.cpp:4098
Q_STATIC_INLINE_FUNCTION uint PREMUL(uint x)
static const QCssKnownValue positions[NumKnownPositionModes - 1]
Definition: qcssparser.cpp:329
void drawStaticTextItem(QStaticTextItem *staticTextItem)
Qt::PenJoinStyle joinStyle() const
Returns the pen&#39;s join style.
Definition: qpen.cpp:736
QFixed round() const
Definition: qfixed_p.h:80
static bool init
void drawPoints(const QPointF *points, int pointCount)
Draws the first pointCount points in the buffer points.
qreal height() const
Returns the height of the rectangle.
Definition: qrect.h:710
QTransform & rotate(qreal a, Qt::Axis axis=Qt::ZAxis)
Rotates the coordinate system counterclockwise by the given angle about the specified axis and return...
Definition: qtransform.cpp:615
QSize size() const
Returns the size of the rectangle.
Definition: qrect.h:309
QRegion intersect(const QRegion &r) const
Use intersected(r) instead.
Definition: qregion.cpp:4249
qreal y1() const
Returns the y-coordinate of the line&#39;s start point.
Definition: qline.h:299
void getGlyphPositions(const QGlyphLayout &glyphs, const QTransform &matrix, QTextItem::RenderFlags flags, QVarLengthArray< glyph_t > &glyphs_out, QVarLengthArray< QFixedPoint > &positions)
bool isNull() const
Returns true if both the x and y coordinates are set to 0, otherwise returns false.
Definition: qpoint.h:125
static bool qt_vg_pathToRect(const QPainterPath &path, QRectF *rect)
Q_CORE_EXPORT void qWarning(const char *,...)
QPoint map(const QPoint &p) const
Creates and returns a QPoint object that is a copy of the given point, mapped into the coordinate sys...
Internal QTextItem.
The QImage class provides a hardware-independent image representation that allows direct access to th...
Definition: qimage.h:87
int x2() const
Returns the x-coordinate of the line&#39;s end point.
Definition: qline.h:122
static const char * data(const QByteArray &arr)
bool needsEmulation(const QBrush &brush) const
void drawTextItem(const QPointF &p, const QTextItem &textItem)
This function draws the text item textItem at position p.
qreal width() const
Returns the width of the rectangle.
Definition: qrect.h:707
QPaintEngine * paintEngine() const
Returns the paint engine that the painter is currently operating on if the painter is active; otherwi...
Definition: qpainter.cpp:1991
void setupColorRamp(const QGradient *grad, VGPaint paint)
The QRegion class specifies a clip region for a painter.
Definition: qregion.h:68
bool begin(QPaintDevice *pdev)
Reimplement this function to initialise your paint engine when painting is to start on the paint devi...
void setImageMode(VGImageMode mode)
virtual void setState(QPainterState *s)
ClassId classId() const
int pixelSize() const
Returns the pixel size of the matched window system font.
Definition: qfont.cpp:2722
QBrush brush() const
Returns the brush used to fill strokes generated with this pen.
Definition: qpen.cpp:797
int depth() const
Returns the depth of the image.
Definition: qimage.cpp:1620
virtual glyph_metrics_t boundingBox(const QGlyphLayout &glyphs)=0
Qt::FillRule fillRule() const
Returns the painter path&#39;s currently set fill rule.
Qt::BrushStyle style() const
Returns the brush style.
Definition: qbrush.h:182
QPixmap texture() const
Returns the custom brush pattern, or a null pixmap if no custom brush pattern has been set...
Definition: qbrush.cpp:785
Q_OPENVG_EXPORT QVGPaintEngine * qt_vg_create_paint_engine(void)
quint16 values[128]
bool isOpaque() const
Returns true if the brush is fully opaque otherwise false.
Definition: qbrush.cpp:910
int count() const
const uchar * constBits() const
Returns a pointer to the first pixel data.
Definition: qimage.cpp:1985
QScopedPointer< QPixmapFilter > dropShadowFilter
void drawImage(const QRectF &r, const QImage &pm, const QRectF &sr, Qt::ImageConversionFlags flags=Qt::AutoColor)
Reimplement this function to draw the part of the image specified by the sr rectangle in the given re...
VGRenderingQuality renderingQuality
QPointF start() const
Returns the start point of this linear gradient in logical coordinates.
Definition: qbrush.cpp:1796
The QFontInfo class provides general information about fonts.
Definition: qfontinfo.h:54
virtual void getUnscaledGlyph(glyph_t glyph, QPainterPath *path, glyph_metrics_t *metrics)
void fillBackground(const QRegion &region, const QBrush &brush)
QRect toRect() const
Returns a QRect based on the values of this rectangle.
Definition: qrect.h:845
bool hasWindingFill() const
#define Q_OBJECT
Definition: qobjectdefs.h:157
void reset(T *other=0)
Deletes the existing object it is pointing to if any, and sets its pointer to other.
void ensureBrush(const QBrush &brush)
void fill(const QVectorPath &path, const QBrush &brush)
const QPainterPath convertToPainterPath() const
const T & at(int i) const
Returns the item at index position i in the vector.
Definition: qvector.h:350
QSize size() const
Returns the size of the image, i.
Definition: qimage.cpp:1587
qreal m31() const
Returns the horizontal translation factor.
Definition: qtransform.h:261
Spread
Specifies how the area outside the gradient area should be filled.
Definition: qbrush.h:213
bool isDefaultClipRegion(const QRegion &region)
void draw(VGPath path, const QPen &pen, const QBrush &brush, VGint rule=VG_EVEN_ODD)
const uchar * constScanLine(int) const
Returns a pointer to the pixel data at the scanline with index i.
Definition: qimage.cpp:1926
QVolatileImage source
bool end()
Reimplement this function to finish painting on the current paint device.
virtual void drawPolygon(const QPointF *points, int pointCount, PolygonDrawMode mode)
Reimplement this virtual function to draw the polygon defined by the pointCount first points in point...
const QBrush & brush() const
Returns the painter&#39;s current brush.
Definition: qpainter.cpp:4232
QRegion unite(const QRegion &r) const
Use united(r) instead.
Definition: qregion.cpp:4125
QScopedPointer< QPixmapFilter > colorizeFilter
virtual void drawLines(const QLine *lines, int lineCount)
The default implementation converts the first lineCount lines in lines to a QLineF and calls the floa...
The QBrush class defines the fill pattern of shapes drawn by QPainter.
Definition: qbrush.h:76
static QByteArray prototype(const QList< QByteArray > &parameterTypes, const QList< QByteArray > &parameterNames, bool *ok)
Definition: qaxserver.cpp:685
QFixed x
Definition: qfixed_p.h:190
static QVGImagePool * instance()
bool isValid() const
static VGImage toVGImage(const QImage &image, Qt::ImageConversionFlags flags=Qt::AutoColor)
int width() const
Returns the width of the image.
Definition: qimage.cpp:1557
QScopedPointer< QPaintEnginePrivate > d_ptr
Definition: qpaintengine.h:246
#define Q_DECLARE_PUBLIC(Class)
Definition: qglobal.h:2477
QImage convertToFormat(Format f, Qt::ImageConversionFlags flags=Qt::AutoColor) const Q_REQUIRED_RESULT
Returns a copy of the image in the given format.
Definition: qimage.cpp:3966
void restoreState(QPaintEngine::DirtyFlags dirty)
virtual Properties properties() const
virtual void drawRoundedRect(const QRectF &rect, qreal xrad, qreal yrad, Qt::SizeMode mode)
void setAlphaF(qreal alpha)
Sets the alpha of this color to alpha.
Definition: qcolor.cpp:1117
QPixmapFilter * pixmapFilter(int type, const QPixmapFilter *prototype)
Type type() const
Returns the type of gradient.
Definition: qbrush.h:232
void ensureMask(QVGPaintEngine *engine, int width, int height)
ushort alpha
Returns the alpha color component of this color.
Definition: qcolor.h:242
The QLinearGradient class is used in combination with QBrush to specify a linear gradient brush...
Definition: qbrush.h:280
The QFont class specifies a font used for drawing text.
Definition: qfont.h:64
int y() const
Returns the y-coordinate of the rectangle&#39;s top edge.
Definition: qrect.h:255
The QGradient class is used in combination with QBrush to specify gradient fills. ...
Definition: qbrush.h:201
qreal x() const
Returns the x-coordinate of the rectangle&#39;s left edge.
Definition: qrect.h:664
This class is used in conjunction with the QPainter::drawPixmapFragments() function to specify how a ...
Definition: qpainter.h:103
qreal scaleX
the horizontal scale of the target rectangle.
Definition: qpainter.h:111
The QPixmapFilter class provides the basic functionality for pixmap filter classes.
uint clipEnabled
Definition: qpainter_p.h:169
qreal miterLimit() const
Returns the miter limit of the pen.
Definition: qpen.cpp:589
void qt_vg_drawVGImageStencil(QPainter *painter, const QPointF &pos, VGImage vgImg, const QBrush &brush)
QRegion defaultClipRegion()
qreal redF() const
Returns the red color component of this color.
Definition: qcolor.cpp:1213
int x() const
Returns the x-coordinate of the rectangle&#39;s left edge.
Definition: qrect.h:252
void drawPixmapFragments(const QPainter::PixmapFragment *drawingData, int dataCount, const QPixmap &pixmap, QFlags< QPainter::PixmapFragmentHint > hints)
The QPoint class defines a point in the plane using integer precision.
Definition: qpoint.h:53
QVector< QRect > rects() const
Returns an array of non-overlapping rectangles that make up the region.
Definition: qregion.cpp:4412
Q_GUI_EXPORT bool qt_isExtendedRadialGradient(const QBrush &brush)
Definition: qbrush.cpp:881
void setBrush(const QBrush &brush)
Sets the painter&#39;s brush to the given brush.
Definition: qpainter.cpp:4171
static bool clipTransformIsSimple(const QTransform &transform)
const qreal * points() const
qreal m23() const
Returns the vertical projection factor.
Definition: qtransform.h:257
QPointF p2() const
Returns the line&#39;s end point.
Definition: qline.h:319
bool isMoveTo() const
Returns true if the element is moving the current position, otherwise returns false.
Definition: qpainterpath.h:83
QPointF brushOrigin
Definition: qpainter_p.h:149
int height() const
Returns the height.
Definition: qsize.h:129
qreal widthF() const
Returns the pen width with floating point precision.
Definition: qpen.cpp:645
qreal blueF() const
Returns the blue color component of this color.
Definition: qcolor.cpp:1269
The QRect class defines a rectangle in the plane using integer precision.
Definition: qrect.h:58
void modifyMask(QVGPaintEngine *engine, VGMaskOperation op, const QRegion &region)
Spread spread() const
Returns the spread method use by this gradient.
Definition: qbrush.h:235
static VGImage toVGImageSubRect(const QImage &image, const QRect &sr, Qt::ImageConversionFlags flags=Qt::AutoColor)
qreal toReal() const
Definition: qfixed_p.h:77
bool isNull() const
Returns true if both the x and y coordinates are set to +0.
Definition: qpoint.h:277
bool hasImplicitClose() const
int height() const
Returns the height of the image.
Definition: qimage.cpp:1572
QSizeF size() const
Returns the size of the rectangle.
Definition: qrect.h:713
qreal dx() const
Returns the horizontal translation factor.
Definition: qtransform.h:273
int y() const
Returns the y coordinate of this point.
Definition: qpoint.h:131
qreal x
the x coordinate of the element&#39;s position.
Definition: qpainterpath.h:79
void drawImage(const QRectF &targetRect, const QImage &image, const QRectF &sourceRect, Qt::ImageConversionFlags flags=Qt::AutoColor)
Definition: qpainter.cpp:5936
qreal y() const
Returns the y-coordinate of this point.
Definition: qpoint.h:287
QPointF center() const
Returns the center of this radial gradient in logical coordinates.
Definition: qbrush.cpp:2102
The QPixmap class is an off-screen image representation that can be used as a paint device...
Definition: qpixmap.h:71
static const QTextHtmlElement elements[Html_NumElements]
Q_GUI_EXPORT bool qt_scaleForTransform(const QTransform &transform, qreal *scale)
virtual QImage * buffer()
void fillRect(const QRectF &rect, const QBrush &brush)
qreal top() const
Returns the y-coordinate of the rectangle&#39;s top edge.
Definition: qrect.h:526
qreal dashOffset() const
Returns the dash offset for the pen.
Definition: qpen.cpp:547
QPaintDevice * pdev
VGPath roundedRectPath(const QRectF &rect, qreal xRadius, qreal yRadius, Qt::SizeMode mode)
The QSize class defines the size of a two-dimensional object using integer point precision.
Definition: qsize.h:53
T * data()
Returns a pointer to the data stored in the vector.
Definition: qvector.h:152
void draw(const QVectorPath &path)
static QTransform fromTranslate(qreal dx, qreal dy)
Creates a matrix which corresponds to a translation of dx along the x axis and dy along the y axis...
Definition: qtransform.cpp:462
QBrush brush
Definition: qpainter_p.h:153
QTransform & scale(qreal sx, qreal sy)
Scales the coordinate system by sx horizontally and sy vertically, and returns a reference to the mat...
Definition: qtransform.cpp:485
void invertPixels(InvertMode=InvertRgb)
Inverts all pixel values in the image.
Definition: qimage.cpp:2179
Q_GUI_EXPORT QPainterPath qt_painterPathFromVectorPath(const QVectorPath &path)
int elementCount() const
Returns the number of path elements in the painter path.
Definition: qpainterpath.h:397
void drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr)
Reimplement this function to draw the part of the pm specified by the sr rectangle in the given r...
The QFlags class provides a type-safe way of storing OR-combinations of enum values.
Definition: qglobal.h:2313
int y2() const
Returns the y-coordinate of the line&#39;s end point.
Definition: qline.h:127
int x() const
Returns the x coordinate of this point.
Definition: qpoint.h:128
virtual void drawRects(const QRect *rects, int rectCount)
The default implementation converts the first rectCount rectangles in the buffer rects to a QRectF an...
SizeMode
Definition: qnamespace.h:1187
void fill(VGPath path, const QBrush &brush, VGint rule=VG_EVEN_ODD)
QPaintEngine::DirtyFlags dirty
void setOpacity(qreal opacity)
Sets the opacity of the painter to opacity.
Definition: qpainter.cpp:2139
qreal m13() const
Returns the horizontal projection factor.
Definition: qtransform.h:245
QRgb rgba() const
Returns the RGB value of the color, including its alpha.
Definition: qcolor.cpp:1019
qreal bottom() const
Returns the y-coordinate of the rectangle&#39;s bottom edge.
Definition: qrect.h:528
The QTextItem class provides all the information required to draw text in a custom paint engine...
Definition: qpaintengine.h:68
#define slots
Definition: qobjectdefs.h:68
bool isValid() const
Returns true if the rectangle is valid, otherwise returns false.
Definition: qrect.h:237
QPointF topRight() const
Returns the position of the rectangle&#39;s top-right corner.
Definition: qrect.h:541
Qt::PenCapStyle capStyle() const
Returns the pen&#39;s cap style.
Definition: qpen.cpp:706
qreal x1() const
Returns the x-coordinate of the line&#39;s start point.
Definition: qline.h:294
int x1() const
Returns the x-coordinate of the line&#39;s start point.
Definition: qline.h:112
static void drawVGImage(QVGPaintEnginePrivate *d, const QRectF &r, VGImage vgImg, const QSize &imageSize, const QRectF &sr)
Qt::PenStyle qpen_style(const QPen &p)
Definition: qpainter_p.h:89
static void fillBackgroundRect(const QRect &rect, QVGPaintEnginePrivate *d)
static const qreal aliasedCoordinateDelta
#define Q_UNUSED(x)
Indicates to the compiler that the parameter with the specified name is not used in the body of a fun...
Definition: qglobal.h:1729
VGPath vectorPathToVGPath(const QVectorPath &path)
void updateTransform(QPaintDevice *pdev)
int size() const
Returns the number of items in the vector.
Definition: qvector.h:137
QFont font() const
Returns the font that should be used to draw the text.
QImage & imageRef()
Returns a reference to the image that is potentially using some native buffer internally.
QPainterState * createState(QPainterState *orig) const
virtual void detachImageFromPool()
static void drawImageTiled(QVGPaintEnginePrivate *d, const QRectF &r, const QImage &image, const QRectF &sr=QRectF())
unsigned int glyph_t
void fillRegion(const QRegion &region, const QColor &color, const QSize &surfaceSize)
virtual void drawEllipse(const QRectF &r)
Reimplement this function to draw the largest ellipse that can be contained within rectangle rect...
bool end()
Ends painting.
Definition: qpainter.cpp:1929
uchar * scanLine(int)
Returns a pointer to the pixel data at the scanline with index i.
Definition: qimage.cpp:1886
qreal m11() const
Returns the horizontal scaling factor.
Definition: qtransform.h:237
void blitWindow(VGImage image, const QSize &imageSize, const QRect &rect, const QPoint &topLeft, int opacity)
qreal m33() const
Returns the division factor.
Definition: qtransform.h:269
void setFillRule(VGint mode)
int size() const
The QTransform class specifies 2D transformations of a coordinate system.
Definition: qtransform.h:65
QVGPainterState * state()
bool needsPenEmulation() const
QVGFontEngineCleaner(QVGPaintEnginePrivate *d)
QScopedPointer< QPainterPrivate > d_ptr
Definition: qpainter.h:546
QPoint topLeft() const
Returns the position of the rectangle&#39;s top-left corner.
Definition: qrect.h:288
ClipOperation
Definition: qnamespace.h:1495
virtual void clip(const QVectorPath &path, Qt::ClipOperation op)=0
glyph_t * glyphs
Hint shape() const
bool drawCachedGlyphs(int numGlyphs, const glyph_t *glyphs, const QFont &font, QFontEngine *fontEngine, const QPointF &p, const QFixedPoint *positions)
QPixmapData * pixmapData() const
Definition: qpixmap.cpp:2277
virtual void drawTextItem(const QPointF &p, const QTextItem &textItem)
This function draws the text item textItem at position p.