~ubuntu-branches/ubuntu/raring/qtwebkit-source/raring-proposed

« back to all changes in this revision

Viewing changes to Source/WebCore/svg/SVGAnimateMotionElement.cpp

  • Committer: Package Import Robot
  • Author(s): Jonathan Riddell
  • Date: 2013-02-18 14:24:18 UTC
  • Revision ID: package-import@ubuntu.com-20130218142418-eon0jmjg3nj438uy
Tags: upstream-2.3
ImportĀ upstreamĀ versionĀ 2.3

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (C) 2007 Eric Seidel <eric@webkit.org>
 
3
 * Copyright (C) 2007 Rob Buis <buis@kde.org>
 
4
 * Copyright (C) 2008 Apple Inc. All rights reserved.
 
5
 *
 
6
 * This library is free software; you can redistribute it and/or
 
7
 * modify it under the terms of the GNU Library General Public
 
8
 * License as published by the Free Software Foundation; either
 
9
 * version 2 of the License, or (at your option) any later version.
 
10
 *
 
11
 * This library is distributed in the hope that it will be useful,
 
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
14
 * Library General Public License for more details.
 
15
 *
 
16
 * You should have received a copy of the GNU Library General Public License
 
17
 * along with this library; see the file COPYING.LIB.  If not, write to
 
18
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 
19
 * Boston, MA 02110-1301, USA.
 
20
 */
 
21
 
 
22
#include "config.h"
 
23
 
 
24
#if ENABLE(SVG)
 
25
#include "SVGAnimateMotionElement.h"
 
26
 
 
27
#include "Attribute.h"
 
28
#include "RenderObject.h"
 
29
#include "RenderSVGResource.h"
 
30
#include "SVGElementInstance.h"
 
31
#include "SVGMPathElement.h"
 
32
#include "SVGNames.h"
 
33
#include "SVGParserUtilities.h"
 
34
#include "SVGPathData.h"
 
35
#include "SVGPathElement.h"
 
36
#include "SVGPathUtilities.h"
 
37
#include "SVGTransformList.h"
 
38
#include <wtf/MathExtras.h>
 
39
#include <wtf/StdLibExtras.h>
 
40
 
 
41
namespace WebCore {
 
42
    
 
43
using namespace SVGNames;
 
44
 
 
45
inline SVGAnimateMotionElement::SVGAnimateMotionElement(const QualifiedName& tagName, Document* document)
 
46
    : SVGAnimationElement(tagName, document)
 
47
    , m_hasToPointAtEndOfDuration(false)
 
48
{
 
49
    setCalcMode(CalcModePaced);
 
50
    ASSERT(hasTagName(animateMotionTag));
 
51
}
 
52
 
 
53
PassRefPtr<SVGAnimateMotionElement> SVGAnimateMotionElement::create(const QualifiedName& tagName, Document* document)
 
54
{
 
55
    return adoptRef(new SVGAnimateMotionElement(tagName, document));
 
56
}
 
57
 
 
58
bool SVGAnimateMotionElement::hasValidAttributeType()
 
59
{
 
60
    SVGElement* targetElement = this->targetElement();
 
61
    if (!targetElement)
 
62
        return false;
 
63
 
 
64
    // We don't have a special attribute name to verify the animation type. Check the element name instead.
 
65
    if (!targetElement->isStyledTransformable() && !targetElement->hasTagName(SVGNames::textTag))
 
66
        return false;
 
67
    // Spec: SVG 1.1 section 19.2.15
 
68
    // FIXME: svgTag is missing. Needs to be checked, if transforming <svg> could cause problems.
 
69
    if (targetElement->hasTagName(gTag)
 
70
        || targetElement->hasTagName(defsTag)
 
71
        || targetElement->hasTagName(useTag)
 
72
        || targetElement->hasTagName(imageTag)
 
73
        || targetElement->hasTagName(switchTag)
 
74
        || targetElement->hasTagName(pathTag)
 
75
        || targetElement->hasTagName(rectTag)
 
76
        || targetElement->hasTagName(circleTag)
 
77
        || targetElement->hasTagName(ellipseTag)
 
78
        || targetElement->hasTagName(lineTag)
 
79
        || targetElement->hasTagName(polylineTag)
 
80
        || targetElement->hasTagName(polygonTag)
 
81
        || targetElement->hasTagName(textTag)
 
82
        || targetElement->hasTagName(clipPathTag)
 
83
        || targetElement->hasTagName(maskTag)
 
84
        || targetElement->hasTagName(aTag)
 
85
        || targetElement->hasTagName(foreignObjectTag)
 
86
        )
 
87
        return true;
 
88
    return false;
 
89
}
 
90
 
 
91
bool SVGAnimateMotionElement::hasValidAttributeName()
 
92
{
 
93
    // AnimateMotion does not use attributeName so it is always valid.
 
94
    return true;
 
95
}
 
96
 
 
97
bool SVGAnimateMotionElement::isSupportedAttribute(const QualifiedName& attrName)
 
98
{
 
99
    DEFINE_STATIC_LOCAL(HashSet<QualifiedName>, supportedAttributes, ());
 
100
    if (supportedAttributes.isEmpty())
 
101
        supportedAttributes.add(SVGNames::pathAttr);
 
102
    return supportedAttributes.contains<QualifiedName, SVGAttributeHashTranslator>(attrName);
 
103
}
 
104
 
 
105
void SVGAnimateMotionElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
 
106
{
 
107
    if (!isSupportedAttribute(name)) {
 
108
        SVGAnimationElement::parseAttribute(name, value);
 
109
        return;
 
110
    }
 
111
 
 
112
    if (name == SVGNames::pathAttr) {
 
113
        m_path = Path();
 
114
        buildPathFromString(value, m_path);
 
115
        updateAnimationPath();
 
116
        return;
 
117
    }
 
118
 
 
119
    ASSERT_NOT_REACHED();
 
120
}
 
121
    
 
122
SVGAnimateMotionElement::RotateMode SVGAnimateMotionElement::rotateMode() const
 
123
{
 
124
    DEFINE_STATIC_LOCAL(const AtomicString, autoVal, ("auto", AtomicString::ConstructFromLiteral));
 
125
    DEFINE_STATIC_LOCAL(const AtomicString, autoReverse, ("auto-reverse", AtomicString::ConstructFromLiteral));
 
126
    const AtomicString& rotate = getAttribute(SVGNames::rotateAttr);
 
127
    if (rotate == autoVal)
 
128
        return RotateAuto;
 
129
    if (rotate == autoReverse)
 
130
        return RotateAutoReverse;
 
131
    return RotateAngle;
 
132
}
 
133
 
 
134
void SVGAnimateMotionElement::updateAnimationPath()
 
135
{
 
136
    m_animationPath = Path();
 
137
    bool foundMPath = false;
 
138
 
 
139
    for (Node* child = firstChild(); child; child = child->nextSibling()) {
 
140
        if (child->hasTagName(SVGNames::mpathTag)) {
 
141
            SVGMPathElement* mPath = static_cast<SVGMPathElement*>(child);
 
142
            SVGPathElement* pathElement = mPath->pathElement();
 
143
            if (pathElement) {
 
144
                updatePathFromGraphicsElement(pathElement, m_animationPath);
 
145
                foundMPath = true;
 
146
                break;
 
147
            }
 
148
        }
 
149
    }
 
150
 
 
151
    if (!foundMPath && fastHasAttribute(SVGNames::pathAttr))
 
152
        m_animationPath = m_path;
 
153
 
 
154
    updateAnimationMode();
 
155
}
 
156
 
 
157
static bool parsePoint(const String& s, FloatPoint& point)
 
158
{
 
159
    if (s.isEmpty())
 
160
        return false;
 
161
    const UChar* cur = s.characters();
 
162
    const UChar* end = cur + s.length();
 
163
    
 
164
    if (!skipOptionalSVGSpaces(cur, end))
 
165
        return false;
 
166
    
 
167
    float x = 0;
 
168
    if (!parseNumber(cur, end, x))
 
169
        return false;
 
170
    
 
171
    float y = 0;
 
172
    if (!parseNumber(cur, end, y))
 
173
        return false;
 
174
    
 
175
    point = FloatPoint(x, y);
 
176
    
 
177
    // disallow anything except spaces at the end
 
178
    return !skipOptionalSVGSpaces(cur, end);
 
179
}
 
180
    
 
181
void SVGAnimateMotionElement::resetAnimatedType()
 
182
{
 
183
    if (!hasValidAttributeType())
 
184
        return;
 
185
    SVGElement* targetElement = this->targetElement();
 
186
    if (!targetElement)
 
187
        return;
 
188
    if (AffineTransform* transform = targetElement->supplementalTransform())
 
189
        transform->makeIdentity();
 
190
}
 
191
 
 
192
void SVGAnimateMotionElement::clearAnimatedType(SVGElement* targetElement)
 
193
{
 
194
    if (!targetElement)
 
195
        return;
 
196
    if (AffineTransform* transform = targetElement->supplementalTransform())
 
197
        transform->makeIdentity();
 
198
}
 
199
 
 
200
bool SVGAnimateMotionElement::calculateToAtEndOfDurationValue(const String& toAtEndOfDurationString)
 
201
{
 
202
    parsePoint(toAtEndOfDurationString, m_toPointAtEndOfDuration);
 
203
    m_hasToPointAtEndOfDuration = true;
 
204
    return true;
 
205
}
 
206
 
 
207
bool SVGAnimateMotionElement::calculateFromAndToValues(const String& fromString, const String& toString)
 
208
{
 
209
    m_hasToPointAtEndOfDuration = false;
 
210
    parsePoint(fromString, m_fromPoint);
 
211
    parsePoint(toString, m_toPoint);
 
212
    return true;
 
213
}
 
214
    
 
215
bool SVGAnimateMotionElement::calculateFromAndByValues(const String& fromString, const String& byString)
 
216
{
 
217
    m_hasToPointAtEndOfDuration = false;
 
218
    if (animationMode() == ByAnimation && !isAdditive())
 
219
        return false;
 
220
    parsePoint(fromString, m_fromPoint);
 
221
    FloatPoint byPoint;
 
222
    parsePoint(byString, byPoint);
 
223
    m_toPoint = FloatPoint(m_fromPoint.x() + byPoint.x(), m_fromPoint.y() + byPoint.y());
 
224
    return true;
 
225
}
 
226
 
 
227
void SVGAnimateMotionElement::buildTransformForProgress(AffineTransform* transform, float percentage)
 
228
{
 
229
    ASSERT(!m_animationPath.isEmpty());
 
230
 
 
231
    bool ok = false;
 
232
    float positionOnPath = m_animationPath.length() * percentage;
 
233
    FloatPoint position = m_animationPath.pointAtLength(positionOnPath, ok);
 
234
    if (!ok)
 
235
        return;
 
236
    transform->translate(position.x(), position.y());
 
237
    RotateMode rotateMode = this->rotateMode();
 
238
    if (rotateMode != RotateAuto && rotateMode != RotateAutoReverse)
 
239
        return;
 
240
    float angle = m_animationPath.normalAngleAtLength(positionOnPath, ok);
 
241
    if (rotateMode == RotateAutoReverse)
 
242
        angle += 180;
 
243
    transform->rotate(angle);
 
244
}
 
245
 
 
246
void SVGAnimateMotionElement::calculateAnimatedValue(float percentage, unsigned repeatCount, SVGSMILElement*)
 
247
{
 
248
    SVGElement* targetElement = this->targetElement();
 
249
    if (!targetElement)
 
250
        return;
 
251
    AffineTransform* transform = targetElement->supplementalTransform();
 
252
    if (!transform)
 
253
        return;
 
254
 
 
255
    if (RenderObject* targetRenderer = targetElement->renderer())
 
256
        targetRenderer->setNeedsTransformUpdate();
 
257
 
 
258
    if (!isAdditive())
 
259
        transform->makeIdentity();
 
260
 
 
261
    if (animationMode() != PathAnimation) {
 
262
        FloatPoint toPointAtEndOfDuration = m_toPoint;
 
263
        if (isAccumulated() && repeatCount && m_hasToPointAtEndOfDuration)
 
264
            toPointAtEndOfDuration = m_toPointAtEndOfDuration;
 
265
 
 
266
        float animatedX = 0;
 
267
        animateAdditiveNumber(percentage, repeatCount, m_fromPoint.x(), m_toPoint.x(), toPointAtEndOfDuration.x(), animatedX);
 
268
 
 
269
        float animatedY = 0;
 
270
        animateAdditiveNumber(percentage, repeatCount, m_fromPoint.y(), m_toPoint.y(), toPointAtEndOfDuration.y(), animatedY);
 
271
 
 
272
        transform->translate(animatedX, animatedY);
 
273
        return;
 
274
    }
 
275
 
 
276
    buildTransformForProgress(transform, percentage);
 
277
 
 
278
    // Handle accumulate="sum".
 
279
    if (isAccumulated() && repeatCount) {
 
280
        for (unsigned i = 0; i < repeatCount; ++i)
 
281
            buildTransformForProgress(transform, 1);
 
282
    }
 
283
}
 
284
 
 
285
void SVGAnimateMotionElement::applyResultsToTarget()
 
286
{
 
287
    // We accumulate to the target element transform list so there is not much to do here.
 
288
    SVGElement* targetElement = this->targetElement();
 
289
    if (!targetElement)
 
290
        return;
 
291
 
 
292
    if (RenderObject* renderer = targetElement->renderer())
 
293
        RenderSVGResource::markForLayoutAndParentResourceInvalidation(renderer);
 
294
 
 
295
    AffineTransform* t = targetElement->supplementalTransform();
 
296
    if (!t)
 
297
        return;
 
298
 
 
299
    // ...except in case where we have additional instances in <use> trees.
 
300
    const HashSet<SVGElementInstance*>& instances = targetElement->instancesForElement();
 
301
    const HashSet<SVGElementInstance*>::const_iterator end = instances.end();
 
302
    for (HashSet<SVGElementInstance*>::const_iterator it = instances.begin(); it != end; ++it) {
 
303
        SVGElement* shadowTreeElement = (*it)->shadowTreeElement();
 
304
        ASSERT(shadowTreeElement);
 
305
        AffineTransform* transform = shadowTreeElement->supplementalTransform();
 
306
        if (!transform)
 
307
            continue;
 
308
        transform->setMatrix(t->a(), t->b(), t->c(), t->d(), t->e(), t->f());
 
309
        if (RenderObject* renderer = shadowTreeElement->renderer()) {
 
310
            renderer->setNeedsTransformUpdate();
 
311
            RenderSVGResource::markForLayoutAndParentResourceInvalidation(renderer);
 
312
        }
 
313
    }
 
314
}
 
315
 
 
316
float SVGAnimateMotionElement::calculateDistance(const String& fromString, const String& toString)
 
317
{
 
318
    FloatPoint from;
 
319
    FloatPoint to;
 
320
    if (!parsePoint(fromString, from))
 
321
        return -1;
 
322
    if (!parsePoint(toString, to))
 
323
        return -1;
 
324
    FloatSize diff = to - from;
 
325
    return sqrtf(diff.width() * diff.width() + diff.height() * diff.height());
 
326
}
 
327
 
 
328
void SVGAnimateMotionElement::updateAnimationMode()
 
329
{
 
330
    if (!m_animationPath.isEmpty())
 
331
        setAnimationMode(PathAnimation);
 
332
    else
 
333
        SVGAnimationElement::updateAnimationMode();
 
334
}
 
335
 
 
336
}
 
337
#endif // ENABLE(SVG)