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#if ENABLE(SVG)
25#include "AnimationUtilities.h"
26#include "SVGLengthContext.h"
27#include "SVGParsingError.h"
28#include "SVGPropertyTraits.h"
29
30namespace WebCore {
31
32class CSSPrimitiveValue;
33class QualifiedName;
34
35typedef int ExceptionCode;
36
37enum SVGLengthNegativeValuesMode {
38    AllowNegativeLengths,
39    ForbidNegativeLengths
40};
41
42class SVGLength {
43    WTF_MAKE_FAST_ALLOCATED;
44public:
45    // Forward declare these enums in the w3c naming scheme, for IDL generation
46    enum {
47        SVG_LENGTHTYPE_UNKNOWN = LengthTypeUnknown,
48        SVG_LENGTHTYPE_NUMBER = LengthTypeNumber,
49        SVG_LENGTHTYPE_PERCENTAGE = LengthTypePercentage,
50        SVG_LENGTHTYPE_EMS = LengthTypeEMS,
51        SVG_LENGTHTYPE_EXS = LengthTypeEXS,
52        SVG_LENGTHTYPE_PX = LengthTypePX,
53        SVG_LENGTHTYPE_CM = LengthTypeCM,
54        SVG_LENGTHTYPE_MM = LengthTypeMM,
55        SVG_LENGTHTYPE_IN = LengthTypeIN,
56        SVG_LENGTHTYPE_PT = LengthTypePT,
57        SVG_LENGTHTYPE_PC = LengthTypePC
58    };
59
60    SVGLength(SVGLengthMode = LengthModeOther, const String& valueAsString = String());
61    SVGLength(const SVGLengthContext&, float, SVGLengthMode = LengthModeOther, SVGLengthType = LengthTypeNumber);
62    SVGLength(const SVGLength&);
63
64    SVGLengthType unitType() const;
65    SVGLengthMode unitMode() const;
66
67    bool operator==(const SVGLength&) const;
68    bool operator!=(const SVGLength&) const;
69
70    static SVGLength construct(SVGLengthMode, const String&, SVGParsingError&, SVGLengthNegativeValuesMode = AllowNegativeLengths);
71
72    float value(const SVGLengthContext&) const;
73    float value(const SVGLengthContext&, ExceptionCode&) const;
74    void setValue(float, const SVGLengthContext&, ExceptionCode&);
75    void setValue(const SVGLengthContext&, float, SVGLengthMode, SVGLengthType, ExceptionCode&);
76
77    float valueInSpecifiedUnits() const { return m_valueInSpecifiedUnits; }
78    void setValueInSpecifiedUnits(float value) { m_valueInSpecifiedUnits = value; }
79
80    float valueAsPercentage() const;
81
82    String valueAsString() const;
83    void setValueAsString(const String&, ExceptionCode&);
84    void setValueAsString(const String&, SVGLengthMode, ExceptionCode&);
85
86    void newValueSpecifiedUnits(unsigned short, float valueInSpecifiedUnits, ExceptionCode&);
87    void convertToSpecifiedUnits(unsigned short, const SVGLengthContext&, ExceptionCode&);
88
89    // Helper functions
90    inline bool isRelative() const
91    {
92        SVGLengthType type = unitType();
93        return type == LengthTypePercentage || type == LengthTypeEMS || type == LengthTypeEXS;
94    }
95
96    bool isZero() const
97    {
98        return !m_valueInSpecifiedUnits;
99    }
100
101    static SVGLength fromCSSPrimitiveValue(CSSPrimitiveValue*);
102    static PassRefPtr<CSSPrimitiveValue> toCSSPrimitiveValue(const SVGLength&);
103    static SVGLengthMode lengthModeForAnimatedLengthAttribute(const QualifiedName&);
104
105    SVGLength blend(const SVGLength& from, float progress) const
106    {
107        SVGLengthType toType = unitType();
108        SVGLengthType fromType = from.unitType();
109        if ((from.isZero() && isZero())
110            || fromType == LengthTypeUnknown
111            || toType == LengthTypeUnknown
112            || (!from.isZero() && fromType != LengthTypePercentage && toType == LengthTypePercentage)
113            || (!isZero() && fromType == LengthTypePercentage && toType != LengthTypePercentage)
114            || (!from.isZero() && !isZero() && (fromType == LengthTypeEMS || fromType == LengthTypeEXS) && fromType != toType))
115            return *this;
116
117        SVGLength length;
118        ExceptionCode ec = 0;
119
120        if (fromType == LengthTypePercentage || toType == LengthTypePercentage) {
121            float fromPercent = from.valueAsPercentage() * 100;
122            float toPercent = valueAsPercentage() * 100;
123            length.newValueSpecifiedUnits(LengthTypePercentage, WebCore::blend(fromPercent, toPercent, progress), ec);
124            if (ec)
125                return SVGLength();
126            return length;
127        }
128
129        if (fromType == toType || from.isZero() || isZero() || fromType == LengthTypeEMS || fromType == LengthTypeEXS) {
130            float fromValue = from.valueInSpecifiedUnits();
131            float toValue = valueInSpecifiedUnits();
132            if (isZero())
133                length.newValueSpecifiedUnits(fromType, WebCore::blend(fromValue, toValue, progress), ec);
134            else
135                length.newValueSpecifiedUnits(toType, WebCore::blend(fromValue, toValue, progress), ec);
136            if (ec)
137                return SVGLength();
138            return length;
139        }
140
141        ASSERT(!isRelative());
142        ASSERT(!from.isRelative());
143
144        SVGLengthContext nonRelativeLengthContext(0);
145        float fromValueInUserUnits = nonRelativeLengthContext.convertValueToUserUnits(from.valueInSpecifiedUnits(), from.unitMode(), fromType, ec);
146        if (ec)
147            return SVGLength();
148
149        float fromValue = nonRelativeLengthContext.convertValueFromUserUnits(fromValueInUserUnits, unitMode(), toType, ec);
150        if (ec)
151            return SVGLength();
152
153        float toValue = valueInSpecifiedUnits();
154        length.newValueSpecifiedUnits(toType, WebCore::blend(fromValue, toValue, progress), ec);
155
156        if (ec)
157            return SVGLength();
158        return length;
159    }
160
161private:
162    float m_valueInSpecifiedUnits;
163    unsigned int m_unit;
164};
165
166template<>
167struct SVGPropertyTraits<SVGLength> {
168    static SVGLength initialValue() { return SVGLength(); }
169    static String toString(const SVGLength& type) { return type.valueAsString(); }
170};
171
172
173} // namespace WebCore
174
175#endif // ENABLE(SVG)
176#endif // SVGLength_h
177