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