2bcf932628fcca9ea2e8b3c17ffa1e2fc60c41df
[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
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 #ifndef Length_h
23 #define Length_h
24
25 #include "AnimationUtilities.h"
26 #include <wtf/Assertions.h>
27 #include <wtf/FastAllocBase.h>
28 #include <wtf/Forward.h>
29 #include <wtf/HashMap.h>
30 #include <wtf/MathExtras.h>
31 #include <wtf/PassOwnArrayPtr.h>
32
33 namespace WebCore {
34
35 const int intMaxForLength = 0x7ffffff; // max value for a 28-bit int
36 const int intMinForLength = (-0x7ffffff - 1); // min value for a 28-bit int
37
38 enum LengthType { Auto, Relative, Percent, Fixed, Intrinsic, MinIntrinsic, Calculated, Undefined };
39  
40 class CalculationValue;    
41     
42 struct Length {
43     WTF_MAKE_FAST_ALLOCATED;
44 public:
45     Length()
46         :  m_intValue(0), m_quirk(false), m_type(Auto), m_isFloat(false)
47     {
48     }
49
50     Length(LengthType t)
51         : m_intValue(0), m_quirk(false), m_type(t), m_isFloat(false)
52     {
53     }
54
55     Length(int v, LengthType t, bool q = false)
56         : m_intValue(v), m_quirk(q), m_type(t), m_isFloat(false)
57     {
58     }
59     
60     Length(float v, LengthType t, bool q = false)
61     : m_floatValue(v), m_quirk(q), m_type(t), m_isFloat(true)
62     {
63     }
64
65     Length(double v, LengthType t, bool q = false)
66         : m_quirk(q), m_type(t), m_isFloat(true)
67     {
68         m_floatValue = static_cast<float>(v);    
69     }
70
71     explicit Length(PassRefPtr<CalculationValue>);
72
73     Length(const Length& length)
74     {
75         initFromLength(length);
76     }
77     
78     Length& operator=(const Length& length)
79     {
80         initFromLength(length);
81         return *this;
82     }
83     
84     ~Length()
85     {
86         if (isCalculated())
87             decrementCalculatedRef();
88     }  
89     
90     bool operator==(const Length& o) const { return (m_type == o.m_type) && (m_quirk == o.m_quirk) && (isUndefined() || (getFloatValue() == o.getFloatValue())); }
91     bool operator!=(const Length& o) const { return !(*this == o); }
92
93     const Length& operator*=(float v)
94     {       
95         if (isCalculated()) {
96             ASSERT_NOT_REACHED();
97             return *this;
98         }
99         
100         if (m_isFloat)
101             m_floatValue = static_cast<float>(m_floatValue * v);
102         else        
103             m_intValue = static_cast<int>(m_intValue * v);
104         
105         return *this;
106     }
107     
108     int value() const
109     {
110         if (isCalculated()) {
111             ASSERT_NOT_REACHED();
112             return 0;
113         }
114         return getIntValue();
115     }
116
117     float percent() const
118     {
119         ASSERT(type() == Percent);
120         return getFloatValue();
121     }
122
123     PassRefPtr<CalculationValue> calculationValue() const;
124
125     LengthType type() const { return static_cast<LengthType>(m_type); }
126     bool quirk() const { return m_quirk; }
127
128     void setQuirk(bool quirk)
129     {
130         m_quirk = quirk;
131     }
132
133     void setValue(LengthType t, int value)
134     {
135         m_type = t;
136         m_intValue = value;
137         m_isFloat = false;
138     }
139
140     void setValue(int value)
141     {
142         if (isCalculated()) {
143             ASSERT_NOT_REACHED();
144             return;
145         }
146         setValue(Fixed, value);
147     }
148
149     void setValue(LengthType t, float value)
150     {
151         m_type = t;
152         m_floatValue = value;
153         m_isFloat = true;    
154     }
155
156     void setValue(float value)
157     {
158         *this = Length(value, Fixed);
159     }
160
161     int calcValue(int maxValue, bool roundPercentages = false) const
162     {
163         switch (type()) {
164             case Fixed:
165             case Percent:
166             case Calculated:
167                 return calcMinValue(maxValue, roundPercentages);
168             case Auto:
169                 return maxValue;
170             case Relative:
171             case Intrinsic:
172             case MinIntrinsic:
173             case Undefined:
174                 ASSERT_NOT_REACHED();
175                 return 0;
176         }
177         ASSERT_NOT_REACHED();
178         return 0;
179     }
180
181     int calcMinValue(int maxValue, bool roundPercentages = false) const
182     {
183         switch (type()) {
184             case Fixed:
185                 return value();
186             case Percent:
187                 if (roundPercentages)
188                     return static_cast<int>(round(maxValue * percent() / 100.0f));
189                 // Don't remove the extra cast to float. It is needed for rounding on 32-bit Intel machines that use the FPU stack.
190                 return static_cast<int>(static_cast<float>(maxValue * percent() / 100.0f));
191             case Calculated:
192                 return nonNanCalculatedValue(maxValue);
193             case Auto:
194                 return 0;
195             case Relative:
196             case Intrinsic:
197             case MinIntrinsic:
198             case Undefined:
199                 ASSERT_NOT_REACHED();
200                 return 0;
201         }
202         ASSERT_NOT_REACHED();
203         return 0;
204     }
205
206     float calcFloatValue(int maxValue) const
207     {
208         switch (type()) {
209             case Fixed:
210                 return getFloatValue();
211             case Percent:
212                 return static_cast<float>(maxValue * percent() / 100.0f);
213             case Auto:
214                 return static_cast<float>(maxValue);
215             case Calculated:
216                 return nonNanCalculatedValue(maxValue);                
217             case Relative:
218             case Intrinsic:
219             case MinIntrinsic:
220             case Undefined:
221                 ASSERT_NOT_REACHED();
222                 return 0;
223         }
224         ASSERT_NOT_REACHED();
225         return 0;
226     }
227
228     bool isUndefined() const { return type() == Undefined; }
229
230     // FIXME calc: https://bugs.webkit.org/show_bug.cgi?id=80357. A calculated Length 
231     // always contains a percentage, and without a maxValue passed to these functions
232     // it's impossible to determine the sign or zero-ness. We assume all calc values
233     // are positive and non-zero for now.    
234     bool isZero() const 
235     {
236         ASSERT(!isUndefined());
237         if (isCalculated())
238             return false;
239             
240         return m_isFloat ? !m_floatValue : !m_intValue;
241     }
242     bool isPositive() const
243     {
244         if (isUndefined())
245             return false;
246         if (isCalculated())
247             return true;
248                 
249         return getFloatValue() > 0;
250     }
251     bool isNegative() const
252     {
253         if (isUndefined() || isCalculated())
254             return false;
255             
256         return getFloatValue() < 0;
257     }
258     
259     bool isAuto() const { return type() == Auto; }
260     bool isRelative() const { return type() == Relative; }
261     bool isPercent() const { return type() == Percent || type() == Calculated; }
262     bool isFixed() const { return type() == Fixed; }
263     bool isIntrinsicOrAuto() const { return type() == Auto || type() == MinIntrinsic || type() == Intrinsic; }
264     bool isSpecified() const { return type() == Fixed || type() == Percent || type() == Calculated; }
265     bool isCalculated() const { return type() == Calculated; }
266
267     Length blend(const Length& from, double progress) const
268     {
269         // Blend two lengths to produce a new length that is in between them.  Used for animation.
270         if (!from.isZero() && !isZero() && from.type() != type())
271             return *this;
272
273         if (from.isZero() && isZero())
274             return *this;
275         
276         LengthType resultType = type();
277         if (isZero())
278             resultType = from.type();
279         
280         if (resultType == Percent) {
281             float fromPercent = from.isZero() ? 0 : from.percent();
282             float toPercent = isZero() ? 0 : percent();
283             return Length(WebCore::blend(fromPercent, toPercent, progress), Percent);
284         } 
285
286         float fromValue = from.isZero() ? 0 : from.value();
287         float toValue = isZero() ? 0 : value();
288         return Length(WebCore::blend(fromValue, toValue, progress), resultType);
289     }
290
291 private:
292     int getIntValue() const
293     {
294         ASSERT(!isUndefined());
295         return m_isFloat ? static_cast<int>(m_floatValue) : m_intValue;
296     }
297
298     float getFloatValue() const
299     {
300         ASSERT(!isUndefined());
301         return m_isFloat ? m_floatValue : m_intValue;
302     }
303
304     void initFromLength(const Length &length) 
305     {
306         m_quirk = length.m_quirk;
307         m_type = length.m_type;
308         m_isFloat = length.m_isFloat;
309         
310         if (m_isFloat)
311             m_floatValue = length.m_floatValue;
312         else
313             m_intValue = length.m_intValue;
314         
315         if (isCalculated())
316             incrementCalculatedRef();
317     }
318     
319     float nonNanCalculatedValue(int maxValue) const;
320     int calculationHandle() const
321     {
322         ASSERT(isCalculated());
323         return getIntValue();
324     }
325     void incrementCalculatedRef() const;
326     void decrementCalculatedRef() const;    
327     
328     union {
329         int m_intValue;
330         float m_floatValue;
331     };
332     bool m_quirk;
333     unsigned char m_type;
334     bool m_isFloat;
335 };
336
337 PassOwnArrayPtr<Length> newCoordsArray(const String&, int& len);
338 PassOwnArrayPtr<Length> newLengthArray(const String&, int& len);
339
340 } // namespace WebCore
341
342 #endif // Length_h