1/*
2 * Copyright (C) 2004, 2005, 2006, 2008 Nikolas Zimmermann <zimmermann@kde.org>
3 * Copyright (C) 2004, 2005, 2006 Rob Buis <buis@kde.org>
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 * Library General Public License for more details.
14 *
15 * You should have received a copy of the GNU Library General Public License
16 * along with this library; see the file COPYING.LIB.  If not, write to
17 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
19 */
20
21#ifndef SVGLength_h
22#define SVGLength_h
23
24#include "AnimationUtilities.h"
25#include "SVGLengthContext.h"
26#include "SVGParsingError.h"
27#include "SVGPropertyTraits.h"
28
29namespace WebCore {
30
31class CSSPrimitiveValue;
32class QualifiedName;
33
34typedef int ExceptionCode;
35
36enum SVGLengthNegativeValuesMode {
37    AllowNegativeLengths,
38    ForbidNegativeLengths
39};
40
41class SVGLength {
42    WTF_MAKE_FAST_ALLOCATED;
43public:
44    // Forward declare these enums in the w3c naming scheme, for IDL generation
45    enum {
46        SVG_LENGTHTYPE_UNKNOWN = LengthTypeUnknown,
47        SVG_LENGTHTYPE_NUMBER = LengthTypeNumber,
48        SVG_LENGTHTYPE_PERCENTAGE = LengthTypePercentage,
49        SVG_LENGTHTYPE_EMS = LengthTypeEMS,
50        SVG_LENGTHTYPE_EXS = LengthTypeEXS,
51        SVG_LENGTHTYPE_PX = LengthTypePX,
52        SVG_LENGTHTYPE_CM = LengthTypeCM,
53        SVG_LENGTHTYPE_MM = LengthTypeMM,
54        SVG_LENGTHTYPE_IN = LengthTypeIN,
55        SVG_LENGTHTYPE_PT = LengthTypePT,
56        SVG_LENGTHTYPE_PC = LengthTypePC
57    };
58
59    SVGLength(SVGLengthMode = LengthModeOther, const String& valueAsString = String());
60    SVGLength(const SVGLengthContext&, float, SVGLengthMode = LengthModeOther, SVGLengthType = LengthTypeNumber);
61    SVGLength(const SVGLength&);
62
63    SVGLengthType unitType() const;
64    SVGLengthMode unitMode() const;
65
66    bool operator==(const SVGLength&) const;
67    bool operator!=(const SVGLength&) const;
68
69    static SVGLength construct(SVGLengthMode, const String&, SVGParsingError&, SVGLengthNegativeValuesMode = AllowNegativeLengths);
70
71    float value(const SVGLengthContext&) const;
72    float value(const SVGLengthContext&, ExceptionCode&) const;
73    void setValue(float, const SVGLengthContext&, ExceptionCode&);
74    void setValue(const SVGLengthContext&, float, SVGLengthMode, SVGLengthType, ExceptionCode&);
75
76    float valueInSpecifiedUnits() const { return m_valueInSpecifiedUnits; }
77    void setValueInSpecifiedUnits(float value) { m_valueInSpecifiedUnits = value; }
78
79    float valueAsPercentage() const;
80
81    String valueAsString() const;
82    void setValueAsString(const String&, ExceptionCode&);
83    void setValueAsString(const String&, SVGLengthMode, ExceptionCode&);
84
85    void newValueSpecifiedUnits(unsigned short, float valueInSpecifiedUnits, ExceptionCode&);
86    void convertToSpecifiedUnits(unsigned short, const SVGLengthContext&, ExceptionCode&);
87
88    // Helper functions
89    inline bool isRelative() const
90    {
91        SVGLengthType type = unitType();
92        return type == LengthTypePercentage || type == LengthTypeEMS || type == LengthTypeEXS;
93    }
94
95    bool isZero() const
96    {
97        return !m_valueInSpecifiedUnits;
98    }
99
100    static SVGLength fromCSSPrimitiveValue(CSSPrimitiveValue*);
101    static PassRefPtr<CSSPrimitiveValue> toCSSPrimitiveValue(const SVGLength&);
102    static SVGLengthMode lengthModeForAnimatedLengthAttribute(const QualifiedName&);
103
104    SVGLength blend(const SVGLength& from, float progress) const
105    {
106        SVGLengthType toType = unitType();
107        SVGLengthType fromType = from.unitType();
108        if ((from.isZero() && isZero())
109            || fromType == LengthTypeUnknown
110            || toType == LengthTypeUnknown
111            || (!from.isZero() && fromType != LengthTypePercentage && toType == LengthTypePercentage)
112            || (!isZero() && fromType == LengthTypePercentage && toType != LengthTypePercentage)
113            || (!from.isZero() && !isZero() && (fromType == LengthTypeEMS || fromType == LengthTypeEXS) && fromType != toType))
114            return *this;
115
116        SVGLength length;
117        ExceptionCode ec = 0;
118
119        if (fromType == LengthTypePercentage || toType == LengthTypePercentage) {
120            float fromPercent = from.valueAsPercentage() * 100;
121            float toPercent = valueAsPercentage() * 100;
122            length.newValueSpecifiedUnits(LengthTypePercentage, WebCore::blend(fromPercent, toPercent, progress), ec);
123            if (ec)
124                return SVGLength();
125            return length;
126        }
127
128        if (fromType == toType || from.isZero() || isZero() || fromType == LengthTypeEMS || fromType == LengthTypeEXS) {
129            float fromValue = from.valueInSpecifiedUnits();
130            float toValue = valueInSpecifiedUnits();
131            if (isZero())
132                length.newValueSpecifiedUnits(fromType, WebCore::blend(fromValue, toValue, progress), ec);
133            else
134                length.newValueSpecifiedUnits(toType, WebCore::blend(fromValue, toValue, progress), ec);
135            if (ec)
136                return SVGLength();
137            return length;
138        }
139
140        ASSERT(!isRelative());
141        ASSERT(!from.isRelative());
142
143        SVGLengthContext nonRelativeLengthContext(0);
144        float fromValueInUserUnits = nonRelativeLengthContext.convertValueToUserUnits(from.valueInSpecifiedUnits(), from.unitMode(), fromType, ec);
145        if (ec)
146            return SVGLength();
147
148        float fromValue = nonRelativeLengthContext.convertValueFromUserUnits(fromValueInUserUnits, unitMode(), toType, ec);
149        if (ec)
150            return SVGLength();
151
152        float toValue = valueInSpecifiedUnits();
153        length.newValueSpecifiedUnits(toType, WebCore::blend(fromValue, toValue, progress), ec);
154
155        if (ec)
156            return SVGLength();
157        return length;
158    }
159
160private:
161    float m_valueInSpecifiedUnits;
162    unsigned int m_unit;
163};
164
165template<>
166struct SVGPropertyTraits<SVGLength> {
167    static SVGLength initialValue() { return SVGLength(); }
168    static String toString(const SVGLength& type) { return type.valueAsString(); }
169};
170
171
172} // namespace WebCore
173
174#endif // SVGLength_h
175