1 /****************************************************************************
3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the QtSvg module of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
11 ** Licensees holding valid Qt Commercial licenses may use this file in
12 ** accordance with the Qt Commercial License Agreement provided with the
13 ** Software or, alternatively, in accordance with the terms contained in
14 ** a written agreement between you and Nokia.
16 ** GNU Lesser General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU Lesser
18 ** General Public License version 2.1 as published by the Free Software
19 ** Foundation and appearing in the file LICENSE.LGPL included in the
20 ** packaging of this file. Please review the following information to
21 ** ensure the GNU Lesser General Public License version 2.1 requirements
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 ** In addition, as a special exception, Nokia gives you certain additional
25 ** rights. These rights are described in the Nokia Qt LGPL Exception
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 ** GNU General Public License Usage
29 ** Alternatively, this file may be used under the terms of the GNU
30 ** General Public License version 3.0 as published by the Free Software
31 ** Foundation and appearing in the file LICENSE.GPL included in the
32 ** packaging of this file. Please review the following information to
33 ** ensure the GNU General Public License version 3.0 requirements will be
34 ** met: http://www.gnu.org/copyleft/gpl.html.
36 ** If you have questions regarding the use of this file, please contact
37 ** Nokia at qt-info@nokia.com.
40 ****************************************************************************/
42 #include "qsvgstyle_p.h"
46 #include "qsvgfont_p.h"
47 #include "qsvggraphics_p.h"
48 #include "qsvgnode_p.h"
49 #include "qsvgtinydocument_p.h"
60 QSvgExtraStates::QSvgExtraStates()
65 QSvgStyleProperty::~QSvgStyleProperty()
69 QSvgQualityStyle::QSvgQualityStyle(int color
)
70 : m_colorRendering(color
)
74 void QSvgQualityStyle::apply(QPainter
*, const QRectF
&, QSvgNode
*, QSvgExtraStates
&)
78 void QSvgQualityStyle::revert(QPainter
*, QSvgExtraStates
&)
83 QSvgFillStyle::QSvgFillStyle(const QBrush
&brush
)
84 : m_fill(brush
), m_style(0), m_fillRuleSet(false), m_fillRule(Qt::OddEvenFill
),
85 m_fillOpacitySet(false), m_fillOpacity(0),m_oldOpacity(0)
89 QSvgFillStyle::QSvgFillStyle(QSvgStyleProperty
*style
)
90 : m_style(style
), m_fillRuleSet(false), m_fillRule(Qt::OddEvenFill
),
91 m_fillOpacitySet(false), m_fillOpacity(0),m_oldOpacity(0)
95 void QSvgFillStyle::setFillRule(Qt::FillRule f
)
101 void QSvgFillStyle::setFillOpacity(qreal opacity
)
103 m_fillOpacitySet
= true;
104 m_fillOpacity
= opacity
;
107 static void recursivelySetFill(QSvgNode
*node
, Qt::FillRule f
)
109 if (node
->type() == QSvgNode::PATH
) {
110 QSvgPath
*path
= static_cast<QSvgPath
*>(node
);
111 path
->qpath()->setFillRule(f
);
112 } else if (node
->type() == QSvgNode::G
) {
113 QList
<QSvgNode
*> renderers
= static_cast<QSvgG
*>(node
)->renderers();
114 foreach(QSvgNode
*n
, renderers
) {
115 recursivelySetFill(n
, f
);
119 void QSvgFillStyle::apply(QPainter
*p
, const QRectF
&rect
, QSvgNode
*node
, QSvgExtraStates
&states
)
121 m_oldFill
= p
->brush();
122 m_oldOpacity
= states
.fillOpacity
;
125 recursivelySetFill(node
, m_fillRule
);
126 m_fillRuleSet
= false;//set it only on the first run
129 if (m_fillOpacitySet
)
130 states
.fillOpacity
= m_fillOpacity
;
132 m_style
->apply(p
, rect
, node
, states
);
135 void QSvgFillStyle::revert(QPainter
*p
, QSvgExtraStates
&states
)
138 m_style
->revert(p
, states
);
139 p
->setBrush(m_oldFill
);
140 if (m_fillOpacitySet
)
141 states
.fillOpacity
= m_oldOpacity
;
144 QSvgViewportFillStyle::QSvgViewportFillStyle(const QBrush
&brush
)
145 : m_viewportFill(brush
)
149 void QSvgViewportFillStyle::apply(QPainter
*p
, const QRectF
&, QSvgNode
*, QSvgExtraStates
&)
151 m_oldFill
= p
->brush();
152 p
->setBrush(m_viewportFill
);
155 void QSvgViewportFillStyle::revert(QPainter
*p
, QSvgExtraStates
&)
157 p
->setBrush(m_oldFill
);
160 QSvgFontStyle::QSvgFontStyle(QSvgFont
*font
, QSvgTinyDocument
*doc
)
161 : m_font(font
), m_pointSize(24), m_doc(doc
)
165 QSvgFontStyle::QSvgFontStyle(const QFont
&font
, QSvgTinyDocument
*doc
)
166 : m_font(0), m_pointSize(24), m_doc(doc
), m_qfont(font
)
171 void QSvgFontStyle::setPointSize(qreal size
)
176 qreal
QSvgFontStyle::pointSize() const
181 void QSvgFontStyle::apply(QPainter
*p
, const QRectF
&, QSvgNode
*, QSvgExtraStates
&)
184 m_oldFont
= p
->font();
189 void QSvgFontStyle::revert(QPainter
*p
, QSvgExtraStates
&)
192 p
->setFont(m_oldFont
);
196 QSvgStrokeStyle::QSvgStrokeStyle(const QPen
&pen
)
201 void QSvgStrokeStyle::apply(QPainter
*p
, const QRectF
&, QSvgNode
*, QSvgExtraStates
&)
203 m_oldStroke
= p
->pen();
207 void QSvgStrokeStyle::revert(QPainter
*p
, QSvgExtraStates
&)
209 p
->setPen(m_oldStroke
);
212 QSvgSolidColorStyle::QSvgSolidColorStyle(const QColor
&color
)
213 : m_solidColor(color
)
217 void QSvgSolidColorStyle::apply(QPainter
*p
, const QRectF
&, QSvgNode
*, QSvgExtraStates
&)
219 m_oldFill
= p
->brush();
220 m_oldStroke
= p
->pen();
221 QBrush b
= m_oldFill
;
222 b
.setColor(m_solidColor
);
224 QPen pen
= m_oldStroke
;
225 pen
.setColor(m_solidColor
);
229 void QSvgSolidColorStyle::revert(QPainter
*p
, QSvgExtraStates
&)
231 p
->setBrush(m_oldFill
);
232 p
->setPen(m_oldStroke
);
235 QSvgGradientStyle::QSvgGradientStyle(QGradient
*grad
)
236 : m_gradient(grad
), m_gradientStopsSet(false)
240 void QSvgGradientStyle::apply(QPainter
*p
, const QRectF
&/*rect*/, QSvgNode
*, QSvgExtraStates
&)
242 if (!m_link
.isEmpty()) {
246 m_oldFill
= p
->brush();
248 //resolving stop colors
249 if (!m_resolvePoints
.isEmpty()) {
250 QColor color
= p
->brush().color();
251 if (!color
.isValid())
252 color
= p
->pen().color();
253 QList
<qreal
>::const_iterator itr
= m_resolvePoints
.constBegin();
254 for (; itr
!= m_resolvePoints
.constEnd(); ++itr
) {
255 //qDebug()<<"resolving "<<(*itr)<<" to "<<color;
256 m_gradient
->setColorAt(*itr
, color
);
260 // If the gradient is marked as empty, insert transparent black
261 if (!m_gradientStopsSet
) {
262 m_gradient
->setStops(QGradientStops() << QGradientStop(0.0, QColor(0, 0, 0, 0)));
263 m_gradientStopsSet
= true;
267 brush
= QBrush(*m_gradient
);
269 if (!m_matrix
.isIdentity())
270 brush
.setMatrix(m_matrix
);
275 void QSvgGradientStyle::revert(QPainter
*p
, QSvgExtraStates
&)
277 p
->setBrush(m_oldFill
);
281 void QSvgGradientStyle::setMatrix(const QMatrix
&mat
)
286 void QSvgGradientStyle::addResolve(qreal offset
)
288 m_resolvePoints
.append(offset
);
291 QSvgTransformStyle::QSvgTransformStyle(const QTransform
&trans
)
296 void QSvgTransformStyle::apply(QPainter
*p
, const QRectF
&, QSvgNode
*, QSvgExtraStates
&)
298 m_oldWorldTransform
= p
->worldTransform();
299 p
->setWorldTransform(m_transform
, true);
302 void QSvgTransformStyle::revert(QPainter
*p
, QSvgExtraStates
&)
304 p
->setWorldTransform(m_oldWorldTransform
, false /* don't combine */);
307 QSvgStyleProperty::Type
QSvgQualityStyle::type() const
312 QSvgStyleProperty::Type
QSvgFillStyle::type() const
317 QSvgStyleProperty::Type
QSvgViewportFillStyle::type() const
319 return VIEWPORT_FILL
;
322 QSvgStyleProperty::Type
QSvgFontStyle::type() const
327 QSvgStyleProperty::Type
QSvgStrokeStyle::type() const
332 QSvgStyleProperty::Type
QSvgSolidColorStyle::type() const
337 QSvgStyleProperty::Type
QSvgGradientStyle::type() const
342 QSvgStyleProperty::Type
QSvgTransformStyle::type() const
348 QSvgCompOpStyle::QSvgCompOpStyle(QPainter::CompositionMode mode
)
354 void QSvgCompOpStyle::apply(QPainter
*p
, const QRectF
&, QSvgNode
*, QSvgExtraStates
&)
356 m_oldMode
= p
->compositionMode();
357 p
->setCompositionMode(m_mode
);
360 void QSvgCompOpStyle::revert(QPainter
*p
, QSvgExtraStates
&)
362 p
->setCompositionMode(m_oldMode
);
365 QSvgStyleProperty::Type
QSvgCompOpStyle::type() const
370 QSvgStyle::~QSvgStyle()
374 void QSvgStyle::apply(QPainter
*p
, const QRectF
&rect
, QSvgNode
*node
, QSvgExtraStates
&states
)
377 quality
->apply(p
, rect
, node
, states
);
381 fill
->apply(p
, rect
, node
, states
);
385 viewportFill
->apply(p
, rect
, node
, states
);
389 font
->apply(p
, rect
, node
, states
);
393 stroke
->apply(p
, rect
, node
, states
);
397 solidColor
->apply(p
, rect
, node
, states
);
401 gradient
->apply(p
, rect
, node
, states
);
405 transform
->apply(p
, rect
, node
, states
);
409 animateColor
->apply(p
, rect
, node
, states
);
412 //animated transforms have to be applied
413 //_after_ the original object transformations
414 if (!animateTransforms
.isEmpty()) {
415 QList
<QSvgRefCounter
<QSvgAnimateTransform
> >::const_iterator itr
;
416 for (itr
= animateTransforms
.constBegin(); itr
!= animateTransforms
.constEnd();
418 (*itr
)->apply(p
, rect
, node
, states
);
423 opacity
->apply(p
, rect
, node
, states
);
427 compop
->apply(p
, rect
, node
, states
);
431 void QSvgStyle::revert(QPainter
*p
, QSvgExtraStates
&states
)
434 quality
->revert(p
, states
);
438 fill
->revert(p
, states
);
442 viewportFill
->revert(p
, states
);
446 font
->revert(p
, states
);
450 stroke
->revert(p
, states
);
454 solidColor
->revert(p
, states
);
458 gradient
->revert(p
, states
);
461 //animated transforms need to be reverted _before_
462 //the native transforms
463 if (!animateTransforms
.isEmpty()) {
464 QList
<QSvgRefCounter
<QSvgAnimateTransform
> >::const_iterator itr
;
465 itr
= animateTransforms
.constBegin();
466 //only need to rever the first one because that
467 //one has the original world matrix for the primitve
468 if (itr
!= animateTransforms
.constEnd()) {
469 (*itr
)->revert(p
, states
);
474 transform
->revert(p
, states
);
478 animateColor
->revert(p
, states
);
482 opacity
->revert(p
, states
);
486 compop
->revert(p
, states
);
490 QSvgAnimateTransform::QSvgAnimateTransform(int startMs
, int endMs
, int byMs
)
491 : QSvgStyleProperty(),
492 m_from(startMs
), m_to(endMs
), m_by(byMs
),
493 m_type(Empty
), m_count(0), m_finished(false)
495 m_totalRunningTime
= m_to
- m_from
;
498 void QSvgAnimateTransform::setArgs(TransformType type
, const QVector
<qreal
> &args
)
502 Q_ASSERT(!(args
.count()%3));
503 m_count
= args
.count() / 3;
506 void QSvgAnimateTransform::apply(QPainter
*p
, const QRectF
&, QSvgNode
*node
, QSvgExtraStates
&)
508 m_oldWorldTransform
= p
->worldTransform();
510 if (!m_finished
|| m_freeze
)
511 p
->setWorldTransform(m_transform
, true);
514 void QSvgAnimateTransform::revert(QPainter
*p
, QSvgExtraStates
&)
516 if (!m_finished
|| m_freeze
) {
517 p
->setWorldTransform(m_oldWorldTransform
, false /* don't combine */);
521 void QSvgAnimateTransform::resolveMatrix(QSvgNode
*node
)
523 static const qreal deg2rad
= qreal(0.017453292519943295769);
524 qreal totalTimeElapsed
= node
->document()->currentElapsed();
525 if (totalTimeElapsed
< m_from
|| m_finished
)
528 qreal animationFrame
= 0;
529 if (m_totalRunningTime
!= 0) {
530 animationFrame
= (totalTimeElapsed
- m_from
) / m_totalRunningTime
;
532 if (m_repeatCount
>= 0 && m_repeatCount
< animationFrame
) {
534 animationFrame
= m_repeatCount
;
538 qreal percentOfAnimation
= animationFrame
;
539 if (percentOfAnimation
> 1) {
540 percentOfAnimation
-= ((int)percentOfAnimation
);
543 qreal currentPosition
= percentOfAnimation
* (m_count
- 1);
544 int startElem
= qFloor(currentPosition
);
545 int endElem
= qCeil(currentPosition
);
552 qreal from1
, from2
, from3
;
554 from1
= m_args
[startElem
++];
555 from2
= m_args
[startElem
++];
556 from3
= m_args
[startElem
++];
557 to1
= m_args
[endElem
++];
558 to2
= m_args
[endElem
++];
559 to3
= m_args
[endElem
++];
561 qreal transXDiff
= (to1
-from1
) * percentOfAnimation
;
562 qreal transX
= from1
+ transXDiff
;
563 qreal transYDiff
= (to2
-from2
) * percentOfAnimation
;
564 qreal transY
= from2
+ transYDiff
;
565 m_transform
= QTransform();
566 m_transform
.translate(transX
, transY
);
572 qreal from1
, from2
, from3
;
574 from1
= m_args
[startElem
++];
575 from2
= m_args
[startElem
++];
576 from3
= m_args
[startElem
++];
577 to1
= m_args
[endElem
++];
578 to2
= m_args
[endElem
++];
579 to3
= m_args
[endElem
++];
581 qreal transXDiff
= (to1
-from1
) * percentOfAnimation
;
582 qreal transX
= from1
+ transXDiff
;
583 qreal transYDiff
= (to2
-from2
) * percentOfAnimation
;
584 qreal transY
= from2
+ transYDiff
;
587 m_transform
= QTransform();
588 m_transform
.scale(transX
, transY
);
594 qreal from1
, from2
, from3
;
596 from1
= m_args
[startElem
++];
597 from2
= m_args
[startElem
++];
598 from3
= m_args
[startElem
++];
599 to1
= m_args
[endElem
++];
600 to2
= m_args
[endElem
++];
601 to3
= m_args
[endElem
++];
603 qreal rotationDiff
= (to1
- from1
) * percentOfAnimation
;
604 //qreal rotation = from1 + rotationDiff;
606 qreal transXDiff
= (to2
-from2
) * percentOfAnimation
;
607 qreal transX
= from2
+ transXDiff
;
608 qreal transYDiff
= (to3
-from3
) * percentOfAnimation
;
609 qreal transY
= from3
+ transYDiff
;
610 m_transform
= QTransform();
611 m_transform
.translate(transX
, transY
);
612 m_transform
.rotate(rotationDiff
);
613 m_transform
.translate(-transX
, -transY
);
619 qreal from1
, from2
, from3
;
621 from1
= m_args
[startElem
++];
622 from2
= m_args
[startElem
++];
623 from3
= m_args
[startElem
++];
624 to1
= m_args
[endElem
++];
625 to2
= m_args
[endElem
++];
626 to3
= m_args
[endElem
++];
628 qreal transXDiff
= (to1
-from1
) * percentOfAnimation
;
629 qreal transX
= from1
+ transXDiff
;
630 m_transform
= QTransform();
631 m_transform
.shear(tan(transX
* deg2rad
), 0);
637 qreal from1
, from2
, from3
;
639 from1
= m_args
[startElem
++];
640 from2
= m_args
[startElem
++];
641 from3
= m_args
[startElem
++];
642 to1
= m_args
[endElem
++];
643 to2
= m_args
[endElem
++];
644 to3
= m_args
[endElem
++];
647 qreal transYDiff
= (to1
- from1
) * percentOfAnimation
;
648 qreal transY
= from1
+ transYDiff
;
649 m_transform
= QTransform();
650 m_transform
.shear(0, tan(transY
* deg2rad
));
658 QSvgStyleProperty::Type
QSvgAnimateTransform::type() const
660 return ANIMATE_TRANSFORM
;
663 void QSvgAnimateTransform::setFreeze(bool freeze
)
668 void QSvgAnimateTransform::setRepeatCount(qreal repeatCount
)
670 m_repeatCount
= repeatCount
;
673 QSvgAnimateColor::QSvgAnimateColor(int startMs
, int endMs
, int byMs
)
674 : QSvgStyleProperty(),
675 m_from(startMs
), m_to(endMs
), m_by(byMs
),
678 m_totalRunningTime
= m_to
- m_from
;
681 void QSvgAnimateColor::setArgs(bool fill
,
682 const QList
<QColor
> &colors
)
688 void QSvgAnimateColor::setFreeze(bool freeze
)
693 void QSvgAnimateColor::setRepeatCount(qreal repeatCount
)
695 m_repeatCount
= repeatCount
;
698 void QSvgAnimateColor::apply(QPainter
*p
, const QRectF
&, QSvgNode
*node
, QSvgExtraStates
&)
700 qreal totalTimeElapsed
= node
->document()->currentElapsed();
701 if (totalTimeElapsed
< m_from
|| m_finished
)
704 qreal animationFrame
= (totalTimeElapsed
- m_from
) / m_to
;
706 if (m_repeatCount
>= 0 && m_repeatCount
< animationFrame
) {
708 animationFrame
= m_repeatCount
;
711 qreal percentOfAnimation
= animationFrame
;
712 if (percentOfAnimation
> 1) {
713 percentOfAnimation
-= ((int)percentOfAnimation
);
716 qreal currentPosition
= percentOfAnimation
* (m_colors
.count() - 1);
718 int startElem
= qFloor(currentPosition
);
719 int endElem
= qCeil(currentPosition
);
720 QColor start
= m_colors
[startElem
];
721 QColor end
= m_colors
[endElem
];
723 qreal percentOfColorMorph
= currentPosition
;
724 if (percentOfColorMorph
> 1) {
725 percentOfColorMorph
-= ((int)percentOfColorMorph
);
728 // Interpolate between the two fixed colors start and end
729 qreal aDiff
= (end
.alpha() - start
.alpha()) * percentOfColorMorph
;
730 qreal rDiff
= (end
.red() - start
.red()) * percentOfColorMorph
;
731 qreal gDiff
= (end
.green() - start
.green()) * percentOfColorMorph
;
732 qreal bDiff
= (end
.blue() - start
.blue()) * percentOfColorMorph
;
734 int alpha
= int(start
.alpha() + aDiff
);
735 int red
= int(start
.red() + rDiff
);
736 int green
= int(start
.green() + gDiff
);
737 int blue
= int(start
.blue() + bDiff
);
739 QColor
color(red
, green
, blue
, alpha
);
742 QBrush b
= p
->brush();
754 void QSvgAnimateColor::revert(QPainter
*p
, QSvgExtraStates
&)
757 p
->setBrush(m_oldBrush
);
763 QSvgStyleProperty::Type
QSvgAnimateColor::type() const
765 return ANIMATE_COLOR
;
768 QString
QSvgFontStyle::textAnchor() const
773 void QSvgFontStyle::setTextAnchor(const QString
&anchor
)
775 m_textAnchor
= anchor
;
778 QSvgOpacityStyle::QSvgOpacityStyle(qreal opacity
)
784 void QSvgOpacityStyle::apply(QPainter
*p
, const QRectF
&, QSvgNode
*, QSvgExtraStates
&)
786 m_oldOpacity
= p
->opacity();
787 p
->setOpacity(m_opacity
* m_oldOpacity
);
790 void QSvgOpacityStyle::revert(QPainter
*p
, QSvgExtraStates
&)
792 p
->setOpacity(m_oldOpacity
);
795 QSvgStyleProperty::Type
QSvgOpacityStyle::type() const
800 void QSvgGradientStyle::setStopLink(const QString
&link
, QSvgTinyDocument
*doc
)
806 void QSvgGradientStyle::resolveStops()
808 if (!m_link
.isEmpty() && m_doc
) {
809 QSvgStyleProperty
*prop
= m_doc
->scopeStyle(m_link
);
811 if (prop
->type() == QSvgStyleProperty::GRADIENT
) {
812 QSvgGradientStyle
*st
=
813 static_cast<QSvgGradientStyle
*>(prop
);
815 m_gradient
->setStops(st
->qgradient()->stops());
816 m_gradientStopsSet
= st
->gradientStopsSet();