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 <wtf/Assertions.h>
26 #include <wtf/FastAllocBase.h>
27 #include <wtf/Forward.h>
28 #include <wtf/MathExtras.h>
29 #include <wtf/PassOwnArrayPtr.h>
30 
31 namespace WebCore {
32 
33 const int undefinedLength = -1;
34 const int intMaxForLength = 0x7ffffff; // max value for a 28-bit int
35 const int intMinForLength = (-0x7ffffff - 1); // min value for a 28-bit int
36 
37 enum LengthType { Auto, Relative, Percent, Fixed, Intrinsic, MinIntrinsic };
38 
39 struct Length {
40     WTF_MAKE_FAST_ALLOCATED;
41 public:
LengthLength42     Length()
43         :  m_intValue(0), m_quirk(false), m_type(Auto), m_isFloat(false)
44     {
45     }
46 
LengthLength47     Length(LengthType t)
48         : m_intValue(0), m_quirk(false), m_type(t), m_isFloat(false)
49     {
50     }
51 
52     Length(int v, LengthType t, bool q = false)
m_intValueLength53         : m_intValue(v), m_quirk(q), m_type(t), m_isFloat(false)
54     {
55     }
56 
57     Length(float v, LengthType t, bool q = false)
m_floatValueLength58     : m_floatValue(v), m_quirk(q), m_type(t), m_isFloat(true)
59     {
60     }
61 
62     Length(double v, LengthType t, bool q = false)
m_quirkLength63         : m_quirk(q), m_type(t), m_isFloat(true)
64     {
65         m_floatValue = static_cast<float>(v);
66     }
67 
68     bool operator==(const Length& o) const { return (getFloatValue() == o.getFloatValue()) && (m_type == o.m_type) && (m_quirk == o.m_quirk); }
69     bool operator!=(const Length& o) const { return (getFloatValue() != o.getFloatValue()) || (m_type != o.m_type) || (m_quirk != o.m_quirk); }
70 
71     const Length& operator*=(float v)
72     {
73         if (m_isFloat)
74             m_floatValue = static_cast<float>(m_floatValue * v);
75         else
76             m_intValue = static_cast<int>(m_intValue * v);
77 
78         return *this;
79     }
80 
valueLength81     int value() const {
82         return getIntValue();
83     }
84 
percentLength85     float percent() const
86     {
87         ASSERT(type() == Percent);
88         return getFloatValue();
89     }
90 
typeLength91     LengthType type() const { return static_cast<LengthType>(m_type); }
quirkLength92     bool quirk() const { return m_quirk; }
93 
setValueLength94     void setValue(LengthType t, int value)
95     {
96         m_type = t;
97         m_intValue = value;
98         m_isFloat = false;
99     }
100 
setValueLength101     void setValue(int value)
102     {
103         setValue(Fixed, value);
104     }
105 
setValueLength106     void setValue(LengthType t, float value)
107     {
108         m_type = t;
109         m_floatValue = value;
110         m_isFloat = true;
111     }
112 
setValueLength113     void setValue(float value)
114     {
115         *this = Length(value, Fixed);
116     }
117 
118     // note: works only for certain types, returns undefinedLength otherwise
119     int calcValue(int maxValue, bool roundPercentages = false) const
120     {
121         switch (type()) {
122             case Fixed:
123             case Percent:
124                 return calcMinValue(maxValue, roundPercentages);
125             case Auto:
126                 return maxValue;
127             default:
128                 return undefinedLength;
129         }
130     }
131 
132     int calcMinValue(int maxValue, bool roundPercentages = false) const
133     {
134         switch (type()) {
135             case Fixed:
136                 return value();
137             case Percent:
138                 if (roundPercentages)
139                     return static_cast<int>(round(maxValue * percent() / 100.0f));
140                 // Don't remove the extra cast to float. It is needed for rounding on 32-bit Intel machines that use the FPU stack.
141                 return static_cast<int>(static_cast<float>(maxValue * percent() / 100.0f));
142             case Auto:
143             default:
144                 return 0;
145         }
146     }
147 
calcFloatValueLength148     float calcFloatValue(int maxValue) const
149     {
150         switch (type()) {
151             case Fixed:
152                 return getFloatValue();
153             case Percent:
154                 return static_cast<float>(maxValue * percent() / 100.0f);
155             case Auto:
156                 return static_cast<float>(maxValue);
157             default:
158                 return static_cast<float>(undefinedLength);
159         }
160     }
161 
isUndefinedLength162     bool isUndefined() const { return value() == undefinedLength; }
isZeroLength163     bool isZero() const
164     {
165         return m_isFloat ? !m_floatValue : !m_intValue;
166     }
167 
isPositiveLength168     bool isPositive() const { return getFloatValue() > 0; }
isNegativeLength169     bool isNegative() const { return getFloatValue() < 0; }
170 
isAutoLength171     bool isAuto() const { return type() == Auto; }
isRelativeLength172     bool isRelative() const { return type() == Relative; }
isPercentLength173     bool isPercent() const { return type() == Percent; }
isFixedLength174     bool isFixed() const { return type() == Fixed; }
isIntrinsicOrAutoLength175     bool isIntrinsicOrAuto() const { return type() == Auto || type() == MinIntrinsic || type() == Intrinsic; }
176 
blendLength177     Length blend(const Length& from, float progress) const
178     {
179         // Blend two lengths to produce a new length that is in between them.  Used for animation.
180         if (!from.isZero() && !isZero() && from.type() != type())
181             return *this;
182 
183         if (from.isZero() && isZero())
184             return *this;
185 
186         LengthType resultType = type();
187         if (isZero())
188             resultType = from.type();
189 
190         if (resultType == Percent) {
191             float fromPercent = from.isZero() ? 0 : from.percent();
192             float toPercent = isZero() ? 0 : percent();
193             return Length(fromPercent + (toPercent - fromPercent) * progress, Percent);
194         }
195 
196         float fromValue = from.isZero() ? 0 : from.value();
197         float toValue = isZero() ? 0 : value();
198         return Length(fromValue + (toValue - fromValue) * progress, resultType);
199     }
200 
201 private:
getIntValueLength202     int getIntValue() const
203     {
204         return m_isFloat ? static_cast<int>(m_floatValue) : m_intValue;
205     }
206 
getFloatValueLength207     float getFloatValue() const
208     {
209         return m_isFloat ? m_floatValue : m_intValue;
210     }
211 
212     union {
213         int m_intValue;
214         float m_floatValue;
215     };
216     bool m_quirk;
217     unsigned char m_type;
218     bool m_isFloat;
219 };
220 
221 PassOwnArrayPtr<Length> newCoordsArray(const String&, int& len);
222 PassOwnArrayPtr<Length> newLengthArray(const String&, int& len);
223 
224 } // namespace WebCore
225 
226 #endif // Length_h
227