/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt SVG module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QSVGSTYLE_P_H #define QSVGSTYLE_P_H // // W A R N I N G // ------------- // // This file is not part of the Qt API. It exists purely as an // implementation detail. This header file may change from version to // version without notice, or even be removed. // // We mean it. // #include "QtGui/qpainter.h" #include "QtGui/qpen.h" #include "QtGui/qbrush.h" #include "QtGui/qtransform.h" #include "QtGui/qcolor.h" #include "QtGui/qfont.h" #include #include "qtsvgglobal_p.h" QT_BEGIN_NAMESPACE class QPainter; class QSvgNode; class QSvgFont; class QSvgTinyDocument; template class QSvgRefCounter { public: QSvgRefCounter() { t = 0; } QSvgRefCounter(T *_t) { t = _t; if (t) t->ref(); } QSvgRefCounter(const QSvgRefCounter &other) { t = other.t; if (t) t->ref(); } QSvgRefCounter &operator =(T *_t) { if(_t) _t->ref(); if (t) t->deref(); t = _t; return *this; } QSvgRefCounter &operator =(const QSvgRefCounter &other) { if(other.t) other.t->ref(); if (t) t->deref(); t = other.t; return *this; } ~QSvgRefCounter() { if (t) t->deref(); } inline T *operator->() const { return t; } inline operator T*() const { return t; } private: T *t; }; class Q_SVG_PRIVATE_EXPORT QSvgRefCounted { public: QSvgRefCounted() { _ref = 0; } virtual ~QSvgRefCounted() {} void ref() { ++_ref; // qDebug() << this << ": adding ref, now " << _ref; } void deref() { // qDebug() << this << ": removing ref, now " << _ref; if(!--_ref) { // qDebug(" deleting"); delete this; } } private: int _ref; }; struct Q_SVG_PRIVATE_EXPORT QSvgExtraStates { QSvgExtraStates(); qreal fillOpacity; qreal strokeOpacity; QSvgFont *svgFont; Qt::Alignment textAnchor; int fontWeight; Qt::FillRule fillRule; qreal strokeDashOffset; int nestedUseLevel = 0; int nestedUseCount = 0; bool vectorEffect; // true if pen is cosmetic }; class Q_SVG_PRIVATE_EXPORT QSvgStyleProperty : public QSvgRefCounted { public: enum Type { QUALITY, FILL, VIEWPORT_FILL, FONT, STROKE, SOLID_COLOR, GRADIENT, TRANSFORM, ANIMATE_TRANSFORM, ANIMATE_COLOR, OPACITY, COMP_OP }; public: virtual ~QSvgStyleProperty(); virtual void apply(QPainter *p, const QSvgNode *node, QSvgExtraStates &states) = 0; virtual void revert(QPainter *p, QSvgExtraStates &states) =0; virtual Type type() const=0; }; class Q_SVG_PRIVATE_EXPORT QSvgFillStyleProperty : public QSvgStyleProperty { public: virtual QBrush brush(QPainter *p, QSvgExtraStates &states) = 0; void apply(QPainter *p, const QSvgNode *node, QSvgExtraStates &states) override; void revert(QPainter *p, QSvgExtraStates &states) override; }; class Q_SVG_PRIVATE_EXPORT QSvgQualityStyle : public QSvgStyleProperty { public: QSvgQualityStyle(int color); void apply(QPainter *p, const QSvgNode *node, QSvgExtraStates &states) override; void revert(QPainter *p, QSvgExtraStates &states) override; Type type() const override; private: // color-render ing v v 'auto' | 'optimizeSpeed' | // 'optimizeQuality' | 'inherit' //int m_colorRendering; // shape-rendering v v 'auto' | 'optimizeSpeed' | 'crispEdges' | // 'geometricPrecision' | 'inherit' //QSvgShapeRendering m_shapeRendering; // text-rendering v v 'auto' | 'optimizeSpeed' | 'optimizeLegibility' // | 'geometricPrecision' | 'inherit' //QSvgTextRendering m_textRendering; // vector-effect v x 'default' | 'non-scaling-stroke' | 'inherit' //QSvgVectorEffect m_vectorEffect; // image-rendering v v 'auto' | 'optimizeSpeed' | 'optimizeQuality' | // 'inherit' //QSvgImageRendering m_imageRendering; }; class Q_SVG_PRIVATE_EXPORT QSvgOpacityStyle : public QSvgStyleProperty { public: QSvgOpacityStyle(qreal opacity); void apply(QPainter *p, const QSvgNode *node, QSvgExtraStates &states) override; void revert(QPainter *p, QSvgExtraStates &states) override; Type type() const override; private: qreal m_opacity; qreal m_oldOpacity; }; class Q_SVG_PRIVATE_EXPORT QSvgFillStyle : public QSvgStyleProperty { public: QSvgFillStyle(); void apply(QPainter *p, const QSvgNode *node, QSvgExtraStates &states) override; void revert(QPainter *p, QSvgExtraStates &states) override; Type type() const override; void setFillRule(Qt::FillRule f); void setFillOpacity(qreal opacity); void setFillStyle(QSvgFillStyleProperty* style); void setBrush(QBrush brush); const QBrush & qbrush() const { return m_fill; } qreal fillOpacity() const { return m_fillOpacity; } Qt::FillRule fillRule() const { return m_fillRule; } QSvgFillStyleProperty* style() const { return m_style; } void setGradientId(const QString &Id) { m_gradientId = Id; } QString gradientId() const { return m_gradientId; } void setGradientResolved(bool resolved) { m_gradientResolved = resolved; } bool isGradientResolved() const { return m_gradientResolved; } private: // fill v v 'inherit' | // fill-opacity v v 'inherit' | QBrush m_fill; QBrush m_oldFill; QSvgFillStyleProperty *m_style; Qt::FillRule m_fillRule; Qt::FillRule m_oldFillRule; qreal m_fillOpacity; qreal m_oldFillOpacity; QString m_gradientId; uint m_gradientResolved : 1; uint m_fillRuleSet : 1; uint m_fillOpacitySet : 1; uint m_fillSet : 1; }; class Q_SVG_PRIVATE_EXPORT QSvgViewportFillStyle : public QSvgStyleProperty { public: QSvgViewportFillStyle(const QBrush &brush); void apply(QPainter *p, const QSvgNode *node, QSvgExtraStates &states) override; void revert(QPainter *p, QSvgExtraStates &states) override; Type type() const override; const QBrush & qbrush() const { return m_viewportFill; } private: // viewport-fill v x 'inherit' | // viewport-fill-opacity v x 'inherit' | QBrush m_viewportFill; QBrush m_oldFill; }; class Q_SVG_PRIVATE_EXPORT QSvgFontStyle : public QSvgStyleProperty { public: static const int LIGHTER = -1; static const int BOLDER = 1; QSvgFontStyle(QSvgFont *font, QSvgTinyDocument *doc); QSvgFontStyle(); void apply(QPainter *p, const QSvgNode *node, QSvgExtraStates &states) override; void revert(QPainter *p, QSvgExtraStates &states) override; Type type() const override; void setSize(qreal size) { // Store the _pixel_ size in the font. Since QFont::setPixelSize() only takes an int, call // QFont::SetPointSize() instead. Set proper font size just before rendering. m_qfont.setPointSizeF(size); m_sizeSet = 1; } void setTextAnchor(Qt::Alignment anchor) { m_textAnchor = anchor; m_textAnchorSet = 1; } void setFamily(const QString &family) { m_qfont.setFamily(family); m_familySet = 1; } void setStyle(QFont::Style fontStyle) { m_qfont.setStyle(fontStyle); m_styleSet = 1; } void setVariant(QFont::Capitalization fontVariant) { m_qfont.setCapitalization(fontVariant); m_variantSet = 1; } static int SVGToQtWeight(int weight); void setWeight(int weight) { m_weight = weight; m_weightSet = 1; } QSvgFont * svgFont() const { return m_svgFont; } const QFont &qfont() const { return m_qfont; } QSvgTinyDocument *doc() const {return m_doc;} private: QSvgFont *m_svgFont; QSvgTinyDocument *m_doc; QFont m_qfont; int m_weight; Qt::Alignment m_textAnchor; QSvgFont *m_oldSvgFont; QFont m_oldQFont; Qt::Alignment m_oldTextAnchor; int m_oldWeight; uint m_familySet : 1; uint m_sizeSet : 1; uint m_styleSet : 1; uint m_variantSet : 1; uint m_weightSet : 1; uint m_textAnchorSet : 1; }; class Q_SVG_PRIVATE_EXPORT QSvgStrokeStyle : public QSvgStyleProperty { public: QSvgStrokeStyle(); void apply(QPainter *p, const QSvgNode *node, QSvgExtraStates &states) override; void revert(QPainter *p, QSvgExtraStates &states) override; Type type() const override; void setStroke(QBrush brush) { m_stroke.setBrush(brush); m_style = 0; m_strokeSet = 1; } void setStyle(QSvgFillStyleProperty *style) { m_style = style; m_strokeSet = 1; } void setDashArray(const QVector &dashes); void setDashArrayNone() { m_stroke.setStyle(Qt::SolidLine); m_strokeDashArraySet = 1; } void setDashOffset(qreal offset) { m_strokeDashOffset = offset; m_strokeDashOffsetSet = 1; } void setLineCap(Qt::PenCapStyle cap) { m_stroke.setCapStyle(cap); m_strokeLineCapSet = 1; } void setLineJoin(Qt::PenJoinStyle join) { m_stroke.setJoinStyle(join); m_strokeLineJoinSet = 1; } void setMiterLimit(qreal limit) { m_stroke.setMiterLimit(limit); m_strokeMiterLimitSet = 1; } void setOpacity(qreal opacity) { m_strokeOpacity = opacity; m_strokeOpacitySet = 1; } void setWidth(qreal width) { m_stroke.setWidthF(width); m_strokeWidthSet = 1; Q_ASSERT(!m_strokeDashArraySet); // set width before dash array. } qreal width() { return m_stroke.widthF(); } void setVectorEffect(bool nonScalingStroke) { m_vectorEffect = nonScalingStroke; m_vectorEffectSet = 1; } QSvgFillStyleProperty* style() const { return m_style; } void setGradientId(const QString &Id) { m_gradientId = Id; } QString gradientId() const { return m_gradientId; } void setGradientResolved(bool resolved) { m_gradientResolved = resolved; } bool isGradientResolved() const { return m_gradientResolved; } QPen stroke() const { return m_stroke; } private: // stroke v v 'inherit' | // stroke-dasharray v v 'inherit' | // stroke-dashoffset v v 'inherit' | // stroke-linecap v v 'butt' | 'round' | 'square' | 'inherit' // stroke-linejoin v v 'miter' | 'round' | 'bevel' | 'inherit' // stroke-miterlimit v v 'inherit' | // stroke-opacity v v 'inherit' | // stroke-width v v 'inherit' | QPen m_stroke; QPen m_oldStroke; qreal m_strokeOpacity; qreal m_oldStrokeOpacity; qreal m_strokeDashOffset; qreal m_oldStrokeDashOffset; QSvgFillStyleProperty *m_style; QString m_gradientId; uint m_gradientResolved : 1; uint m_vectorEffect : 1; uint m_oldVectorEffect : 1; uint m_strokeSet : 1; uint m_strokeDashArraySet : 1; uint m_strokeDashOffsetSet : 1; uint m_strokeLineCapSet : 1; uint m_strokeLineJoinSet : 1; uint m_strokeMiterLimitSet : 1; uint m_strokeOpacitySet : 1; uint m_strokeWidthSet : 1; uint m_vectorEffectSet : 1; }; class Q_SVG_PRIVATE_EXPORT QSvgSolidColorStyle : public QSvgFillStyleProperty { public: QSvgSolidColorStyle(const QColor &color); Type type() const override; const QColor & qcolor() const { return m_solidColor; } QBrush brush(QPainter *, QSvgExtraStates &) override { return m_solidColor; } private: // solid-color v x 'inherit' | // solid-opacity v x 'inherit' | QColor m_solidColor; QBrush m_oldFill; QPen m_oldStroke; }; class Q_SVG_PRIVATE_EXPORT QSvgGradientStyle : public QSvgFillStyleProperty { public: QSvgGradientStyle(QGradient *grad); ~QSvgGradientStyle() { delete m_gradient; } Type type() const override; void setStopLink(const QString &link, QSvgTinyDocument *doc); QString stopLink() const { return m_link; } void resolveStops(); void resolveStops_helper(QStringList *visited); void setTransform(const QTransform &transform); QTransform qtransform() const { return m_transform; } QGradient *qgradient() const { return m_gradient; } bool gradientStopsSet() const { return m_gradientStopsSet; } void setGradientStopsSet(bool set) { m_gradientStopsSet = set; } QBrush brush(QPainter *, QSvgExtraStates &) override; private: QGradient *m_gradient; QTransform m_transform; QSvgTinyDocument *m_doc; QString m_link; bool m_gradientStopsSet; }; class Q_SVG_PRIVATE_EXPORT QSvgTransformStyle : public QSvgStyleProperty { public: QSvgTransformStyle(const QTransform &transform); void apply(QPainter *p, const QSvgNode *node, QSvgExtraStates &states) override; void revert(QPainter *p, QSvgExtraStates &states) override; Type type() const override; const QTransform & qtransform() const { return m_transform; } private: //7.6 The transform attribute QTransform m_transform; QTransform m_oldWorldTransform; }; class Q_SVG_PRIVATE_EXPORT QSvgAnimateTransform : public QSvgStyleProperty { public: enum TransformType { Empty, Translate, Scale, Rotate, SkewX, SkewY }; enum Additive { Sum, Replace }; public: QSvgAnimateTransform(int startMs, int endMs, int by = 0); void setArgs(TransformType type, Additive additive, const QVector &args); void setFreeze(bool freeze); void setRepeatCount(qreal repeatCount); void apply(QPainter *p, const QSvgNode *node, QSvgExtraStates &states) override; void revert(QPainter *p, QSvgExtraStates &states) override; Type type() const override; QSvgAnimateTransform::Additive additiveType() const { return m_additive; } bool animActive(qreal totalTimeElapsed) { if (totalTimeElapsed < m_from) return false; if (m_freeze || m_repeatCount < 0) // fill="freeze" or repeat="indefinite" return true; if (m_totalRunningTime == 0) return false; qreal animationFrame = (totalTimeElapsed - m_from) / m_totalRunningTime; if (animationFrame > m_repeatCount) return false; return true; } bool transformApplied() const { return m_transformApplied; } // Call this instead of revert if you know that revert is unnecessary. void clearTransformApplied() { m_transformApplied = false; } protected: void resolveMatrix(const QSvgNode *node); private: qreal m_from; qreal m_totalRunningTime; TransformType m_type; Additive m_additive; QVector m_args; int m_count; QTransform m_transform; QTransform m_oldWorldTransform; bool m_finished; bool m_freeze; qreal m_repeatCount; bool m_transformApplied; }; class Q_SVG_PRIVATE_EXPORT QSvgAnimateColor : public QSvgStyleProperty { public: QSvgAnimateColor(int startMs, int endMs, int by = 0); void setArgs(bool fill, const QList &colors); void setFreeze(bool freeze); void setRepeatCount(qreal repeatCount); void apply(QPainter *p, const QSvgNode *node, QSvgExtraStates &states) override; void revert(QPainter *p, QSvgExtraStates &states) override; Type type() const override; private: qreal m_from; qreal m_totalRunningTime; QList m_colors; QBrush m_oldBrush; QPen m_oldPen; bool m_fill; bool m_finished; bool m_freeze; qreal m_repeatCount; }; class Q_SVG_PRIVATE_EXPORT QSvgCompOpStyle : public QSvgStyleProperty { public: QSvgCompOpStyle(QPainter::CompositionMode mode); void apply(QPainter *p, const QSvgNode *node, QSvgExtraStates &states) override; void revert(QPainter *p, QSvgExtraStates &states) override; Type type() const override; const QPainter::CompositionMode & compOp() const { return m_mode; } private: //comp-op attribute QPainter::CompositionMode m_mode; QPainter::CompositionMode m_oldMode; }; class Q_SVG_PRIVATE_EXPORT QSvgStyle { public: QSvgStyle() : quality(0), fill(0), viewportFill(0), font(0), stroke(0), solidColor(0), gradient(0), transform(0), animateColor(0), opacity(0), compop(0) {} ~QSvgStyle(); void apply(QPainter *p, const QSvgNode *node, QSvgExtraStates &states); void revert(QPainter *p, QSvgExtraStates &states); QSvgRefCounter quality; QSvgRefCounter fill; QSvgRefCounter viewportFill; QSvgRefCounter font; QSvgRefCounter stroke; QSvgRefCounter solidColor; QSvgRefCounter gradient; QSvgRefCounter transform; QSvgRefCounter animateColor; QList > animateTransforms; QSvgRefCounter opacity; QSvgRefCounter compop; }; /********************************************************/ // NOT implemented: // color v v 'inherit' | //QColor m_color; // display v x 'inline' | 'block' | 'list-item' // | 'run-in' | 'compact' | 'marker' | // 'table' | 'inline-table' | // 'table-row-group' | 'table-header-group' | // 'table-footer-group' | 'table-row' | // 'table-column-group' | 'table-column' | // 'table-cell' | 'table-caption' | // 'none' | 'inherit' //QSvgDisplayStyle m_display; // display-align v v 'auto' | 'before' | 'center' | 'after' | 'inherit' //QSvgDisplayAlign m_displayAlign; // line-increment v v 'auto' | 'inherit' | //int m_lineIncrement; // text-anchor v v 'start' | 'middle' | 'end' | 'inherit' //QSvgTextAnchor m_textAnchor; // visibility v v 'visible' | 'hidden' | 'inherit' //QSvgVisibility m_visibility; /******************************************************/ // the following do not make sense for us // pointer-events v v 'visiblePainted' | 'visibleFill' | 'visibleStroke' | // 'visible' | 'painted' | 'fill' | 'stroke' | 'all' | // 'none' | 'inherit' //QSvgPointEvents m_pointerEvents; // audio-level v x 'inherit' | QT_END_NAMESPACE #endif // QSVGSTYLE_P_H