SVG should support transform-origin and relative values
[WebKit-https.git] / Source / WebCore / platform / Length.h
1 /*
2     Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3     Copyright (C) 2006, 2008 Apple Inc. All rights reserved.
4     Copyright (C) 2011 Rik Cabanier (cabanier@adobe.com)
5     Copyright (C) 2011 Adobe Systems Incorporated. All rights reserved.
6
7     This library is free software; you can redistribute it and/or
8     modify it under the terms of the GNU Library General Public
9     License as published by the Free Software Foundation; either
10     version 2 of the License, or (at your option) any later version.
11
12     This library is distributed in the hope that it will be useful,
13     but WITHOUT ANY WARRANTY; without even the implied warranty of
14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15     Library General Public License for more details.
16
17     You should have received a copy of the GNU Library General Public License
18     along with this library; see the file COPYING.LIB.  If not, write to
19     the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20     Boston, MA 02110-1301, USA.
21 */
22
23 #ifndef Length_h
24 #define Length_h
25
26 #include "AnimationUtilities.h"
27 #include <wtf/Assertions.h>
28 #include <wtf/FastAllocBase.h>
29 #include <wtf/Forward.h>
30 #include <wtf/HashMap.h>
31 #include <wtf/MathExtras.h>
32 #include <wtf/PassOwnArrayPtr.h>
33
34 namespace WebCore {
35
36 const int intMaxForLength = 0x7ffffff; // max value for a 28-bit int
37 const int intMinForLength = (-0x7ffffff - 1); // min value for a 28-bit int
38
39 enum LengthType { Auto, Relative, Percent, Fixed, Intrinsic, MinIntrinsic, Calculated, Undefined };
40  
41 class CalculationValue;    
42     
43 struct Length {
44     WTF_MAKE_FAST_ALLOCATED;
45 public:
46     Length()
47         :  m_intValue(0), m_quirk(false), m_type(Auto), m_isFloat(false)
48     {
49     }
50
51     Length(LengthType t)
52         : m_intValue(0), m_quirk(false), m_type(t), m_isFloat(false)
53     {
54     }
55
56     Length(int v, LengthType t, bool q = false)
57         : m_intValue(v), m_quirk(q), m_type(t), m_isFloat(false)
58     {
59     }
60     
61     Length(float v, LengthType t, bool q = false)
62     : m_floatValue(v), m_quirk(q), m_type(t), m_isFloat(true)
63     {
64     }
65
66     Length(double v, LengthType t, bool q = false)
67         : m_quirk(q), m_type(t), m_isFloat(true)
68     {
69         m_floatValue = static_cast<float>(v);    
70     }
71
72     explicit Length(PassRefPtr<CalculationValue>);
73
74     Length(const Length& length)
75     {
76         initFromLength(length);
77     }
78     
79     Length& operator=(const Length& length)
80     {
81         initFromLength(length);
82         return *this;
83     }
84     
85     ~Length()
86     {
87         if (isCalculated())
88             decrementCalculatedRef();
89     }  
90     
91     bool operator==(const Length& o) const { return (m_type == o.m_type) && (m_quirk == o.m_quirk) && (isUndefined() || (getFloatValue() == o.getFloatValue())); }
92     bool operator!=(const Length& o) const { return !(*this == o); }
93
94     const Length& operator*=(float v)
95     {       
96         if (isCalculated()) {
97             ASSERT_NOT_REACHED();
98             return *this;
99         }
100         
101         if (m_isFloat)
102             m_floatValue = static_cast<float>(m_floatValue * v);
103         else        
104             m_intValue = static_cast<int>(m_intValue * v);
105         
106         return *this;
107     }
108     
109     int value() const
110     {
111         if (isCalculated()) {
112             ASSERT_NOT_REACHED();
113             return 0;
114         }
115         return getIntValue();
116     }
117
118     float percent() const
119     {
120         ASSERT(type() == Percent);
121         return getFloatValue();
122     }
123
124     PassRefPtr<CalculationValue> calculationValue() const;
125
126     LengthType type() const { return static_cast<LengthType>(m_type); }
127     bool quirk() const { return m_quirk; }
128
129     void setQuirk(bool quirk)
130     {
131         m_quirk = quirk;
132     }
133
134     void setValue(LengthType t, int value)
135     {
136         m_type = t;
137         m_intValue = value;
138         m_isFloat = false;
139     }
140
141     void setValue(int value)
142     {
143         if (isCalculated()) {
144             ASSERT_NOT_REACHED();
145             return;
146         }
147         setValue(Fixed, value);
148     }
149
150     void setValue(LengthType t, float value)
151     {
152         m_type = t;
153         m_floatValue = value;
154         m_isFloat = true;    
155     }
156
157     void setValue(float value)
158     {
159         *this = Length(value, Fixed);
160     }
161
162     int calcValue(int maxValue, bool roundPercentages = false) const
163     {
164         switch (type()) {
165             case Fixed:
166             case Percent:
167             case Calculated:
168                 return calcMinValue(maxValue, roundPercentages);
169             case Auto:
170                 return maxValue;
171             case Relative:
172             case Intrinsic:
173             case MinIntrinsic:
174             case Undefined:
175                 ASSERT_NOT_REACHED();
176                 return 0;
177         }
178         ASSERT_NOT_REACHED();
179         return 0;
180     }
181
182     int calcMinValue(int maxValue, bool roundPercentages = false) const
183     {
184         switch (type()) {
185             case Fixed:
186                 return value();
187             case Percent:
188                 if (roundPercentages)
189                     return static_cast<int>(round(maxValue * percent() / 100.0f));
190                 // Don't remove the extra cast to float. It is needed for rounding on 32-bit Intel machines that use the FPU stack.
191                 return static_cast<int>(static_cast<float>(maxValue * percent() / 100.0f));
192             case Calculated:
193                 return nonNanCalculatedValue(maxValue);
194             case Auto:
195                 return 0;
196             case Relative:
197             case Intrinsic:
198             case MinIntrinsic:
199             case Undefined:
200                 ASSERT_NOT_REACHED();
201                 return 0;
202         }
203         ASSERT_NOT_REACHED();
204         return 0;
205     }
206
207     // FIXME: when subpixel layout is supported this copy of calcFloatValue() can be removed. See bug 71143.
208     float calcFloatValue(int maxValue) const
209     {
210         switch (type()) {
211             case Fixed:
212                 return getFloatValue();
213             case Percent:
214                 return static_cast<float>(maxValue * percent() / 100.0f);
215             case Auto:
216                 return static_cast<float>(maxValue);
217             case Calculated:
218                 return nonNanCalculatedValue(maxValue);                
219             case Relative:
220             case Intrinsic:
221             case MinIntrinsic:
222             case Undefined:
223                 ASSERT_NOT_REACHED();
224                 return 0;
225         }
226         ASSERT_NOT_REACHED();
227         return 0;
228     }
229
230     float calcFloatValue(float maxValue) const
231     {
232         switch (type()) {
233         case Fixed:
234             return getFloatValue();
235         case Percent:
236             return static_cast<float>(maxValue * percent() / 100.0f);
237         case Auto:
238             return static_cast<float>(maxValue);
239         case Calculated:
240             return nonNanCalculatedValue(maxValue);
241         case Relative:
242         case Intrinsic:
243         case MinIntrinsic:
244         case Undefined:
245             ASSERT_NOT_REACHED();
246             return 0;
247         }
248         ASSERT_NOT_REACHED();
249         return 0;
250     }
251
252     bool isUndefined() const { return type() == Undefined; }
253
254     // FIXME calc: https://bugs.webkit.org/show_bug.cgi?id=80357. A calculated Length 
255     // always contains a percentage, and without a maxValue passed to these functions
256     // it's impossible to determine the sign or zero-ness. We assume all calc values
257     // are positive and non-zero for now.    
258     bool isZero() const 
259     {
260         ASSERT(!isUndefined());
261         if (isCalculated())
262             return false;
263             
264         return m_isFloat ? !m_floatValue : !m_intValue;
265     }
266     bool isPositive() const
267     {
268         if (isUndefined())
269             return false;
270         if (isCalculated())
271             return true;
272                 
273         return getFloatValue() > 0;
274     }
275     bool isNegative() const
276     {
277         if (isUndefined() || isCalculated())
278             return false;
279             
280         return getFloatValue() < 0;
281     }
282     
283     bool isAuto() const { return type() == Auto; }
284     bool isRelative() const { return type() == Relative; }
285     bool isPercent() const { return type() == Percent || type() == Calculated; }
286     bool isFixed() const { return type() == Fixed; }
287     bool isIntrinsicOrAuto() const { return type() == Auto || type() == MinIntrinsic || type() == Intrinsic; }
288     bool isSpecified() const { return type() == Fixed || type() == Percent || type() == Calculated; }
289     bool isCalculated() const { return type() == Calculated; }
290
291     Length blend(const Length& from, double progress) const
292     {
293         // Blend two lengths to produce a new length that is in between them.  Used for animation.
294         if (!from.isZero() && !isZero() && from.type() != type())
295             return *this;
296
297         if (from.isZero() && isZero())
298             return *this;
299         
300         LengthType resultType = type();
301         if (isZero())
302             resultType = from.type();
303         
304         if (resultType == Percent) {
305             float fromPercent = from.isZero() ? 0 : from.percent();
306             float toPercent = isZero() ? 0 : percent();
307             return Length(WebCore::blend(fromPercent, toPercent, progress), Percent);
308         } 
309
310         float fromValue = from.isZero() ? 0 : from.value();
311         float toValue = isZero() ? 0 : value();
312         return Length(WebCore::blend(fromValue, toValue, progress), resultType);
313     }
314
315 private:
316     int getIntValue() const
317     {
318         ASSERT(!isUndefined());
319         return m_isFloat ? static_cast<int>(m_floatValue) : m_intValue;
320     }
321
322     float getFloatValue() const
323     {
324         ASSERT(!isUndefined());
325         return m_isFloat ? m_floatValue : m_intValue;
326     }
327
328     void initFromLength(const Length &length) 
329     {
330         m_quirk = length.m_quirk;
331         m_type = length.m_type;
332         m_isFloat = length.m_isFloat;
333         
334         if (m_isFloat)
335             m_floatValue = length.m_floatValue;
336         else
337             m_intValue = length.m_intValue;
338         
339         if (isCalculated())
340             incrementCalculatedRef();
341     }
342     
343     float nonNanCalculatedValue(int maxValue) const;
344     int calculationHandle() const
345     {
346         ASSERT(isCalculated());
347         return getIntValue();
348     }
349     void incrementCalculatedRef() const;
350     void decrementCalculatedRef() const;    
351     
352     union {
353         int m_intValue;
354         float m_floatValue;
355     };
356     bool m_quirk;
357     unsigned char m_type;
358     bool m_isFloat;
359 };
360
361 PassOwnArrayPtr<Length> newCoordsArray(const String&, int& len);
362 PassOwnArrayPtr<Length> newLengthArray(const String&, int& len);
363
364 } // namespace WebCore
365
366 #endif // Length_h