author | Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com> |
Fri, 19 Feb 2010 23:40:16 +0200 | |
branch | RCL_3 |
changeset 4 | 3b1da2848fc7 |
parent 3 | 41300fa6a67c |
permissions | -rw-r--r-- |
0 | 1 |
/**************************************************************************** |
2 |
** |
|
4
3b1da2848fc7
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
3
diff
changeset
|
3 |
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). |
0 | 4 |
** All rights reserved. |
5 |
** Contact: Nokia Corporation (qt-info@nokia.com) |
|
6 |
** |
|
7 |
** This file is part of the QtSvg module of the Qt Toolkit. |
|
8 |
** |
|
9 |
** $QT_BEGIN_LICENSE:LGPL$ |
|
10 |
** No Commercial Usage |
|
11 |
** This file contains pre-release code and may not be distributed. |
|
12 |
** You may use this file in accordance with the terms and conditions |
|
13 |
** contained in the Technology Preview License Agreement accompanying |
|
14 |
** this package. |
|
15 |
** |
|
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. |
|
23 |
** |
|
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. |
|
27 |
** |
|
28 |
** If you have questions regarding the use of this file, please contact |
|
29 |
** Nokia at qt-info@nokia.com. |
|
30 |
** |
|
31 |
** |
|
32 |
** |
|
33 |
** |
|
34 |
** |
|
35 |
** |
|
36 |
** |
|
37 |
** |
|
38 |
** $QT_END_LICENSE$ |
|
39 |
** |
|
40 |
****************************************************************************/ |
|
41 |
||
42 |
#include "qsvgstyle_p.h" |
|
43 |
||
44 |
#ifndef QT_NO_SVG |
|
45 |
||
46 |
#include "qsvgfont_p.h" |
|
47 |
#include "qsvggraphics_p.h" |
|
48 |
#include "qsvgnode_p.h" |
|
49 |
#include "qsvgtinydocument_p.h" |
|
50 |
||
51 |
#include "qpainter.h" |
|
52 |
#include "qpair.h" |
|
53 |
#include "qcolor.h" |
|
54 |
#include "qdebug.h" |
|
55 |
#include "qmath.h" |
|
56 |
#include "qnumeric.h" |
|
57 |
||
58 |
QT_BEGIN_NAMESPACE |
|
59 |
||
60 |
QSvgExtraStates::QSvgExtraStates() |
|
61 |
: fillOpacity(1.0) |
|
62 |
, strokeOpacity(1.0) |
|
63 |
, svgFont(0) |
|
64 |
, textAnchor(Qt::AlignLeft) |
|
65 |
, fontWeight(400) |
|
66 |
, fillRule(Qt::WindingFill) |
|
67 |
, strokeDashOffset(0) |
|
68 |
, vectorEffect(false) |
|
69 |
{ |
|
70 |
} |
|
71 |
||
72 |
QSvgStyleProperty::~QSvgStyleProperty() |
|
73 |
{ |
|
74 |
} |
|
75 |
||
76 |
void QSvgFillStyleProperty::apply(QPainter *, const QRectF &, QSvgNode *, QSvgExtraStates &) |
|
77 |
{ |
|
78 |
Q_ASSERT(!"This should not be called!"); |
|
79 |
} |
|
80 |
||
81 |
void QSvgFillStyleProperty::revert(QPainter *, QSvgExtraStates &) |
|
82 |
{ |
|
83 |
Q_ASSERT(!"This should not be called!"); |
|
84 |
} |
|
85 |
||
86 |
||
87 |
QSvgQualityStyle::QSvgQualityStyle(int color) |
|
88 |
: m_colorRendering(color) |
|
89 |
{ |
|
90 |
||
91 |
} |
|
92 |
void QSvgQualityStyle::apply(QPainter *, const QRectF &, QSvgNode *, QSvgExtraStates &) |
|
93 |
{ |
|
94 |
||
95 |
} |
|
96 |
void QSvgQualityStyle::revert(QPainter *, QSvgExtraStates &) |
|
97 |
{ |
|
98 |
||
99 |
} |
|
100 |
||
101 |
QSvgFillStyle::QSvgFillStyle() |
|
102 |
: m_style(0) |
|
103 |
, m_fillRule(Qt::WindingFill) |
|
104 |
, m_oldFillRule(Qt::WindingFill) |
|
105 |
, m_fillOpacity(1.0) |
|
106 |
, m_oldFillOpacity(0) |
|
107 |
, m_gradientResolved(1) |
|
108 |
, m_fillRuleSet(0) |
|
109 |
, m_fillOpacitySet(0) |
|
110 |
, m_fillSet(0) |
|
111 |
{ |
|
112 |
} |
|
113 |
||
114 |
void QSvgFillStyle::setFillRule(Qt::FillRule f) |
|
115 |
{ |
|
116 |
m_fillRuleSet = 1; |
|
117 |
m_fillRule = f; |
|
118 |
} |
|
119 |
||
120 |
void QSvgFillStyle::setFillOpacity(qreal opacity) |
|
121 |
{ |
|
122 |
m_fillOpacitySet = 1; |
|
123 |
m_fillOpacity = opacity; |
|
124 |
} |
|
125 |
||
126 |
void QSvgFillStyle::setFillStyle(QSvgFillStyleProperty* style) |
|
127 |
{ |
|
128 |
m_style = style; |
|
129 |
m_fillSet = 1; |
|
130 |
} |
|
131 |
||
132 |
void QSvgFillStyle::setBrush(QBrush brush) |
|
133 |
{ |
|
134 |
m_fill = brush; |
|
135 |
m_style = 0; |
|
136 |
m_fillSet = 1; |
|
137 |
} |
|
138 |
||
139 |
void QSvgFillStyle::apply(QPainter *p, const QRectF &, QSvgNode *, QSvgExtraStates &states) |
|
140 |
{ |
|
141 |
m_oldFill = p->brush(); |
|
142 |
m_oldFillRule = states.fillRule; |
|
143 |
m_oldFillOpacity = states.fillOpacity; |
|
144 |
||
145 |
if (m_fillRuleSet) |
|
146 |
states.fillRule = m_fillRule; |
|
147 |
if (m_fillSet) { |
|
148 |
if (m_style) |
|
149 |
p->setBrush(m_style->brush(p, states)); |
|
150 |
else |
|
151 |
p->setBrush(m_fill); |
|
152 |
} |
|
153 |
if (m_fillOpacitySet) |
|
154 |
states.fillOpacity = m_fillOpacity; |
|
155 |
} |
|
156 |
||
157 |
void QSvgFillStyle::revert(QPainter *p, QSvgExtraStates &states) |
|
158 |
{ |
|
159 |
if (m_fillOpacitySet) |
|
160 |
states.fillOpacity = m_oldFillOpacity; |
|
161 |
if (m_fillSet) |
|
162 |
p->setBrush(m_oldFill); |
|
163 |
if (m_fillRuleSet) |
|
164 |
states.fillRule = m_oldFillRule; |
|
165 |
} |
|
166 |
||
167 |
QSvgViewportFillStyle::QSvgViewportFillStyle(const QBrush &brush) |
|
168 |
: m_viewportFill(brush) |
|
169 |
{ |
|
170 |
} |
|
171 |
||
172 |
void QSvgViewportFillStyle::apply(QPainter *p, const QRectF &, QSvgNode *, QSvgExtraStates &) |
|
173 |
{ |
|
174 |
m_oldFill = p->brush(); |
|
175 |
p->setBrush(m_viewportFill); |
|
176 |
} |
|
177 |
||
178 |
void QSvgViewportFillStyle::revert(QPainter *p, QSvgExtraStates &) |
|
179 |
{ |
|
180 |
p->setBrush(m_oldFill); |
|
181 |
} |
|
182 |
||
183 |
QSvgFontStyle::QSvgFontStyle(QSvgFont *font, QSvgTinyDocument *doc) |
|
184 |
: m_svgFont(font) |
|
185 |
, m_doc(doc) |
|
186 |
, m_familySet(0) |
|
187 |
, m_sizeSet(0) |
|
188 |
, m_styleSet(0) |
|
189 |
, m_variantSet(0) |
|
190 |
, m_weightSet(0) |
|
191 |
, m_textAnchorSet(0) |
|
192 |
{ |
|
193 |
} |
|
194 |
||
195 |
QSvgFontStyle::QSvgFontStyle() |
|
196 |
: m_svgFont(0) |
|
197 |
, m_doc(0) |
|
198 |
, m_familySet(0) |
|
199 |
, m_sizeSet(0) |
|
200 |
, m_styleSet(0) |
|
201 |
, m_variantSet(0) |
|
202 |
, m_weightSet(0) |
|
203 |
, m_textAnchorSet(0) |
|
204 |
{ |
|
205 |
} |
|
206 |
||
207 |
int QSvgFontStyle::SVGToQtWeight(int weight) { |
|
208 |
switch (weight) { |
|
209 |
case 100: |
|
210 |
case 200: |
|
211 |
return QFont::Light; |
|
212 |
case 300: |
|
213 |
case 400: |
|
214 |
return QFont::Normal; |
|
215 |
case 500: |
|
216 |
case 600: |
|
217 |
return QFont::DemiBold; |
|
218 |
case 700: |
|
219 |
case 800: |
|
220 |
return QFont::Bold; |
|
221 |
case 900: |
|
222 |
return QFont::Black; |
|
223 |
} |
|
224 |
return QFont::Normal; |
|
225 |
} |
|
226 |
||
227 |
void QSvgFontStyle::apply(QPainter *p, const QRectF &, QSvgNode *, QSvgExtraStates &states) |
|
228 |
{ |
|
229 |
m_oldQFont = p->font(); |
|
230 |
m_oldSvgFont = states.svgFont; |
|
231 |
m_oldTextAnchor = states.textAnchor; |
|
232 |
m_oldWeight = states.fontWeight; |
|
233 |
||
234 |
if (m_textAnchorSet) |
|
235 |
states.textAnchor = m_textAnchor; |
|
236 |
||
237 |
QFont font = m_oldQFont; |
|
238 |
if (m_familySet) { |
|
239 |
states.svgFont = m_svgFont; |
|
240 |
font.setFamily(m_qfont.family()); |
|
241 |
} |
|
242 |
||
243 |
if (m_sizeSet) |
|
244 |
font.setPointSize(m_qfont.pointSizeF()); |
|
245 |
||
246 |
if (m_styleSet) |
|
247 |
font.setStyle(m_qfont.style()); |
|
248 |
||
249 |
if (m_variantSet) |
|
250 |
font.setCapitalization(m_qfont.capitalization()); |
|
251 |
||
252 |
if (m_weightSet) { |
|
253 |
if (m_weight == BOLDER) { |
|
254 |
states.fontWeight = qMin(states.fontWeight + 100, 900); |
|
255 |
} else if (m_weight == LIGHTER) { |
|
256 |
states.fontWeight = qMax(states.fontWeight - 100, 100); |
|
257 |
} else { |
|
258 |
states.fontWeight = m_weight; |
|
259 |
} |
|
260 |
font.setWeight(SVGToQtWeight(states.fontWeight)); |
|
261 |
} |
|
262 |
||
263 |
p->setFont(font); |
|
264 |
} |
|
265 |
||
266 |
void QSvgFontStyle::revert(QPainter *p, QSvgExtraStates &states) |
|
267 |
{ |
|
268 |
p->setFont(m_oldQFont); |
|
269 |
states.svgFont = m_oldSvgFont; |
|
270 |
states.textAnchor = m_oldTextAnchor; |
|
271 |
states.fontWeight = m_oldWeight; |
|
272 |
} |
|
273 |
||
274 |
QSvgStrokeStyle::QSvgStrokeStyle() |
|
275 |
: m_strokeOpacity(1.0) |
|
276 |
, m_oldStrokeOpacity(0.0) |
|
277 |
, m_strokeDashOffset(0) |
|
278 |
, m_oldStrokeDashOffset(0) |
|
279 |
, m_style(0) |
|
280 |
, m_gradientResolved(1) |
|
281 |
, m_vectorEffect(0) |
|
282 |
, m_oldVectorEffect(0) |
|
283 |
, m_strokeSet(0) |
|
284 |
, m_strokeDashArraySet(0) |
|
285 |
, m_strokeDashOffsetSet(0) |
|
286 |
, m_strokeLineCapSet(0) |
|
287 |
, m_strokeLineJoinSet(0) |
|
288 |
, m_strokeMiterLimitSet(0) |
|
289 |
, m_strokeOpacitySet(0) |
|
290 |
, m_strokeWidthSet(0) |
|
291 |
, m_vectorEffectSet(0) |
|
292 |
{ |
|
293 |
} |
|
294 |
||
295 |
void QSvgStrokeStyle::apply(QPainter *p, const QRectF &, QSvgNode *, QSvgExtraStates &states) |
|
296 |
{ |
|
297 |
m_oldStroke = p->pen(); |
|
298 |
m_oldStrokeOpacity = states.strokeOpacity; |
|
299 |
m_oldStrokeDashOffset = states.strokeDashOffset; |
|
300 |
m_oldVectorEffect = states.vectorEffect; |
|
301 |
||
302 |
QPen pen = p->pen(); |
|
303 |
||
304 |
qreal oldWidth = pen.widthF(); |
|
305 |
qreal width = m_stroke.widthF(); |
|
306 |
if (oldWidth == 0) |
|
307 |
oldWidth = 1; |
|
308 |
if (width == 0) |
|
309 |
width = 1; |
|
310 |
qreal scale = oldWidth / width; |
|
311 |
||
312 |
if (m_strokeOpacitySet) |
|
313 |
states.strokeOpacity = m_strokeOpacity; |
|
314 |
||
315 |
if (m_vectorEffectSet) |
|
316 |
states.vectorEffect = m_vectorEffect; |
|
317 |
||
318 |
if (m_strokeSet) { |
|
319 |
if (m_style) |
|
320 |
pen.setBrush(m_style->brush(p, states)); |
|
321 |
else |
|
322 |
pen.setBrush(m_stroke.brush()); |
|
323 |
} |
|
324 |
||
325 |
if (m_strokeWidthSet) |
|
326 |
pen.setWidthF(m_stroke.widthF()); |
|
327 |
||
328 |
bool setDashOffsetNeeded = false; |
|
329 |
||
330 |
if (m_strokeDashOffsetSet) { |
|
331 |
states.strokeDashOffset = m_strokeDashOffset; |
|
332 |
setDashOffsetNeeded = true; |
|
333 |
} |
|
334 |
||
335 |
if (m_strokeDashArraySet) { |
|
336 |
if (m_stroke.style() == Qt::SolidLine) { |
|
337 |
pen.setStyle(Qt::SolidLine); |
|
338 |
} else if (m_strokeWidthSet || oldWidth == 1) { |
|
339 |
// If both width and dash array was set, the dash array is already scaled correctly. |
|
340 |
pen.setDashPattern(m_stroke.dashPattern()); |
|
341 |
setDashOffsetNeeded = true; |
|
342 |
} else { |
|
343 |
// If dash array was set, but not the width, the dash array has to be scaled with respect to the old width. |
|
344 |
QVector<qreal> dashes = m_stroke.dashPattern(); |
|
345 |
for (int i = 0; i < dashes.size(); ++i) |
|
346 |
dashes[i] /= oldWidth; |
|
347 |
pen.setDashPattern(dashes); |
|
348 |
setDashOffsetNeeded = true; |
|
349 |
} |
|
350 |
} else if (m_strokeWidthSet && pen.style() != Qt::SolidLine && scale != 1) { |
|
351 |
// If the width was set, but not the dash array, the old dash array must be scaled with respect to the new width. |
|
352 |
QVector<qreal> dashes = pen.dashPattern(); |
|
353 |
for (int i = 0; i < dashes.size(); ++i) |
|
354 |
dashes[i] *= scale; |
|
355 |
pen.setDashPattern(dashes); |
|
356 |
setDashOffsetNeeded = true; |
|
357 |
} |
|
358 |
||
359 |
if (m_strokeLineCapSet) |
|
360 |
pen.setCapStyle(m_stroke.capStyle()); |
|
361 |
if (m_strokeLineJoinSet) |
|
362 |
pen.setJoinStyle(m_stroke.joinStyle()); |
|
363 |
if (m_strokeMiterLimitSet) |
|
364 |
pen.setMiterLimit(m_stroke.miterLimit()); |
|
365 |
||
3
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
366 |
// You can have dash offset on solid strokes in SVG files, but not in Qt. |
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
367 |
// QPen::setDashOffset() will set the pen style to Qt::CustomDashLine, |
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
368 |
// so don't call the method if the pen is solid. |
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
369 |
if (setDashOffsetNeeded && pen.style() != Qt::SolidLine) { |
0 | 370 |
qreal currentWidth = pen.widthF(); |
371 |
if (currentWidth == 0) |
|
372 |
currentWidth = 1; |
|
373 |
pen.setDashOffset(states.strokeDashOffset / currentWidth); |
|
374 |
} |
|
375 |
||
376 |
pen.setCosmetic(states.vectorEffect); |
|
377 |
||
378 |
p->setPen(pen); |
|
379 |
} |
|
380 |
||
381 |
void QSvgStrokeStyle::revert(QPainter *p, QSvgExtraStates &states) |
|
382 |
{ |
|
383 |
p->setPen(m_oldStroke); |
|
384 |
states.strokeOpacity = m_oldStrokeOpacity; |
|
385 |
states.strokeDashOffset = m_oldStrokeDashOffset; |
|
386 |
states.vectorEffect = m_oldVectorEffect; |
|
387 |
} |
|
388 |
||
389 |
void QSvgStrokeStyle::setDashArray(const QVector<qreal> &dashes) |
|
390 |
{ |
|
391 |
if (m_strokeWidthSet) { |
|
392 |
QVector<qreal> d = dashes; |
|
393 |
qreal w = m_stroke.widthF(); |
|
394 |
if (w != 0 && w != 1) { |
|
395 |
for (int i = 0; i < d.size(); ++i) |
|
396 |
d[i] /= w; |
|
397 |
} |
|
398 |
m_stroke.setDashPattern(d); |
|
399 |
} else { |
|
400 |
m_stroke.setDashPattern(dashes); |
|
401 |
} |
|
402 |
m_strokeDashArraySet = 1; |
|
403 |
} |
|
404 |
||
405 |
QSvgSolidColorStyle::QSvgSolidColorStyle(const QColor &color) |
|
406 |
: m_solidColor(color) |
|
407 |
{ |
|
408 |
} |
|
409 |
||
410 |
QSvgGradientStyle::QSvgGradientStyle(QGradient *grad) |
|
411 |
: m_gradient(grad), m_gradientStopsSet(false) |
|
412 |
{ |
|
413 |
} |
|
414 |
||
415 |
QBrush QSvgGradientStyle::brush(QPainter *, QSvgExtraStates &) |
|
416 |
{ |
|
417 |
if (!m_link.isEmpty()) { |
|
418 |
resolveStops(); |
|
419 |
} |
|
420 |
||
421 |
// If the gradient is marked as empty, insert transparent black |
|
422 |
if (!m_gradientStopsSet) { |
|
423 |
m_gradient->setStops(QGradientStops() << QGradientStop(0.0, QColor(0, 0, 0, 0))); |
|
424 |
m_gradientStopsSet = true; |
|
425 |
} |
|
426 |
||
427 |
QBrush b(*m_gradient); |
|
428 |
||
429 |
if (!m_matrix.isIdentity()) |
|
430 |
b.setMatrix(m_matrix); |
|
431 |
||
432 |
return b; |
|
433 |
} |
|
434 |
||
435 |
||
436 |
void QSvgGradientStyle::setMatrix(const QMatrix &mat) |
|
437 |
{ |
|
438 |
m_matrix = mat; |
|
439 |
} |
|
440 |
||
441 |
QSvgTransformStyle::QSvgTransformStyle(const QTransform &trans) |
|
442 |
: m_transform(trans) |
|
443 |
{ |
|
444 |
} |
|
445 |
||
446 |
void QSvgTransformStyle::apply(QPainter *p, const QRectF &, QSvgNode *, QSvgExtraStates &) |
|
447 |
{ |
|
448 |
m_oldWorldTransform = p->worldTransform(); |
|
449 |
p->setWorldTransform(m_transform, true); |
|
450 |
} |
|
451 |
||
452 |
void QSvgTransformStyle::revert(QPainter *p, QSvgExtraStates &) |
|
453 |
{ |
|
454 |
p->setWorldTransform(m_oldWorldTransform, false /* don't combine */); |
|
455 |
} |
|
456 |
||
457 |
QSvgStyleProperty::Type QSvgQualityStyle::type() const |
|
458 |
{ |
|
459 |
return QUALITY; |
|
460 |
} |
|
461 |
||
462 |
QSvgStyleProperty::Type QSvgFillStyle::type() const |
|
463 |
{ |
|
464 |
return FILL; |
|
465 |
} |
|
466 |
||
467 |
QSvgStyleProperty::Type QSvgViewportFillStyle::type() const |
|
468 |
{ |
|
469 |
return VIEWPORT_FILL; |
|
470 |
} |
|
471 |
||
472 |
QSvgStyleProperty::Type QSvgFontStyle::type() const |
|
473 |
{ |
|
474 |
return FONT; |
|
475 |
} |
|
476 |
||
477 |
QSvgStyleProperty::Type QSvgStrokeStyle::type() const |
|
478 |
{ |
|
479 |
return STROKE; |
|
480 |
} |
|
481 |
||
482 |
QSvgStyleProperty::Type QSvgSolidColorStyle::type() const |
|
483 |
{ |
|
484 |
return SOLID_COLOR; |
|
485 |
} |
|
486 |
||
487 |
QSvgStyleProperty::Type QSvgGradientStyle::type() const |
|
488 |
{ |
|
489 |
return GRADIENT; |
|
490 |
} |
|
491 |
||
492 |
QSvgStyleProperty::Type QSvgTransformStyle::type() const |
|
493 |
{ |
|
494 |
return TRANSFORM; |
|
495 |
} |
|
496 |
||
497 |
||
498 |
QSvgCompOpStyle::QSvgCompOpStyle(QPainter::CompositionMode mode) |
|
499 |
: m_mode(mode) |
|
500 |
{ |
|
501 |
||
502 |
} |
|
503 |
||
504 |
void QSvgCompOpStyle::apply(QPainter *p, const QRectF &, QSvgNode *, QSvgExtraStates &) |
|
505 |
{ |
|
506 |
m_oldMode = p->compositionMode(); |
|
507 |
p->setCompositionMode(m_mode); |
|
508 |
} |
|
509 |
||
510 |
void QSvgCompOpStyle::revert(QPainter *p, QSvgExtraStates &) |
|
511 |
{ |
|
512 |
p->setCompositionMode(m_oldMode); |
|
513 |
} |
|
514 |
||
515 |
QSvgStyleProperty::Type QSvgCompOpStyle::type() const |
|
516 |
{ |
|
517 |
return COMP_OP; |
|
518 |
} |
|
519 |
||
520 |
QSvgStyle::~QSvgStyle() |
|
521 |
{ |
|
522 |
} |
|
523 |
||
524 |
void QSvgStyle::apply(QPainter *p, const QRectF &rect, QSvgNode *node, QSvgExtraStates &states) |
|
525 |
{ |
|
526 |
if (quality) { |
|
527 |
quality->apply(p, rect, node, states); |
|
528 |
} |
|
529 |
||
530 |
if (fill) { |
|
531 |
fill->apply(p, rect, node, states); |
|
532 |
} |
|
533 |
||
534 |
if (viewportFill) { |
|
535 |
viewportFill->apply(p, rect, node, states); |
|
536 |
} |
|
537 |
||
538 |
if (font) { |
|
539 |
font->apply(p, rect, node, states); |
|
540 |
} |
|
541 |
||
542 |
if (stroke) { |
|
543 |
stroke->apply(p, rect, node, states); |
|
544 |
} |
|
545 |
||
546 |
if (transform) { |
|
547 |
transform->apply(p, rect, node, states); |
|
548 |
} |
|
549 |
||
550 |
if (animateColor) { |
|
551 |
animateColor->apply(p, rect, node, states); |
|
552 |
} |
|
553 |
||
554 |
//animated transforms have to be applied |
|
555 |
//_after_ the original object transformations |
|
556 |
if (!animateTransforms.isEmpty()) { |
|
557 |
qreal totalTimeElapsed = node->document()->currentElapsed(); |
|
558 |
// Find the last animateTransform with additive="replace", since this will override all |
|
559 |
// previous animateTransforms. |
|
560 |
QList<QSvgRefCounter<QSvgAnimateTransform> >::const_iterator itr = animateTransforms.constEnd(); |
|
561 |
do { |
|
562 |
--itr; |
|
563 |
if ((*itr)->animActive(totalTimeElapsed) |
|
564 |
&& (*itr)->additiveType() == QSvgAnimateTransform::Replace) { |
|
565 |
// An animateTransform with additive="replace" will replace the transform attribute. |
|
566 |
if (transform) |
|
567 |
transform->revert(p, states); |
|
568 |
break; |
|
569 |
} |
|
570 |
} while (itr != animateTransforms.constBegin()); |
|
571 |
||
572 |
// Apply the animateTransforms after and including the last one with additive="replace". |
|
573 |
for (; itr != animateTransforms.constEnd(); ++itr) { |
|
574 |
if ((*itr)->animActive(totalTimeElapsed)) |
|
575 |
(*itr)->apply(p, rect, node, states); |
|
576 |
} |
|
577 |
} |
|
578 |
||
579 |
if (opacity) { |
|
580 |
opacity->apply(p, rect, node, states); |
|
581 |
} |
|
582 |
||
583 |
if (compop) { |
|
584 |
compop->apply(p, rect, node, states); |
|
585 |
} |
|
586 |
} |
|
587 |
||
588 |
void QSvgStyle::revert(QPainter *p, QSvgExtraStates &states) |
|
589 |
{ |
|
590 |
if (quality) { |
|
591 |
quality->revert(p, states); |
|
592 |
} |
|
593 |
||
594 |
if (fill) { |
|
595 |
fill->revert(p, states); |
|
596 |
} |
|
597 |
||
598 |
if (viewportFill) { |
|
599 |
viewportFill->revert(p, states); |
|
600 |
} |
|
601 |
||
602 |
if (font) { |
|
603 |
font->revert(p, states); |
|
604 |
} |
|
605 |
||
606 |
if (stroke) { |
|
607 |
stroke->revert(p, states); |
|
608 |
} |
|
609 |
||
610 |
//animated transforms need to be reverted _before_ |
|
611 |
//the native transforms |
|
612 |
if (!animateTransforms.isEmpty()) { |
|
613 |
QList<QSvgRefCounter<QSvgAnimateTransform> >::const_iterator itr = animateTransforms.constBegin(); |
|
614 |
for (; itr != animateTransforms.constEnd(); ++itr) { |
|
615 |
if ((*itr)->transformApplied()) { |
|
616 |
(*itr)->revert(p, states); |
|
617 |
break; |
|
618 |
} |
|
619 |
} |
|
620 |
for (; itr != animateTransforms.constEnd(); ++itr) |
|
621 |
(*itr)->clearTransformApplied(); |
|
622 |
} |
|
623 |
||
624 |
if (transform) { |
|
625 |
transform->revert(p, states); |
|
626 |
} |
|
627 |
||
628 |
if (animateColor) { |
|
629 |
animateColor->revert(p, states); |
|
630 |
} |
|
631 |
||
632 |
if (opacity) { |
|
633 |
opacity->revert(p, states); |
|
634 |
} |
|
635 |
||
636 |
if (compop) { |
|
637 |
compop->revert(p, states); |
|
638 |
} |
|
639 |
} |
|
640 |
||
641 |
QSvgAnimateTransform::QSvgAnimateTransform(int startMs, int endMs, int byMs ) |
|
642 |
: QSvgStyleProperty(), |
|
643 |
m_from(startMs), m_to(endMs), m_by(byMs), |
|
644 |
m_type(Empty), m_additive(Replace), m_count(0), m_finished(false), m_transformApplied(false) |
|
645 |
{ |
|
646 |
m_totalRunningTime = m_to - m_from; |
|
647 |
} |
|
648 |
||
649 |
void QSvgAnimateTransform::setArgs(TransformType type, Additive additive, const QVector<qreal> &args) |
|
650 |
{ |
|
651 |
m_type = type; |
|
652 |
m_args = args; |
|
653 |
m_additive = additive; |
|
654 |
Q_ASSERT(!(args.count()%3)); |
|
655 |
m_count = args.count() / 3; |
|
656 |
} |
|
657 |
||
658 |
void QSvgAnimateTransform::apply(QPainter *p, const QRectF &, QSvgNode *node, QSvgExtraStates &) |
|
659 |
{ |
|
660 |
m_oldWorldTransform = p->worldTransform(); |
|
661 |
resolveMatrix(node); |
|
662 |
p->setWorldTransform(m_transform, true); |
|
663 |
m_transformApplied = true; |
|
664 |
} |
|
665 |
||
666 |
void QSvgAnimateTransform::revert(QPainter *p, QSvgExtraStates &) |
|
667 |
{ |
|
668 |
p->setWorldTransform(m_oldWorldTransform, false /* don't combine */); |
|
669 |
m_transformApplied = false; |
|
670 |
} |
|
671 |
||
672 |
void QSvgAnimateTransform::resolveMatrix(QSvgNode *node) |
|
673 |
{ |
|
674 |
static const qreal deg2rad = qreal(0.017453292519943295769); |
|
675 |
qreal totalTimeElapsed = node->document()->currentElapsed(); |
|
676 |
if (totalTimeElapsed < m_from || m_finished) |
|
677 |
return; |
|
678 |
||
679 |
qreal animationFrame = 0; |
|
680 |
if (m_totalRunningTime != 0) { |
|
681 |
animationFrame = (totalTimeElapsed - m_from) / m_totalRunningTime; |
|
682 |
||
683 |
if (m_repeatCount >= 0 && m_repeatCount < animationFrame) { |
|
684 |
m_finished = true; |
|
685 |
animationFrame = m_repeatCount; |
|
686 |
} |
|
687 |
} |
|
688 |
||
689 |
qreal percentOfAnimation = animationFrame; |
|
690 |
if (percentOfAnimation > 1) { |
|
691 |
percentOfAnimation -= ((int)percentOfAnimation); |
|
692 |
} |
|
693 |
||
694 |
qreal currentPosition = percentOfAnimation * (m_count - 1); |
|
695 |
int startElem = qFloor(currentPosition); |
|
696 |
int endElem = qCeil(currentPosition); |
|
697 |
||
698 |
switch(m_type) |
|
699 |
{ |
|
700 |
case Translate: { |
|
701 |
startElem *= 3; |
|
702 |
endElem *= 3; |
|
703 |
qreal from1, from2; |
|
704 |
qreal to1, to2; |
|
705 |
from1 = m_args[startElem++]; |
|
706 |
from2 = m_args[startElem++]; |
|
707 |
to1 = m_args[endElem++]; |
|
708 |
to2 = m_args[endElem++]; |
|
709 |
||
710 |
qreal transXDiff = (to1-from1) * percentOfAnimation; |
|
711 |
qreal transX = from1 + transXDiff; |
|
712 |
qreal transYDiff = (to2-from2) * percentOfAnimation; |
|
713 |
qreal transY = from2 + transYDiff; |
|
714 |
m_transform = QTransform(); |
|
715 |
m_transform.translate(transX, transY); |
|
716 |
break; |
|
717 |
} |
|
718 |
case Scale: { |
|
719 |
startElem *= 3; |
|
720 |
endElem *= 3; |
|
721 |
qreal from1, from2; |
|
722 |
qreal to1, to2; |
|
723 |
from1 = m_args[startElem++]; |
|
724 |
from2 = m_args[startElem++]; |
|
725 |
to1 = m_args[endElem++]; |
|
726 |
to2 = m_args[endElem++]; |
|
727 |
||
728 |
qreal transXDiff = (to1-from1) * percentOfAnimation; |
|
729 |
qreal transX = from1 + transXDiff; |
|
730 |
qreal transYDiff = (to2-from2) * percentOfAnimation; |
|
731 |
qreal transY = from2 + transYDiff; |
|
732 |
if (transY == 0) |
|
733 |
transY = transX; |
|
734 |
m_transform = QTransform(); |
|
735 |
m_transform.scale(transX, transY); |
|
736 |
break; |
|
737 |
} |
|
738 |
case Rotate: { |
|
739 |
startElem *= 3; |
|
740 |
endElem *= 3; |
|
741 |
qreal from1, from2, from3; |
|
742 |
qreal to1, to2, to3; |
|
743 |
from1 = m_args[startElem++]; |
|
744 |
from2 = m_args[startElem++]; |
|
745 |
from3 = m_args[startElem++]; |
|
746 |
to1 = m_args[endElem++]; |
|
747 |
to2 = m_args[endElem++]; |
|
748 |
to3 = m_args[endElem++]; |
|
749 |
||
750 |
qreal rotationDiff = (to1 - from1) * percentOfAnimation; |
|
751 |
//qreal rotation = from1 + rotationDiff; |
|
752 |
||
753 |
qreal transXDiff = (to2-from2) * percentOfAnimation; |
|
754 |
qreal transX = from2 + transXDiff; |
|
755 |
qreal transYDiff = (to3-from3) * percentOfAnimation; |
|
756 |
qreal transY = from3 + transYDiff; |
|
757 |
m_transform = QTransform(); |
|
758 |
m_transform.translate(transX, transY); |
|
759 |
m_transform.rotate(rotationDiff); |
|
760 |
m_transform.translate(-transX, -transY); |
|
761 |
break; |
|
762 |
} |
|
763 |
case SkewX: { |
|
764 |
startElem *= 3; |
|
765 |
endElem *= 3; |
|
766 |
qreal from1; |
|
767 |
qreal to1; |
|
768 |
from1 = m_args[startElem++]; |
|
769 |
to1 = m_args[endElem++]; |
|
770 |
||
771 |
qreal transXDiff = (to1-from1) * percentOfAnimation; |
|
772 |
qreal transX = from1 + transXDiff; |
|
773 |
m_transform = QTransform(); |
|
3
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
774 |
m_transform.shear(qTan(transX * deg2rad), 0); |
0 | 775 |
break; |
776 |
} |
|
777 |
case SkewY: { |
|
778 |
startElem *= 3; |
|
779 |
endElem *= 3; |
|
780 |
qreal from1; |
|
781 |
qreal to1; |
|
782 |
from1 = m_args[startElem++]; |
|
783 |
to1 = m_args[endElem++]; |
|
784 |
||
785 |
||
786 |
qreal transYDiff = (to1 - from1) * percentOfAnimation; |
|
787 |
qreal transY = from1 + transYDiff; |
|
788 |
m_transform = QTransform(); |
|
3
41300fa6a67c
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
789 |
m_transform.shear(0, qTan(transY * deg2rad)); |
0 | 790 |
break; |
791 |
} |
|
792 |
default: |
|
793 |
break; |
|
794 |
} |
|
795 |
} |
|
796 |
||
797 |
QSvgStyleProperty::Type QSvgAnimateTransform::type() const |
|
798 |
{ |
|
799 |
return ANIMATE_TRANSFORM; |
|
800 |
} |
|
801 |
||
802 |
void QSvgAnimateTransform::setFreeze(bool freeze) |
|
803 |
{ |
|
804 |
m_freeze = freeze; |
|
805 |
} |
|
806 |
||
807 |
void QSvgAnimateTransform::setRepeatCount(qreal repeatCount) |
|
808 |
{ |
|
809 |
m_repeatCount = repeatCount; |
|
810 |
} |
|
811 |
||
812 |
QSvgAnimateColor::QSvgAnimateColor(int startMs, int endMs, int byMs) |
|
813 |
: QSvgStyleProperty(), |
|
814 |
m_from(startMs), m_to(endMs), m_by(byMs), |
|
815 |
m_finished(false) |
|
816 |
{ |
|
817 |
m_totalRunningTime = m_to - m_from; |
|
818 |
} |
|
819 |
||
820 |
void QSvgAnimateColor::setArgs(bool fill, |
|
821 |
const QList<QColor> &colors) |
|
822 |
{ |
|
823 |
m_fill = fill; |
|
824 |
m_colors = colors; |
|
825 |
} |
|
826 |
||
827 |
void QSvgAnimateColor::setFreeze(bool freeze) |
|
828 |
{ |
|
829 |
m_freeze = freeze; |
|
830 |
} |
|
831 |
||
832 |
void QSvgAnimateColor::setRepeatCount(qreal repeatCount) |
|
833 |
{ |
|
834 |
m_repeatCount = repeatCount; |
|
835 |
} |
|
836 |
||
837 |
void QSvgAnimateColor::apply(QPainter *p, const QRectF &, QSvgNode *node, QSvgExtraStates &) |
|
838 |
{ |
|
839 |
qreal totalTimeElapsed = node->document()->currentElapsed(); |
|
840 |
if (totalTimeElapsed < m_from || m_finished) |
|
841 |
return; |
|
842 |
||
843 |
qreal animationFrame = 0; |
|
844 |
if (m_totalRunningTime != 0) |
|
845 |
animationFrame = (totalTimeElapsed - m_from) / m_totalRunningTime; |
|
846 |
||
847 |
if (m_repeatCount >= 0 && m_repeatCount < animationFrame) { |
|
848 |
m_finished = true; |
|
849 |
animationFrame = m_repeatCount; |
|
850 |
} |
|
851 |
||
852 |
qreal percentOfAnimation = animationFrame; |
|
853 |
if (percentOfAnimation > 1) { |
|
854 |
percentOfAnimation -= ((int)percentOfAnimation); |
|
855 |
} |
|
856 |
||
857 |
qreal currentPosition = percentOfAnimation * (m_colors.count() - 1); |
|
858 |
||
859 |
int startElem = qFloor(currentPosition); |
|
860 |
int endElem = qCeil(currentPosition); |
|
861 |
QColor start = m_colors[startElem]; |
|
862 |
QColor end = m_colors[endElem]; |
|
863 |
||
864 |
qreal percentOfColorMorph = currentPosition; |
|
865 |
if (percentOfColorMorph > 1) { |
|
866 |
percentOfColorMorph -= ((int)percentOfColorMorph); |
|
867 |
} |
|
868 |
||
869 |
// Interpolate between the two fixed colors start and end |
|
870 |
qreal aDiff = (end.alpha() - start.alpha()) * percentOfColorMorph; |
|
871 |
qreal rDiff = (end.red() - start.red()) * percentOfColorMorph; |
|
872 |
qreal gDiff = (end.green() - start.green()) * percentOfColorMorph; |
|
873 |
qreal bDiff = (end.blue() - start.blue()) * percentOfColorMorph; |
|
874 |
||
875 |
int alpha = int(start.alpha() + aDiff); |
|
876 |
int red = int(start.red() + rDiff); |
|
877 |
int green = int(start.green() + gDiff); |
|
878 |
int blue = int(start.blue() + bDiff); |
|
879 |
||
880 |
QColor color(red, green, blue, alpha); |
|
881 |
||
882 |
if (m_fill) { |
|
883 |
QBrush b = p->brush(); |
|
884 |
m_oldBrush = b; |
|
885 |
b.setColor(color); |
|
886 |
p->setBrush(b); |
|
887 |
} else { |
|
888 |
QPen pen = p->pen(); |
|
889 |
m_oldPen = pen; |
|
890 |
pen.setColor(color); |
|
891 |
p->setPen(pen); |
|
892 |
} |
|
893 |
} |
|
894 |
||
895 |
void QSvgAnimateColor::revert(QPainter *p, QSvgExtraStates &) |
|
896 |
{ |
|
897 |
if (m_fill) { |
|
898 |
p->setBrush(m_oldBrush); |
|
899 |
} else { |
|
900 |
p->setPen(m_oldPen); |
|
901 |
} |
|
902 |
} |
|
903 |
||
904 |
QSvgStyleProperty::Type QSvgAnimateColor::type() const |
|
905 |
{ |
|
906 |
return ANIMATE_COLOR; |
|
907 |
} |
|
908 |
||
909 |
QSvgOpacityStyle::QSvgOpacityStyle(qreal opacity) |
|
910 |
: m_opacity(opacity), m_oldOpacity(0) |
|
911 |
{ |
|
912 |
||
913 |
} |
|
914 |
||
915 |
void QSvgOpacityStyle::apply(QPainter *p, const QRectF &, QSvgNode *, QSvgExtraStates &) |
|
916 |
{ |
|
917 |
m_oldOpacity = p->opacity(); |
|
918 |
p->setOpacity(m_opacity * m_oldOpacity); |
|
919 |
} |
|
920 |
||
921 |
void QSvgOpacityStyle::revert(QPainter *p, QSvgExtraStates &) |
|
922 |
{ |
|
923 |
p->setOpacity(m_oldOpacity); |
|
924 |
} |
|
925 |
||
926 |
QSvgStyleProperty::Type QSvgOpacityStyle::type() const |
|
927 |
{ |
|
928 |
return OPACITY; |
|
929 |
} |
|
930 |
||
931 |
void QSvgGradientStyle::setStopLink(const QString &link, QSvgTinyDocument *doc) |
|
932 |
{ |
|
933 |
m_link = link; |
|
934 |
m_doc = doc; |
|
935 |
} |
|
936 |
||
937 |
void QSvgGradientStyle::resolveStops() |
|
938 |
{ |
|
939 |
if (!m_link.isEmpty() && m_doc) { |
|
940 |
QSvgStyleProperty *prop = m_doc->styleProperty(m_link); |
|
941 |
if (prop) { |
|
942 |
if (prop->type() == QSvgStyleProperty::GRADIENT) { |
|
943 |
QSvgGradientStyle *st = |
|
944 |
static_cast<QSvgGradientStyle*>(prop); |
|
945 |
st->resolveStops(); |
|
946 |
m_gradient->setStops(st->qgradient()->stops()); |
|
947 |
m_gradientStopsSet = st->gradientStopsSet(); |
|
948 |
} |
|
949 |
} else { |
|
950 |
qWarning("Could not resolve property : %s", qPrintable(m_link)); |
|
951 |
} |
|
952 |
m_link = QString(); |
|
953 |
} |
|
954 |
} |
|
955 |
||
956 |
QT_END_NAMESPACE |
|
957 |
||
958 |
#endif // QT_NO_SVG |