src/openvg/qpaintengine_vg.cpp
changeset 18 2f34d5167611
parent 3 41300fa6a67c
child 19 fcece45ef507
equal deleted inserted replaced
3:41300fa6a67c 18:2f34d5167611
     1 /****************************************************************************
     1 /****************************************************************************
     2 **
     2 **
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
     3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     4 ** All rights reserved.
     4 ** All rights reserved.
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
     6 **
     6 **
     7 ** This file is part of the QtOpenVG module of the Qt Toolkit.
     7 ** This file is part of the QtOpenVG module of the Qt Toolkit.
     8 **
     8 **
   129     void setTransform(VGMatrixMode mode, const QTransform& transform);
   129     void setTransform(VGMatrixMode mode, const QTransform& transform);
   130     void updateTransform(QPaintDevice *pdev);
   130     void updateTransform(QPaintDevice *pdev);
   131     void draw(VGPath path, const QPen& pen, const QBrush& brush, VGint rule = VG_EVEN_ODD);
   131     void draw(VGPath path, const QPen& pen, const QBrush& brush, VGint rule = VG_EVEN_ODD);
   132     void stroke(VGPath path, const QPen& pen);
   132     void stroke(VGPath path, const QPen& pen);
   133     void fill(VGPath path, const QBrush& brush, VGint rule = VG_EVEN_ODD);
   133     void fill(VGPath path, const QBrush& brush, VGint rule = VG_EVEN_ODD);
   134     VGPath vectorPathToVGPath(const QVectorPath& path);
   134     inline void releasePath(VGPath path);
   135     VGPath painterPathToVGPath(const QPainterPath& path);
   135     VGPath vectorPathToVGPath(const QVectorPath& path, bool forceNewPath = false);
       
   136     VGPath painterPathToVGPath(const QPainterPath& path, bool forceNewPath = false);
   136     VGPath roundedRectPath(const QRectF &rect, qreal xRadius, qreal yRadius, Qt::SizeMode mode);
   137     VGPath roundedRectPath(const QRectF &rect, qreal xRadius, qreal yRadius, Qt::SizeMode mode);
   137     VGPaintType setBrush
   138     VGPaintType setBrush
   138         (VGPaint paint, const QBrush& brush, VGMatrixMode mode,
   139         (VGPaint paint, const QBrush& brush, VGMatrixMode mode,
   139          VGPaintType prevPaintType);
   140          VGPaintType prevPaintType);
   140     void setPenParams(const QPen& pen);
   141     void setPenParams(const QPen& pen);
   176     VGPath rectPath;        // Cached path for quick drawing of rectangles.
   177     VGPath rectPath;        // Cached path for quick drawing of rectangles.
   177     VGPath linePath;        // Cached path for quick drawing of lines.
   178     VGPath linePath;        // Cached path for quick drawing of lines.
   178     VGPath roundRectPath;   // Cached path for quick drawing of rounded rects.
   179     VGPath roundRectPath;   // Cached path for quick drawing of rounded rects.
   179 #endif
   180 #endif
   180 
   181 
       
   182     VGPath reusablePath;    // Reusable path for vectorPathToVGPath(), etc.
       
   183 
   181     QTransform transform;   // Currently active transform.
   184     QTransform transform;   // Currently active transform.
   182     bool simpleTransform;   // True if the transform is simple (non-projective).
   185     bool simpleTransform;   // True if the transform is simple (non-projective).
   183     qreal penScale;         // Pen scaling factor from "transform".
   186     qreal penScale;         // Pen scaling factor from "transform".
   184 
   187 
   185     QTransform pathTransform;  // Calculated VG path transformation.
   188     QTransform pathTransform;  // Calculated VG path transformation.
   186     QTransform imageTransform; // Calculated VG image transformation.
   189     QTransform imageTransform; // Calculated VG image transformation.
   187     bool pathTransformSet;  // True if path transform set in the VG context.
   190     bool pathTransformSet;  // True if path transform set in the VG context.
   188 
   191 
   189     bool maskValid;         // True if vgMask() contains valid data.
   192     bool maskValid;         // True if vgMask() contains valid data.
   190     bool maskIsSet;         // True if mask would be fully set if it was valid.
   193     bool maskIsSet;         // True if mask would be fully set if it was valid.
       
   194     bool scissorMask;       // True if scissor is used in place of the mask.
   191     bool rawVG;             // True if processing a raw VG escape.
   195     bool rawVG;             // True if processing a raw VG escape.
   192 
   196 
   193     QRect maskRect;         // Rectangle version of mask if it is simple.
   197     QRect maskRect;         // Rectangle version of mask if it is simple.
   194 
   198 
   195     QTransform penTransform;   // Transform for the pen.
   199     QTransform penTransform;   // Transform for the pen.
   198     VGMatrixMode matrixMode;    // Last matrix mode that was set.
   202     VGMatrixMode matrixMode;    // Last matrix mode that was set.
   199     VGImageMode imageMode;      // Last image mode that was set.
   203     VGImageMode imageMode;      // Last image mode that was set.
   200 
   204 
   201     QRegion scissorRegion;  // Currently active scissor region.
   205     QRegion scissorRegion;  // Currently active scissor region.
   202     bool scissorActive;     // True if scissor region is active.
   206     bool scissorActive;     // True if scissor region is active.
       
   207     bool scissorDirty;      // True if scissor is dirty after native painting.
   203 
   208 
   204     QPaintEngine::DirtyFlags dirty;
   209     QPaintEngine::DirtyFlags dirty;
   205 
   210 
   206     QColor clearColor;      // Last clear color that was set.
   211     QColor clearColor;      // Last clear color that was set.
   207     VGfloat clearOpacity;   // Opacity during the last clear.
   212     VGfloat clearOpacity;   // Opacity during the last clear.
   346     rectPath = 0;
   351     rectPath = 0;
   347     linePath = 0;
   352     linePath = 0;
   348     roundRectPath = 0;
   353     roundRectPath = 0;
   349 #endif
   354 #endif
   350 
   355 
       
   356     reusablePath = 0;
       
   357 
   351     simpleTransform = true;
   358     simpleTransform = true;
   352     pathTransformSet = false;
   359     pathTransformSet = false;
   353     penScale = 1.0;
   360     penScale = 1.0;
   354 
   361 
   355     maskValid = false;
   362     maskValid = false;
   356     maskIsSet = false;
   363     maskIsSet = false;
       
   364     scissorMask = false;
   357     rawVG = false;
   365     rawVG = false;
   358 
   366 
   359     scissorActive = false;
   367     scissorActive = false;
       
   368     scissorDirty = false;
   360 
   369 
   361     dirty = 0;
   370     dirty = 0;
   362 
   371 
   363     clearOpacity = 1.0f;
   372     clearOpacity = 1.0f;
   364 
   373 
   440                             2,    // segmentCapacityHint
   449                             2,    // segmentCapacityHint
   441                             4,    // coordCapacityHint
   450                             4,    // coordCapacityHint
   442                             VG_PATH_CAPABILITY_ALL);
   451                             VG_PATH_CAPABILITY_ALL);
   443     vgAppendPathData(linePath, 2, segments, coords);
   452     vgAppendPathData(linePath, 2, segments, coords);
   444 #endif
   453 #endif
       
   454 
       
   455     // This path can be reused over and over by calling vgClearPath().
       
   456     reusablePath = vgCreatePath(VG_PATH_FORMAT_STANDARD,
       
   457                                 VG_PATH_DATATYPE_F,
       
   458                                 1.0f,        // scale
       
   459                                 0.0f,        // bias
       
   460                                 32 + 1,      // segmentCapacityHint
       
   461                                 32 * 2,      // coordCapacityHint
       
   462                                 VG_PATH_CAPABILITY_ALL);
   445 }
   463 }
   446 
   464 
   447 void QVGPaintEnginePrivate::destroy()
   465 void QVGPaintEnginePrivate::destroy()
   448 {
   466 {
   449     if (penPaint)
   467     if (penPaint)
   459     if (linePath)
   477     if (linePath)
   460         vgDestroyPath(linePath);
   478         vgDestroyPath(linePath);
   461     if (roundRectPath)
   479     if (roundRectPath)
   462         vgDestroyPath(roundRectPath);
   480         vgDestroyPath(roundRectPath);
   463 #endif
   481 #endif
       
   482     if (reusablePath)
       
   483         vgDestroyPath(reusablePath);
   464 
   484 
   465 #if !defined(QVG_NO_DRAW_GLYPHS)
   485 #if !defined(QVG_NO_DRAW_GLYPHS)
   466     QVGFontCache::Iterator it;
   486     QVGFontCache::Iterator it;
   467     for (it = fontCache.begin(); it != fontCache.end(); ++it)
   487     for (it = fontCache.begin(); it != fontCache.end(); ++it)
   468         delete it.value();
   488         delete it.value();
   510     //      3. Flip the co-ordinate system upside down.
   530     //      3. Flip the co-ordinate system upside down.
   511     QTransform viewport(1.0f, 0.0f, 0.0f,
   531     QTransform viewport(1.0f, 0.0f, 0.0f,
   512                         0.0f, -1.0f, 0.0f,
   532                         0.0f, -1.0f, 0.0f,
   513                         0.5f, devh + 0.5f, 1.0f);
   533                         0.5f, devh + 0.5f, 1.0f);
   514 
   534 
   515     // The image transform is always the full transformation,
   535     // Compute the path transform and determine if it is projective. 
   516     // because it can be projective.
   536      pathTransform = transform * viewport; 
   517     imageTransform = transform * viewport;
   537      bool projective = (pathTransform.m13() != 0.0f || 
   518 
   538      pathTransform.m23() != 0.0f || 
   519     // Determine if the transformation is projective.
   539      pathTransform.m33() != 1.0f); 
   520     bool projective = (imageTransform.m13() != 0.0f ||
   540     
   521                        imageTransform.m23() != 0.0f ||
       
   522                        imageTransform.m33() != 1.0f);
       
   523     if (projective) {
   541     if (projective) {
   524         // The engine cannot do projective path transforms for us,
   542         // The engine cannot do projective path transforms for us,
   525         // so we will have to convert the co-ordinates ourselves.
   543         // so we will have to convert the co-ordinates ourselves.
   526         // Change the matrix to just the viewport transformation.
   544         // Change the matrix to just the viewport transformation.
   527         pathTransform = viewport;
   545         pathTransform = viewport;
   528         simpleTransform = false;
   546         simpleTransform = false;
   529     } else {
   547     } else {
   530         pathTransform = imageTransform;
       
   531         simpleTransform = true;
   548         simpleTransform = true;
   532     }
   549     }
   533     pathTransformSet = false;
   550     pathTransformSet = false;
       
   551 
       
   552     // The image transform is always the full transformation, 
       
   553     // because it can be projective. It also does not need the 
       
   554     // (0.5, -0.5) translation because vgDrawImage() implicitly 
       
   555     // adds 0.5 to each co-ordinate. 
       
   556     QTransform viewport2(1.0f, 0.0f, 0.0f, 
       
   557     0.0f, -1.0f, 0.0f, 
       
   558     0.0f, devh, 1.0f); 
       
   559     imageTransform = transform * viewport2; 
   534 
   560 
   535     // Calculate the scaling factor to use for turning cosmetic pens
   561     // Calculate the scaling factor to use for turning cosmetic pens
   536     // into ordinary non-cosmetic pens.
   562     // into ordinary non-cosmetic pens.
   537     qt_scaleForTransform(transform, &penScale);
   563     qt_scaleForTransform(transform, &penScale);
   538 }
   564 }
   539 
   565 
   540 VGPath QVGPaintEnginePrivate::vectorPathToVGPath(const QVectorPath& path)
   566 inline void QVGPaintEnginePrivate::releasePath(VGPath path)
       
   567 {
       
   568     if (path == reusablePath)
       
   569         vgClearPath(path, VG_PATH_CAPABILITY_ALL);
       
   570     else
       
   571         vgDestroyPath(path);
       
   572 }
       
   573 
       
   574 VGPath QVGPaintEnginePrivate::vectorPathToVGPath(const QVectorPath& path, bool forceNewPath)
   541 {
   575 {
   542     int count = path.elementCount();
   576     int count = path.elementCount();
   543     const qreal *points = path.points();
   577     const qreal *points = path.points();
   544     const QPainterPath::ElementType *elements = path.elements();
   578     const QPainterPath::ElementType *elements = path.elements();
   545 
   579 
   546     VGPath vgpath = vgCreatePath(VG_PATH_FORMAT_STANDARD,
   580     VGPath vgpath;
   547                                  VG_PATH_DATATYPE_F,
   581     if (forceNewPath) {
   548                                  1.0f,        // scale
   582         vgpath = vgCreatePath(VG_PATH_FORMAT_STANDARD,
   549                                  0.0f,        // bias
   583                               VG_PATH_DATATYPE_F,
   550                                  count + 1,   // segmentCapacityHint
   584                               1.0f,        // scale
   551                                  count * 2,   // coordCapacityHint
   585                               0.0f,        // bias
   552                                  VG_PATH_CAPABILITY_ALL);
   586                               count + 1,   // segmentCapacityHint
       
   587                               count * 2,   // coordCapacityHint
       
   588                               VG_PATH_CAPABILITY_ALL);
       
   589     } else {
       
   590         vgpath = reusablePath;
       
   591     }
   553 
   592 
   554     // Size is sufficient segments for drawRoundedRect() paths.
   593     // Size is sufficient segments for drawRoundedRect() paths.
   555     QVarLengthArray<VGubyte, 20> segments;
   594     QVarLengthArray<VGubyte, 20> segments;
   556 
   595 
   557     if (sizeof(qreal) == sizeof(VGfloat) && elements && simpleTransform) {
   596     if (sizeof(qreal) == sizeof(VGfloat) && elements && simpleTransform) {
   719                      segments.constData(), coords.constData());
   758                      segments.constData(), coords.constData());
   720 
   759 
   721     return vgpath;
   760     return vgpath;
   722 }
   761 }
   723 
   762 
   724 VGPath QVGPaintEnginePrivate::painterPathToVGPath(const QPainterPath& path)
   763 VGPath QVGPaintEnginePrivate::painterPathToVGPath(const QPainterPath& path, bool forceNewPath)
   725 {
   764 {
   726     int count = path.elementCount();
   765     int count = path.elementCount();
   727 
   766 
   728     VGPath vgpath = vgCreatePath(VG_PATH_FORMAT_STANDARD,
   767     VGPath vgpath;
   729                                  VG_PATH_DATATYPE_F,
   768     if (forceNewPath) {
   730                                  1.0f,        // scale
   769         vgpath = vgCreatePath(VG_PATH_FORMAT_STANDARD,
   731                                  0.0f,        // bias
   770                               VG_PATH_DATATYPE_F,
   732                                  count + 1,   // segmentCapacityHint
   771                               1.0f,        // scale
   733                                  count * 2,   // coordCapacityHint
   772                               0.0f,        // bias
   734                                  VG_PATH_CAPABILITY_ALL);
   773                               count + 1,   // segmentCapacityHint
       
   774                               count * 2,   // coordCapacityHint
       
   775                               VG_PATH_CAPABILITY_ALL);
       
   776     } else {
       
   777         vgpath = reusablePath;
       
   778     }
   735 
   779 
   736     if (count == 0)
   780     if (count == 0)
   737         return vgpath;
   781         return vgpath;
   738 
   782 
   739     const QPainterPath::Element *elements = &(path.elementAt(0));
   783     const QPainterPath::Element *elements = &(path.elementAt(0));
   948         roundRectPath = vgpath;
   992         roundRectPath = vgpath;
   949     } else {
   993     } else {
   950         vgModifyPathCoords(vgpath, 0, 9, pts);
   994         vgModifyPathCoords(vgpath, 0, 9, pts);
   951     }
   995     }
   952 #else
   996 #else
   953     VGPath vgpath = vgCreatePath(VG_PATH_FORMAT_STANDARD,
   997     VGPath vgpath = reusablePath;
   954                                  VG_PATH_DATATYPE_F,
       
   955                                  1.0f,        // scale
       
   956                                  0.0f,        // bias
       
   957                                  10,          // segmentCapacityHint
       
   958                                  17 * 2,      // coordCapacityHint
       
   959                                  VG_PATH_CAPABILITY_ALL);
       
   960     vgAppendPathData(vgpath, 10, roundedrect_types, pts);
   998     vgAppendPathData(vgpath, 10, roundedrect_types, pts);
   961 #endif
   999 #endif
   962 
  1000 
   963     return vgpath;
  1001     return vgpath;
   964 }
  1002 }
   981         for (int x=0; x < width; ++x)
  1019         for (int x=0; x < width; ++x)
   982             target[x] = (source[x>>3] >> (x&7)) & 1 ? fg : bg;
  1020             target[x] = (source[x>>3] >> (x&7)) & 1 ? fg : bg;
   983     }
  1021     }
   984     return dest;
  1022     return dest;
   985 }
  1023 }
       
  1024 
       
  1025 // defined in qpixmapdata_vg.cpp.
       
  1026 const uchar *qt_vg_imageBits(const QImage& image);
   986 
  1027 
   987 static VGImage toVGImage
  1028 static VGImage toVGImage
   988     (const QImage & image, Qt::ImageConversionFlags flags = Qt::AutoColor)
  1029     (const QImage & image, Qt::ImageConversionFlags flags = Qt::AutoColor)
   989 {
  1030 {
   990     QImage img(image);
  1031     QImage img(image);
  1015         img = image.convertToFormat(QImage::Format_ARGB32_Premultiplied, flags);
  1056         img = image.convertToFormat(QImage::Format_ARGB32_Premultiplied, flags);
  1016         format = VG_sARGB_8888_PRE;
  1057         format = VG_sARGB_8888_PRE;
  1017         break;
  1058         break;
  1018     }
  1059     }
  1019 
  1060 
  1020     const uchar *pixels = img.bits();
  1061     const uchar *pixels = qt_vg_imageBits(img);
  1021 
  1062 
  1022     VGImage vgImg = QVGImagePool::instance()->createPermanentImage
  1063     VGImage vgImg = QVGImagePool::instance()->createPermanentImage
  1023         (format, img.width(), img.height(), VG_IMAGE_QUALITY_FASTER);
  1064         (format, img.width(), img.height(), VG_IMAGE_QUALITY_FASTER);
  1024     vgImageSubData
  1065     vgImageSubData
  1025         (vgImg, pixels, img.bytesPerLine(), format, 0, 0,
  1066         (vgImg, pixels, img.bytesPerLine(), format, 0, 0,
  1059         img = image.convertToFormat(QImage::Format_ARGB32_Premultiplied, flags);
  1100         img = image.convertToFormat(QImage::Format_ARGB32_Premultiplied, flags);
  1060         format = VG_sARGB_8888_PRE;
  1101         format = VG_sARGB_8888_PRE;
  1061         break;
  1102         break;
  1062     }
  1103     }
  1063 
  1104 
  1064     const uchar *pixels = img.bits() + bpp * sr.x() +
  1105     const uchar *pixels = qt_vg_imageBits(img) + bpp * sr.x() +
  1065                           img.bytesPerLine() * sr.y();
  1106                           img.bytesPerLine() * sr.y();
  1066 
  1107 
  1067     VGImage vgImg = QVGImagePool::instance()->createPermanentImage
  1108     VGImage vgImg = QVGImagePool::instance()->createPermanentImage
  1068         (format, sr.width(), sr.height(), VG_IMAGE_QUALITY_FASTER);
  1109         (format, sr.width(), sr.height(), VG_IMAGE_QUALITY_FASTER);
  1069     vgImageSubData
  1110     vgImageSubData
  1081     painter.begin(&img);
  1122     painter.begin(&img);
  1082     painter.setOpacity(opacity);
  1123     painter.setOpacity(opacity);
  1083     painter.drawImage(0, 0, image);
  1124     painter.drawImage(0, 0, image);
  1084     painter.end();
  1125     painter.end();
  1085 
  1126 
  1086     const uchar *pixels = img.bits();
  1127     const uchar *pixels = qt_vg_imageBits(img);
  1087 
  1128 
  1088     VGImage vgImg = QVGImagePool::instance()->createPermanentImage
  1129     VGImage vgImg = QVGImagePool::instance()->createPermanentImage
  1089         (VG_sARGB_8888_PRE, img.width(), img.height(), VG_IMAGE_QUALITY_FASTER);
  1130         (VG_sARGB_8888_PRE, img.width(), img.height(), VG_IMAGE_QUALITY_FASTER);
  1090     vgImageSubData
  1131     vgImageSubData
  1091         (vgImg, pixels, img.bytesPerLine(), VG_sARGB_8888_PRE, 0, 0,
  1132         (vgImg, pixels, img.bytesPerLine(), VG_sARGB_8888_PRE, 0, 0,
  1103     painter.begin(&img);
  1144     painter.begin(&img);
  1104     painter.setOpacity(opacity);
  1145     painter.setOpacity(opacity);
  1105     painter.drawImage(QPoint(0, 0), image, sr);
  1146     painter.drawImage(QPoint(0, 0), image, sr);
  1106     painter.end();
  1147     painter.end();
  1107 
  1148 
  1108     const uchar *pixels = img.bits();
  1149     const uchar *pixels = qt_vg_imageBits(img);
  1109 
  1150 
  1110     VGImage vgImg = QVGImagePool::instance()->createPermanentImage
  1151     VGImage vgImg = QVGImagePool::instance()->createPermanentImage
  1111         (VG_sARGB_8888_PRE, img.width(), img.height(), VG_IMAGE_QUALITY_FASTER);
  1152         (VG_sARGB_8888_PRE, img.width(), img.height(), VG_IMAGE_QUALITY_FASTER);
  1112     vgImageSubData
  1153     vgImageSubData
  1113         (vgImg, pixels, img.bytesPerLine(), VG_sARGB_8888_PRE, 0, 0,
  1154         (vgImg, pixels, img.bytesPerLine(), VG_sARGB_8888_PRE, 0, 0,
  1507     VGPath vgpath = d->vectorPathToVGPath(path);
  1548     VGPath vgpath = d->vectorPathToVGPath(path);
  1508     if (!path.hasWindingFill())
  1549     if (!path.hasWindingFill())
  1509         d->draw(vgpath, s->pen, s->brush, VG_EVEN_ODD);
  1550         d->draw(vgpath, s->pen, s->brush, VG_EVEN_ODD);
  1510     else
  1551     else
  1511         d->draw(vgpath, s->pen, s->brush, VG_NON_ZERO);
  1552         d->draw(vgpath, s->pen, s->brush, VG_NON_ZERO);
  1512     vgDestroyPath(vgpath);
  1553     d->releasePath(vgpath);
  1513 }
  1554 }
  1514 
  1555 
  1515 void QVGPaintEngine::fill(const QVectorPath &path, const QBrush &brush)
  1556 void QVGPaintEngine::fill(const QVectorPath &path, const QBrush &brush)
  1516 {
  1557 {
  1517     Q_D(QVGPaintEngine);
  1558     Q_D(QVGPaintEngine);
  1518     VGPath vgpath = d->vectorPathToVGPath(path);
  1559     VGPath vgpath = d->vectorPathToVGPath(path);
  1519     if (!path.hasWindingFill())
  1560     if (!path.hasWindingFill())
  1520         d->fill(vgpath, brush, VG_EVEN_ODD);
  1561         d->fill(vgpath, brush, VG_EVEN_ODD);
  1521     else
  1562     else
  1522         d->fill(vgpath, brush, VG_NON_ZERO);
  1563         d->fill(vgpath, brush, VG_NON_ZERO);
  1523     vgDestroyPath(vgpath);
  1564     d->releasePath(vgpath);
  1524 }
  1565 }
  1525 
  1566 
  1526 void QVGPaintEngine::stroke(const QVectorPath &path, const QPen &pen)
  1567 void QVGPaintEngine::stroke(const QVectorPath &path, const QPen &pen)
  1527 {
  1568 {
  1528     Q_D(QVGPaintEngine);
  1569     Q_D(QVGPaintEngine);
  1529     VGPath vgpath = d->vectorPathToVGPath(path);
  1570     VGPath vgpath = d->vectorPathToVGPath(path);
  1530     d->stroke(vgpath, pen);
  1571     d->stroke(vgpath, pen);
  1531     vgDestroyPath(vgpath);
  1572     d->releasePath(vgpath);
  1532 }
  1573 }
  1533 
  1574 
  1534 // Determine if a co-ordinate transform is simple enough to allow
  1575 // Determine if a co-ordinate transform is simple enough to allow
  1535 // rectangle-based clipping with vgMask().  Simple transforms most
  1576 // rectangle-based clipping with vgMask().  Simple transforms most
  1536 // often result from origin translations.
  1577 // often result from origin translations.
  1537 static inline bool clipTransformIsSimple(const QTransform& transform)
  1578 static inline bool clipTransformIsSimple(const QTransform& transform)
  1538 {
  1579 {
  1539     QTransform::TransformationType type = transform.type();
  1580     QTransform::TransformationType type = transform.type();
  1540     return (type == QTransform::TxNone || type == QTransform::TxTranslate);
  1581     if (type == QTransform::TxNone || type == QTransform::TxTranslate)
       
  1582         return true;
       
  1583     if (type == QTransform::TxRotate) {
       
  1584         // Check for 0, 90, 180, and 270 degree rotations.
       
  1585         // (0 might happen after 4 rotations of 90 degrees).
       
  1586         qreal m11 = transform.m11();
       
  1587         qreal m12 = transform.m12();
       
  1588         qreal m21 = transform.m21();
       
  1589         qreal m22 = transform.m22();
       
  1590         if (m11 == 0.0f && m22 == 0.0f) {
       
  1591             if (m12 == 1.0f && m21 == -1.0f)
       
  1592                 return true;    // 90 degrees.
       
  1593             else if (m12 == -1.0f && m21 == 1.0f)
       
  1594                 return true;    // 270 degrees.
       
  1595         } else if (m12 == 0.0f && m21 == 0.0f) {
       
  1596             if (m11 == -1.0f && m22 == -1.0f)
       
  1597                 return true;    // 180 degrees.
       
  1598             else if (m11 == 1.0f && m22 == 1.0f)
       
  1599                 return true;    // 0 degrees.
       
  1600         }
       
  1601     }
       
  1602     return false;
  1541 }
  1603 }
  1542 
  1604 
  1543 #if defined(QVG_SCISSOR_CLIP)
  1605 #if defined(QVG_SCISSOR_CLIP)
  1544 
  1606 
  1545 void QVGPaintEngine::clip(const QVectorPath &path, Qt::ClipOperation op)
  1607 void QVGPaintEngine::clip(const QVectorPath &path, Qt::ClipOperation op)
  1657     d->dirty |= QPaintEngine::DirtyClipRegion;
  1719     d->dirty |= QPaintEngine::DirtyClipRegion;
  1658 
  1720 
  1659     if (op == Qt::NoClip) {
  1721     if (op == Qt::NoClip) {
  1660         d->maskValid = false;
  1722         d->maskValid = false;
  1661         d->maskIsSet = true;
  1723         d->maskIsSet = true;
       
  1724         d->scissorMask = false;
  1662         d->maskRect = QRect();
  1725         d->maskRect = QRect();
  1663         vgSeti(VG_MASKING, VG_FALSE);
  1726         vgSeti(VG_MASKING, VG_FALSE);
  1664         return;
  1727         return;
  1665     }
  1728     }
  1666 
  1729 
  1667 #if defined(QVG_NO_RENDER_TO_MASK)
       
  1668     // We don't have vgRenderToMask(), so handle simple QRectF's only.
  1730     // We don't have vgRenderToMask(), so handle simple QRectF's only.
  1669     if (path.shape() == QVectorPath::RectangleHint &&
  1731     if (path.shape() == QVectorPath::RectangleHint &&
  1670             path.elementCount() == 4 && clipTransformIsSimple(d->transform)) {
  1732             path.elementCount() == 4 && clipTransformIsSimple(d->transform)) {
  1671         // Clipping region that resulted from QPainter::setClipRect(QRectF).
  1733         // Clipping region that resulted from QPainter::setClipRect(QRectF).
  1672         // Convert it into a QRect and apply.
  1734         // Convert it into a QRect and apply.
  1673         const qreal *points = path.points();
  1735         const qreal *points = path.points();
  1674         QRectF rect(points[0], points[1], points[2] - points[0],
  1736         QRectF rect(points[0], points[1], points[2] - points[0],
  1675                     points[5] - points[1]);
  1737                     points[5] - points[1]);
  1676         clip(rect.toRect(), op);
  1738         clip(rect.toRect(), op);
  1677     }
  1739         return;
  1678 #else
  1740     }
       
  1741 
       
  1742 #if !defined(QVG_NO_RENDER_TO_MASK)
  1679     QPaintDevice *pdev = paintDevice();
  1743     QPaintDevice *pdev = paintDevice();
  1680     int width = pdev->width();
  1744     int width = pdev->width();
  1681     int height = pdev->height();
  1745     int height = pdev->height();
  1682 
  1746 
  1683     if (op == Qt::ReplaceClip) {
  1747     if (op == Qt::ReplaceClip) {
  1699             vgRenderToMask(vgpath, VG_FILL_PATH, VG_INTERSECT_MASK);
  1763             vgRenderToMask(vgpath, VG_FILL_PATH, VG_INTERSECT_MASK);
  1700             break;
  1764             break;
  1701 
  1765 
  1702         default: break;
  1766         default: break;
  1703     }
  1767     }
  1704     vgDestroyPath(vgpath);
  1768     d->releasePath(vgpath);
  1705 
  1769 
  1706     vgSeti(VG_MASKING, VG_TRUE);
  1770     vgSeti(VG_MASKING, VG_TRUE);
  1707     d->maskValid = true;
  1771     d->maskValid = true;
  1708     d->maskIsSet = false;
  1772     d->maskIsSet = false;
       
  1773     d->scissorMask = false;
  1709 #endif
  1774 #endif
  1710 }
  1775 }
  1711 
  1776 
  1712 void QVGPaintEngine::clip(const QRect &rect, Qt::ClipOperation op)
  1777 void QVGPaintEngine::clip(const QRect &rect, Qt::ClipOperation op)
  1713 {
  1778 {
  1724     switch (op) {
  1789     switch (op) {
  1725         case Qt::NoClip:
  1790         case Qt::NoClip:
  1726         {
  1791         {
  1727             d->maskValid = false;
  1792             d->maskValid = false;
  1728             d->maskIsSet = true;
  1793             d->maskIsSet = true;
       
  1794             d->scissorMask = false;
  1729             d->maskRect = QRect();
  1795             d->maskRect = QRect();
  1730             vgSeti(VG_MASKING, VG_FALSE);
  1796             vgSeti(VG_MASKING, VG_FALSE);
  1731         }
  1797         }
  1732         break;
  1798         break;
  1733 
  1799 
  1739                 // same as turning off clipping.
  1805                 // same as turning off clipping.
  1740                 if (d->maskValid)
  1806                 if (d->maskValid)
  1741                     vgSeti(VG_MASKING, VG_FALSE);
  1807                     vgSeti(VG_MASKING, VG_FALSE);
  1742                 d->maskValid = false;
  1808                 d->maskValid = false;
  1743                 d->maskIsSet = true;
  1809                 d->maskIsSet = true;
       
  1810                 d->scissorMask = false;
  1744                 d->maskRect = QRect();
  1811                 d->maskRect = QRect();
  1745             } else {
  1812             } else {
  1746                 // Special case: if the intersection of the system
  1813                 // Special case: if the intersection of the system
  1747                 // clip and "r" is a single rectangle, then use the
  1814                 // clip and "r" is a single rectangle, then use the
  1748                 // scissor for clipping.  We try to avoid allocating a
  1815                 // scissor for clipping.  We try to avoid allocating a
  1756                 } else {
  1823                 } else {
  1757                     clip = clip.intersect(r);
  1824                     clip = clip.intersect(r);
  1758                     if (clip.rectCount() != 1) {
  1825                     if (clip.rectCount() != 1) {
  1759                         d->maskValid = false;
  1826                         d->maskValid = false;
  1760                         d->maskIsSet = false;
  1827                         d->maskIsSet = false;
       
  1828                         d->scissorMask = false;
  1761                         d->maskRect = QRect();
  1829                         d->maskRect = QRect();
  1762                         d->modifyMask(this, VG_FILL_MASK, r);
  1830                         d->modifyMask(this, VG_FILL_MASK, r);
  1763                         break;
  1831                         break;
  1764                     }
  1832                     }
  1765                     clipRect = clip.boundingRect();
  1833                     clipRect = clip.boundingRect();
  1766                 }
  1834                 }
  1767                 d->maskValid = false;
  1835                 d->maskValid = false;
  1768                 d->maskIsSet = false;
  1836                 d->maskIsSet = false;
       
  1837                 d->scissorMask = true;
  1769                 d->maskRect = clipRect;
  1838                 d->maskRect = clipRect;
  1770                 vgSeti(VG_MASKING, VG_FALSE);
  1839                 vgSeti(VG_MASKING, VG_FALSE);
  1771                 updateScissor();
  1840                 updateScissor();
  1772             }
  1841             }
  1773         }
  1842         }
  1774         break;
  1843         break;
  1775 
  1844 
  1776         case Qt::IntersectClip:
  1845         case Qt::IntersectClip:
  1777         {
  1846         {
  1778             QRect r = d->transform.mapRect(rect);
  1847             QRect r = d->transform.mapRect(rect);
  1779             if (d->maskIsSet && isDefaultClipRect(r)) {
  1848             if (!d->maskValid) {
       
  1849                 // Mask has not been used yet, so intersect with
       
  1850                 // the previous scissor-based region in maskRect.
       
  1851                 if (d->scissorMask)
       
  1852                     r = r.intersect(d->maskRect);
       
  1853                 if (isDefaultClipRect(r)) {
       
  1854                     // The clip is the full window, so turn off clipping.
       
  1855                     d->maskIsSet = true;
       
  1856                     d->maskRect = QRect();
       
  1857                 } else {
       
  1858                     // Activate the scissor on a smaller maskRect.
       
  1859                     d->maskIsSet = false;
       
  1860                     d->maskRect = r;
       
  1861                 }
       
  1862                 d->scissorMask = true;
       
  1863                 updateScissor();
       
  1864             } else if (d->maskIsSet && isDefaultClipRect(r)) {
  1780                 // Intersecting a full-window clip with a full-window
  1865                 // Intersecting a full-window clip with a full-window
  1781                 // region is the same as turning off clipping.
  1866                 // region is the same as turning off clipping.
  1782                 if (d->maskValid)
  1867                 if (d->maskValid)
  1783                     vgSeti(VG_MASKING, VG_FALSE);
  1868                     vgSeti(VG_MASKING, VG_FALSE);
  1784                 d->maskValid = false;
  1869                 d->maskValid = false;
  1785                 d->maskIsSet = true;
  1870                 d->maskIsSet = true;
       
  1871                 d->scissorMask = false;
  1786                 d->maskRect = QRect();
  1872                 d->maskRect = QRect();
  1787             } else {
  1873             } else {
  1788                 d->modifyMask(this, VG_INTERSECT_MASK, r);
  1874                 d->modifyMask(this, VG_INTERSECT_MASK, r);
  1789             }
  1875             }
  1790         }
  1876         }
  1822     switch (op) {
  1908     switch (op) {
  1823         case Qt::NoClip:
  1909         case Qt::NoClip:
  1824         {
  1910         {
  1825             d->maskValid = false;
  1911             d->maskValid = false;
  1826             d->maskIsSet = true;
  1912             d->maskIsSet = true;
       
  1913             d->scissorMask = false;
  1827             d->maskRect = QRect();
  1914             d->maskRect = QRect();
  1828             vgSeti(VG_MASKING, VG_FALSE);
  1915             vgSeti(VG_MASKING, VG_FALSE);
  1829         }
  1916         }
  1830         break;
  1917         break;
  1831 
  1918 
  1837                 // same as turning off clipping.
  1924                 // same as turning off clipping.
  1838                 if (d->maskValid)
  1925                 if (d->maskValid)
  1839                     vgSeti(VG_MASKING, VG_FALSE);
  1926                     vgSeti(VG_MASKING, VG_FALSE);
  1840                 d->maskValid = false;
  1927                 d->maskValid = false;
  1841                 d->maskIsSet = true;
  1928                 d->maskIsSet = true;
       
  1929                 d->scissorMask = false;
  1842                 d->maskRect = QRect();
  1930                 d->maskRect = QRect();
  1843             } else {
  1931             } else {
  1844                 // Special case: if the intersection of the system
  1932                 // Special case: if the intersection of the system
  1845                 // clip and the region is a single rectangle, then
  1933                 // clip and the region is a single rectangle, then
  1846                 // use the scissor for clipping.
  1934                 // use the scissor for clipping.
  1850                 else
  1938                 else
  1851                     clip = clip.intersect(r);
  1939                     clip = clip.intersect(r);
  1852                 if (clip.rectCount() == 1) {
  1940                 if (clip.rectCount() == 1) {
  1853                     d->maskValid = false;
  1941                     d->maskValid = false;
  1854                     d->maskIsSet = false;
  1942                     d->maskIsSet = false;
       
  1943                     d->scissorMask = true;
  1855                     d->maskRect = clip.boundingRect();
  1944                     d->maskRect = clip.boundingRect();
  1856                     vgSeti(VG_MASKING, VG_FALSE);
  1945                     vgSeti(VG_MASKING, VG_FALSE);
  1857                     updateScissor();
  1946                     updateScissor();
  1858                 } else {
  1947                 } else {
  1859                     d->maskValid = false;
  1948                     d->maskValid = false;
  1860                     d->maskIsSet = false;
  1949                     d->maskIsSet = false;
       
  1950                     d->scissorMask = false;
  1861                     d->maskRect = QRect();
  1951                     d->maskRect = QRect();
  1862                     d->modifyMask(this, VG_FILL_MASK, r);
  1952                     d->modifyMask(this, VG_FILL_MASK, r);
  1863                 }
  1953                 }
  1864             }
  1954             }
  1865         }
  1955         }
  1880                 // region is the same as turning off clipping.
  1970                 // region is the same as turning off clipping.
  1881                 if (d->maskValid)
  1971                 if (d->maskValid)
  1882                     vgSeti(VG_MASKING, VG_FALSE);
  1972                     vgSeti(VG_MASKING, VG_FALSE);
  1883                 d->maskValid = false;
  1973                 d->maskValid = false;
  1884                 d->maskIsSet = true;
  1974                 d->maskIsSet = true;
       
  1975                 d->scissorMask = false;
  1885                 d->maskRect = QRect();
  1976                 d->maskRect = QRect();
  1886             } else {
  1977             } else {
  1887                 d->modifyMask(this, VG_INTERSECT_MASK, r);
  1978                 d->modifyMask(this, VG_INTERSECT_MASK, r);
  1888             }
  1979             }
  1889         }
  1980         }
  1958     d->dirty |= QPaintEngine::DirtyClipRegion;
  2049     d->dirty |= QPaintEngine::DirtyClipRegion;
  1959 
  2050 
  1960     if (op == Qt::NoClip) {
  2051     if (op == Qt::NoClip) {
  1961         d->maskValid = false;
  2052         d->maskValid = false;
  1962         d->maskIsSet = true;
  2053         d->maskIsSet = true;
       
  2054         d->scissorMask = false;
  1963         d->maskRect = QRect();
  2055         d->maskRect = QRect();
  1964         vgSeti(VG_MASKING, VG_FALSE);
  2056         vgSeti(VG_MASKING, VG_FALSE);
  1965         return;
  2057         return;
  1966     }
  2058     }
  1967 
  2059 
  1988             vgRenderToMask(vgpath, VG_FILL_PATH, VG_INTERSECT_MASK);
  2080             vgRenderToMask(vgpath, VG_FILL_PATH, VG_INTERSECT_MASK);
  1989             break;
  2081             break;
  1990 
  2082 
  1991         default: break;
  2083         default: break;
  1992     }
  2084     }
  1993     vgDestroyPath(vgpath);
  2085     d->releasePath(vgpath);
  1994 
  2086 
  1995     vgSeti(VG_MASKING, VG_TRUE);
  2087     vgSeti(VG_MASKING, VG_TRUE);
  1996     d->maskValid = true;
  2088     d->maskValid = true;
  1997     d->maskIsSet = false;
  2089     d->maskIsSet = false;
       
  2090     d->scissorMask = false;
  1998 #else
  2091 #else
  1999     QPaintEngineEx::clip(path, op);
  2092     QPaintEngineEx::clip(path, op);
  2000 #endif
  2093 #endif
  2001 }
  2094 }
  2002 
  2095 
  2003 void QVGPaintEnginePrivate::ensureMask
  2096 void QVGPaintEnginePrivate::ensureMask
  2004         (QVGPaintEngine *engine, int width, int height)
  2097         (QVGPaintEngine *engine, int width, int height)
  2005 {
  2098 {
       
  2099 	  scissorMask = false;
  2006     if (maskIsSet) {
  2100     if (maskIsSet) {
  2007         vgMask(VG_INVALID_HANDLE, VG_FILL_MASK, 0, 0, width, height);
  2101         vgMask(VG_INVALID_HANDLE, VG_FILL_MASK, 0, 0, width, height);
  2008         maskRect = QRect();
  2102         maskRect = QRect();
  2009     } else {
  2103     } else {
  2010         vgMask(VG_INVALID_HANDLE, VG_CLEAR_MASK, 0, 0, width, height);
  2104         vgMask(VG_INVALID_HANDLE, VG_CLEAR_MASK, 0, 0, width, height);
  2036     }
  2130     }
  2037 
  2131 
  2038     vgSeti(VG_MASKING, VG_TRUE);
  2132     vgSeti(VG_MASKING, VG_TRUE);
  2039     maskValid = true;
  2133     maskValid = true;
  2040     maskIsSet = false;
  2134     maskIsSet = false;
       
  2135     scissorMask = false;
  2041 }
  2136 }
  2042 
  2137 
  2043 void QVGPaintEnginePrivate::modifyMask
  2138 void QVGPaintEnginePrivate::modifyMask
  2044         (QVGPaintEngine *engine, VGMaskOperation op, const QRect& rect)
  2139         (QVGPaintEngine *engine, VGMaskOperation op, const QRect& rect)
  2045 {
  2140 {
  2057     }
  2152     }
  2058 
  2153 
  2059     vgSeti(VG_MASKING, VG_TRUE);
  2154     vgSeti(VG_MASKING, VG_TRUE);
  2060     maskValid = true;
  2155     maskValid = true;
  2061     maskIsSet = false;
  2156     maskIsSet = false;
       
  2157     scissorMask = false;
  2062 }
  2158 }
  2063 
  2159 
  2064 #endif // !QVG_SCISSOR_CLIP
  2160 #endif // !QVG_SCISSOR_CLIP
  2065 
  2161 
  2066 void QVGPaintEngine::updateScissor()
  2162 void QVGPaintEngine::updateScissor()
  2081         if (isDefaultClipRegion(region)) {
  2177         if (isDefaultClipRegion(region)) {
  2082             // The scissor region is the entire drawing surface,
  2178             // The scissor region is the entire drawing surface,
  2083             // so there is no point doing any scissoring.
  2179             // so there is no point doing any scissoring.
  2084             vgSeti(VG_SCISSORING, VG_FALSE);
  2180             vgSeti(VG_SCISSORING, VG_FALSE);
  2085             d->scissorActive = false;
  2181             d->scissorActive = false;
       
  2182             d->scissorDirty = false;
  2086             return;
  2183             return;
  2087         }
  2184         }
  2088     } else
  2185     } else
  2089 #endif
  2186 #endif
  2090     {
  2187     {
  2091 #if !defined(QVG_SCISSOR_CLIP)
  2188 #if !defined(QVG_SCISSOR_CLIP)
  2092         // Combine the system clip with the simple mask rectangle.
  2189         // Combine the system clip with the simple mask rectangle.
  2093         if (!d->maskRect.isNull()) {
  2190         if (d->scissorMask) {
  2094             if (region.isEmpty())
  2191             if (region.isEmpty())
  2095                 region = d->maskRect;
  2192                 region = d->maskRect;
  2096             else
  2193             else
  2097                 region = region.intersect(d->maskRect);
  2194                 region = region.intersect(d->maskRect);
  2098             if (isDefaultClipRegion(region)) {
  2195             if (isDefaultClipRegion(region)) {
  2099                 // The scissor region is the entire drawing surface,
  2196                 // The scissor region is the entire drawing surface,
  2100                 // so there is no point doing any scissoring.
  2197                 // so there is no point doing any scissoring.
  2101                 vgSeti(VG_SCISSORING, VG_FALSE);
  2198                 vgSeti(VG_SCISSORING, VG_FALSE);
  2102                 d->scissorActive = false;
  2199                 d->scissorActive = false;
       
  2200                 d->scissorDirty = false;
  2103                 return;
  2201                 return;
  2104             }
  2202             }
  2105         } else
  2203         } else
  2106 #endif
  2204 #endif
  2107 
  2205 
  2108         // Disable the scissor completely if the system clip is empty.
  2206         // Disable the scissor completely if the system clip is empty.
  2109         if (region.isEmpty()) {
  2207         if (region.isEmpty()) {
  2110             vgSeti(VG_SCISSORING, VG_FALSE);
  2208             vgSeti(VG_SCISSORING, VG_FALSE);
  2111             d->scissorActive = false;
  2209             d->scissorActive = false;
       
  2210             d->scissorDirty = false;
  2112             return;
  2211             return;
  2113         }
  2212         }
  2114     }
  2213     }
  2115 
  2214 
  2116     if (d->scissorActive && region == d->scissorRegion)
  2215     if (d->scissorActive && region == d->scissorRegion && !d->scissorDirty)
  2117         return;
  2216         return;
  2118 
  2217 
  2119     QVector<QRect> rects = region.rects();
  2218     QVector<QRect> rects = region.rects();
  2120     int count = rects.count();
  2219     int count = rects.count();
  2121     if (count > d->maxScissorRects)
  2220     if (count > d->maxScissorRects)
  2129         params[i * 4 + 3] = rects[i].height();
  2228         params[i * 4 + 3] = rects[i].height();
  2130     }
  2229     }
  2131 
  2230 
  2132     vgSetiv(VG_SCISSOR_RECTS, count * 4, params.data());
  2231     vgSetiv(VG_SCISSOR_RECTS, count * 4, params.data());
  2133     vgSeti(VG_SCISSORING, VG_TRUE);
  2232     vgSeti(VG_SCISSORING, VG_TRUE);
       
  2233     d->scissorDirty = false;
  2134     d->scissorActive = true;
  2234     d->scissorActive = true;
  2135     d->scissorRegion = region;
  2235     d->scissorRegion = region;
  2136 }
  2236 }
  2137 
  2237 
  2138 QRegion QVGPaintEngine::defaultClipRegion()
  2238 QRegion QVGPaintEngine::defaultClipRegion()
  2176     d->dirty |= QPaintEngine::DirtyClipEnabled;
  2276     d->dirty |= QPaintEngine::DirtyClipEnabled;
  2177     if (s->clipEnabled && s->clipOperation != Qt::NoClip) {
  2277     if (s->clipEnabled && s->clipOperation != Qt::NoClip) {
  2178         // Replay the entire clip stack to put the mask into the right state.
  2278         // Replay the entire clip stack to put the mask into the right state.
  2179         d->maskValid = false;
  2279         d->maskValid = false;
  2180         d->maskIsSet = true;
  2280         d->maskIsSet = true;
       
  2281         d->scissorMask = false;
  2181         d->maskRect = QRect();
  2282         d->maskRect = QRect();
  2182         s->clipRegion = defaultClipRegion();
  2283         s->clipRegion = defaultClipRegion();
  2183         d->replayClipOperations();
  2284         d->replayClipOperations();
  2184         d->transform = s->transform();
  2285         d->transform = s->transform();
  2185         d->updateTransform(paintDevice());
  2286         d->updateTransform(paintDevice());
  2186     } else {
  2287     } else {
  2187         vgSeti(VG_MASKING, VG_FALSE);
  2288         vgSeti(VG_MASKING, VG_FALSE);
  2188         d->maskValid = false;
  2289         d->maskValid = false;
  2189         d->maskIsSet = false;
  2290         d->maskIsSet = false;
       
  2291         d->scissorMask = false;
  2190         d->maskRect = QRect();
  2292         d->maskRect = QRect();
  2191     }
  2293     }
  2192 #endif
  2294 #endif
  2193 }
  2295 }
  2194 
  2296 
  2303 bool QVGPaintEngine::clearRect(const QRectF &rect, const QColor &color)
  2405 bool QVGPaintEngine::clearRect(const QRectF &rect, const QColor &color)
  2304 {
  2406 {
  2305     Q_D(QVGPaintEngine);
  2407     Q_D(QVGPaintEngine);
  2306     QVGPainterState *s = state();
  2408     QVGPainterState *s = state();
  2307     if (!s->clipEnabled || s->clipOperation == Qt::NoClip) {
  2409     if (!s->clipEnabled || s->clipOperation == Qt::NoClip) {
  2308         // The transform will either be identity or a simple translation,
  2410         QRect r = d->transform.mapRect(rect).toRect();
  2309         // so do a simpler version of "r = d->transform.map(rect).toRect()".
       
  2310         QRect r = QRect(qRound(rect.x() + d->transform.dx()),
       
  2311                         qRound(rect.y() + d->transform.dy()),
       
  2312                         qRound(rect.width()),
       
  2313                         qRound(rect.height()));
       
  2314         int height = paintDevice()->height();
  2411         int height = paintDevice()->height();
  2315         if (d->clearColor != color || d->clearOpacity != s->opacity) {
  2412         if (d->clearColor != color || d->clearOpacity != s->opacity) {
  2316             VGfloat values[4];
  2413             VGfloat values[4];
  2317             values[0] = color.redF();
  2414             values[0] = color.redF();
  2318             values[1] = color.greenF();
  2415             values[1] = color.greenF();
  2335 
  2432 
  2336     if (brush.style() == Qt::NoBrush)
  2433     if (brush.style() == Qt::NoBrush)
  2337         return;
  2434         return;
  2338 
  2435 
  2339     // Check to see if we can use vgClear() for faster filling.
  2436     // Check to see if we can use vgClear() for faster filling.
  2340     if (brush.style() == Qt::SolidPattern &&
  2437     if (brush.style() == Qt::SolidPattern && brush.isOpaque() &&
  2341             clipTransformIsSimple(d->transform) && d->opacity == 1.0f &&
  2438             clipTransformIsSimple(d->transform) && d->opacity == 1.0f &&
  2342             clearRect(rect, brush.color())) {
  2439             clearRect(rect, brush.color())) {
  2343         return;
  2440         return;
  2344     }
  2441     }
  2345 
  2442 
  2378 void QVGPaintEngine::fillRect(const QRectF &rect, const QColor &color)
  2475 void QVGPaintEngine::fillRect(const QRectF &rect, const QColor &color)
  2379 {
  2476 {
  2380     Q_D(QVGPaintEngine);
  2477     Q_D(QVGPaintEngine);
  2381 
  2478 
  2382     // Check to see if we can use vgClear() for faster filling.
  2479     // Check to see if we can use vgClear() for faster filling.
  2383     if (clipTransformIsSimple(d->transform) && d->opacity == 1.0f &&
  2480     if (clipTransformIsSimple(d->transform) && d->opacity == 1.0f && color.alpha() == 255 &&
  2384             clearRect(rect, color)) {
  2481             clearRect(rect, color)) {
  2385         return;
  2482         return;
  2386     }
  2483     }
  2387 
  2484 
  2388 #if !defined(QVG_NO_MODIFY_PATH)
  2485 #if !defined(QVG_NO_MODIFY_PATH)
  2423     if (d->simpleTransform) {
  2520     if (d->simpleTransform) {
  2424         QVGPainterState *s = state();
  2521         QVGPainterState *s = state();
  2425         VGPath vgpath = d->roundedRectPath(rect, xrad, yrad, mode);
  2522         VGPath vgpath = d->roundedRectPath(rect, xrad, yrad, mode);
  2426         d->draw(vgpath, s->pen, s->brush);
  2523         d->draw(vgpath, s->pen, s->brush);
  2427 #if defined(QVG_NO_MODIFY_PATH)
  2524 #if defined(QVG_NO_MODIFY_PATH)
  2428         vgDestroyPath(vgpath);
  2525         d->releasePath(vgpath);
  2429 #endif
  2526 #endif
  2430     } else {
  2527     } else {
  2431         QPaintEngineEx::drawRoundedRect(rect, xrad, yrad, mode);
  2528         QPaintEngineEx::drawRoundedRect(rect, xrad, yrad, mode);
  2432     }
  2529     }
  2433 }
  2530 }
  2572     // Based on the description of vguEllipse() in the OpenVG specification.
  2669     // Based on the description of vguEllipse() in the OpenVG specification.
  2573     // We don't use vguEllipse(), to avoid unnecessary library dependencies.
  2670     // We don't use vguEllipse(), to avoid unnecessary library dependencies.
  2574     Q_D(QVGPaintEngine);
  2671     Q_D(QVGPaintEngine);
  2575     if (d->simpleTransform) {
  2672     if (d->simpleTransform) {
  2576         QVGPainterState *s = state();
  2673         QVGPainterState *s = state();
  2577         VGPath path = vgCreatePath(VG_PATH_FORMAT_STANDARD,
  2674         VGPath path = d->reusablePath;
  2578                                    VG_PATH_DATATYPE_F,
       
  2579                                    1.0f, // scale
       
  2580                                    0.0f, // bias
       
  2581                                    4,    // segmentCapacityHint
       
  2582                                    12,   // coordCapacityHint
       
  2583                                    VG_PATH_CAPABILITY_ALL);
       
  2584         static VGubyte segments[4] = {
  2675         static VGubyte segments[4] = {
  2585             VG_MOVE_TO_ABS,
  2676             VG_MOVE_TO_ABS,
  2586             VG_SCCWARC_TO_REL,
  2677             VG_SCCWARC_TO_REL,
  2587             VG_SCCWARC_TO_REL,
  2678             VG_SCCWARC_TO_REL,
  2588             VG_CLOSE_PATH
  2679             VG_CLOSE_PATH
  2602         coords[9]  = 0.0f;
  2693         coords[9]  = 0.0f;
  2603         coords[10] = r.width();
  2694         coords[10] = r.width();
  2604         coords[11] = 0.0f;
  2695         coords[11] = 0.0f;
  2605         vgAppendPathData(path, 4, segments, coords);
  2696         vgAppendPathData(path, 4, segments, coords);
  2606         d->draw(path, s->pen, s->brush);
  2697         d->draw(path, s->pen, s->brush);
  2607         vgDestroyPath(path);
  2698         d->releasePath(path);
  2608     } else {
  2699     } else {
  2609         // The projective transform version of an ellipse is difficult.
  2700         // The projective transform version of an ellipse is difficult.
  2610         // Generate a QVectorPath containing cubic curves and transform that.
  2701         // Generate a QVectorPath containing cubic curves and transform that.
  2611         QPaintEngineEx::drawEllipse(r);
  2702         QPaintEngineEx::drawEllipse(r);
  2612     }
  2703     }
  2626     VGPath vgpath = d->painterPathToVGPath(path);
  2717     VGPath vgpath = d->painterPathToVGPath(path);
  2627     if (path.fillRule() == Qt::OddEvenFill)
  2718     if (path.fillRule() == Qt::OddEvenFill)
  2628         d->draw(vgpath, s->pen, s->brush, VG_EVEN_ODD);
  2719         d->draw(vgpath, s->pen, s->brush, VG_EVEN_ODD);
  2629     else
  2720     else
  2630         d->draw(vgpath, s->pen, s->brush, VG_NON_ZERO);
  2721         d->draw(vgpath, s->pen, s->brush, VG_NON_ZERO);
  2631     vgDestroyPath(vgpath);
  2722     d->releasePath(vgpath);
  2632 }
  2723 }
  2633 
  2724 
  2634 void QVGPaintEngine::drawPoints(const QPointF *points, int pointCount)
  2725 void QVGPaintEngine::drawPoints(const QPointF *points, int pointCount)
  2635 {
  2726 {
  2636 #if !defined(QVG_NO_MODIFY_PATH)
  2727 #if !defined(QVG_NO_MODIFY_PATH)
  2701 
  2792 
  2702 void QVGPaintEngine::drawPolygon(const QPointF *points, int pointCount, PolygonDrawMode mode)
  2793 void QVGPaintEngine::drawPolygon(const QPointF *points, int pointCount, PolygonDrawMode mode)
  2703 {
  2794 {
  2704     Q_D(QVGPaintEngine);
  2795     Q_D(QVGPaintEngine);
  2705     QVGPainterState *s = state();
  2796     QVGPainterState *s = state();
  2706     VGPath path = vgCreatePath(VG_PATH_FORMAT_STANDARD,
  2797     VGPath path = d->reusablePath;
  2707                                VG_PATH_DATATYPE_F,
       
  2708                                1.0f,             // scale
       
  2709                                0.0f,             // bias
       
  2710                                pointCount + 1,   // segmentCapacityHint
       
  2711                                pointCount * 2,   // coordCapacityHint
       
  2712                                VG_PATH_CAPABILITY_ALL);
       
  2713     QVarLengthArray<VGfloat, 16> coords;
  2798     QVarLengthArray<VGfloat, 16> coords;
  2714     QVarLengthArray<VGubyte, 10> segments;
  2799     QVarLengthArray<VGubyte, 10> segments;
  2715     for (int i = 0; i < pointCount; ++i, ++points) {
  2800     for (int i = 0; i < pointCount; ++i, ++points) {
  2716         if (d->simpleTransform) {
  2801         if (d->simpleTransform) {
  2717             coords.append(points->x());
  2802             coords.append(points->x());
  2741 
  2826 
  2742         default:
  2827         default:
  2743             d->draw(path, s->pen, s->brush, VG_EVEN_ODD);
  2828             d->draw(path, s->pen, s->brush, VG_EVEN_ODD);
  2744             break;
  2829             break;
  2745     }
  2830     }
  2746     vgDestroyPath(path);
  2831     d->releasePath(path);
  2747 }
  2832 }
  2748 
  2833 
  2749 void QVGPaintEngine::drawPolygon(const QPoint *points, int pointCount, PolygonDrawMode mode)
  2834 void QVGPaintEngine::drawPolygon(const QPoint *points, int pointCount, PolygonDrawMode mode)
  2750 {
  2835 {
  2751     Q_D(QVGPaintEngine);
  2836     Q_D(QVGPaintEngine);
  2752     QVGPainterState *s = state();
  2837     QVGPainterState *s = state();
  2753     VGPath path = vgCreatePath(VG_PATH_FORMAT_STANDARD,
  2838     VGPath path = d->reusablePath;
  2754                                VG_PATH_DATATYPE_F,
       
  2755                                1.0f,             // scale
       
  2756                                0.0f,             // bias
       
  2757                                pointCount + 1,   // segmentCapacityHint
       
  2758                                pointCount * 2,   // coordCapacityHint
       
  2759                                VG_PATH_CAPABILITY_ALL);
       
  2760     QVarLengthArray<VGfloat, 16> coords;
  2839     QVarLengthArray<VGfloat, 16> coords;
  2761     QVarLengthArray<VGubyte, 10> segments;
  2840     QVarLengthArray<VGubyte, 10> segments;
  2762     for (int i = 0; i < pointCount; ++i, ++points) {
  2841     for (int i = 0; i < pointCount; ++i, ++points) {
  2763         if (d->simpleTransform) {
  2842         if (d->simpleTransform) {
  2764             coords.append(points->x());
  2843             coords.append(points->x());
  2788 
  2867 
  2789         default:
  2868         default:
  2790             d->draw(path, s->pen, s->brush, VG_EVEN_ODD);
  2869             d->draw(path, s->pen, s->brush, VG_EVEN_ODD);
  2791             break;
  2870             break;
  2792     }
  2871     }
  2793     vgDestroyPath(path);
  2872     d->releasePath(path);
  2794 }
  2873 }
  2795 
  2874 
  2796 void QVGPaintEnginePrivate::setImageOptions()
  2875 void QVGPaintEnginePrivate::setImageOptions()
  2797 {
  2876 {
  2798     if (opacity != 1.0f && simpleTransform) {
  2877     if (opacity != 1.0f && simpleTransform) {
  3164         VGImage vgImage = VG_INVALID_HANDLE;
  3243         VGImage vgImage = VG_INVALID_HANDLE;
  3165         metrics = ti.fontEngine->boundingBox(glyph);
  3244         metrics = ti.fontEngine->boundingBox(glyph);
  3166         if (!scaledImage.isNull()) {  // Not a space character
  3245         if (!scaledImage.isNull()) {  // Not a space character
  3167             if (scaledImage.format() == QImage::Format_Indexed8) {
  3246             if (scaledImage.format() == QImage::Format_Indexed8) {
  3168                 vgImage = vgCreateImage(VG_A_8, scaledImage.width(), scaledImage.height(), VG_IMAGE_QUALITY_FASTER);
  3247                 vgImage = vgCreateImage(VG_A_8, scaledImage.width(), scaledImage.height(), VG_IMAGE_QUALITY_FASTER);
  3169                 vgImageSubData(vgImage, scaledImage.bits(), scaledImage.bytesPerLine(), VG_A_8, 0, 0, scaledImage.width(), scaledImage.height());
  3248                 vgImageSubData(vgImage, qt_vg_imageBits(scaledImage), scaledImage.bytesPerLine(), VG_A_8, 0, 0, scaledImage.width(), scaledImage.height());
  3170             } else if (scaledImage.format() == QImage::Format_Mono) {
  3249             } else if (scaledImage.format() == QImage::Format_Mono) {
  3171                 QImage img = scaledImage.convertToFormat(QImage::Format_Indexed8);
  3250                 QImage img = scaledImage.convertToFormat(QImage::Format_Indexed8);
  3172                 vgImage = vgCreateImage(VG_A_8, img.width(), img.height(), VG_IMAGE_QUALITY_FASTER);
  3251                 vgImage = vgCreateImage(VG_A_8, img.width(), img.height(), VG_IMAGE_QUALITY_FASTER);
  3173                 vgImageSubData(vgImage, img.bits(), img.bytesPerLine(), VG_A_8, 0, 0, img.width(), img.height());
  3252                 vgImageSubData(vgImage, qt_vg_imageBits(img), img.bytesPerLine(), VG_A_8, 0, 0, img.width(), img.height());
  3174             } else {
  3253             } else {
  3175                 QImage img = scaledImage.convertToFormat(QImage::Format_ARGB32_Premultiplied);
  3254                 QImage img = scaledImage.convertToFormat(QImage::Format_ARGB32_Premultiplied);
  3176                 vgImage = vgCreateImage(VG_sARGB_8888_PRE, img.width(), img.height(), VG_IMAGE_QUALITY_FASTER);
  3255                 vgImage = vgCreateImage(VG_sARGB_8888_PRE, img.width(), img.height(), VG_IMAGE_QUALITY_FASTER);
  3177                 vgImageSubData(vgImage, img.bits(), img.bytesPerLine(), VG_sARGB_8888_PRE, 0, 0, img.width(), img.height());
  3256                 vgImageSubData(vgImage, qt_vg_imageBits(img), img.bytesPerLine(), VG_sARGB_8888_PRE, 0, 0, img.width(), img.height());
  3178             }
  3257             }
  3179         }
  3258         }
  3180         origin[0] = -metrics.x.toReal() + 0.5f;
  3259         origin[0] = -metrics.x.toReal() + 0.5f;
  3181         origin[1] = -metrics.y.toReal() + 0.5f;
  3260         origin[1] = -metrics.y.toReal() + 0.5f;
  3182         escapement[0] = metrics.xoff.toReal();
  3261         escapement[0] = metrics.xoff.toReal();
  3187         // Calculate the path for the glyph and cache it.
  3266         // Calculate the path for the glyph and cache it.
  3188         QPainterPath path;
  3267         QPainterPath path;
  3189         ti.fontEngine->getUnscaledGlyph(glyph, &path, &metrics);
  3268         ti.fontEngine->getUnscaledGlyph(glyph, &path, &metrics);
  3190         VGPath vgPath;
  3269         VGPath vgPath;
  3191         if (!path.isEmpty()) {
  3270         if (!path.isEmpty()) {
  3192             vgPath = d->painterPathToVGPath(path);
  3271             vgPath = d->painterPathToVGPath(path, true);
  3193         } else {
  3272         } else {
  3194             // Probably a "space" character with no visible outline.
  3273             // Probably a "space" character with no visible outline.
  3195             vgPath = VG_INVALID_HANDLE;
  3274             vgPath = VG_INVALID_HANDLE;
  3196         }
  3275         }
  3197         origin[0] = 0;
  3276         origin[0] = 0;
  3331     d->forceBrushChange = true;
  3410     d->forceBrushChange = true;
  3332     d->penType = (VGPaintType)0;
  3411     d->penType = (VGPaintType)0;
  3333     d->brushType = (VGPaintType)0;
  3412     d->brushType = (VGPaintType)0;
  3334     d->clearColor = QColor();
  3413     d->clearColor = QColor();
  3335     d->fillPaint = d->brushPaint;
  3414     d->fillPaint = d->brushPaint;
       
  3415     d->scissorDirty = true;
  3336     restoreState(QPaintEngine::AllDirty);
  3416     restoreState(QPaintEngine::AllDirty);
  3337     d->dirty = dirty;
  3417     d->dirty = dirty;
  3338     d->rawVG = false;
  3418     d->rawVG = false;
  3339     vgSetPaint(d->penPaint, VG_STROKE_PATH);
  3419     vgSetPaint(d->penPaint, VG_STROKE_PATH);
  3340     vgSetPaint(d->brushPaint, VG_FILL_PATH);
  3420     vgSetPaint(d->brushPaint, VG_FILL_PATH);
  3386     if ((dirty & (QPaintEngine::DirtyClipRegion |
  3466     if ((dirty & (QPaintEngine::DirtyClipRegion |
  3387                   QPaintEngine::DirtyClipPath |
  3467                   QPaintEngine::DirtyClipPath |
  3388                   QPaintEngine::DirtyClipEnabled)) != 0) {
  3468                   QPaintEngine::DirtyClipEnabled)) != 0) {
  3389         d->maskValid = false;
  3469         d->maskValid = false;
  3390         d->maskIsSet = false;
  3470         d->maskIsSet = false;
       
  3471         d->scissorMask = false;
  3391         d->maskRect = QRect();
  3472         d->maskRect = QRect();
  3392         clipEnabledChanged();
  3473         clipEnabledChanged();
  3393     }
  3474     }
  3394 
  3475 
  3395 #if defined(QVG_SCISSOR_CLIP)
  3476 #if defined(QVG_SCISSOR_CLIP)
  3638             (VG_sARGB_8888_PRE, img.width(), img.height(),
  3719             (VG_sARGB_8888_PRE, img.width(), img.height(),
  3639              VG_IMAGE_QUALITY_FASTER);
  3720              VG_IMAGE_QUALITY_FASTER);
  3640         if (vgImage == VG_INVALID_HANDLE)
  3721         if (vgImage == VG_INVALID_HANDLE)
  3641             return;
  3722             return;
  3642         vgImageSubData
  3723         vgImageSubData
  3643             (vgImage, img.bits() + img.bytesPerLine() * (img.height() - 1),
  3724             (vgImage, qt_vg_imageBits(img) + img.bytesPerLine() * (img.height() - 1),
  3644              -(img.bytesPerLine()), VG_sARGB_8888_PRE, 0, 0,
  3725              -(img.bytesPerLine()), VG_sARGB_8888_PRE, 0, 0,
  3645              img.width(), img.height());
  3726              img.width(), img.height());
  3646 
  3727 
  3647         vgDrawImage(vgImage);
  3728         vgDrawImage(vgImage);
  3648         vgDestroyImage(vgImage);
  3729         vgDestroyImage(vgImage);
  3664         params[i * 4 + 3] = rects[i].height();
  3745         params[i * 4 + 3] = rects[i].height();
  3665     }
  3746     }
  3666 
  3747 
  3667     vgSetiv(VG_SCISSOR_RECTS, count * 4, params.data());
  3748     vgSetiv(VG_SCISSOR_RECTS, count * 4, params.data());
  3668     vgSeti(VG_SCISSORING, VG_TRUE);
  3749     vgSeti(VG_SCISSORING, VG_TRUE);
       
  3750     d->scissorDirty = false;
  3669     d->scissorActive = true;
  3751     d->scissorActive = true;
  3670     d->scissorRegion = region;
  3752     d->scissorRegion = region;
  3671 }
  3753 }
  3672 
  3754 
  3673 void QVGCompositionHelper::clearScissor()
  3755 void QVGCompositionHelper::clearScissor()
  3674 {
  3756 {
  3675     if (d->scissorActive) {
  3757     if (d->scissorActive || d->scissorDirty) {
  3676         vgSeti(VG_SCISSORING, VG_FALSE);
  3758         vgSeti(VG_SCISSORING, VG_FALSE);
  3677         d->scissorActive = false;
  3759         d->scissorActive = false;
       
  3760         d->scissorDirty = false;
  3678     }
  3761     }
  3679 }
  3762 }
  3680 
  3763 
  3681 #endif // !QVG_NO_SINGLE_CONTEXT && !QT_NO_EGL
  3764 #endif // !QVG_NO_SINGLE_CONTEXT && !QT_NO_EGL
  3682 
  3765