+++ /dev/null
-/****************************************************************************
-**
-** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
-** All rights reserved.
-** Contact: Nokia Corporation (qt-info@nokia.com)
-**
-** This file is part of the QtOpenVG module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** No Commercial Usage
-** This file contains pre-release code and may not be distributed.
-** You may use this file in accordance with the terms and conditions
-** contained in the Technology Preview License Agreement accompanying
-** this package.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 2.1 requirements
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, Nokia gives you certain additional
-** rights. These rights are described in the Nokia Qt LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** If you have questions regarding the use of this file, please contact
-** Nokia at qt-info@nokia.com.
-**
-**
-**
-**
-**
-**
-**
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qpaintengine_vg_p.h"
-#include "qpixmapdata_vg_p.h"
-#include "qpixmapfilter_vg_p.h"
-#include "qvgcompositionhelper_p.h"
-#include "qvgimagepool_p.h"
-#include "qvgfontglyphcache_p.h"
-#if !defined(QT_NO_EGL)
-#include <QtGui/private/qeglcontext_p.h>
-#include "qwindowsurface_vgegl_p.h"
-#endif
-#include <QtCore/qvarlengtharray.h>
-#include <QtGui/private/qdrawhelper_p.h>
-#include <QtGui/private/qtextengine_p.h>
-#include <QtGui/private/qfontengine_p.h>
-#include <QtGui/private/qpainterpath_p.h>
-#include <QtGui/private/qstatictext_p.h>
-#include <QtGui/QApplication>
-#include <QtGui/QDesktopWidget>
-#include <QtCore/qmath.h>
-#include <QDebug>
-#include <QSet>
-
-QT_BEGIN_NAMESPACE
-
-// vgRenderToMask() only exists in OpenVG 1.1 and higher.
-// Also, disable masking completely if we are using the scissor to clip.
-#if !defined(OPENVG_VERSION_1_1) && !defined(QVG_NO_RENDER_TO_MASK)
-#define QVG_NO_RENDER_TO_MASK 1
-#endif
-#if defined(QVG_SCISSOR_CLIP) && !defined(QVG_NO_RENDER_TO_MASK)
-#define QVG_NO_RENDER_TO_MASK 1
-#endif
-
-// use the same rounding as in qrasterizer.cpp (6 bit fixed point)
-static const qreal aliasedCoordinateDelta = 0.5 - 0.015625;
-
-#if !defined(QVG_NO_DRAW_GLYPHS)
-
-class QVGPaintEnginePrivate;
-
-typedef QHash<QFontEngine*, QVGFontGlyphCache*> QVGFontCache;
-
-#endif
-
-class QVGFontEngineCleaner : public QObject
-{
- Q_OBJECT
-public:
- QVGFontEngineCleaner(QVGPaintEnginePrivate *d);
- ~QVGFontEngineCleaner();
-
-public slots:
- void fontEngineDestroyed();
-
-private:
- QVGPaintEnginePrivate *d_ptr;
-};
-
-class QVGPaintEnginePrivate : public QPaintEngineExPrivate
-{
- Q_DECLARE_PUBLIC(QVGPaintEngine)
-public:
- // Extra blending modes from VG_KHR_advanced_blending extension.
- // Use the QT_VG prefix to avoid conflicts with any definitions
- // that may come in via <VG/vgext.h>.
- enum AdvancedBlending {
- QT_VG_BLEND_OVERLAY_KHR = 0x2010,
- QT_VG_BLEND_HARDLIGHT_KHR = 0x2011,
- QT_VG_BLEND_SOFTLIGHT_SVG_KHR = 0x2012,
- QT_VG_BLEND_SOFTLIGHT_KHR = 0x2013,
- QT_VG_BLEND_COLORDODGE_KHR = 0x2014,
- QT_VG_BLEND_COLORBURN_KHR = 0x2015,
- QT_VG_BLEND_DIFFERENCE_KHR = 0x2016,
- QT_VG_BLEND_SUBTRACT_KHR = 0x2017,
- QT_VG_BLEND_INVERT_KHR = 0x2018,
- QT_VG_BLEND_EXCLUSION_KHR = 0x2019,
- QT_VG_BLEND_LINEARDODGE_KHR = 0x201a,
- QT_VG_BLEND_LINEARBURN_KHR = 0x201b,
- QT_VG_BLEND_VIVIDLIGHT_KHR = 0x201c,
- QT_VG_BLEND_LINEARLIGHT_KHR = 0x201d,
- QT_VG_BLEND_PINLIGHT_KHR = 0x201e,
- QT_VG_BLEND_HARDMIX_KHR = 0x201f,
- QT_VG_BLEND_CLEAR_KHR = 0x2020,
- QT_VG_BLEND_DST_KHR = 0x2021,
- QT_VG_BLEND_SRC_OUT_KHR = 0x2022,
- QT_VG_BLEND_DST_OUT_KHR = 0x2023,
- QT_VG_BLEND_SRC_ATOP_KHR = 0x2024,
- QT_VG_BLEND_DST_ATOP_KHR = 0x2025,
- QT_VG_BLEND_XOR_KHR = 0x2026
- };
-
- QVGPaintEnginePrivate(QVGPaintEngine *q_ptr);
- ~QVGPaintEnginePrivate();
-
- void init();
- void initObjects();
- void destroy();
- void setTransform(VGMatrixMode mode, const QTransform& transform);
- void updateTransform(QPaintDevice *pdev);
- void draw(VGPath path, const QPen& pen, const QBrush& brush, VGint rule = VG_EVEN_ODD);
- void stroke(VGPath path, const QPen& pen);
- void fill(VGPath path, const QBrush& brush, VGint rule = VG_EVEN_ODD);
- VGPath vectorPathToVGPath(const QVectorPath& path);
- VGPath painterPathToVGPath(const QPainterPath& path);
- VGPath roundedRectPath(const QRectF &rect, qreal xRadius, qreal yRadius, Qt::SizeMode mode);
- VGPaintType setBrush
- (VGPaint paint, const QBrush& brush, VGMatrixMode mode,
- VGPaintType prevPaintType);
- void setPenParams(const QPen& pen);
- void setBrushTransform(const QBrush& brush, VGMatrixMode mode);
- void setupColorRamp(const QGradient *grad, VGPaint paint);
- void setImageOptions();
- void systemStateChanged();
-#if !defined(QVG_SCISSOR_CLIP)
- void ensureMask(QVGPaintEngine *engine, int width, int height);
- void modifyMask
- (QVGPaintEngine *engine, VGMaskOperation op, const QRegion& region);
- void modifyMask
- (QVGPaintEngine *engine, VGMaskOperation op, const QRect& rect);
-#endif
-
- VGint maxScissorRects; // Maximum scissor rectangles for clipping.
-
- VGPaint penPaint; // Paint for currently active pen.
- VGPaint brushPaint; // Paint for currently active brush.
- VGPaint opacityPaint; // Paint for drawing images with opacity.
- VGPaint fillPaint; // Current fill paint that is active.
-
- QPen currentPen; // Current pen set in "penPaint".
- QBrush currentBrush; // Current brush set in "brushPaint".
-
- bool forcePenChange; // Force a pen change, even if the same.
- bool forceBrushChange; // Force a brush change, even if the same.
-
- VGPaintType penType; // Type of the last pen that was set.
- VGPaintType brushType; // Type of the last brush that was set.
-
- QPointF brushOrigin; // Current brush origin.
-
- VGint fillRule; // Last fill rule that was set.
-
- qreal opacity; // Current drawing opacity.
- qreal paintOpacity; // Opacity in opacityPaint.
-
-#if !defined(QVG_NO_MODIFY_PATH)
- VGPath rectPath; // Cached path for quick drawing of rectangles.
- VGPath linePath; // Cached path for quick drawing of lines.
- VGPath roundRectPath; // Cached path for quick drawing of rounded rects.
-#endif
-
- QTransform transform; // Currently active transform.
- bool simpleTransform; // True if the transform is simple (non-projective).
- qreal penScale; // Pen scaling factor from "transform".
-
- QTransform pathTransform; // Calculated VG path transformation.
- QTransform imageTransform; // Calculated VG image transformation.
- bool pathTransformSet; // True if path transform set in the VG context.
-
- bool maskValid; // True if vgMask() contains valid data.
- bool maskIsSet; // True if mask would be fully set if it was valid.
- bool scissorMask; // True if scissor is used in place of the mask.
- bool rawVG; // True if processing a raw VG escape.
-
- QRect maskRect; // Rectangle version of mask if it is simple.
-
- QTransform penTransform; // Transform for the pen.
- QTransform brushTransform; // Transform for the brush.
-
- VGMatrixMode matrixMode; // Last matrix mode that was set.
- VGImageMode imageMode; // Last image mode that was set.
-
- QRegion scissorRegion; // Currently active scissor region.
- bool scissorActive; // True if scissor region is active.
- bool scissorDirty; // True if scissor is dirty after native painting.
-
- QPaintEngine::DirtyFlags dirty;
-
- QColor clearColor; // Last clear color that was set.
- VGfloat clearOpacity; // Opacity during the last clear.
-
- VGBlendMode blendMode; // Active blend mode.
- VGRenderingQuality renderingQuality; // Active rendering quality.
- VGImageQuality imageQuality; // Active image quality.
-
-#if !defined(QVG_NO_DRAW_GLYPHS)
- QVGFontCache fontCache;
- QVGFontEngineCleaner *fontEngineCleaner;
-#endif
-
- bool hasAdvancedBlending;
-
- QScopedPointer<QPixmapFilter> convolutionFilter;
- QScopedPointer<QPixmapFilter> colorizeFilter;
- QScopedPointer<QPixmapFilter> dropShadowFilter;
- QScopedPointer<QPixmapFilter> blurFilter;
-
- // Ensure that the path transform is properly set in the VG context
- // before we perform a vgDrawPath() operation.
- inline void ensurePathTransform()
- {
- if (!pathTransformSet) {
- QTransform aliasedTransform = pathTransform;
- if (renderingQuality == VG_RENDERING_QUALITY_NONANTIALIASED && currentPen != Qt::NoPen)
- aliasedTransform = aliasedTransform
- * QTransform::fromTranslate(aliasedCoordinateDelta, -aliasedCoordinateDelta);
- setTransform(VG_MATRIX_PATH_USER_TO_SURFACE, aliasedTransform);
- pathTransformSet = true;
- }
- }
-
- // Ensure that a specific pen has been set into penPaint.
- inline void ensurePen(const QPen& pen) {
- if (forcePenChange || pen != currentPen) {
- currentPen = pen;
- forcePenChange = false;
- penType = setBrush
- (penPaint, pen.brush(),
- VG_MATRIX_STROKE_PAINT_TO_USER, penType);
- setPenParams(pen);
- }
- }
-
- // Ensure that a specific brush has been set into brushPaint.
- inline void ensureBrush(const QBrush& brush) {
- if (forceBrushChange || brush != currentBrush) {
- currentBrush = brush;
- forceBrushChange = false;
- brushType = setBrush
- (brushPaint, brush, VG_MATRIX_FILL_PAINT_TO_USER, brushType);
- }
- if (fillPaint != brushPaint) {
- vgSetPaint(brushPaint, VG_FILL_PATH);
- fillPaint = brushPaint;
- }
- }
-
- // Set various modes, but only if different.
- inline void setImageMode(VGImageMode mode);
- inline void setRenderingQuality(VGRenderingQuality mode);
- inline void setImageQuality(VGImageQuality mode);
- inline void setBlendMode(VGBlendMode mode);
- inline void setFillRule(VGint mode);
-
- // Clear all lazily-set modes.
- void clearModes();
-
-private:
- QVGPaintEngine *q;
-};
-
-inline void QVGPaintEnginePrivate::setImageMode(VGImageMode mode)
-{
- if (imageMode != mode) {
- imageMode = mode;
- vgSeti(VG_IMAGE_MODE, mode);
- }
-}
-
-inline void QVGPaintEnginePrivate::setRenderingQuality(VGRenderingQuality mode)
-{
- if (renderingQuality != mode) {
- vgSeti(VG_RENDERING_QUALITY, mode);
- renderingQuality = mode;
- pathTransformSet = false; // need to tweak transform for aliased stroking
- }
-}
-
-inline void QVGPaintEnginePrivate::setImageQuality(VGImageQuality mode)
-{
- if (imageQuality != mode) {
- vgSeti(VG_IMAGE_QUALITY, mode);
- imageQuality = mode;
- }
-}
-
-inline void QVGPaintEnginePrivate::setBlendMode(VGBlendMode mode)
-{
- if (blendMode != mode) {
- vgSeti(VG_BLEND_MODE, mode);
- blendMode = mode;
- }
-}
-
-inline void QVGPaintEnginePrivate::setFillRule(VGint mode)
-{
- if (fillRule != mode) {
- fillRule = mode;
- vgSeti(VG_FILL_RULE, mode);
- }
-}
-
-void QVGPaintEnginePrivate::clearModes()
-{
- matrixMode = (VGMatrixMode)0;
- imageMode = (VGImageMode)0;
- blendMode = (VGBlendMode)0;
- renderingQuality = (VGRenderingQuality)0;
- imageQuality = (VGImageQuality)0;
-}
-
-QVGPaintEnginePrivate::QVGPaintEnginePrivate(QVGPaintEngine *q_ptr) : q(q_ptr)
-{
- init();
-}
-
-void QVGPaintEnginePrivate::init()
-{
- maxScissorRects = 0;
-
- penPaint = 0;
- brushPaint = 0;
- opacityPaint = 0;
- fillPaint = 0;
-
- forcePenChange = true;
- forceBrushChange = true;
- penType = (VGPaintType)0;
- brushType = (VGPaintType)0;
-
- brushOrigin = QPointF(0.0f, 0.0f);
-
- fillRule = 0;
-
- opacity = 1.0;
- paintOpacity = 1.0f;
-
-#if !defined(QVG_NO_MODIFY_PATH)
- rectPath = 0;
- linePath = 0;
- roundRectPath = 0;
-#endif
-
- simpleTransform = true;
- pathTransformSet = false;
- penScale = 1.0;
-
- maskValid = false;
- maskIsSet = false;
- scissorMask = false;
- rawVG = false;
-
- scissorActive = false;
- scissorDirty = false;
-
- dirty = 0;
-
- clearOpacity = 1.0f;
-
-#if !defined(QVG_NO_DRAW_GLYPHS)
- fontEngineCleaner = 0;
-#endif
-
- hasAdvancedBlending = false;
-
- clearModes();
-}
-
-QVGPaintEnginePrivate::~QVGPaintEnginePrivate()
-{
- destroy();
-}
-
-void QVGPaintEnginePrivate::initObjects()
-{
- maxScissorRects = vgGeti(VG_MAX_SCISSOR_RECTS);
-
- penPaint = vgCreatePaint();
- vgSetParameteri(penPaint, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR);
- vgSetPaint(penPaint, VG_STROKE_PATH);
-
- vgSeti(VG_MATRIX_MODE, VG_MATRIX_STROKE_PAINT_TO_USER);
- vgLoadIdentity();
-
- brushPaint = vgCreatePaint();
- vgSetParameteri(brushPaint, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR);
- vgSetPaint(brushPaint, VG_FILL_PATH);
- fillPaint = brushPaint;
-
- vgSeti(VG_MATRIX_MODE, VG_MATRIX_FILL_PAINT_TO_USER);
- vgLoadIdentity();
- matrixMode = VG_MATRIX_FILL_PAINT_TO_USER;
-
- opacityPaint = vgCreatePaint();
- vgSetParameteri(opacityPaint, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR);
- VGfloat values[4];
- values[0] = 1.0f;
- values[1] = 1.0f;
- values[2] = 1.0f;
- values[3] = paintOpacity;
- vgSetParameterfv(opacityPaint, VG_PAINT_COLOR, 4, values);
-
-#if !defined(QVG_NO_MODIFY_PATH)
- // Create a dummy path for rectangle drawing, which we can
- // modify later with vgModifyPathCoords(). This should be
- // faster than constantly creating and destroying paths.
- rectPath = vgCreatePath(VG_PATH_FORMAT_STANDARD,
- VG_PATH_DATATYPE_F,
- 1.0f, // scale
- 0.0f, // bias
- 5, // segmentCapacityHint
- 8, // coordCapacityHint
- VG_PATH_CAPABILITY_ALL);
- static VGubyte const segments[5] = {
- VG_MOVE_TO_ABS,
- VG_LINE_TO_ABS,
- VG_LINE_TO_ABS,
- VG_LINE_TO_ABS,
- VG_CLOSE_PATH
- };
- VGfloat coords[8];
- coords[0] = 0.0f;
- coords[1] = 0.0f;
- coords[2] = 100.0f;
- coords[3] = coords[1];
- coords[4] = coords[2];
- coords[5] = 100.0f;
- coords[6] = coords[0];
- coords[7] = coords[5];
- vgAppendPathData(rectPath, 5, segments, coords);
-
- // Create a dummy line drawing path as well.
- linePath = vgCreatePath(VG_PATH_FORMAT_STANDARD,
- VG_PATH_DATATYPE_F,
- 1.0f, // scale
- 0.0f, // bias
- 2, // segmentCapacityHint
- 4, // coordCapacityHint
- VG_PATH_CAPABILITY_ALL);
- vgAppendPathData(linePath, 2, segments, coords);
-#endif
-
- const char *extensions = reinterpret_cast<const char *>(vgGetString(VG_EXTENSIONS));
- if (extensions)
- hasAdvancedBlending = strstr(extensions, "VG_KHR_advanced_blending") != 0;
-}
-
-void QVGPaintEnginePrivate::destroy()
-{
- if (penPaint)
- vgDestroyPaint(penPaint);
- if (brushPaint)
- vgDestroyPaint(brushPaint);
- if (opacityPaint)
- vgDestroyPaint(opacityPaint);
-
-#if !defined(QVG_NO_MODIFY_PATH)
- if (rectPath)
- vgDestroyPath(rectPath);
- if (linePath)
- vgDestroyPath(linePath);
- if (roundRectPath)
- vgDestroyPath(roundRectPath);
-#endif
-
-#if !defined(QVG_NO_DRAW_GLYPHS)
- QVGFontCache::Iterator it;
- for (it = fontCache.begin(); it != fontCache.end(); ++it)
- delete it.value();
- fontCache.clear();
- delete fontEngineCleaner;
-#endif
-}
-
-// Set a specific VG transformation matrix in the current VG context.
-void QVGPaintEnginePrivate::setTransform
- (VGMatrixMode mode, const QTransform& transform)
-{
- VGfloat mat[9];
- if (mode != matrixMode) {
- vgSeti(VG_MATRIX_MODE, mode);
- matrixMode = mode;
- }
- mat[0] = transform.m11();
- mat[1] = transform.m12();
- mat[2] = transform.m13();
- mat[3] = transform.m21();
- mat[4] = transform.m22();
- mat[5] = transform.m23();
- mat[6] = transform.m31();
- mat[7] = transform.m32();
- mat[8] = transform.m33();
- vgLoadMatrix(mat);
-}
-
-Q_GUI_EXPORT bool qt_scaleForTransform(const QTransform &transform, qreal *scale);
-
-void QVGPaintEnginePrivate::updateTransform(QPaintDevice *pdev)
-{
- VGfloat devh = pdev->height();
-
- // Construct the VG transform by combining the Qt transform with
- // the following viewport transformation:
- // | 1 0 0 |
- // | 0 -1 devh |
- // | 0 0 1 |
- // The full VG transform is effectively:
- // 1. Apply the user's transformation matrix.
- // 2. Flip the co-ordinate system upside down.
- QTransform viewport(1.0f, 0.0f, 0.0f,
- 0.0f, -1.0f, 0.0f,
- 0.0f, devh, 1.0f);
-
- // Compute the path transform and determine if it is projective.
- pathTransform = transform * viewport;
- bool projective = (pathTransform.m13() != 0.0f ||
- pathTransform.m23() != 0.0f ||
- pathTransform.m33() != 1.0f);
- if (projective) {
- // The engine cannot do projective path transforms for us,
- // so we will have to convert the co-ordinates ourselves.
- // Change the matrix to just the viewport transformation.
- pathTransform = viewport;
- simpleTransform = false;
- } else {
- simpleTransform = true;
- }
- pathTransformSet = false;
-
- // The image transform is always the full transformation,
- imageTransform = transform * viewport;
-
- // Calculate the scaling factor to use for turning cosmetic pens
- // into ordinary non-cosmetic pens.
- qt_scaleForTransform(transform, &penScale);
-}
-
-VGPath QVGPaintEnginePrivate::vectorPathToVGPath(const QVectorPath& path)
-{
- int count = path.elementCount();
- const qreal *points = path.points();
- const QPainterPath::ElementType *elements = path.elements();
-
- VGPath vgpath = vgCreatePath(VG_PATH_FORMAT_STANDARD,
- VG_PATH_DATATYPE_F,
- 1.0f, // scale
- 0.0f, // bias
- count + 1, // segmentCapacityHint
- count * 2, // coordCapacityHint
- VG_PATH_CAPABILITY_ALL);
-
- // Size is sufficient segments for drawRoundedRect() paths.
- QVarLengthArray<VGubyte, 20> segments;
-
- if (sizeof(qreal) == sizeof(VGfloat) && elements && simpleTransform) {
- // If Qt was compiled with qreal the same size as VGfloat,
- // then convert the segment types and use the incoming
- // points array directly.
- for (int i = 0; i < count; ++i) {
- switch (elements[i]) {
-
- case QPainterPath::MoveToElement:
- segments.append(VG_MOVE_TO_ABS); break;
-
- case QPainterPath::LineToElement:
- segments.append(VG_LINE_TO_ABS); break;
-
- case QPainterPath::CurveToElement:
- segments.append(VG_CUBIC_TO_ABS); break;
-
- case QPainterPath::CurveToDataElement: break;
-
- }
- }
- if (path.hasImplicitClose())
- segments.append(VG_CLOSE_PATH);
-
- vgAppendPathData(vgpath, segments.count(), segments.constData(),
- reinterpret_cast<const VGfloat *>(points));
-
- return vgpath;
- }
-
- // Sizes chosen so that drawRoundedRect() paths fit in these arrays.
- QVarLengthArray<VGfloat, 48> coords;
-
- int curvePos = 0;
- QPointF temp;
-
- if (elements && simpleTransform) {
- // Convert the members of the element array.
- for (int i = 0; i < count; ++i) {
- switch (elements[i]) {
-
- case QPainterPath::MoveToElement:
- {
- coords.append(points[0]);
- coords.append(points[1]);
- segments.append(VG_MOVE_TO_ABS);
- }
- break;
-
- case QPainterPath::LineToElement:
- {
- coords.append(points[0]);
- coords.append(points[1]);
- segments.append(VG_LINE_TO_ABS);
- }
- break;
-
- case QPainterPath::CurveToElement:
- {
- coords.append(points[0]);
- coords.append(points[1]);
- curvePos = 2;
- }
- break;
-
- case QPainterPath::CurveToDataElement:
- {
- coords.append(points[0]);
- coords.append(points[1]);
- curvePos += 2;
- if (curvePos == 6) {
- curvePos = 0;
- segments.append(VG_CUBIC_TO_ABS);
- }
- }
- break;
-
- }
- points += 2;
- }
- } else if (elements && !simpleTransform) {
- // Convert the members of the element array after applying the
- // current transform to the path locally.
- for (int i = 0; i < count; ++i) {
- switch (elements[i]) {
-
- case QPainterPath::MoveToElement:
- {
- temp = transform.map(QPointF(points[0], points[1]));
- coords.append(temp.x());
- coords.append(temp.y());
- segments.append(VG_MOVE_TO_ABS);
- }
- break;
-
- case QPainterPath::LineToElement:
- {
- temp = transform.map(QPointF(points[0], points[1]));
- coords.append(temp.x());
- coords.append(temp.y());
- segments.append(VG_LINE_TO_ABS);
- }
- break;
-
- case QPainterPath::CurveToElement:
- {
- temp = transform.map(QPointF(points[0], points[1]));
- coords.append(temp.x());
- coords.append(temp.y());
- curvePos = 2;
- }
- break;
-
- case QPainterPath::CurveToDataElement:
- {
- temp = transform.map(QPointF(points[0], points[1]));
- coords.append(temp.x());
- coords.append(temp.y());
- curvePos += 2;
- if (curvePos == 6) {
- curvePos = 0;
- segments.append(VG_CUBIC_TO_ABS);
- }
- }
- break;
-
- }
- points += 2;
- }
- } else if (count > 0 && simpleTransform) {
- // If there is no element array, then the path is assumed
- // to be a MoveTo followed by several LineTo's.
- coords.append(points[0]);
- coords.append(points[1]);
- segments.append(VG_MOVE_TO_ABS);
- while (count > 1) {
- points += 2;
- coords.append(points[0]);
- coords.append(points[1]);
- segments.append(VG_LINE_TO_ABS);
- --count;
- }
- } else if (count > 0 && !simpleTransform) {
- // Convert a simple path, and apply the transform locally.
- temp = transform.map(QPointF(points[0], points[1]));
- coords.append(temp.x());
- coords.append(temp.y());
- segments.append(VG_MOVE_TO_ABS);
- while (count > 1) {
- points += 2;
- temp = transform.map(QPointF(points[0], points[1]));
- coords.append(temp.x());
- coords.append(temp.y());
- segments.append(VG_LINE_TO_ABS);
- --count;
- }
- }
-
- // Close the path if specified.
- if (path.hasImplicitClose())
- segments.append(VG_CLOSE_PATH);
-
- vgAppendPathData(vgpath, segments.count(),
- segments.constData(), coords.constData());
-
- return vgpath;
-}
-
-VGPath QVGPaintEnginePrivate::painterPathToVGPath(const QPainterPath& path)
-{
- int count = path.elementCount();
-
- VGPath vgpath = vgCreatePath(VG_PATH_FORMAT_STANDARD,
- VG_PATH_DATATYPE_F,
- 1.0f, // scale
- 0.0f, // bias
- count + 1, // segmentCapacityHint
- count * 2, // coordCapacityHint
- VG_PATH_CAPABILITY_ALL);
-
- if (count == 0)
- return vgpath;
-
- const QPainterPath::Element *elements = &(path.elementAt(0));
-
- // Sizes chosen so that drawRoundedRect() paths fit in these arrays.
- QVarLengthArray<VGfloat, 48> coords;
- QVarLengthArray<VGubyte, 20> segments;
-
- int curvePos = 0;
- QPointF temp;
-
- // Keep track of the start and end of each sub-path. QPainterPath
- // does not have an "implicit close" flag like QVectorPath does.
- // We therefore have to detect closed paths by looking for a LineTo
- // element that connects back to the initial MoveTo element.
- qreal startx = 0.0;
- qreal starty = 0.0;
- qreal endx = 0.0;
- qreal endy = 0.0;
- bool haveStart = false;
- bool haveEnd = false;
-
- if (simpleTransform) {
- // Convert the members of the element array.
- for (int i = 0; i < count; ++i) {
- switch (elements[i].type) {
-
- case QPainterPath::MoveToElement:
- {
- if (haveStart && haveEnd && startx == endx && starty == endy) {
- // Implicitly close the previous sub-path.
- segments.append(VG_CLOSE_PATH);
- }
- startx = elements[i].x;
- starty = elements[i].y;
- coords.append(startx);
- coords.append(starty);
- haveStart = true;
- haveEnd = false;
- segments.append(VG_MOVE_TO_ABS);
- }
- break;
-
- case QPainterPath::LineToElement:
- {
- endx = elements[i].x;
- endy = elements[i].y;
- coords.append(endx);
- coords.append(endy);
- haveEnd = true;
- segments.append(VG_LINE_TO_ABS);
- }
- break;
-
- case QPainterPath::CurveToElement:
- {
- coords.append(elements[i].x);
- coords.append(elements[i].y);
- haveEnd = false;
- curvePos = 2;
- }
- break;
-
- case QPainterPath::CurveToDataElement:
- {
- coords.append(elements[i].x);
- coords.append(elements[i].y);
- haveEnd = false;
- curvePos += 2;
- if (curvePos == 6) {
- curvePos = 0;
- segments.append(VG_CUBIC_TO_ABS);
- }
- }
- break;
-
- }
- }
- } else {
- // Convert the members of the element array after applying the
- // current transform to the path locally.
- for (int i = 0; i < count; ++i) {
- switch (elements[i].type) {
-
- case QPainterPath::MoveToElement:
- {
- if (haveStart && haveEnd && startx == endx && starty == endy) {
- // Implicitly close the previous sub-path.
- segments.append(VG_CLOSE_PATH);
- }
- temp = transform.map(QPointF(elements[i].x, elements[i].y));
- startx = temp.x();
- starty = temp.y();
- coords.append(startx);
- coords.append(starty);
- haveStart = true;
- haveEnd = false;
- segments.append(VG_MOVE_TO_ABS);
- }
- break;
-
- case QPainterPath::LineToElement:
- {
- temp = transform.map(QPointF(elements[i].x, elements[i].y));
- endx = temp.x();
- endy = temp.y();
- coords.append(endx);
- coords.append(endy);
- haveEnd = true;
- segments.append(VG_LINE_TO_ABS);
- }
- break;
-
- case QPainterPath::CurveToElement:
- {
- temp = transform.map(QPointF(elements[i].x, elements[i].y));
- coords.append(temp.x());
- coords.append(temp.y());
- haveEnd = false;
- curvePos = 2;
- }
- break;
-
- case QPainterPath::CurveToDataElement:
- {
- temp = transform.map(QPointF(elements[i].x, elements[i].y));
- coords.append(temp.x());
- coords.append(temp.y());
- haveEnd = false;
- curvePos += 2;
- if (curvePos == 6) {
- curvePos = 0;
- segments.append(VG_CUBIC_TO_ABS);
- }
- }
- break;
-
- }
- }
- }
-
- if (haveStart && haveEnd && startx == endx && starty == endy) {
- // Implicitly close the last sub-path.
- segments.append(VG_CLOSE_PATH);
- }
-
- vgAppendPathData(vgpath, segments.count(),
- segments.constData(), coords.constData());
-
- return vgpath;
-}
-
-VGPath QVGPaintEnginePrivate::roundedRectPath(const QRectF &rect, qreal xRadius, qreal yRadius, Qt::SizeMode mode)
-{
- static VGubyte roundedrect_types[] = {
- VG_MOVE_TO_ABS,
- VG_LINE_TO_ABS,
- VG_CUBIC_TO_ABS,
- VG_LINE_TO_ABS,
- VG_CUBIC_TO_ABS,
- VG_LINE_TO_ABS,
- VG_CUBIC_TO_ABS,
- VG_LINE_TO_ABS,
- VG_CUBIC_TO_ABS,
- VG_CLOSE_PATH
- };
-
- qreal x1 = rect.left();
- qreal x2 = rect.right();
- qreal y1 = rect.top();
- qreal y2 = rect.bottom();
-
- if (mode == Qt::RelativeSize) {
- xRadius = xRadius * rect.width() / 200.;
- yRadius = yRadius * rect.height() / 200.;
- }
-
- xRadius = qMin(xRadius, rect.width() / 2);
- yRadius = qMin(yRadius, rect.height() / 2);
-
- VGfloat pts[] = {
- x1 + xRadius, y1, // MoveTo
- x2 - xRadius, y1, // LineTo
- x2 - (1 - KAPPA) * xRadius, y1, // CurveTo
- x2, y1 + (1 - KAPPA) * yRadius,
- x2, y1 + yRadius,
- x2, y2 - yRadius, // LineTo
- x2, y2 - (1 - KAPPA) * yRadius, // CurveTo
- x2 - (1 - KAPPA) * xRadius, y2,
- x2 - xRadius, y2,
- x1 + xRadius, y2, // LineTo
- x1 + (1 - KAPPA) * xRadius, y2, // CurveTo
- x1, y2 - (1 - KAPPA) * yRadius,
- x1, y2 - yRadius,
- x1, y1 + yRadius, // LineTo
- x1, y1 + (1 - KAPPA) * yRadius, // CurveTo
- x1 + (1 - KAPPA) * xRadius, y1,
- x1 + xRadius, y1
- };
-
-#if !defined(QVG_NO_MODIFY_PATH)
- VGPath vgpath = roundRectPath;
- if (!vgpath) {
- vgpath = vgCreatePath(VG_PATH_FORMAT_STANDARD,
- VG_PATH_DATATYPE_F,
- 1.0f, // scale
- 0.0f, // bias
- 10, // segmentCapacityHint
- 17 * 2, // coordCapacityHint
- VG_PATH_CAPABILITY_ALL);
- vgAppendPathData(vgpath, 10, roundedrect_types, pts);
- roundRectPath = vgpath;
- } else {
- vgModifyPathCoords(vgpath, 0, 9, pts);
- }
-#else
- VGPath vgpath = vgCreatePath(VG_PATH_FORMAT_STANDARD,
- VG_PATH_DATATYPE_F,
- 1.0f, // scale
- 0.0f, // bias
- 10, // segmentCapacityHint
- 17 * 2, // coordCapacityHint
- VG_PATH_CAPABILITY_ALL);
- vgAppendPathData(vgpath, 10, roundedrect_types, pts);
-#endif
-
- return vgpath;
-}
-
-Q_GUI_EXPORT QImage qt_imageForBrush(int style, bool invert);
-
-static QImage colorizeBitmap(const QImage &image, const QColor &color)
-{
- QImage sourceImage = image.convertToFormat(QImage::Format_MonoLSB);
- QImage dest = QImage(sourceImage.size(), QImage::Format_ARGB32_Premultiplied);
-
- QRgb fg = PREMUL(color.rgba());
- QRgb bg = 0;
-
- int height = sourceImage.height();
- int width = sourceImage.width();
- for (int y=0; y<height; ++y) {
- const uchar *source = sourceImage.constScanLine(y);
- QRgb *target = reinterpret_cast<QRgb *>(dest.scanLine(y));
- for (int x=0; x < width; ++x)
- target[x] = (source[x>>3] >> (x&7)) & 1 ? fg : bg;
- }
- return dest;
-}
-
-static VGImage toVGImage
- (const QImage & image, Qt::ImageConversionFlags flags = Qt::AutoColor)
-{
- QImage img(image);
-
- VGImageFormat format;
- switch (img.format()) {
- case QImage::Format_Mono:
- img = image.convertToFormat(QImage::Format_MonoLSB, flags);
- img.invertPixels();
- format = VG_BW_1;
- break;
- case QImage::Format_MonoLSB:
- img.invertPixels();
- format = VG_BW_1;
- break;
- case QImage::Format_RGB32:
- format = VG_sXRGB_8888;
- break;
- case QImage::Format_ARGB32:
- format = VG_sARGB_8888;
- break;
- case QImage::Format_ARGB32_Premultiplied:
- format = VG_sARGB_8888_PRE;
- break;
- case QImage::Format_RGB16:
- format = VG_sRGB_565;
- break;
- default:
- // Convert everything else into ARGB32_Premultiplied.
- img = image.convertToFormat(QImage::Format_ARGB32_Premultiplied, flags);
- format = VG_sARGB_8888_PRE;
- break;
- }
-
- const uchar *pixels = img.constBits();
-
- VGImage vgImg = QVGImagePool::instance()->createPermanentImage
- (format, img.width(), img.height(), VG_IMAGE_QUALITY_FASTER);
- vgImageSubData
- (vgImg, pixels, img.bytesPerLine(), format, 0, 0,
- img.width(), img.height());
-
- return vgImg;
-}
-
-static VGImage toVGImageSubRect
- (const QImage & image, const QRect& sr,
- Qt::ImageConversionFlags flags = Qt::AutoColor)
-{
- QImage img(image);
-
- VGImageFormat format;
- int bpp = 4;
-
- switch (img.format()) {
- case QImage::Format_Mono:
- case QImage::Format_MonoLSB:
- return VG_INVALID_HANDLE;
- case QImage::Format_RGB32:
- format = VG_sXRGB_8888;
- break;
- case QImage::Format_ARGB32:
- format = VG_sARGB_8888;
- break;
- case QImage::Format_ARGB32_Premultiplied:
- format = VG_sARGB_8888_PRE;
- break;
- case QImage::Format_RGB16:
- format = VG_sRGB_565;
- bpp = 2;
- break;
- default:
- // Convert everything else into ARGB32_Premultiplied.
- img = image.convertToFormat(QImage::Format_ARGB32_Premultiplied, flags);
- format = VG_sARGB_8888_PRE;
- break;
- }
-
- const uchar *pixels = img.constBits() + bpp * sr.x() +
- img.bytesPerLine() * sr.y();
-
- VGImage vgImg = QVGImagePool::instance()->createPermanentImage
- (format, sr.width(), sr.height(), VG_IMAGE_QUALITY_FASTER);
- vgImageSubData
- (vgImg, pixels, img.bytesPerLine(), format, 0, 0,
- sr.width(), sr.height());
-
- return vgImg;
-}
-
-static VGImage toVGImageWithOpacity(const QImage & image, qreal opacity)
-{
- QImage img(image.size(), QImage::Format_ARGB32_Premultiplied);
- img.fill(0);
- QPainter painter;
- painter.begin(&img);
- painter.setOpacity(opacity);
- painter.drawImage(0, 0, image);
- painter.end();
-
- const uchar *pixels = img.constBits();
-
- VGImage vgImg = QVGImagePool::instance()->createPermanentImage
- (VG_sARGB_8888_PRE, img.width(), img.height(), VG_IMAGE_QUALITY_FASTER);
- vgImageSubData
- (vgImg, pixels, img.bytesPerLine(), VG_sARGB_8888_PRE, 0, 0,
- img.width(), img.height());
-
- return vgImg;
-}
-
-static VGImage toVGImageWithOpacitySubRect
- (const QImage & image, qreal opacity, const QRect& sr)
-{
- QImage img(sr.size(), QImage::Format_ARGB32_Premultiplied);
- img.fill(0);
- QPainter painter;
- painter.begin(&img);
- painter.setOpacity(opacity);
- painter.drawImage(QPoint(0, 0), image, sr);
- painter.end();
-
- const uchar *pixels = img.constBits();
-
- VGImage vgImg = QVGImagePool::instance()->createPermanentImage
- (VG_sARGB_8888_PRE, img.width(), img.height(), VG_IMAGE_QUALITY_FASTER);
- vgImageSubData
- (vgImg, pixels, img.bytesPerLine(), VG_sARGB_8888_PRE, 0, 0,
- img.width(), img.height());
-
- return vgImg;
-}
-
-VGPaintType QVGPaintEnginePrivate::setBrush
- (VGPaint paint, const QBrush& brush, VGMatrixMode mode,
- VGPaintType prevType)
-{
- VGfloat values[5];
- setBrushTransform(brush, mode);
-
- // Reset the paint pattern on the brush, which will discard
- // the previous VGImage if one was set.
- if (prevType == VG_PAINT_TYPE_PATTERN || prevType == (VGPaintType)0)
- vgPaintPattern(paint, VG_INVALID_HANDLE);
-
- switch (brush.style()) {
-
- case Qt::SolidPattern: {
- // The brush is a solid color.
- QColor color(brush.color());
- values[0] = color.redF();
- values[1] = color.greenF();
- values[2] = color.blueF();
- values[3] = color.alphaF() * opacity;
- if (prevType != VG_PAINT_TYPE_COLOR)
- vgSetParameteri(paint, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR);
- vgSetParameterfv(paint, VG_PAINT_COLOR, 4, values);
- return VG_PAINT_TYPE_COLOR;
- }
-
- case Qt::LinearGradientPattern: {
- // The brush is a linear gradient.
- Q_ASSERT(brush.gradient()->type() == QGradient::LinearGradient);
- const QLinearGradient *grad =
- static_cast<const QLinearGradient*>(brush.gradient());
- values[0] = grad->start().x();
- values[1] = grad->start().y();
- values[2] = grad->finalStop().x();
- values[3] = grad->finalStop().y();
- if (prevType != VG_PAINT_TYPE_LINEAR_GRADIENT)
- vgSetParameteri(paint, VG_PAINT_TYPE, VG_PAINT_TYPE_LINEAR_GRADIENT);
- vgSetParameterfv(paint, VG_PAINT_LINEAR_GRADIENT, 4, values);
- setupColorRamp(grad, paint);
- return VG_PAINT_TYPE_LINEAR_GRADIENT;
- }
-
- case Qt::RadialGradientPattern: {
- // The brush is a radial gradient.
- Q_ASSERT(brush.gradient()->type() == QGradient::RadialGradient);
- const QRadialGradient *grad =
- static_cast<const QRadialGradient*>(brush.gradient());
- values[0] = grad->center().x();
- values[1] = grad->center().y();
- values[2] = grad->focalPoint().x();
- values[3] = grad->focalPoint().y();
- values[4] = grad->radius();
- if (prevType != VG_PAINT_TYPE_RADIAL_GRADIENT)
- vgSetParameteri(paint, VG_PAINT_TYPE, VG_PAINT_TYPE_RADIAL_GRADIENT);
- vgSetParameterfv(paint, VG_PAINT_RADIAL_GRADIENT, 5, values);
- setupColorRamp(grad, paint);
- return VG_PAINT_TYPE_RADIAL_GRADIENT;
- }
-
- case Qt::TexturePattern: {
- // The brush is a texture specified by a QPixmap/QImage.
- QPixmapData *pd = brush.texture().pixmapData();
- if (!pd)
- break; // null QPixmap
- VGImage vgImg;
- bool deref = false;
- if (pd->pixelType() == QPixmapData::BitmapType) {
- // Colorize bitmaps using the brush color and opacity.
- QColor color = brush.color();
- if (opacity != 1.0)
- color.setAlphaF(color.alphaF() * opacity);
- QImage image = colorizeBitmap(*(pd->buffer()), color);
- vgImg = toVGImage(image);
- deref = true;
- } else if (opacity == 1.0) {
- if (pd->classId() == QPixmapData::OpenVGClass) {
- QVGPixmapData *vgpd = static_cast<QVGPixmapData *>(pd);
- vgImg = vgpd->toVGImage();
-
- // We don't want the pool to reclaim this image
- // because we cannot predict when the paint object
- // will stop using it. Replacing the image with
- // new data will make the paint object invalid.
- vgpd->detachImageFromPool();
- } else {
- vgImg = toVGImage(*(pd->buffer()));
- deref = true;
- }
- } else if (pd->classId() == QPixmapData::OpenVGClass) {
- QVGPixmapData *vgpd = static_cast<QVGPixmapData *>(pd);
- vgImg = vgpd->toVGImage(opacity);
- vgpd->detachImageFromPool();
- } else {
- vgImg = toVGImageWithOpacity(*(pd->buffer()), opacity);
- deref = true;
- }
- if (vgImg == VG_INVALID_HANDLE)
- break;
- if (prevType != VG_PAINT_TYPE_PATTERN)
- vgSetParameteri(paint, VG_PAINT_TYPE, VG_PAINT_TYPE_PATTERN);
- vgSetParameteri(paint, VG_PAINT_PATTERN_TILING_MODE, VG_TILE_REPEAT);
- vgPaintPattern(paint, vgImg);
- if (deref)
- vgDestroyImage(vgImg); // Will be valid until pattern is destroyed.
- return VG_PAINT_TYPE_PATTERN;
- }
-
- case Qt::ConicalGradientPattern: {
- // Convert conical gradients into the first stop color.
- qWarning() << "QVGPaintEnginePrivate::setBrush: conical gradients are not supported by OpenVG";
- Q_ASSERT(brush.gradient()->type() == QGradient::ConicalGradient);
- const QConicalGradient *grad =
- static_cast<const QConicalGradient*>(brush.gradient());
- const QGradientStops stops = grad->stops();
- QColor color;
- if (stops.size() > 0)
- color = stops[0].second;
- values[0] = color.redF();
- values[1] = color.greenF();
- values[2] = color.blueF();
- values[3] = color.alphaF() * opacity;
- if (prevType != VG_PAINT_TYPE_COLOR)
- vgSetParameteri(paint, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR);
- vgSetParameterfv(paint, VG_PAINT_COLOR, 4, values);
- return VG_PAINT_TYPE_COLOR;
- }
-
- case Qt::Dense1Pattern:
- case Qt::Dense2Pattern:
- case Qt::Dense3Pattern:
- case Qt::Dense4Pattern:
- case Qt::Dense5Pattern:
- case Qt::Dense6Pattern:
- case Qt::Dense7Pattern:
- case Qt::HorPattern:
- case Qt::VerPattern:
- case Qt::CrossPattern:
- case Qt::BDiagPattern:
- case Qt::FDiagPattern:
- case Qt::DiagCrossPattern: {
- // The brush is a traditional dotted or cross-hatched pattern brush.
- QColor color = brush.color();
- if (opacity != 1.0)
- color.setAlphaF(color.alphaF() * opacity);
- QImage image = colorizeBitmap
- (qt_imageForBrush(brush.style(), true), color);
- VGImage vgImg = toVGImage(image);
- if (prevType != VG_PAINT_TYPE_PATTERN)
- vgSetParameteri(paint, VG_PAINT_TYPE, VG_PAINT_TYPE_PATTERN);
- vgSetParameteri(paint, VG_PAINT_PATTERN_TILING_MODE, VG_TILE_REPEAT);
- vgPaintPattern(paint, vgImg);
- vgDestroyImage(vgImg); // Will stay valid until pattern is destroyed.
- return VG_PAINT_TYPE_PATTERN;
- }
-
- default: break;
- }
- return (VGPaintType)0;
-}
-
-void QVGPaintEnginePrivate::setPenParams(const QPen& pen)
-{
- // Note: OpenVG does not support zero-width or cosmetic pens,
- // so we have to simulate cosmetic pens by reversing the scale.
- VGfloat width = pen.widthF();
- if (width <= 0.0f)
- width = 1.0f;
- if (pen.isCosmetic()) {
- if (penScale != 1.0 && penScale != 0.0)
- width /= penScale;
- }
- vgSetf(VG_STROKE_LINE_WIDTH, width);
-
- if (pen.capStyle() == Qt::FlatCap)
- vgSetf(VG_STROKE_CAP_STYLE, VG_CAP_BUTT);
- else if (pen.capStyle() == Qt::SquareCap)
- vgSetf(VG_STROKE_CAP_STYLE, VG_CAP_SQUARE);
- else
- vgSetf(VG_STROKE_CAP_STYLE, VG_CAP_ROUND);
-
- if (pen.joinStyle() == Qt::MiterJoin) {
- vgSetf(VG_STROKE_JOIN_STYLE, VG_JOIN_MITER);
- vgSetf(VG_STROKE_MITER_LIMIT, pen.miterLimit());
- } else if (pen.joinStyle() == Qt::BevelJoin) {
- vgSetf(VG_STROKE_JOIN_STYLE, VG_JOIN_BEVEL);
- } else {
- vgSetf(VG_STROKE_JOIN_STYLE, VG_JOIN_ROUND);
- }
-
- if (pen.style() == Qt::SolidLine) {
- vgSetfv(VG_STROKE_DASH_PATTERN, 0, NULL);
- } else {
- const QVector<qreal> dashPattern = pen.dashPattern();
- QVector<VGfloat> currentDashPattern(dashPattern.count());
- for (int i = 0; i < dashPattern.count(); ++i)
- currentDashPattern[i] = dashPattern[i] * width;
- vgSetfv(VG_STROKE_DASH_PATTERN, currentDashPattern.count(), currentDashPattern.data());
- vgSetf(VG_STROKE_DASH_PHASE, pen.dashOffset());
- vgSetf(VG_STROKE_DASH_PHASE_RESET, VG_FALSE);
- }
-}
-
-void QVGPaintEnginePrivate::setBrushTransform
- (const QBrush& brush, VGMatrixMode mode)
-{
- // Compute the new brush transformation matrix.
- QTransform transform(brush.transform());
- if (brushOrigin.x() != 0.0f || brushOrigin.y() != 0.0f)
- transform.translate(brushOrigin.x(), brushOrigin.y());
-
- // Bail out if the matrix is the same as last time, to avoid
- // updating the VG context state unless absolutely necessary.
- // Most applications won't have a brush transformation set,
- // which will leave the VG setting at its default of identity.
- // Always change the transform if coming out of raw VG mode.
- if (mode == VG_MATRIX_FILL_PAINT_TO_USER) {
- if (!rawVG && transform == brushTransform)
- return;
- brushTransform = transform;
- } else {
- if (!rawVG && transform == penTransform)
- return;
- penTransform = transform;
- }
-
- // Set the brush transformation matrix.
- if (mode != matrixMode) {
- vgSeti(VG_MATRIX_MODE, mode);
- matrixMode = mode;
- }
- if (transform.isIdentity()) {
- vgLoadIdentity();
- } else {
- VGfloat mat[9];
- mat[0] = transform.m11();
- mat[1] = transform.m12();
- mat[2] = transform.m13();
- mat[3] = transform.m21();
- mat[4] = transform.m22();
- mat[5] = transform.m23();
- mat[6] = transform.m31();
- mat[7] = transform.m32();
- mat[8] = transform.m33();
- vgLoadMatrix(mat);
- }
-}
-
-void QVGPaintEnginePrivate::setupColorRamp(const QGradient *grad, VGPaint paint)
-{
- QGradient::Spread spread = grad->spread();
- VGColorRampSpreadMode spreadMode;
- if (spread == QGradient::ReflectSpread)
- spreadMode = VG_COLOR_RAMP_SPREAD_REFLECT;
- else if (spread == QGradient::RepeatSpread)
- spreadMode = VG_COLOR_RAMP_SPREAD_REPEAT;
- else
- spreadMode = VG_COLOR_RAMP_SPREAD_PAD;
-
- const QGradientStops stops = grad->stops();
- int n = 5*stops.size();
- QVector<VGfloat> fill_stops(n);
-
- for (int i = 0; i < stops.size(); ++i ) {
- QColor col = stops[i].second;
- fill_stops[i*5] = stops[i].first;
- fill_stops[i*5 + 1] = col.redF();
- fill_stops[i*5 + 2] = col.greenF();
- fill_stops[i*5 + 3] = col.blueF();
- fill_stops[i*5 + 4] = col.alphaF() * opacity;
- }
-
- vgSetParameteri(paint, VG_PAINT_COLOR_RAMP_SPREAD_MODE, spreadMode);
- vgSetParameteri(paint, VG_PAINT_COLOR_RAMP_PREMULTIPLIED, VG_FALSE);
- vgSetParameterfv(paint, VG_PAINT_COLOR_RAMP_STOPS, n, fill_stops.data());
-}
-
-QVGPainterState::QVGPainterState(QVGPainterState& other)
- : QPainterState(other),
- isNew(true), clipRegion(other.clipRegion),
- savedDirty(0)
-{
-}
-
-QVGPainterState::QVGPainterState()
- : isNew(true), savedDirty(0)
-{
-}
-
-QVGPainterState::~QVGPainterState()
-{
-}
-
-QVGPaintEngine::QVGPaintEngine()
- : QPaintEngineEx(*new QVGPaintEnginePrivate(this))
-{
-}
-
-QVGPaintEngine::QVGPaintEngine(QVGPaintEnginePrivate &data)
- : QPaintEngineEx(data)
-{
-}
-
-QVGPaintEngine::~QVGPaintEngine()
-{
-}
-
-QPainterState *QVGPaintEngine::createState(QPainterState *orig) const
-{
- if (!orig) {
- return new QVGPainterState();
- } else {
- Q_D(const QVGPaintEngine);
- QVGPaintEnginePrivate *d2 = const_cast<QVGPaintEnginePrivate*>(d);
- QVGPainterState *origState = static_cast<QVGPainterState *>(orig);
- origState->savedDirty = d2->dirty;
- d2->dirty = 0;
- return new QVGPainterState(*origState);
- }
-}
-
-void QVGPaintEnginePrivate::draw
- (VGPath path, const QPen& pen, const QBrush& brush, VGint rule)
-{
- VGbitfield mode = 0;
- if (qpen_style(pen) != Qt::NoPen && qbrush_style(qpen_brush(pen)) != Qt::NoBrush) {
- ensurePen(pen);
- mode |= VG_STROKE_PATH;
- }
- if (brush.style() != Qt::NoBrush) {
- ensureBrush(brush);
- setFillRule(rule);
- mode |= VG_FILL_PATH;
- }
- if (mode != 0) {
- ensurePathTransform();
- vgDrawPath(path, mode);
- }
-}
-
-void QVGPaintEnginePrivate::stroke(VGPath path, const QPen& pen)
-{
- if (pen.style() == Qt::NoPen)
- return;
- ensurePen(pen);
- ensurePathTransform();
- vgDrawPath(path, VG_STROKE_PATH);
-}
-
-void QVGPaintEnginePrivate::fill(VGPath path, const QBrush& brush, VGint rule)
-{
- if (brush.style() == Qt::NoBrush)
- return;
- ensureBrush(brush);
- setFillRule(rule);
- QPen savedPen = currentPen;
- currentPen = Qt::NoPen;
- ensurePathTransform();
- currentPen = savedPen;
- vgDrawPath(path, VG_FILL_PATH);
-}
-
-bool QVGPaintEngine::begin(QPaintDevice *pdev)
-{
- Q_UNUSED(pdev);
- Q_D(QVGPaintEngine);
-
- // Initialize the VG painting objects if we haven't done it yet.
- if (!d->penPaint)
- d->initObjects();
-
- // The initial clip region is the entire device area.
- QVGPainterState *s = state();
- s->clipRegion = defaultClipRegion();
-
- // Initialize the VG state for this paint operation.
- restoreState(QPaintEngine::AllDirty);
- d->dirty = 0;
- d->rawVG = false;
- return true;
-}
-
-bool QVGPaintEngine::end()
-{
- return true;
-}
-
-void QVGPaintEngine::draw(const QVectorPath &path)
-{
- Q_D(QVGPaintEngine);
- QVGPainterState *s = state();
- VGPath vgpath = d->vectorPathToVGPath(path);
- if (!path.hasWindingFill())
- d->draw(vgpath, s->pen, s->brush, VG_EVEN_ODD);
- else
- d->draw(vgpath, s->pen, s->brush, VG_NON_ZERO);
- vgDestroyPath(vgpath);
-}
-
-void QVGPaintEngine::fill(const QVectorPath &path, const QBrush &brush)
-{
- Q_D(QVGPaintEngine);
- VGPath vgpath = d->vectorPathToVGPath(path);
- if (!path.hasWindingFill())
- d->fill(vgpath, brush, VG_EVEN_ODD);
- else
- d->fill(vgpath, brush, VG_NON_ZERO);
- vgDestroyPath(vgpath);
-}
-
-void QVGPaintEngine::stroke(const QVectorPath &path, const QPen &pen)
-{
- Q_D(QVGPaintEngine);
- VGPath vgpath = d->vectorPathToVGPath(path);
- d->stroke(vgpath, pen);
- vgDestroyPath(vgpath);
-}
-
-// Determine if a co-ordinate transform is simple enough to allow
-// rectangle-based clipping with vgMask(). Simple transforms most
-// often result from origin translations.
-static inline bool clipTransformIsSimple(const QTransform& transform)
-{
- QTransform::TransformationType type = transform.type();
- if (type == QTransform::TxNone || type == QTransform::TxTranslate)
- return true;
- if (type == QTransform::TxRotate) {
- // Check for 0, 90, 180, and 270 degree rotations.
- // (0 might happen after 4 rotations of 90 degrees).
- qreal m11 = transform.m11();
- qreal m12 = transform.m12();
- qreal m21 = transform.m21();
- qreal m22 = transform.m22();
- if (m11 == 0.0f && m22 == 0.0f) {
- if (m12 == 1.0f && m21 == -1.0f)
- return true; // 90 degrees.
- else if (m12 == -1.0f && m21 == 1.0f)
- return true; // 270 degrees.
- } else if (m12 == 0.0f && m21 == 0.0f) {
- if (m11 == -1.0f && m22 == -1.0f)
- return true; // 180 degrees.
- else if (m11 == 1.0f && m22 == 1.0f)
- return true; // 0 degrees.
- }
- }
- return false;
-}
-
-#if defined(QVG_SCISSOR_CLIP)
-
-void QVGPaintEngine::clip(const QVectorPath &path, Qt::ClipOperation op)
-{
- Q_D(QVGPaintEngine);
- QVGPainterState *s = state();
-
- d->dirty |= QPaintEngine::DirtyClipRegion;
-
- if (op == Qt::NoClip) {
- s->clipRegion = defaultClipRegion();
- updateScissor();
- return;
- }
-
- // We aren't using masking, so handle simple QRectF's only.
- if (path.shape() == QVectorPath::RectangleHint &&
- path.elementCount() == 4 && clipTransformIsSimple(d->transform)) {
- // Clipping region that resulted from QPainter::setClipRect(QRectF).
- // Convert it into a QRect and apply.
- const qreal *points = path.points();
- QRectF rect(points[0], points[1], points[2] - points[0],
- points[5] - points[1]);
- clip(rect.toRect(), op);
- return;
- }
-
- // Try converting the path into a QRegion that tightly follows
- // the outline of the path we want to clip with.
- QRegion region;
- if (!path.isEmpty())
- region = QRegion(path.convertToPainterPath().toFillPolygon(QTransform()).toPolygon());
-
- switch (op) {
- case Qt::NoClip:
- {
- region = defaultClipRegion();
- }
- break;
-
- case Qt::ReplaceClip:
- {
- region = d->transform.map(region);
- }
- break;
-
- case Qt::IntersectClip:
- {
- region = s->clipRegion.intersect(d->transform.map(region));
- }
- break;
-
- case Qt::UniteClip:
- {
- region = s->clipRegion.unite(d->transform.map(region));
- }
- break;
- }
- if (region.numRects() <= d->maxScissorRects) {
- // We haven't reached the maximum scissor count yet, so we can
- // still make use of this region.
- s->clipRegion = region;
- updateScissor();
- return;
- }
-
- // The best we can do is clip to the bounding rectangle
- // of all control points.
- clip(path.controlPointRect().toRect(), op);
-}
-
-void QVGPaintEngine::clip(const QRect &rect, Qt::ClipOperation op)
-{
- Q_D(QVGPaintEngine);
- QVGPainterState *s = state();
-
- d->dirty |= QPaintEngine::DirtyClipRegion;
-
- switch (op) {
- case Qt::NoClip:
- {
- s->clipRegion = defaultClipRegion();
- }
- break;
-
- case Qt::ReplaceClip:
- {
- s->clipRegion = d->transform.map(QRegion(rect));
- }
- break;
-
- case Qt::IntersectClip:
- {
- s->clipRegion = s->clipRegion.intersect(d->transform.map(QRegion(rect)));
- }
- break;
-
- case Qt::UniteClip:
- {
- s->clipRegion = s->clipRegion.unite(d->transform.map(QRegion(rect)));
- }
- break;
- }
-
- updateScissor();
-}
-
-void QVGPaintEngine::clip(const QRegion ®ion, Qt::ClipOperation op)
-{
- Q_D(QVGPaintEngine);
- QVGPainterState *s = state();
-
- d->dirty |= QPaintEngine::DirtyClipRegion;
-
- switch (op) {
- case Qt::NoClip:
- {
- s->clipRegion = defaultClipRegion();
- }
- break;
-
- case Qt::ReplaceClip:
- {
- s->clipRegion = d->transform.map(region);
- }
- break;
-
- case Qt::IntersectClip:
- {
- s->clipRegion = s->clipRegion.intersect(d->transform.map(region));
- }
- break;
-
- case Qt::UniteClip:
- {
- s->clipRegion = s->clipRegion.unite(d->transform.map(region));
- }
- break;
- }
-
- updateScissor();
-}
-
-void QVGPaintEngine::clip(const QPainterPath &path, Qt::ClipOperation op)
-{
- QPaintEngineEx::clip(path, op);
-}
-
-#else // !QVG_SCISSOR_CLIP
-
-void QVGPaintEngine::clip(const QVectorPath &path, Qt::ClipOperation op)
-{
- Q_D(QVGPaintEngine);
-
- d->dirty |= QPaintEngine::DirtyClipRegion;
-
- if (op == Qt::NoClip) {
- d->maskValid = false;
- d->maskIsSet = true;
- d->scissorMask = false;
- d->maskRect = QRect();
- vgSeti(VG_MASKING, VG_FALSE);
- return;
- }
-
- // We don't have vgRenderToMask(), so handle simple QRectF's only.
- if (path.shape() == QVectorPath::RectangleHint &&
- path.elementCount() == 4 && clipTransformIsSimple(d->transform)) {
- // Clipping region that resulted from QPainter::setClipRect(QRectF).
- // Convert it into a QRect and apply.
- const qreal *points = path.points();
- QRectF rect(points[0], points[1], points[2] - points[0],
- points[5] - points[1]);
- clip(rect.toRect(), op);
- return;
- }
-
-#if !defined(QVG_NO_RENDER_TO_MASK)
- QPaintDevice *pdev = paintDevice();
- int width = pdev->width();
- int height = pdev->height();
-
- if (op == Qt::ReplaceClip) {
- vgMask(VG_INVALID_HANDLE, VG_CLEAR_MASK, 0, 0, width, height);
- d->maskRect = QRect();
- } else if (!d->maskValid) {
- d->ensureMask(this, width, height);
- }
-
- d->ensurePathTransform();
- VGPath vgpath = d->vectorPathToVGPath(path);
- switch (op) {
- case Qt::ReplaceClip:
- case Qt::UniteClip:
- vgRenderToMask(vgpath, VG_FILL_PATH, VG_UNION_MASK);
- break;
-
- case Qt::IntersectClip:
- vgRenderToMask(vgpath, VG_FILL_PATH, VG_INTERSECT_MASK);
- break;
-
- default: break;
- }
- vgDestroyPath(vgpath);
-
- vgSeti(VG_MASKING, VG_TRUE);
- d->maskValid = true;
- d->maskIsSet = false;
- d->scissorMask = false;
-#endif
-}
-
-void QVGPaintEngine::clip(const QRect &rect, Qt::ClipOperation op)
-{
- Q_D(QVGPaintEngine);
-
- d->dirty |= QPaintEngine::DirtyClipRegion;
-
- // If we have a non-simple transform, then use path-based clipping.
- if (op != Qt::NoClip && !clipTransformIsSimple(d->transform)) {
- QPaintEngineEx::clip(rect, op);
- return;
- }
-
- switch (op) {
- case Qt::NoClip:
- {
- d->maskValid = false;
- d->maskIsSet = true;
- d->scissorMask = false;
- d->maskRect = QRect();
- vgSeti(VG_MASKING, VG_FALSE);
- }
- break;
-
- case Qt::ReplaceClip:
- {
- QRect r = d->transform.mapRect(rect);
- if (isDefaultClipRect(r)) {
- // Replacing the clip with a full-window region is the
- // same as turning off clipping.
- if (d->maskValid)
- vgSeti(VG_MASKING, VG_FALSE);
- d->maskValid = false;
- d->maskIsSet = true;
- d->scissorMask = false;
- d->maskRect = QRect();
- } else {
- // Special case: if the intersection of the system
- // clip and "r" is a single rectangle, then use the
- // scissor for clipping. We try to avoid allocating a
- // QRegion copy on the heap for the test if we can.
- QRegion clip = d->systemClip; // Reference-counted, no alloc.
- QRect clipRect;
- if (clip.rectCount() == 1) {
- clipRect = clip.boundingRect().intersected(r);
- } else if (clip.isEmpty()) {
- clipRect = r;
- } else {
- clip = clip.intersect(r);
- if (clip.rectCount() != 1) {
- d->maskValid = false;
- d->maskIsSet = false;
- d->scissorMask = false;
- d->maskRect = QRect();
- d->modifyMask(this, VG_FILL_MASK, r);
- break;
- }
- clipRect = clip.boundingRect();
- }
- d->maskValid = false;
- d->maskIsSet = false;
- d->scissorMask = true;
- d->maskRect = clipRect;
- vgSeti(VG_MASKING, VG_FALSE);
- updateScissor();
- }
- }
- break;
-
- case Qt::IntersectClip:
- {
- QRect r = d->transform.mapRect(rect);
- if (!d->maskValid) {
- // Mask has not been used yet, so intersect with
- // the previous scissor-based region in maskRect.
- if (d->scissorMask)
- r = r.intersect(d->maskRect);
- if (isDefaultClipRect(r)) {
- // The clip is the full window, so turn off clipping.
- d->maskIsSet = true;
- d->maskRect = QRect();
- } else {
- // Activate the scissor on a smaller maskRect.
- d->maskIsSet = false;
- d->maskRect = r;
- }
- d->scissorMask = true;
- updateScissor();
- } else if (d->maskIsSet && isDefaultClipRect(r)) {
- // Intersecting a full-window clip with a full-window
- // region is the same as turning off clipping.
- if (d->maskValid)
- vgSeti(VG_MASKING, VG_FALSE);
- d->maskValid = false;
- d->maskIsSet = true;
- d->scissorMask = false;
- d->maskRect = QRect();
- } else {
- d->modifyMask(this, VG_INTERSECT_MASK, r);
- }
- }
- break;
-
- case Qt::UniteClip:
- {
- // If we already have a full-window clip, then uniting a
- // region with it will do nothing. Otherwise union.
- if (!(d->maskIsSet))
- d->modifyMask(this, VG_UNION_MASK, d->transform.mapRect(rect));
- }
- break;
- }
-}
-
-void QVGPaintEngine::clip(const QRegion ®ion, Qt::ClipOperation op)
-{
- Q_D(QVGPaintEngine);
-
- // Use the QRect case if the region consists of a single rectangle.
- if (region.rectCount() == 1) {
- clip(region.boundingRect(), op);
- return;
- }
-
- d->dirty |= QPaintEngine::DirtyClipRegion;
-
- // If we have a non-simple transform, then use path-based clipping.
- if (op != Qt::NoClip && !clipTransformIsSimple(d->transform)) {
- QPaintEngineEx::clip(region, op);
- return;
- }
-
- switch (op) {
- case Qt::NoClip:
- {
- d->maskValid = false;
- d->maskIsSet = true;
- d->scissorMask = false;
- d->maskRect = QRect();
- vgSeti(VG_MASKING, VG_FALSE);
- }
- break;
-
- case Qt::ReplaceClip:
- {
- QRegion r = d->transform.map(region);
- if (isDefaultClipRegion(r)) {
- // Replacing the clip with a full-window region is the
- // same as turning off clipping.
- if (d->maskValid)
- vgSeti(VG_MASKING, VG_FALSE);
- d->maskValid = false;
- d->maskIsSet = true;
- d->scissorMask = false;
- d->maskRect = QRect();
- } else {
- // Special case: if the intersection of the system
- // clip and the region is a single rectangle, then
- // use the scissor for clipping.
- QRegion clip = d->systemClip;
- if (clip.isEmpty())
- clip = r;
- else
- clip = clip.intersect(r);
- if (clip.rectCount() == 1) {
- d->maskValid = false;
- d->maskIsSet = false;
- d->scissorMask = true;
- d->maskRect = clip.boundingRect();
- vgSeti(VG_MASKING, VG_FALSE);
- updateScissor();
- } else {
- d->maskValid = false;
- d->maskIsSet = false;
- d->scissorMask = false;
- d->maskRect = QRect();
- d->modifyMask(this, VG_FILL_MASK, r);
- }
- }
- }
- break;
-
- case Qt::IntersectClip:
- {
- if (region.rectCount() != 1) {
- // If there is more than one rectangle, then intersecting
- // the rectangles one by one in modifyMask() will not give
- // the desired result. So fall back to path-based clipping.
- QPaintEngineEx::clip(region, op);
- return;
- }
- QRegion r = d->transform.map(region);
- if (d->maskIsSet && isDefaultClipRegion(r)) {
- // Intersecting a full-window clip with a full-window
- // region is the same as turning off clipping.
- if (d->maskValid)
- vgSeti(VG_MASKING, VG_FALSE);
- d->maskValid = false;
- d->maskIsSet = true;
- d->scissorMask = false;
- d->maskRect = QRect();
- } else {
- d->modifyMask(this, VG_INTERSECT_MASK, r);
- }
- }
- break;
-
- case Qt::UniteClip:
- {
- // If we already have a full-window clip, then uniting a
- // region with it will do nothing. Otherwise union.
- if (!(d->maskIsSet))
- d->modifyMask(this, VG_UNION_MASK, d->transform.map(region));
- }
- break;
- }
-}
-
-#if !defined(QVG_NO_RENDER_TO_MASK)
-
-// Copied from qpathclipper.cpp.
-static bool qt_vg_pathToRect(const QPainterPath &path, QRectF *rect)
-{
- if (path.elementCount() != 5)
- return false;
-
- const bool mightBeRect = path.elementAt(0).isMoveTo()
- && path.elementAt(1).isLineTo()
- && path.elementAt(2).isLineTo()
- && path.elementAt(3).isLineTo()
- && path.elementAt(4).isLineTo();
-
- if (!mightBeRect)
- return false;
-
- const qreal x1 = path.elementAt(0).x;
- const qreal y1 = path.elementAt(0).y;
-
- const qreal x2 = path.elementAt(1).x;
- const qreal y2 = path.elementAt(2).y;
-
- if (path.elementAt(1).y != y1)
- return false;
-
- if (path.elementAt(2).x != x2)
- return false;
-
- if (path.elementAt(3).x != x1 || path.elementAt(3).y != y2)
- return false;
-
- if (path.elementAt(4).x != x1 || path.elementAt(4).y != y1)
- return false;
-
- if (rect)
- *rect = QRectF(QPointF(x1, y1), QPointF(x2, y2));
-
- return true;
-}
-
-#endif
-
-void QVGPaintEngine::clip(const QPainterPath &path, Qt::ClipOperation op)
-{
-#if !defined(QVG_NO_RENDER_TO_MASK)
- Q_D(QVGPaintEngine);
-
- // If the path is a simple rectangle, then use clip(QRect) instead.
- QRectF simpleRect;
- if (qt_vg_pathToRect(path, &simpleRect)) {
- clip(simpleRect.toRect(), op);
- return;
- }
-
- d->dirty |= QPaintEngine::DirtyClipRegion;
-
- if (op == Qt::NoClip) {
- d->maskValid = false;
- d->maskIsSet = true;
- d->scissorMask = false;
- d->maskRect = QRect();
- vgSeti(VG_MASKING, VG_FALSE);
- return;
- }
-
- QPaintDevice *pdev = paintDevice();
- int width = pdev->width();
- int height = pdev->height();
-
- if (op == Qt::ReplaceClip) {
- vgMask(VG_INVALID_HANDLE, VG_CLEAR_MASK, 0, 0, width, height);
- d->maskRect = QRect();
- } else if (!d->maskValid) {
- d->ensureMask(this, width, height);
- }
-
- d->ensurePathTransform();
- VGPath vgpath = d->painterPathToVGPath(path);
- switch (op) {
- case Qt::ReplaceClip:
- case Qt::UniteClip:
- vgRenderToMask(vgpath, VG_FILL_PATH, VG_UNION_MASK);
- break;
-
- case Qt::IntersectClip:
- vgRenderToMask(vgpath, VG_FILL_PATH, VG_INTERSECT_MASK);
- break;
-
- default: break;
- }
- vgDestroyPath(vgpath);
-
- vgSeti(VG_MASKING, VG_TRUE);
- d->maskValid = true;
- d->maskIsSet = false;
- d->scissorMask = false;
-#else
- QPaintEngineEx::clip(path, op);
-#endif
-}
-
-void QVGPaintEnginePrivate::ensureMask
- (QVGPaintEngine *engine, int width, int height)
-{
- scissorMask = false;
- if (maskIsSet) {
- vgMask(VG_INVALID_HANDLE, VG_FILL_MASK, 0, 0, width, height);
- maskRect = QRect();
- } else {
- vgMask(VG_INVALID_HANDLE, VG_CLEAR_MASK, 0, 0, width, height);
- if (maskRect.isValid()) {
- vgMask(VG_INVALID_HANDLE, VG_FILL_MASK,
- maskRect.x(), height - maskRect.y() - maskRect.height(),
- maskRect.width(), maskRect.height());
- maskRect = QRect();
- engine->updateScissor();
- }
- }
-}
-
-void QVGPaintEnginePrivate::modifyMask
- (QVGPaintEngine *engine, VGMaskOperation op, const QRegion& region)
-{
- QPaintDevice *pdev = engine->paintDevice();
- int width = pdev->width();
- int height = pdev->height();
-
- if (!maskValid)
- ensureMask(engine, width, height);
-
- QVector<QRect> rects = region.rects();
- for (int i = 0; i < rects.size(); ++i) {
- vgMask(VG_INVALID_HANDLE, op,
- rects[i].x(), height - rects[i].y() - rects[i].height(),
- rects[i].width(), rects[i].height());
- }
-
- vgSeti(VG_MASKING, VG_TRUE);
- maskValid = true;
- maskIsSet = false;
- scissorMask = false;
-}
-
-void QVGPaintEnginePrivate::modifyMask
- (QVGPaintEngine *engine, VGMaskOperation op, const QRect& rect)
-{
- QPaintDevice *pdev = engine->paintDevice();
- int width = pdev->width();
- int height = pdev->height();
-
- if (!maskValid)
- ensureMask(engine, width, height);
-
- if (rect.isValid()) {
- vgMask(VG_INVALID_HANDLE, op,
- rect.x(), height - rect.y() - rect.height(),
- rect.width(), rect.height());
- }
-
- vgSeti(VG_MASKING, VG_TRUE);
- maskValid = true;
- maskIsSet = false;
- scissorMask = false;
-}
-
-#endif // !QVG_SCISSOR_CLIP
-
-void QVGPaintEngine::updateScissor()
-{
- Q_D(QVGPaintEngine);
-
- QRegion region = d->systemClip;
-
-#if defined(QVG_SCISSOR_CLIP)
- // Using the scissor to do clipping, so combine the systemClip
- // with the current painting clipRegion.
-
- if (d->maskValid) {
- vgSeti(VG_MASKING, VG_FALSE);
- d->maskValid = false;
- }
-
- QVGPainterState *s = state();
- if (s->clipEnabled) {
- if (region.isEmpty())
- region = s->clipRegion;
- else
- region = region.intersect(s->clipRegion);
- if (isDefaultClipRegion(region)) {
- // The scissor region is the entire drawing surface,
- // so there is no point doing any scissoring.
- vgSeti(VG_SCISSORING, VG_FALSE);
- d->scissorActive = false;
- d->scissorDirty = false;
- return;
- }
- } else
-#endif
- {
-#if !defined(QVG_SCISSOR_CLIP)
- // Combine the system clip with the simple mask rectangle.
- if (d->scissorMask) {
- if (region.isEmpty())
- region = d->maskRect;
- else
- region = region.intersect(d->maskRect);
- if (isDefaultClipRegion(region)) {
- // The scissor region is the entire drawing surface,
- // so there is no point doing any scissoring.
- vgSeti(VG_SCISSORING, VG_FALSE);
- d->scissorActive = false;
- d->scissorDirty = false;
- return;
- }
- } else
-#endif
-
- // Disable the scissor completely if the system clip is empty.
- if (region.isEmpty()) {
- vgSeti(VG_SCISSORING, VG_FALSE);
- d->scissorActive = false;
- d->scissorDirty = false;
- return;
- }
- }
-
- if (d->scissorActive && region == d->scissorRegion && !d->scissorDirty)
- return;
-
- QVector<QRect> rects = region.rects();
- int count = rects.count();
- if (count > d->maxScissorRects) {
-#if !defined(QVG_SCISSOR_CLIP)
- count = d->maxScissorRects;
-#else
- // Use masking
- int width = paintDevice()->width();
- int height = paintDevice()->height();
- vgMask(VG_INVALID_HANDLE, VG_CLEAR_MASK,
- 0, 0, width, height);
- for (int i = 0; i < rects.size(); ++i) {
- vgMask(VG_INVALID_HANDLE, VG_FILL_MASK,
- rects[i].x(), height - rects[i].y() - rects[i].height(),
- rects[i].width(), rects[i].height());
- }
-
- vgSeti(VG_SCISSORING, VG_FALSE);
- vgSeti(VG_MASKING, VG_TRUE);
- d->maskValid = true;
- d->maskIsSet = false;
- d->scissorMask = false;
- d->scissorActive = false;
- d->scissorDirty = false;
- d->scissorRegion = region;
- return;
-#endif
- }
-
- QVarLengthArray<VGint> params(count * 4);
- int height = paintDevice()->height();
- for (int i = 0; i < count; ++i) {
- params[i * 4 + 0] = rects[i].x();
- params[i * 4 + 1] = height - rects[i].y() - rects[i].height();
- params[i * 4 + 2] = rects[i].width();
- params[i * 4 + 3] = rects[i].height();
- }
-
- vgSetiv(VG_SCISSOR_RECTS, count * 4, params.data());
- vgSeti(VG_SCISSORING, VG_TRUE);
- d->scissorDirty = false;
- d->scissorActive = true;
- d->scissorRegion = region;
-}
-
-QRegion QVGPaintEngine::defaultClipRegion()
-{
- // The default clip region for a paint device is the whole drawing area.
- QPaintDevice *pdev = paintDevice();
- return QRegion(0, 0, pdev->width(), pdev->height());
-}
-
-bool QVGPaintEngine::isDefaultClipRegion(const QRegion& region)
-{
- if (region.rectCount() != 1)
- return false;
-
- QPaintDevice *pdev = paintDevice();
- int width = pdev->width();
- int height = pdev->height();
-
- QRect rect = region.boundingRect();
- return (rect.x() == 0 && rect.y() == 0 &&
- rect.width() == width && rect.height() == height);
-}
-
-bool QVGPaintEngine::isDefaultClipRect(const QRect& rect)
-{
- QPaintDevice *pdev = paintDevice();
- int width = pdev->width();
- int height = pdev->height();
-
- return (rect.x() == 0 && rect.y() == 0 &&
- rect.width() == width && rect.height() == height);
-}
-
-void QVGPaintEngine::clipEnabledChanged()
-{
-#if defined(QVG_SCISSOR_CLIP)
- vgSeti(VG_MASKING, VG_FALSE); // disable mask fallback
- updateScissor();
-#else
- Q_D(QVGPaintEngine);
- QVGPainterState *s = state();
- d->dirty |= QPaintEngine::DirtyClipEnabled;
- if (s->clipEnabled && s->clipOperation != Qt::NoClip) {
- // Replay the entire clip stack to put the mask into the right state.
- d->maskValid = false;
- d->maskIsSet = true;
- d->scissorMask = false;
- d->maskRect = QRect();
- s->clipRegion = defaultClipRegion();
- d->replayClipOperations();
- d->transform = s->transform();
- d->updateTransform(paintDevice());
- } else {
- vgSeti(VG_MASKING, VG_FALSE);
- d->maskValid = false;
- d->maskIsSet = false;
- d->scissorMask = false;
- d->maskRect = QRect();
- }
-#endif
-}
-
-void QVGPaintEngine::penChanged()
-{
- Q_D(QVGPaintEngine);
- d->dirty |= QPaintEngine::DirtyPen;
-}
-
-void QVGPaintEngine::brushChanged()
-{
- Q_D(QVGPaintEngine);
- d->dirty |= QPaintEngine::DirtyBrush;
-}
-
-void QVGPaintEngine::brushOriginChanged()
-{
- Q_D(QVGPaintEngine);
- d->dirty |= QPaintEngine::DirtyBrushOrigin;
- d->brushOrigin = state()->brushOrigin;
- d->forcePenChange = true;
- d->forceBrushChange = true;
-}
-
-void QVGPaintEngine::opacityChanged()
-{
- Q_D(QVGPaintEngine);
- d->dirty |= QPaintEngine::DirtyOpacity;
- d->opacity = state()->opacity;
- d->forcePenChange = true;
- d->forceBrushChange = true;
-}
-
-void QVGPaintEngine::compositionModeChanged()
-{
- Q_D(QVGPaintEngine);
- d->dirty |= QPaintEngine::DirtyCompositionMode;
-
- VGint vgMode = VG_BLEND_SRC_OVER;
-
- switch (state()->composition_mode) {
- case QPainter::CompositionMode_SourceOver:
- vgMode = VG_BLEND_SRC_OVER;
- break;
- case QPainter::CompositionMode_DestinationOver:
- vgMode = VG_BLEND_DST_OVER;
- break;
- case QPainter::CompositionMode_Source:
- vgMode = VG_BLEND_SRC;
- break;
- case QPainter::CompositionMode_SourceIn:
- vgMode = VG_BLEND_SRC_IN;
- break;
- case QPainter::CompositionMode_DestinationIn:
- vgMode = VG_BLEND_DST_IN;
- break;
- case QPainter::CompositionMode_Plus:
- vgMode = VG_BLEND_ADDITIVE;
- break;
- case QPainter::CompositionMode_Multiply:
- vgMode = VG_BLEND_MULTIPLY;
- break;
- case QPainter::CompositionMode_Screen:
- vgMode = VG_BLEND_SCREEN;
- break;
- case QPainter::CompositionMode_Darken:
- vgMode = VG_BLEND_DARKEN;
- break;
- case QPainter::CompositionMode_Lighten:
- vgMode = VG_BLEND_LIGHTEN;
- break;
- default:
- if (d->hasAdvancedBlending) {
- switch (state()->composition_mode) {
- case QPainter::CompositionMode_Overlay:
- vgMode = QVGPaintEnginePrivate::QT_VG_BLEND_OVERLAY_KHR;
- break;
- case QPainter::CompositionMode_ColorDodge:
- vgMode = QVGPaintEnginePrivate::QT_VG_BLEND_COLORDODGE_KHR;
- break;
- case QPainter::CompositionMode_ColorBurn:
- vgMode = QVGPaintEnginePrivate::QT_VG_BLEND_COLORBURN_KHR;
- break;
- case QPainter::CompositionMode_HardLight:
- vgMode = QVGPaintEnginePrivate::QT_VG_BLEND_HARDLIGHT_KHR;
- break;
- case QPainter::CompositionMode_SoftLight:
- vgMode = QVGPaintEnginePrivate::QT_VG_BLEND_SOFTLIGHT_KHR;
- break;
- case QPainter::CompositionMode_Difference:
- vgMode = QVGPaintEnginePrivate::QT_VG_BLEND_DIFFERENCE_KHR;
- break;
- case QPainter::CompositionMode_Exclusion:
- vgMode = QVGPaintEnginePrivate::QT_VG_BLEND_EXCLUSION_KHR;
- break;
- case QPainter::CompositionMode_SourceOut:
- vgMode = QVGPaintEnginePrivate::QT_VG_BLEND_SRC_OUT_KHR;
- break;
- case QPainter::CompositionMode_DestinationOut:
- vgMode = QVGPaintEnginePrivate::QT_VG_BLEND_DST_OUT_KHR;
- break;
- case QPainter::CompositionMode_SourceAtop:
- vgMode = QVGPaintEnginePrivate::QT_VG_BLEND_SRC_ATOP_KHR;
- break;
- case QPainter::CompositionMode_DestinationAtop:
- vgMode = QVGPaintEnginePrivate::QT_VG_BLEND_DST_ATOP_KHR;
- break;
- case QPainter::CompositionMode_Xor:
- vgMode = QVGPaintEnginePrivate::QT_VG_BLEND_XOR_KHR;
- break;
- default: break; // Fall back to VG_BLEND_SRC_OVER.
- }
- }
- if (vgMode == VG_BLEND_SRC_OVER)
- qWarning() << "QVGPaintEngine::compositionModeChanged unsupported mode" << state()->composition_mode;
- break;
- }
-
- d->setBlendMode(VGBlendMode(vgMode));
-}
-
-void QVGPaintEngine::renderHintsChanged()
-{
- Q_D(QVGPaintEngine);
- d->dirty |= QPaintEngine::DirtyHints;
-
- QPainter::RenderHints hints = state()->renderHints;
-
- VGRenderingQuality rq =
- (hints & QPainter::Antialiasing)
- ? VG_RENDERING_QUALITY_BETTER
- : VG_RENDERING_QUALITY_NONANTIALIASED;
- VGImageQuality iq =
- (hints & QPainter::SmoothPixmapTransform)
- ? VG_IMAGE_QUALITY_BETTER
- : VG_IMAGE_QUALITY_NONANTIALIASED;
-
- d->setRenderingQuality(rq);
- d->setImageQuality(iq);
-}
-
-void QVGPaintEngine::transformChanged()
-{
- Q_D(QVGPaintEngine);
- QVGPainterState *s = state();
- d->dirty |= QPaintEngine::DirtyTransform;
- d->transform = s->transform();
- qreal oldPenScale = d->penScale;
- d->updateTransform(paintDevice());
- if (d->penScale != oldPenScale)
- d->forcePenChange = true;
-}
-
-bool QVGPaintEngine::clearRect(const QRectF &rect, const QColor &color)
-{
- Q_D(QVGPaintEngine);
- QVGPainterState *s = state();
- if (!s->clipEnabled || s->clipOperation == Qt::NoClip) {
- QRect r = d->transform.mapRect(rect).toRect();
- int height = paintDevice()->height();
- if (d->clearColor != color || d->clearOpacity != s->opacity) {
- VGfloat values[4];
- values[0] = color.redF();
- values[1] = color.greenF();
- values[2] = color.blueF();
- values[3] = color.alphaF() * s->opacity;
- vgSetfv(VG_CLEAR_COLOR, 4, values);
- d->clearColor = color;
- d->clearOpacity = s->opacity;
- }
- vgClear(r.x(), height - r.y() - r.height(),
- r.width(), r.height());
- return true;
- }
- return false;
-}
-
-void QVGPaintEngine::fillRect(const QRectF &rect, const QBrush &brush)
-{
- Q_D(QVGPaintEngine);
-
- if (brush.style() == Qt::NoBrush)
- return;
-
- // Check to see if we can use vgClear() for faster filling.
- if (brush.style() == Qt::SolidPattern && brush.isOpaque() &&
- clipTransformIsSimple(d->transform) && d->opacity == 1.0f &&
- clearRect(rect, brush.color())) {
- return;
- }
-
-#if !defined(QVG_NO_MODIFY_PATH)
- VGfloat coords[8];
- if (d->simpleTransform) {
- coords[0] = rect.x();
- coords[1] = rect.y();
- coords[2] = rect.x() + rect.width();
- coords[3] = coords[1];
- coords[4] = coords[2];
- coords[5] = rect.y() + rect.height();
- coords[6] = coords[0];
- coords[7] = coords[5];
- } else {
- QPointF tl = d->transform.map(rect.topLeft());
- QPointF tr = d->transform.map(rect.topRight());
- QPointF bl = d->transform.map(rect.bottomLeft());
- QPointF br = d->transform.map(rect.bottomRight());
- coords[0] = tl.x();
- coords[1] = tl.y();
- coords[2] = tr.x();
- coords[3] = tr.y();
- coords[4] = br.x();
- coords[5] = br.y();
- coords[6] = bl.x();
- coords[7] = bl.y();
- }
- vgModifyPathCoords(d->rectPath, 0, 4, coords);
- d->fill(d->rectPath, brush);
-#else
- QPaintEngineEx::fillRect(rect, brush);
-#endif
-}
-
-void QVGPaintEngine::fillRect(const QRectF &rect, const QColor &color)
-{
- Q_D(QVGPaintEngine);
-
- // Check to see if we can use vgClear() for faster filling.
- if (clipTransformIsSimple(d->transform) && d->opacity == 1.0f && color.alpha() == 255 &&
- clearRect(rect, color)) {
- return;
- }
-
-#if !defined(QVG_NO_MODIFY_PATH)
- VGfloat coords[8];
- if (d->simpleTransform) {
- coords[0] = rect.x();
- coords[1] = rect.y();
- coords[2] = rect.x() + rect.width();
- coords[3] = coords[1];
- coords[4] = coords[2];
- coords[5] = rect.y() + rect.height();
- coords[6] = coords[0];
- coords[7] = coords[5];
- } else {
- QPointF tl = d->transform.map(rect.topLeft());
- QPointF tr = d->transform.map(rect.topRight());
- QPointF bl = d->transform.map(rect.bottomLeft());
- QPointF br = d->transform.map(rect.bottomRight());
- coords[0] = tl.x();
- coords[1] = tl.y();
- coords[2] = tr.x();
- coords[3] = tr.y();
- coords[4] = br.x();
- coords[5] = br.y();
- coords[6] = bl.x();
- coords[7] = bl.y();
- }
- vgModifyPathCoords(d->rectPath, 0, 4, coords);
- d->fill(d->rectPath, QBrush(color));
-#else
- QPaintEngineEx::fillRect(rect, QBrush(color));
-#endif
-}
-
-void QVGPaintEngine::drawRoundedRect(const QRectF &rect, qreal xrad, qreal yrad, Qt::SizeMode mode)
-{
- Q_D(QVGPaintEngine);
- if (d->simpleTransform) {
- QVGPainterState *s = state();
- VGPath vgpath = d->roundedRectPath(rect, xrad, yrad, mode);
- d->draw(vgpath, s->pen, s->brush);
-#if defined(QVG_NO_MODIFY_PATH)
- vgDestroyPath(vgpath);
-#endif
- } else {
- QPaintEngineEx::drawRoundedRect(rect, xrad, yrad, mode);
- }
-}
-
-void QVGPaintEngine::drawRects(const QRect *rects, int rectCount)
-{
-#if !defined(QVG_NO_MODIFY_PATH)
- Q_D(QVGPaintEngine);
- QVGPainterState *s = state();
- for (int i = 0; i < rectCount; ++i, ++rects) {
- VGfloat coords[8];
- if (d->simpleTransform) {
- coords[0] = rects->x();
- coords[1] = rects->y();
- coords[2] = rects->x() + rects->width();
- coords[3] = coords[1];
- coords[4] = coords[2];
- coords[5] = rects->y() + rects->height();
- coords[6] = coords[0];
- coords[7] = coords[5];
- } else {
- QPointF tl = d->transform.map(QPointF(rects->x(), rects->y()));
- QPointF tr = d->transform.map(QPointF(rects->x() + rects->width(),
- rects->y()));
- QPointF bl = d->transform.map(QPointF(rects->x(),
- rects->y() + rects->height()));
- QPointF br = d->transform.map(QPointF(rects->x() + rects->width(),
- rects->y() + rects->height()));
- coords[0] = tl.x();
- coords[1] = tl.y();
- coords[2] = tr.x();
- coords[3] = tr.y();
- coords[4] = br.x();
- coords[5] = br.y();
- coords[6] = bl.x();
- coords[7] = bl.y();
- }
- vgModifyPathCoords(d->rectPath, 0, 4, coords);
- d->draw(d->rectPath, s->pen, s->brush);
- }
-#else
- QPaintEngineEx::drawRects(rects, rectCount);
-#endif
-}
-
-void QVGPaintEngine::drawRects(const QRectF *rects, int rectCount)
-{
-#if !defined(QVG_NO_MODIFY_PATH)
- Q_D(QVGPaintEngine);
- QVGPainterState *s = state();
- for (int i = 0; i < rectCount; ++i, ++rects) {
- VGfloat coords[8];
- if (d->simpleTransform) {
- coords[0] = rects->x();
- coords[1] = rects->y();
- coords[2] = rects->x() + rects->width();
- coords[3] = coords[1];
- coords[4] = coords[2];
- coords[5] = rects->y() + rects->height();
- coords[6] = coords[0];
- coords[7] = coords[5];
- } else {
- QPointF tl = d->transform.map(rects->topLeft());
- QPointF tr = d->transform.map(rects->topRight());
- QPointF bl = d->transform.map(rects->bottomLeft());
- QPointF br = d->transform.map(rects->bottomRight());
- coords[0] = tl.x();
- coords[1] = tl.y();
- coords[2] = tr.x();
- coords[3] = tr.y();
- coords[4] = br.x();
- coords[5] = br.y();
- coords[6] = bl.x();
- coords[7] = bl.y();
- }
- vgModifyPathCoords(d->rectPath, 0, 4, coords);
- d->draw(d->rectPath, s->pen, s->brush);
- }
-#else
- QPaintEngineEx::drawRects(rects, rectCount);
-#endif
-}
-
-void QVGPaintEngine::drawLines(const QLine *lines, int lineCount)
-{
-#if !defined(QVG_NO_MODIFY_PATH)
- Q_D(QVGPaintEngine);
- QVGPainterState *s = state();
- for (int i = 0; i < lineCount; ++i, ++lines) {
- VGfloat coords[4];
- if (d->simpleTransform) {
- coords[0] = lines->x1();
- coords[1] = lines->y1();
- coords[2] = lines->x2();
- coords[3] = lines->y2();
- } else {
- QPointF p1 = d->transform.map(QPointF(lines->x1(), lines->y1()));
- QPointF p2 = d->transform.map(QPointF(lines->x2(), lines->y2()));
- coords[0] = p1.x();
- coords[1] = p1.y();
- coords[2] = p2.x();
- coords[3] = p2.y();
- }
- vgModifyPathCoords(d->linePath, 0, 2, coords);
- d->stroke(d->linePath, s->pen);
- }
-#else
- QPaintEngineEx::drawLines(lines, lineCount);
-#endif
-}
-
-void QVGPaintEngine::drawLines(const QLineF *lines, int lineCount)
-{
-#if !defined(QVG_NO_MODIFY_PATH)
- Q_D(QVGPaintEngine);
- QVGPainterState *s = state();
- for (int i = 0; i < lineCount; ++i, ++lines) {
- VGfloat coords[4];
- if (d->simpleTransform) {
- coords[0] = lines->x1();
- coords[1] = lines->y1();
- coords[2] = lines->x2();
- coords[3] = lines->y2();
- } else {
- QPointF p1 = d->transform.map(lines->p1());
- QPointF p2 = d->transform.map(lines->p2());
- coords[0] = p1.x();
- coords[1] = p1.y();
- coords[2] = p2.x();
- coords[3] = p2.y();
- }
- vgModifyPathCoords(d->linePath, 0, 2, coords);
- d->stroke(d->linePath, s->pen);
- }
-#else
- QPaintEngineEx::drawLines(lines, lineCount);
-#endif
-}
-
-void QVGPaintEngine::drawEllipse(const QRectF &r)
-{
- // Based on the description of vguEllipse() in the OpenVG specification.
- // We don't use vguEllipse(), to avoid unnecessary library dependencies.
- Q_D(QVGPaintEngine);
- if (d->simpleTransform) {
- QVGPainterState *s = state();
- VGPath path = vgCreatePath(VG_PATH_FORMAT_STANDARD,
- VG_PATH_DATATYPE_F,
- 1.0f, // scale
- 0.0f, // bias
- 4, // segmentCapacityHint
- 12, // coordCapacityHint
- VG_PATH_CAPABILITY_ALL);
- static VGubyte segments[4] = {
- VG_MOVE_TO_ABS,
- VG_SCCWARC_TO_REL,
- VG_SCCWARC_TO_REL,
- VG_CLOSE_PATH
- };
- VGfloat coords[12];
- VGfloat halfwid = r.width() / 2;
- VGfloat halfht = r.height() / 2;
- coords[0] = r.x() + r.width();
- coords[1] = r.y() + halfht;
- coords[2] = halfwid;
- coords[3] = halfht;
- coords[4] = 0.0f;
- coords[5] = -r.width();
- coords[6] = 0.0f;
- coords[7] = halfwid;
- coords[8] = halfht;
- coords[9] = 0.0f;
- coords[10] = r.width();
- coords[11] = 0.0f;
- vgAppendPathData(path, 4, segments, coords);
- d->draw(path, s->pen, s->brush);
- vgDestroyPath(path);
- } else {
- // The projective transform version of an ellipse is difficult.
- // Generate a QVectorPath containing cubic curves and transform that.
- QPaintEngineEx::drawEllipse(r);
- }
-}
-
-void QVGPaintEngine::drawEllipse(const QRect &r)
-{
- drawEllipse(QRectF(r));
-}
-
-void QVGPaintEngine::drawPath(const QPainterPath &path)
-{
- // Shortcut past the QPainterPath -> QVectorPath conversion,
- // converting the QPainterPath directly into a VGPath.
- Q_D(QVGPaintEngine);
- QVGPainterState *s = state();
- VGPath vgpath = d->painterPathToVGPath(path);
- if (path.fillRule() == Qt::OddEvenFill)
- d->draw(vgpath, s->pen, s->brush, VG_EVEN_ODD);
- else
- d->draw(vgpath, s->pen, s->brush, VG_NON_ZERO);
- vgDestroyPath(vgpath);
-}
-
-void QVGPaintEngine::drawPoints(const QPointF *points, int pointCount)
-{
-#if !defined(QVG_NO_MODIFY_PATH)
- Q_D(QVGPaintEngine);
-
- // Set up a new pen if necessary.
- QPen pen = state()->pen;
- if (pen.style() == Qt::NoPen)
- return;
- if (pen.capStyle() == Qt::FlatCap)
- pen.setCapStyle(Qt::SquareCap);
-
- for (int i = 0; i < pointCount; ++i, ++points) {
- VGfloat coords[4];
- if (d->simpleTransform) {
- coords[0] = points->x();
- coords[1] = points->y();
- coords[2] = coords[0];
- coords[3] = coords[1];
- } else {
- QPointF p = d->transform.map(*points);
- coords[0] = p.x();
- coords[1] = p.y();
- coords[2] = coords[0];
- coords[3] = coords[1];
- }
- vgModifyPathCoords(d->linePath, 0, 2, coords);
- d->stroke(d->linePath, pen);
- }
-#else
- QPaintEngineEx::drawPoints(points, pointCount);
-#endif
-}
-
-void QVGPaintEngine::drawPoints(const QPoint *points, int pointCount)
-{
-#if !defined(QVG_NO_MODIFY_PATH)
- Q_D(QVGPaintEngine);
-
- // Set up a new pen if necessary.
- QPen pen = state()->pen;
- if (pen.style() == Qt::NoPen)
- return;
- if (pen.capStyle() == Qt::FlatCap)
- pen.setCapStyle(Qt::SquareCap);
-
- for (int i = 0; i < pointCount; ++i, ++points) {
- VGfloat coords[4];
- if (d->simpleTransform) {
- coords[0] = points->x();
- coords[1] = points->y();
- coords[2] = coords[0];
- coords[3] = coords[1];
- } else {
- QPointF p = d->transform.map(QPointF(*points));
- coords[0] = p.x();
- coords[1] = p.y();
- coords[2] = coords[0];
- coords[3] = coords[1];
- }
- vgModifyPathCoords(d->linePath, 0, 2, coords);
- d->stroke(d->linePath, pen);
- }
-#else
- QPaintEngineEx::drawPoints(points, pointCount);
-#endif
-}
-
-void QVGPaintEngine::drawPolygon(const QPointF *points, int pointCount, PolygonDrawMode mode)
-{
- Q_D(QVGPaintEngine);
- QVGPainterState *s = state();
- VGPath path = vgCreatePath(VG_PATH_FORMAT_STANDARD,
- VG_PATH_DATATYPE_F,
- 1.0f, // scale
- 0.0f, // bias
- pointCount + 1, // segmentCapacityHint
- pointCount * 2, // coordCapacityHint
- VG_PATH_CAPABILITY_ALL);
- QVarLengthArray<VGfloat, 16> coords;
- QVarLengthArray<VGubyte, 10> segments;
- for (int i = 0; i < pointCount; ++i, ++points) {
- if (d->simpleTransform) {
- coords.append(points->x());
- coords.append(points->y());
- } else {
- QPointF temp = d->transform.map(*points);
- coords.append(temp.x());
- coords.append(temp.y());
- }
- if (i == 0)
- segments.append(VG_MOVE_TO_ABS);
- else
- segments.append(VG_LINE_TO_ABS);
- }
- if (mode != QPaintEngine::PolylineMode)
- segments.append(VG_CLOSE_PATH);
- vgAppendPathData(path, segments.count(),
- segments.constData(), coords.constData());
- switch (mode) {
- case QPaintEngine::WindingMode:
- d->draw(path, s->pen, s->brush, VG_NON_ZERO);
- break;
-
- case QPaintEngine::PolylineMode:
- d->stroke(path, s->pen);
- break;
-
- default:
- d->draw(path, s->pen, s->brush, VG_EVEN_ODD);
- break;
- }
- vgDestroyPath(path);
-}
-
-void QVGPaintEngine::drawPolygon(const QPoint *points, int pointCount, PolygonDrawMode mode)
-{
- Q_D(QVGPaintEngine);
- QVGPainterState *s = state();
- VGPath path = vgCreatePath(VG_PATH_FORMAT_STANDARD,
- VG_PATH_DATATYPE_F,
- 1.0f, // scale
- 0.0f, // bias
- pointCount + 1, // segmentCapacityHint
- pointCount * 2, // coordCapacityHint
- VG_PATH_CAPABILITY_ALL);
- QVarLengthArray<VGfloat, 16> coords;
- QVarLengthArray<VGubyte, 10> segments;
- for (int i = 0; i < pointCount; ++i, ++points) {
- if (d->simpleTransform) {
- coords.append(points->x());
- coords.append(points->y());
- } else {
- QPointF temp = d->transform.map(QPointF(*points));
- coords.append(temp.x());
- coords.append(temp.y());
- }
- if (i == 0)
- segments.append(VG_MOVE_TO_ABS);
- else
- segments.append(VG_LINE_TO_ABS);
- }
- if (mode != QPaintEngine::PolylineMode)
- segments.append(VG_CLOSE_PATH);
- vgAppendPathData(path, segments.count(),
- segments.constData(), coords.constData());
- switch (mode) {
- case QPaintEngine::WindingMode:
- d->draw(path, s->pen, s->brush, VG_NON_ZERO);
- break;
-
- case QPaintEngine::PolylineMode:
- d->stroke(path, s->pen);
- break;
-
- default:
- d->draw(path, s->pen, s->brush, VG_EVEN_ODD);
- break;
- }
- vgDestroyPath(path);
-}
-
-void QVGPaintEnginePrivate::setImageOptions()
-{
- if (opacity != 1.0f && simpleTransform) {
- if (opacity != paintOpacity) {
- VGfloat values[4];
- values[0] = 1.0f;
- values[1] = 1.0f;
- values[2] = 1.0f;
- values[3] = opacity;
- vgSetParameterfv(opacityPaint, VG_PAINT_COLOR, 4, values);
- paintOpacity = opacity;
- }
- if (fillPaint != opacityPaint) {
- vgSetPaint(opacityPaint, VG_FILL_PATH);
- fillPaint = opacityPaint;
- }
- setImageMode(VG_DRAW_IMAGE_MULTIPLY);
- } else {
- setImageMode(VG_DRAW_IMAGE_NORMAL);
- }
-}
-
-void QVGPaintEnginePrivate::systemStateChanged()
-{
- q->updateScissor();
-}
-
-static void drawVGImage(QVGPaintEnginePrivate *d,
- const QRectF& r, VGImage vgImg,
- const QSize& imageSize, const QRectF& sr)
-{
- if (vgImg == VG_INVALID_HANDLE)
- return;
- VGImage child = VG_INVALID_HANDLE;
-
- if (sr.topLeft().isNull() && sr.size() == imageSize) {
- child = vgImg;
- } else {
- QRect src = sr.toRect();
-#if !defined(QT_SHIVAVG)
- child = vgChildImage(vgImg, src.x(), src.y(), src.width(), src.height());
-#else
- child = vgImg; // XXX: ShivaVG doesn't have vgChildImage().
-#endif
- }
-
- QTransform transform(d->imageTransform);
- VGfloat scaleX = sr.width() == 0.0f ? 0.0f : r.width() / sr.width();
- VGfloat scaleY = sr.height() == 0.0f ? 0.0f : r.height() / sr.height();
- transform.translate(r.x(), r.y());
- transform.scale(scaleX, scaleY);
- d->setTransform(VG_MATRIX_IMAGE_USER_TO_SURFACE, transform);
-
- d->setImageOptions();
- vgDrawImage(child);
-
- if(child != vgImg)
- vgDestroyImage(child);
-}
-
-static void drawVGImage(QVGPaintEnginePrivate *d,
- const QPointF& pos, VGImage vgImg)
-{
- if (vgImg == VG_INVALID_HANDLE)
- return;
-
- QTransform transform(d->imageTransform);
- transform.translate(pos.x(), pos.y());
- d->setTransform(VG_MATRIX_IMAGE_USER_TO_SURFACE, transform);
-
- d->setImageOptions();
- vgDrawImage(vgImg);
-}
-
-static void drawImageTiled(QVGPaintEnginePrivate *d,
- const QRectF &r,
- const QImage &image,
- const QRectF &sr = QRectF())
-{
- const int minTileSize = 16;
- int tileWidth = 512;
- int tileHeight = tileWidth;
-
- VGImageFormat tileFormat = qt_vg_image_to_vg_format(image.format());
- VGImage tile = VG_INVALID_HANDLE;
- QVGImagePool *pool = QVGImagePool::instance();
- while (tile == VG_INVALID_HANDLE && tileWidth >= minTileSize) {
- tile = pool->createPermanentImage(tileFormat, tileWidth, tileHeight,
- VG_IMAGE_QUALITY_FASTER);
- if (tile == VG_INVALID_HANDLE) {
- tileWidth /= 2;
- tileHeight /= 2;
- }
- }
- if (tile == VG_INVALID_HANDLE) {
- qWarning("drawImageTiled: Failed to create %dx%d tile, giving up", tileWidth, tileHeight);
- return;
- }
-
- VGfloat opacityMatrix[20] = {
- 1.0f, 0.0f, 0.0f, 0.0f,
- 0.0f, 1.0f, 0.0f, 0.0f,
- 0.0f, 0.0f, 1.0f, 0.0f,
- 0.0f, 0.0f, 0.0f, d->opacity,
- 0.0f, 0.0f, 0.0f, 0.0f
- };
- VGImage tileWithOpacity = VG_INVALID_HANDLE;
- if (d->opacity != 1) {
- tileWithOpacity = pool->createPermanentImage(VG_sARGB_8888_PRE,
- tileWidth, tileHeight, VG_IMAGE_QUALITY_FASTER);
- if (tileWithOpacity == VG_INVALID_HANDLE)
- qWarning("drawImageTiled: Failed to create extra tile, ignoring opacity");
- }
-
- QRect sourceRect = sr.toRect();
- if (sourceRect.isNull())
- sourceRect = QRect(0, 0, image.width(), image.height());
-
- VGfloat scaleX = r.width() / sourceRect.width();
- VGfloat scaleY = r.height() / sourceRect.height();
-
- d->setImageOptions();
-
- for (int y = sourceRect.y(); y < sourceRect.height(); y += tileHeight) {
- int h = qMin(tileHeight, sourceRect.height() - y);
- if (h < 1)
- break;
- for (int x = sourceRect.x(); x < sourceRect.width(); x += tileWidth) {
- int w = qMin(tileWidth, sourceRect.width() - x);
- if (w < 1)
- break;
-
- int bytesPerPixel = image.depth() / 8;
- const uchar *sptr = image.constBits() + x * bytesPerPixel + y * image.bytesPerLine();
- vgImageSubData(tile, sptr, image.bytesPerLine(), tileFormat, 0, 0, w, h);
-
- QTransform transform(d->imageTransform);
- transform.translate(r.x() + x, r.y() + y);
- transform.scale(scaleX, scaleY);
- d->setTransform(VG_MATRIX_IMAGE_USER_TO_SURFACE, transform);
-
- VGImage actualTile = tile;
- if (tileWithOpacity != VG_INVALID_HANDLE) {
- vgColorMatrix(tileWithOpacity, actualTile, opacityMatrix);
- if (w < tileWidth || h < tileHeight)
- actualTile = vgChildImage(tileWithOpacity, 0, 0, w, h);
- else
- actualTile = tileWithOpacity;
- } else if (w < tileWidth || h < tileHeight) {
- actualTile = vgChildImage(tile, 0, 0, w, h);
- }
- vgDrawImage(actualTile);
-
- if (actualTile != tile && actualTile != tileWithOpacity)
- vgDestroyImage(actualTile);
- }
- }
-
- vgDestroyImage(tile);
- if (tileWithOpacity != VG_INVALID_HANDLE)
- vgDestroyImage(tileWithOpacity);
-}
-
-// Used by qpixmapfilter_vg.cpp to draw filtered VGImage's.
-void qt_vg_drawVGImage(QPainter *painter, const QPointF& pos, VGImage vgImg)
-{
- QVGPaintEngine *engine =
- static_cast<QVGPaintEngine *>(painter->paintEngine());
- drawVGImage(engine->vgPrivate(), pos, vgImg);
-}
-
-// Used by qpixmapfilter_vg.cpp to draw filtered VGImage's as a stencil.
-void qt_vg_drawVGImageStencil
- (QPainter *painter, const QPointF& pos, VGImage vgImg, const QBrush& brush)
-{
- QVGPaintEngine *engine =
- static_cast<QVGPaintEngine *>(painter->paintEngine());
-
- QVGPaintEnginePrivate *d = engine->vgPrivate();
-
- QTransform transform(d->imageTransform);
- transform.translate(pos.x(), pos.y());
- d->setTransform(VG_MATRIX_IMAGE_USER_TO_SURFACE, transform);
-
- d->ensureBrush(brush);
- d->setImageMode(VG_DRAW_IMAGE_STENCIL);
- vgDrawImage(vgImg);
-}
-
-bool QVGPaintEngine::canVgWritePixels(const QImage &image) const
-{
- Q_D(const QVGPaintEngine);
-
- // qt_vg_image_to_vg_format returns VG_sARGB_8888 as
- // fallback case if no matching VG format is found.
- // If given image format is not Format_ARGB32 and returned
- // format is VG_sARGB_8888, it means that no match was
- // found. In that case vgWritePixels cannot be used.
- // Also 1-bit formats cannot be used directly either.
- if ((image.format() != QImage::Format_ARGB32
- && qt_vg_image_to_vg_format(image.format()) == VG_sARGB_8888)
- || image.depth() == 1) {
- return false;
- }
-
- // vgWritePixels ignores masking, blending and xforms so we can only use it if
- // ALL of the following conditions are true:
- // - It is a simple translate, or a scale of -1 on the y-axis (inverted)
- // - The opacity is totally opaque
- // - The composition mode is "source" OR "source over" provided the image is opaque
- return ( d->imageTransform.type() <= QTransform::TxScale
- && d->imageTransform.m11() == 1.0 && qAbs(d->imageTransform.m22()) == 1.0)
- && d->opacity == 1.0f
- && (d->blendMode == VG_BLEND_SRC || (d->blendMode == VG_BLEND_SRC_OVER &&
- !image.hasAlphaChannel()));
-}
-
-void QVGPaintEngine::drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr)
-{
- QPixmapData *pd = pm.pixmapData();
- if (!pd)
- return; // null QPixmap
- if (pd->classId() == QPixmapData::OpenVGClass) {
- Q_D(QVGPaintEngine);
- QVGPixmapData *vgpd = static_cast<QVGPixmapData *>(pd);
- if (!vgpd->isValid())
- return;
- if (d->simpleTransform)
- drawVGImage(d, r, vgpd->toVGImage(), vgpd->size(), sr);
- else
- drawVGImage(d, r, vgpd->toVGImage(d->opacity), vgpd->size(), sr);
-
- if(!vgpd->failedToAlloc)
- return;
-
- // try to reallocate next time if reasonable small pixmap
- QSize screenSize = QApplication::desktop()->screenGeometry().size();
- if (pm.size().width() <= screenSize.width()
- && pm.size().height() <= screenSize.height())
- vgpd->failedToAlloc = false;
-
- vgpd->source.beginDataAccess();
- drawImage(r, vgpd->source.imageRef(), sr, Qt::AutoColor);
- vgpd->source.endDataAccess(true);
- } else {
- drawImage(r, *(pd->buffer()), sr, Qt::AutoColor);
- }
-}
-
-void QVGPaintEngine::drawPixmap(const QPointF &pos, const QPixmap &pm)
-{
- QPixmapData *pd = pm.pixmapData();
- if (!pd)
- return; // null QPixmap
- if (pd->classId() == QPixmapData::OpenVGClass) {
- Q_D(QVGPaintEngine);
- QVGPixmapData *vgpd = static_cast<QVGPixmapData *>(pd);
- if (!vgpd->isValid())
- return;
- if (d->simpleTransform)
- drawVGImage(d, pos, vgpd->toVGImage());
- else
- drawVGImage(d, pos, vgpd->toVGImage(d->opacity));
-
- if (!vgpd->failedToAlloc)
- return;
-
- // try to reallocate next time if reasonable small pixmap
- QSize screenSize = QApplication::desktop()->screenGeometry().size();
- if (pm.size().width() <= screenSize.width()
- && pm.size().height() <= screenSize.height())
- vgpd->failedToAlloc = false;
-
- vgpd->source.beginDataAccess();
- drawImage(pos, vgpd->source.imageRef());
- vgpd->source.endDataAccess(true);
- } else {
- drawImage(pos, *(pd->buffer()));
- }
-}
-
-void QVGPaintEngine::drawImage
- (const QRectF &r, const QImage &image, const QRectF &sr,
- Qt::ImageConversionFlags flags)
-{
- Q_D(QVGPaintEngine);
- if (image.isNull())
- return;
- VGImage vgImg;
- if (d->simpleTransform || d->opacity == 1.0f)
- vgImg = toVGImageSubRect(image, sr.toRect(), flags);
- else
- vgImg = toVGImageWithOpacitySubRect(image, d->opacity, sr.toRect());
- if (vgImg != VG_INVALID_HANDLE) {
- if (r.size() == sr.size()) {
- drawVGImage(d, r.topLeft(), vgImg);
- } else {
- drawVGImage(d, r, vgImg, sr.size().toSize(),
- QRectF(QPointF(0, 0), sr.size()));
- }
- } else {
- if (canVgWritePixels(image) && (r.size() == sr.size()) && !flags) {
- // Optimization for straight blits, no blending
- int x = sr.x();
- int y = sr.y();
- int bpp = image.depth() >> 3; // bytes
- int offset = 0;
- int bpl = image.bytesPerLine();
- if (d->imageTransform.m22() < 0) {
- // inverted
- offset = ((y + sr.height()) * bpl) - ((image.width() - x) * bpp);
- bpl = -bpl;
- } else {
- offset = (y * bpl) + (x * bpp);
- }
- const uchar *bits = image.constBits() + offset;
-
- QPointF mapped = d->imageTransform.map(r.topLeft());
- vgWritePixels(bits, bpl, qt_vg_image_to_vg_format(image.format()),
- mapped.x(), mapped.y() - sr.height(), r.width(), r.height());
- return;
- } else {
- // Monochrome images need to use the vgChildImage() path.
- vgImg = toVGImage(image, flags);
- if (vgImg == VG_INVALID_HANDLE)
- drawImageTiled(d, r, image, sr);
- else
- drawVGImage(d, r, vgImg, image.size(), sr);
- }
- }
- vgDestroyImage(vgImg);
-}
-
-void QVGPaintEngine::drawImage(const QPointF &pos, const QImage &image)
-{
- Q_D(QVGPaintEngine);
- if (image.isNull())
- return;
- VGImage vgImg;
- if (canVgWritePixels(image)) {
- // Optimization for straight blits, no blending
- bool inverted = (d->imageTransform.m22() < 0);
- const uchar *bits = inverted ? image.constBits() + image.byteCount() : image.constBits();
- int bpl = inverted ? -image.bytesPerLine() : image.bytesPerLine();
-
- QPointF mapped = d->imageTransform.map(pos);
- vgWritePixels(bits, bpl, qt_vg_image_to_vg_format(image.format()),
- mapped.x(), mapped.y() - image.height(), image.width(), image.height());
- return;
- } else if (d->simpleTransform || d->opacity == 1.0f) {
- vgImg = toVGImage(image);
- } else {
- vgImg = toVGImageWithOpacity(image, d->opacity);
- }
- if (vgImg == VG_INVALID_HANDLE)
- drawImageTiled(d, QRectF(pos, image.size()), image);
- else
- drawVGImage(d, pos, vgImg);
- vgDestroyImage(vgImg);
-}
-
-void QVGPaintEngine::drawTiledPixmap
- (const QRectF &r, const QPixmap &pixmap, const QPointF &s)
-{
- QBrush brush(state()->pen.color(), pixmap);
- QTransform xform = QTransform::fromTranslate(r.x() - s.x(), r.y() - s.y());
- brush.setTransform(xform);
- fillRect(r, brush);
-}
-
-// Best performance will be achieved with QDrawPixmaps::OpaqueHint
-// (i.e. no opacity), no rotation or scaling, and drawing the full
-// pixmap rather than parts of the pixmap. Even having just one of
-// these conditions will improve performance.
-void QVGPaintEngine::drawPixmapFragments(const QPainter::PixmapFragment *drawingData, int dataCount,
- const QPixmap &pixmap, QFlags<QPainter::PixmapFragmentHint> hints)
-{
-#if !defined(QT_SHIVAVG)
- Q_D(QVGPaintEngine);
-
- // If the pixmap is not VG, or the transformation is projective,
- // then fall back to the default implementation.
- QPixmapData *pd = pixmap.pixmapData();
- if (!pd)
- return; // null QPixmap
- if (pd->classId() != QPixmapData::OpenVGClass || !d->simpleTransform) {
- QPaintEngineEx::drawPixmapFragments(drawingData, dataCount, pixmap, hints);
- return;
- }
-
- // Bail out if nothing to do.
- if (dataCount <= 0)
- return;
-
- // Bail out if we don't have a usable VGImage for the pixmap.
- QVGPixmapData *vgpd = static_cast<QVGPixmapData *>(pd);
- if (!vgpd->isValid())
- return;
- VGImage vgImg = vgpd->toVGImage();
- if (vgImg == VG_INVALID_HANDLE)
- return;
-
- // We cache the results of any vgChildImage() calls because the
- // same child is very likely to be used over and over in particle
- // systems. However, performance is even better if vgChildImage()
- // isn't needed at all, so use full source rects where possible.
- QVarLengthArray<VGImage> cachedImages;
- QVarLengthArray<QRect> cachedSources;
-
- // Select the opacity paint object.
- if ((hints & QPainter::OpaqueHint) != 0 && d->opacity == 1.0f) {
- d->setImageMode(VG_DRAW_IMAGE_NORMAL);
- } else {
- hints = 0;
- if (d->fillPaint != d->opacityPaint) {
- vgSetPaint(d->opacityPaint, VG_FILL_PATH);
- d->fillPaint = d->opacityPaint;
- }
- }
-
- for (int i = 0; i < dataCount; ++i) {
- QTransform transform(d->imageTransform);
- transform.translate(drawingData[i].x, drawingData[i].y);
- transform.rotate(drawingData[i].rotation);
-
- VGImage child;
- QSize imageSize = vgpd->size();
- QRectF sr(drawingData[i].sourceLeft, drawingData[i].sourceTop,
- drawingData[i].width, drawingData[i].height);
- if (sr.topLeft().isNull() && sr.size() == imageSize) {
- child = vgImg;
- } else {
- // Look for a previous child with the same source rectangle
- // to avoid constantly calling vgChildImage()/vgDestroyImage().
- QRect src = sr.toRect();
- int j;
- for (j = 0; j < cachedSources.size(); ++j) {
- if (cachedSources[j] == src)
- break;
- }
- if (j < cachedSources.size()) {
- child = cachedImages[j];
- } else {
- child = vgChildImage
- (vgImg, src.x(), src.y(), src.width(), src.height());
- cachedImages.append(child);
- cachedSources.append(src);
- }
- }
-
- VGfloat scaleX = drawingData[i].scaleX;
- VGfloat scaleY = drawingData[i].scaleY;
- transform.translate(-0.5 * scaleX * sr.width(),
- -0.5 * scaleY * sr.height());
- transform.scale(scaleX, scaleY);
- d->setTransform(VG_MATRIX_IMAGE_USER_TO_SURFACE, transform);
-
- if ((hints & QPainter::OpaqueHint) == 0) {
- qreal opacity = d->opacity * drawingData[i].opacity;
- if (opacity != 1.0f) {
- if (d->paintOpacity != opacity) {
- VGfloat values[4];
- values[0] = 1.0f;
- values[1] = 1.0f;
- values[2] = 1.0f;
- values[3] = opacity;
- d->paintOpacity = opacity;
- vgSetParameterfv
- (d->opacityPaint, VG_PAINT_COLOR, 4, values);
- }
- d->setImageMode(VG_DRAW_IMAGE_MULTIPLY);
- } else {
- d->setImageMode(VG_DRAW_IMAGE_NORMAL);
- }
- }
-
- vgDrawImage(child);
- }
-
- // Destroy the cached child sub-images.
- for (int i = 0; i < cachedImages.size(); ++i)
- vgDestroyImage(cachedImages[i]);
-#else
- QPaintEngineEx::drawPixmapFragments(drawingData, dataCount, pixmap, hints);
-#endif
-}
-
-QVGFontEngineCleaner::QVGFontEngineCleaner(QVGPaintEnginePrivate *d)
- : QObject(), d_ptr(d)
-{
-}
-
-QVGFontEngineCleaner::~QVGFontEngineCleaner()
-{
-}
-
-void QVGFontEngineCleaner::fontEngineDestroyed()
-{
-#if !defined(QVG_NO_DRAW_GLYPHS)
- QFontEngine *engine = static_cast<QFontEngine *>(sender());
- QVGFontCache::Iterator it = d_ptr->fontCache.find(engine);
- if (it != d_ptr->fontCache.end()) {
- delete it.value();
- d_ptr->fontCache.erase(it);
- }
-#endif
-}
-
-#if !defined(QVG_NO_DRAW_GLYPHS)
-
-QVGFontGlyphCache::QVGFontGlyphCache()
-{
- font = vgCreateFont(0);
- scaleX = scaleY = 0.0;
- invertedGlyphs = false;
- memset(cachedGlyphsMask, 0, sizeof(cachedGlyphsMask));
-}
-
-QVGFontGlyphCache::~QVGFontGlyphCache()
-{
- if (font != VG_INVALID_HANDLE)
- vgDestroyFont(font);
-}
-
-void QVGFontGlyphCache::setScaleFromText(const QFont &font, QFontEngine *fontEngine)
-{
- QFontInfo fi(font);
- qreal pixelSize = fi.pixelSize();
- qreal emSquare = fontEngine->properties().emSquare.toReal();
- scaleX = scaleY = static_cast<VGfloat>(pixelSize / emSquare);
-}
-
-void QVGFontGlyphCache::cacheGlyphs(QVGPaintEnginePrivate *d,
- QFontEngine *fontEngine,
- const glyph_t *g, int count)
-{
- VGfloat origin[2];
- VGfloat escapement[2];
- glyph_metrics_t metrics;
- // Some Qt font engines don't set yoff in getUnscaledGlyph().
- // Zero the metric structure so that everything has a default value.
- memset(&metrics, 0, sizeof(metrics));
- while (count-- > 0) {
- // Skip this glyph if we have already cached it before.
- glyph_t glyph = *g++;
- if (glyph < 256) {
- if ((cachedGlyphsMask[glyph / 32] & (1 << (glyph % 32))) != 0)
- continue;
- cachedGlyphsMask[glyph / 32] |= (1 << (glyph % 32));
- } else if (cachedGlyphs.contains(glyph)) {
- continue;
- } else {
- cachedGlyphs.insert(glyph);
- }
-#if !defined(QVG_NO_IMAGE_GLYPHS)
- Q_UNUSED(d);
- QImage scaledImage = fontEngine->alphaMapForGlyph(glyph);
- VGImage vgImage = VG_INVALID_HANDLE;
- metrics = fontEngine->boundingBox(glyph);
- if (!scaledImage.isNull()) { // Not a space character
- if (scaledImage.format() == QImage::Format_Indexed8) {
- vgImage = vgCreateImage(VG_A_8, scaledImage.width(), scaledImage.height(), VG_IMAGE_QUALITY_FASTER);
- vgImageSubData(vgImage, scaledImage.constBits(), scaledImage.bytesPerLine(), VG_A_8, 0, 0, scaledImage.width(), scaledImage.height());
- } else if (scaledImage.format() == QImage::Format_Mono) {
- QImage img = scaledImage.convertToFormat(QImage::Format_Indexed8);
- vgImage = vgCreateImage(VG_A_8, img.width(), img.height(), VG_IMAGE_QUALITY_FASTER);
- vgImageSubData(vgImage, img.constBits(), img.bytesPerLine(), VG_A_8, 0, 0, img.width(), img.height());
- } else {
- QImage img = scaledImage.convertToFormat(QImage::Format_ARGB32_Premultiplied);
- vgImage = vgCreateImage(VG_sARGB_8888_PRE, img.width(), img.height(), VG_IMAGE_QUALITY_FASTER);
- vgImageSubData(vgImage, img.constBits(), img.bytesPerLine(), VG_sARGB_8888_PRE, 0, 0, img.width(), img.height());
- }
- }
- origin[0] = -metrics.x.toReal();
- origin[1] = -metrics.y.toReal();
- escapement[0] = 0;
- escapement[1] = 0;
- vgSetGlyphToImage(font, glyph, vgImage, origin, escapement);
- vgDestroyImage(vgImage); // Reduce reference count.
-#else
- // Calculate the path for the glyph and cache it.
- QPainterPath path;
- fontEngine->getUnscaledGlyph(glyph, &path, &metrics);
- VGPath vgPath;
- if (!path.isEmpty()) {
- vgPath = d->painterPathToVGPath(path);
- } else {
- // Probably a "space" character with no visible outline.
- vgPath = VG_INVALID_HANDLE;
- }
- origin[0] = 0;
- origin[1] = 0;
- escapement[0] = 0;
- escapement[1] = 0;
- vgSetGlyphToPath(font, glyph, vgPath, VG_FALSE, origin, escapement);
- vgDestroyPath(vgPath); // Reduce reference count.
-#endif // !defined(QVG_NO_IMAGE_GLYPHS)
- }
-}
-
-#endif // !defined(QVG_NO_DRAW_GLYPHS)
-
-void QVGPaintEngine::drawTextItem(const QPointF &p, const QTextItem &textItem)
-{
-#if !defined(QVG_NO_DRAW_GLYPHS)
- Q_D(QVGPaintEngine);
- const QTextItemInt &ti = static_cast<const QTextItemInt &>(textItem);
-
- // If we are not using a simple transform, then fall back
- // to the default Qt path stroking algorithm.
- if (!d->simpleTransform) {
- QPaintEngineEx::drawTextItem(p, textItem);
- return;
- }
-
- // Get the glyphs and positions associated with the text item.
- QVarLengthArray<QFixedPoint> positions;
- QVarLengthArray<glyph_t> glyphs;
- QTransform matrix;
- ti.fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions);
-
- if (!drawCachedGlyphs(glyphs.size(), glyphs.data(), ti.font(), ti.fontEngine, p, positions.data()))
- QPaintEngineEx::drawTextItem(p, textItem);
-#else
- // OpenGL 1.0 does not have support for VGFont and glyphs,
- // so fall back to the default Qt path stroking algorithm.
- QPaintEngineEx::drawTextItem(p, textItem);
-#endif
-}
-
-void QVGPaintEngine::drawStaticTextItem(QStaticTextItem *textItem)
-{
- drawCachedGlyphs(textItem->numGlyphs, textItem->glyphs, textItem->font, textItem->fontEngine(),
- QPointF(0, 0), textItem->glyphPositions);
-}
-
- bool QVGPaintEngine::drawCachedGlyphs(int numGlyphs, const glyph_t *glyphs, const QFont &font,
- QFontEngine *fontEngine, const QPointF &p,
- const QFixedPoint *positions)
- {
-#if !defined(QVG_NO_DRAW_GLYPHS)
- Q_D(QVGPaintEngine);
-
- // Find the glyph cache for this font.
- QVGFontCache::ConstIterator it = d->fontCache.constFind(fontEngine);
- QVGFontGlyphCache *glyphCache;
- if (it != d->fontCache.constEnd()) {
- glyphCache = it.value();
- } else {
-#ifdef Q_OS_SYMBIAN
- glyphCache = new QSymbianVGFontGlyphCache();
-#else
- glyphCache = new QVGFontGlyphCache();
-#endif
- if (glyphCache->font == VG_INVALID_HANDLE) {
- qWarning("QVGPaintEngine::drawTextItem: OpenVG fonts are not supported by the OpenVG engine");
- delete glyphCache;
- return false;
- }
- glyphCache->setScaleFromText(font, fontEngine);
- d->fontCache.insert(fontEngine, glyphCache);
- if (!d->fontEngineCleaner)
- d->fontEngineCleaner = new QVGFontEngineCleaner(d);
- QObject::connect(fontEngine, SIGNAL(destroyed()),
- d->fontEngineCleaner, SLOT(fontEngineDestroyed()));
- }
-
- // Set the transformation to use for drawing the current glyphs.
- QTransform glyphTransform(d->pathTransform);
- if (d->transform.type() <= QTransform::TxTranslate) {
- // Prevent blurriness of unscaled, unrotated text by forcing integer coordinates.
- glyphTransform.translate(
- floor(p.x() + glyphTransform.dx() + aliasedCoordinateDelta) - glyphTransform.dx(),
- floor(p.y() - glyphTransform.dy() + aliasedCoordinateDelta) + glyphTransform.dy());
- } else {
- glyphTransform.translate(p.x(), p.y());
- }
-#if defined(QVG_NO_IMAGE_GLYPHS)
- glyphTransform.scale(glyphCache->scaleX, glyphCache->scaleY);
-#endif
-
- // Some glyph caches can create the VGImage upright
- if (glyphCache->invertedGlyphs)
- glyphTransform.scale(1, -1);
-
- d->setTransform(VG_MATRIX_GLYPH_USER_TO_SURFACE, glyphTransform);
-
- // Add the glyphs from the text item into the glyph cache.
- glyphCache->cacheGlyphs(d, fontEngine, glyphs, numGlyphs);
-
- // Create the array of adjustments between glyphs
- QVarLengthArray<VGfloat> adjustments_x(numGlyphs);
- QVarLengthArray<VGfloat> adjustments_y(numGlyphs);
- for (int i = 1; i < numGlyphs; ++i) {
- adjustments_x[i-1] = (positions[i].x - positions[i-1].x).round().toReal();
- adjustments_y[i-1] = (positions[i].y - positions[i-1].y).round().toReal();
- }
-
- // Set the glyph drawing origin.
- VGfloat origin[2];
- origin[0] = positions[0].x.round().toReal();
- origin[1] = positions[0].y.round().toReal();
- vgSetfv(VG_GLYPH_ORIGIN, 2, origin);
-
- // Fast anti-aliasing for paths, better for images.
-#if !defined(QVG_NO_IMAGE_GLYPHS)
- d->setImageQuality(VG_IMAGE_QUALITY_BETTER);
- d->setImageMode(VG_DRAW_IMAGE_STENCIL);
-#else
- d->setRenderingQuality(VG_RENDERING_QUALITY_FASTER);
-#endif
-
- // Draw the glyphs. We need to fill with the brush associated with
- // the Qt pen, not the Qt brush.
- d->ensureBrush(state()->pen.brush());
- vgDrawGlyphs(glyphCache->font, numGlyphs, (VGuint*)glyphs,
- adjustments_x.data(), adjustments_y.data(), VG_FILL_PATH, VG_TRUE);
- return true;
-#else
- Q_UNUSED(numGlyphs);
- Q_UNUSED(glyphs);
- Q_UNUSED(font);
- Q_UNUSED(fontEngine);
- Q_UNUSED(p);
- Q_UNUSED(positions);
- return false;
-#endif
-}
-
-void QVGPaintEngine::setState(QPainterState *s)
-{
- Q_D(QVGPaintEngine);
- QPaintEngineEx::setState(s);
- QVGPainterState *ps = static_cast<QVGPainterState *>(s);
- if (ps->isNew) {
- // Newly created state object. The call to setState()
- // will either be followed by a call to begin(), or we are
- // setting the state as part of a save().
- ps->isNew = false;
- } else {
- // This state object was set as part of a restore().
- restoreState(d->dirty);
- d->dirty = ps->savedDirty;
- }
-}
-
-void QVGPaintEngine::beginNativePainting()
-{
- Q_D(QVGPaintEngine);
-
- // About to enter raw VG mode: flush pending changes and make
- // sure that all matrices are set to the current transformation.
- QVGPainterState *s = this->state();
- d->ensurePen(s->pen);
- d->ensureBrush(s->brush);
- d->ensurePathTransform();
- d->setTransform(VG_MATRIX_IMAGE_USER_TO_SURFACE, d->imageTransform);
-#if !defined(QVG_NO_DRAW_GLYPHS)
- d->setTransform(VG_MATRIX_GLYPH_USER_TO_SURFACE, d->pathTransform);
-#endif
- d->rawVG = true;
-}
-
-void QVGPaintEngine::endNativePainting()
-{
- Q_D(QVGPaintEngine);
- // Exiting raw VG mode: force all state values to be
- // explicitly set on the VG engine to undo any changes
- // that were made by the raw VG function calls.
- QPaintEngine::DirtyFlags dirty = d->dirty;
- d->clearModes();
- d->forcePenChange = true;
- d->forceBrushChange = true;
- d->penType = (VGPaintType)0;
- d->brushType = (VGPaintType)0;
- d->clearColor = QColor();
- d->fillPaint = d->brushPaint;
- d->scissorDirty = true;
- restoreState(QPaintEngine::AllDirty);
- d->dirty = dirty;
- d->rawVG = false;
- vgSetPaint(d->penPaint, VG_STROKE_PATH);
- vgSetPaint(d->brushPaint, VG_FILL_PATH);
-}
-
-QPixmapFilter *QVGPaintEngine::pixmapFilter(int type, const QPixmapFilter *prototype)
-{
-#if !defined(QT_SHIVAVG)
- Q_D(QVGPaintEngine);
- switch (type) {
- case QPixmapFilter::ConvolutionFilter:
- if (!d->convolutionFilter)
- d->convolutionFilter.reset(new QVGPixmapConvolutionFilter);
- return d->convolutionFilter.data();
- case QPixmapFilter::ColorizeFilter:
- if (!d->colorizeFilter)
- d->colorizeFilter.reset(new QVGPixmapColorizeFilter);
- return d->colorizeFilter.data();
- case QPixmapFilter::DropShadowFilter:
- if (!d->dropShadowFilter)
- d->dropShadowFilter.reset(new QVGPixmapDropShadowFilter);
- return d->dropShadowFilter.data();
- case QPixmapFilter::BlurFilter:
- if (!d->blurFilter)
- d->blurFilter.reset(new QVGPixmapBlurFilter);
- return d->blurFilter.data();
- default: break;
- }
-#endif
- return QPaintEngineEx::pixmapFilter(type, prototype);
-}
-
-void QVGPaintEngine::restoreState(QPaintEngine::DirtyFlags dirty)
-{
- Q_D(QVGPaintEngine);
-
- // Restore the pen, brush, and other settings.
- if ((dirty & QPaintEngine::DirtyBrushOrigin) != 0)
- brushOriginChanged();
- d->fillRule = 0;
- if ((dirty & QPaintEngine::DirtyOpacity) != 0)
- opacityChanged();
- if ((dirty & QPaintEngine::DirtyTransform) != 0)
- transformChanged();
- if ((dirty & QPaintEngine::DirtyCompositionMode) != 0)
- compositionModeChanged();
- if ((dirty & QPaintEngine::DirtyHints) != 0)
- renderHintsChanged();
- if ((dirty & (QPaintEngine::DirtyClipRegion |
- QPaintEngine::DirtyClipPath |
- QPaintEngine::DirtyClipEnabled)) != 0) {
- d->maskValid = false;
- d->maskIsSet = false;
- d->scissorMask = false;
- d->maskRect = QRect();
- d->scissorDirty = true;
- clipEnabledChanged();
- }
-
-#if defined(QVG_SCISSOR_CLIP)
- if ((dirty & (QPaintEngine::DirtyClipRegion |
- QPaintEngine::DirtyClipPath |
- QPaintEngine::DirtyClipEnabled)) == 0) {
- updateScissor();
- }
-#else
- updateScissor();
-#endif
-}
-
-void QVGPaintEngine::fillRegion
- (const QRegion& region, const QColor& color, const QSize& surfaceSize)
-{
- Q_D(QVGPaintEngine);
- if (d->clearColor != color || d->clearOpacity != 1.0f) {
- VGfloat values[4];
- values[0] = color.redF();
- values[1] = color.greenF();
- values[2] = color.blueF();
- values[3] = color.alphaF();
- vgSetfv(VG_CLEAR_COLOR, 4, values);
- d->clearColor = color;
- d->clearOpacity = 1.0f;
- }
- if (region.rectCount() == 1) {
- QRect r = region.boundingRect();
- vgClear(r.x(), surfaceSize.height() - r.y() - r.height(),
- r.width(), r.height());
- } else {
- const QVector<QRect> rects = region.rects();
- for (int i = 0; i < rects.size(); ++i) {
- QRect r = rects.at(i);
- vgClear(r.x(), surfaceSize.height() - r.y() - r.height(),
- r.width(), r.height());
- }
- }
-}
-
-#if !defined(QVG_NO_SINGLE_CONTEXT) && !defined(QT_NO_EGL)
-
-QVGCompositionHelper::QVGCompositionHelper()
-{
- d = qt_vg_create_paint_engine()->vgPrivate();
-}
-
-QVGCompositionHelper::~QVGCompositionHelper()
-{
-}
-
-void QVGCompositionHelper::startCompositing(const QSize& screenSize)
-{
- this->screenSize = screenSize;
- clearScissor();
- d->setBlendMode(VG_BLEND_SRC_OVER);
-}
-
-void QVGCompositionHelper::endCompositing()
-{
- clearScissor();
-}
-
-void QVGCompositionHelper::blitWindow
- (VGImage image, const QSize& imageSize,
- const QRect& rect, const QPoint& topLeft, int opacity)
-{
- if (image == VG_INVALID_HANDLE)
- return;
-
- // Determine which sub rectangle of the window to draw.
- QRect sr = rect.translated(-topLeft);
-
- if (opacity >= 255) {
- // Fully opaque: use vgSetPixels() to directly copy the sub-region.
- int y = screenSize.height() - (rect.bottom() + 1);
- vgSetPixels(rect.x(), y, image, sr.x(),
- imageSize.height() - (sr.y() + sr.height()),
- sr.width(), sr.height());
- } else {
- // Extract the child image that we want to draw.
- VGImage child;
- if (sr.topLeft().isNull() && sr.size() == imageSize)
- child = image;
- else {
- child = vgChildImage
- (image, sr.x(), imageSize.height() - (sr.y() + sr.height()),
- sr.width(), sr.height());
- }
-
- // Set the image transform.
- QTransform transform;
- int y = screenSize.height() - (rect.bottom() + 1);
- transform.translate(rect.x() - 0.5f, y - 0.5f);
- d->setTransform(VG_MATRIX_IMAGE_USER_TO_SURFACE, transform);
-
- // Enable opacity for image drawing if necessary.
- if (opacity != d->paintOpacity) {
- VGfloat values[4];
- values[0] = 1.0f;
- values[1] = 1.0f;
- values[2] = 1.0f;
- values[3] = ((VGfloat)opacity) / 255.0f;
- vgSetParameterfv(d->opacityPaint, VG_PAINT_COLOR, 4, values);
- d->paintOpacity = values[3];
- }
- if (d->fillPaint != d->opacityPaint) {
- vgSetPaint(d->opacityPaint, VG_FILL_PATH);
- d->fillPaint = d->opacityPaint;
- }
- d->setImageMode(VG_DRAW_IMAGE_MULTIPLY);
-
- // Draw the child image.
- vgDrawImage(child);
-
- // Destroy the child image.
- if(child != image)
- vgDestroyImage(child);
- }
-}
-
-static void fillBackgroundRect(const QRect& rect, QVGPaintEnginePrivate *d)
-{
- VGfloat coords[8];
- coords[0] = rect.x();
- coords[1] = rect.y();
- coords[2] = rect.x() + rect.width();
- coords[3] = coords[1];
- coords[4] = coords[2];
- coords[5] = rect.y() + rect.height();
- coords[6] = coords[0];
- coords[7] = coords[5];
-#if !defined(QVG_NO_MODIFY_PATH)
- vgModifyPathCoords(d->rectPath, 0, 4, coords);
- vgDrawPath(d->rectPath, VG_FILL_PATH);
-#else
- Q_UNUSED(d);
- VGPath rectPath = vgCreatePath
- (VG_PATH_FORMAT_STANDARD,
- VG_PATH_DATATYPE_F,
- 1.0f, // scale
- 0.0f, // bias
- 5, // segmentCapacityHint
- 8, // coordCapacityHint
- VG_PATH_CAPABILITY_ALL);
- static VGubyte const segments[5] = {
- VG_MOVE_TO_ABS,
- VG_LINE_TO_ABS,
- VG_LINE_TO_ABS,
- VG_LINE_TO_ABS,
- VG_CLOSE_PATH
- };
- vgAppendPathData(rectPath, 5, segments, coords);
- vgDrawPath(rectPath, VG_FILL_PATH);
- vgDestroyPath(rectPath);
-#endif
-}
-
-void QVGCompositionHelper::fillBackground
- (const QRegion& region, const QBrush& brush)
-{
- if (brush.style() == Qt::SolidPattern) {
- // Use vgClear() to quickly fill the background.
- QColor color = brush.color();
- if (d->clearColor != color || d->clearOpacity != 1.0f) {
- VGfloat values[4];
- values[0] = color.redF();
- values[1] = color.greenF();
- values[2] = color.blueF();
- values[3] = color.alphaF();
- vgSetfv(VG_CLEAR_COLOR, 4, values);
- d->clearColor = color;
- d->clearOpacity = 1.0f;
- }
- if (region.rectCount() == 1) {
- QRect r = region.boundingRect();
- vgClear(r.x(), screenSize.height() - r.y() - r.height(),
- r.width(), r.height());
- } else {
- const QVector<QRect> rects = region.rects();
- for (int i = 0; i < rects.size(); ++i) {
- QRect r = rects.at(i);
- vgClear(r.x(), screenSize.height() - r.y() - r.height(),
- r.width(), r.height());
- }
- }
-
- } else {
- // Set the path transform to the default viewport transformation.
- VGfloat devh = screenSize.height();
- QTransform viewport(1.0f, 0.0f, 0.0f,
- 0.0f, -1.0f, 0.0f,
- 0.0f, devh, 1.0f);
- d->setTransform(VG_MATRIX_PATH_USER_TO_SURFACE, viewport);
-
- // Set the brush to use to fill the background.
- d->ensureBrush(brush);
- d->setFillRule(VG_EVEN_ODD);
-
- if (region.rectCount() == 1) {
- fillBackgroundRect(region.boundingRect(), d);
- } else {
- const QVector<QRect> rects = region.rects();
- for (int i = 0; i < rects.size(); ++i)
- fillBackgroundRect(rects.at(i), d);
- }
-
- // We will need to reset the path transform during the next paint.
- d->pathTransformSet = false;
- }
-}
-
-void QVGCompositionHelper::drawCursorPixmap
- (const QPixmap& pixmap, const QPoint& offset)
-{
- VGImage vgImage = VG_INVALID_HANDLE;
-
- // Fetch the VGImage from the pixmap if possible.
- QPixmapData *pd = pixmap.pixmapData();
- if (!pd)
- return; // null QPixmap
- if (pd->classId() == QPixmapData::OpenVGClass) {
- QVGPixmapData *vgpd = static_cast<QVGPixmapData *>(pd);
- if (vgpd->isValid())
- vgImage = vgpd->toVGImage();
- }
-
- // Set the image transformation and modes.
- VGfloat devh = screenSize.height();
- QTransform transform(1.0f, 0.0f, 0.0f,
- 0.0f, -1.0f, 0.0f,
- 0.0f, devh, 1.0f);
- transform.translate(offset.x(), offset.y());
- d->setTransform(VG_MATRIX_IMAGE_USER_TO_SURFACE, transform);
- d->setImageMode(VG_DRAW_IMAGE_NORMAL);
-
- // Draw the VGImage.
- if (vgImage != VG_INVALID_HANDLE) {
- vgDrawImage(vgImage);
- } else {
- QImage img = pixmap.toImage().convertToFormat
- (QImage::Format_ARGB32_Premultiplied);
-
- vgImage = vgCreateImage
- (VG_sARGB_8888_PRE, img.width(), img.height(),
- VG_IMAGE_QUALITY_FASTER);
- if (vgImage == VG_INVALID_HANDLE)
- return;
- vgImageSubData
- (vgImage, img.constBits() + img.bytesPerLine() * (img.height() - 1),
- -(img.bytesPerLine()), VG_sARGB_8888_PRE, 0, 0,
- img.width(), img.height());
-
- vgDrawImage(vgImage);
- vgDestroyImage(vgImage);
- }
-}
-
-void QVGCompositionHelper::setScissor(const QRegion& region)
-{
- QVector<QRect> rects = region.rects();
- int count = rects.count();
- if (count > d->maxScissorRects)
- count = d->maxScissorRects;
- QVarLengthArray<VGint> params(count * 4);
- int height = screenSize.height();
- for (int i = 0; i < count; ++i) {
- params[i * 4 + 0] = rects[i].x();
- params[i * 4 + 1] = height - rects[i].y() - rects[i].height();
- params[i * 4 + 2] = rects[i].width();
- params[i * 4 + 3] = rects[i].height();
- }
-
- vgSetiv(VG_SCISSOR_RECTS, count * 4, params.data());
- vgSeti(VG_SCISSORING, VG_TRUE);
- d->scissorDirty = false;
- d->scissorActive = true;
- d->scissorRegion = region;
-}
-
-void QVGCompositionHelper::clearScissor()
-{
- if (d->scissorActive || d->scissorDirty) {
- vgSeti(VG_SCISSORING, VG_FALSE);
- d->scissorActive = false;
- d->scissorDirty = false;
- }
-}
-
-#endif // !QVG_NO_SINGLE_CONTEXT && !QT_NO_EGL
-
-VGImageFormat qt_vg_image_to_vg_format(QImage::Format format)
-{
- switch (format) {
- case QImage::Format_MonoLSB:
- return VG_BW_1;
- case QImage::Format_Indexed8:
- return VG_sL_8;
- case QImage::Format_ARGB32_Premultiplied:
- return VG_sARGB_8888_PRE;
- case QImage::Format_RGB32:
- return VG_sXRGB_8888;
- case QImage::Format_ARGB32:
- return VG_sARGB_8888;
- case QImage::Format_RGB16:
- return VG_sRGB_565;
- case QImage::Format_ARGB4444_Premultiplied:
- return VG_sARGB_4444;
- default:
- break;
- }
- return VG_sARGB_8888; // XXX
-}
-
-QT_END_NAMESPACE
-
-#include "qpaintengine_vg.moc"