• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "platform/PlatformExport.h"
27 #include "platform/animation/AnimationUtilities.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/Vector.h"
34 #include <cstring>
35 
36 namespace WebCore {
37 
38 // FIXME: This enum makes it hard to tell in general what values may be
39 // appropriate for any given Length.
40 enum LengthType {
41     Auto, Percent, Fixed,
42     Intrinsic, MinIntrinsic,
43     MinContent, MaxContent, FillAvailable, FitContent,
44     Calculated,
45     ExtendToZoom, DeviceWidth, DeviceHeight,
46     Undefined
47 };
48 
49 enum ValueRange {
50     ValueRangeAll,
51     ValueRangeNonNegative
52 };
53 
54 struct PixelsAndPercent {
PixelsAndPercentPixelsAndPercent55     PixelsAndPercent(float pixels, float percent)
56         : pixels(pixels)
57         , percent(percent)
58     {
59     }
60     float pixels;
61     float percent;
62 };
63 
64 class CalculationValue;
65 
66 class PLATFORM_EXPORT Length {
67     WTF_MAKE_FAST_ALLOCATED;
68 public:
Length()69     Length()
70         :  m_intValue(0), m_quirk(false), m_type(Auto), m_isFloat(false)
71     {
72     }
73 
Length(LengthType t)74     Length(LengthType t)
75         : m_intValue(0), m_quirk(false), m_type(t), m_isFloat(false)
76     {
77         ASSERT(t != Calculated);
78     }
79 
80     Length(int v, LengthType t, bool q = false)
m_intValue(v)81         : m_intValue(v), m_quirk(q), m_type(t), m_isFloat(false)
82     {
83         ASSERT(t != Calculated);
84     }
85 
86     Length(LayoutUnit v, LengthType t, bool q = false)
87         : m_floatValue(v.toFloat()), m_quirk(q), m_type(t), m_isFloat(true)
88     {
89         ASSERT(t != Calculated);
90     }
91 
92     Length(float v, LengthType t, bool q = false)
m_floatValue(v)93         : m_floatValue(v), m_quirk(q), m_type(t), m_isFloat(true)
94     {
95         ASSERT(t != Calculated);
96     }
97 
98     Length(double v, LengthType t, bool q = false)
m_quirk(q)99         : m_quirk(q), m_type(t), m_isFloat(true)
100     {
101         m_floatValue = static_cast<float>(v);
102     }
103 
104     explicit Length(PassRefPtr<CalculationValue>);
105 
Length(const Length & length)106     Length(const Length& length)
107     {
108         memcpy(this, &length, sizeof(Length));
109         if (isCalculated())
110             incrementCalculatedRef();
111     }
112 
113     Length& operator=(const Length& length)
114     {
115         if (length.isCalculated())
116             length.incrementCalculatedRef();
117         if (isCalculated())
118             decrementCalculatedRef();
119         memcpy(this, &length, sizeof(Length));
120         return *this;
121     }
122 
123 #if COMPILER_SUPPORTS(CXX_RVALUE_REFERENCES)
Length(Length && length)124     Length(Length&& length)
125     {
126         memcpy(this, &length, sizeof(Length));
127 
128         // Reset |length|'s type to Auto to make sure its destructor
129         // won't call decrementCalculatedRef() as we don't call
130         // incrementCalculatedRef() here.
131         length.m_type = Auto;
132     }
133 
134     Length& operator=(Length&& length)
135     {
136         if (this == &length)
137             return *this;
138 
139         if (isCalculated())
140             decrementCalculatedRef();
141 
142         memcpy(this, &length, sizeof(Length));
143 
144         // Reset |length|'s type to Auto to make sure its destructor
145         // won't call decrementCalculatedRef() as we don't call
146         // incrementCalculatedRef() here.
147         length.m_type = Auto;
148 
149         return *this;
150     }
151 #endif
152 
~Length()153     ~Length()
154     {
155         if (isCalculated())
156             decrementCalculatedRef();
157     }
158 
159     bool operator==(const Length& o) const { return (m_type == o.m_type) && (m_quirk == o.m_quirk) && (isUndefined() || (getFloatValue() == o.getFloatValue()) || isCalculatedEqual(o)); }
160     bool operator!=(const Length& o) const { return !(*this == o); }
161 
162     const Length& operator*=(float v)
163     {
164         if (isCalculated()) {
165             ASSERT_NOT_REACHED();
166             return *this;
167         }
168 
169         if (m_isFloat)
170             m_floatValue = static_cast<float>(m_floatValue * v);
171         else
172             m_intValue = static_cast<int>(m_intValue * v);
173 
174         return *this;
175     }
176 
value()177     inline float value() const
178     {
179         return getFloatValue();
180     }
181 
intValue()182     int intValue() const
183     {
184         if (isCalculated()) {
185             ASSERT_NOT_REACHED();
186             return 0;
187         }
188         return getIntValue();
189     }
190 
percent()191     float percent() const
192     {
193         ASSERT(type() == Percent);
194         return getFloatValue();
195     }
196     PixelsAndPercent pixelsAndPercent() const;
197 
198     CalculationValue& calculationValue() const;
199 
type()200     LengthType type() const { return static_cast<LengthType>(m_type); }
quirk()201     bool quirk() const { return m_quirk; }
202 
setQuirk(bool quirk)203     void setQuirk(bool quirk)
204     {
205         m_quirk = quirk;
206     }
207 
setValue(LengthType t,int value)208     void setValue(LengthType t, int value)
209     {
210         m_type = t;
211         m_intValue = value;
212         m_isFloat = false;
213     }
214 
setValue(int value)215     void setValue(int value)
216     {
217         if (isCalculated()) {
218             ASSERT_NOT_REACHED();
219             return;
220         }
221         setValue(Fixed, value);
222     }
223 
setValue(LengthType t,float value)224     void setValue(LengthType t, float value)
225     {
226         m_type = t;
227         m_floatValue = value;
228         m_isFloat = true;
229     }
230 
setValue(LengthType t,LayoutUnit value)231     void setValue(LengthType t, LayoutUnit value)
232     {
233         m_type = t;
234         m_floatValue = value.toFloat();
235         m_isFloat = true;
236     }
237 
setValue(float value)238     void setValue(float value)
239     {
240         *this = Length(value, Fixed);
241     }
242 
isUndefined()243     bool isUndefined() const { return type() == Undefined; }
244 
245     // FIXME calc: https://bugs.webkit.org/show_bug.cgi?id=80357. A calculated Length
246     // always contains a percentage, and without a maxValue passed to these functions
247     // it's impossible to determine the sign or zero-ness. We assume all calc values
248     // are positive and non-zero for now.
isZero()249     bool isZero() const
250     {
251         ASSERT(!isUndefined());
252         if (isCalculated())
253             return false;
254 
255         return m_isFloat ? !m_floatValue : !m_intValue;
256     }
isPositive()257     bool isPositive() const
258     {
259         if (isUndefined())
260             return false;
261         if (isCalculated())
262             return true;
263 
264         return getFloatValue() > 0;
265     }
isNegative()266     bool isNegative() const
267     {
268         if (isUndefined() || isCalculated())
269             return false;
270 
271         return getFloatValue() < 0;
272     }
273 
isAuto()274     bool isAuto() const { return type() == Auto; }
isPercent()275     bool isPercent() const { return type() == Percent || type() == Calculated; }
isFixed()276     bool isFixed() const { return type() == Fixed; }
isIntrinsicOrAuto()277     bool isIntrinsicOrAuto() const { return type() == Auto || isLegacyIntrinsic() || isIntrinsic(); }
isLegacyIntrinsic()278     bool isLegacyIntrinsic() const { return type() == Intrinsic || type() == MinIntrinsic; }
isIntrinsic()279     bool isIntrinsic() const { return type() == MinContent || type() == MaxContent || type() == FillAvailable || type() == FitContent; }
isSpecified()280     bool isSpecified() const { return type() == Fixed || type() == Percent || type() == Calculated; }
isSpecifiedOrIntrinsic()281     bool isSpecifiedOrIntrinsic() const { return isSpecified() || isIntrinsic(); }
isCalculated()282     bool isCalculated() const { return type() == Calculated; }
283     bool isCalculatedEqual(const Length&) const;
isMinContent()284     bool isMinContent() const { return type() == MinContent; }
isMaxContent()285     bool isMaxContent() const { return type() == MaxContent; }
isFillAvailable()286     bool isFillAvailable() const { return type() == FillAvailable; }
isFitContent()287     bool isFitContent() const { return type() == FitContent; }
288 
blend(const Length & from,double progress,ValueRange range)289     Length blend(const Length& from, double progress, ValueRange range) const
290     {
291         ASSERT(isSpecified() && from.isSpecified());
292 
293         if (progress == 0.0)
294             return from;
295 
296         if (progress == 1.0)
297             return *this;
298 
299         if (from.type() == Calculated || type() == Calculated)
300             return blendMixedTypes(from, progress, range);
301 
302         if (!from.isZero() && !isZero() && from.type() != type())
303             return blendMixedTypes(from, progress, range);
304 
305         if (from.isZero() && isZero())
306             return *this;
307 
308         LengthType resultType = type();
309         if (isZero())
310             resultType = from.type();
311 
312         float blendedValue = WebCore::blend(from.value(), value(), progress);
313         if (range == ValueRangeNonNegative)
314             blendedValue = clampTo<float>(blendedValue, 0);
315         return Length(blendedValue, resultType);
316     }
317 
getFloatValue()318     float getFloatValue() const
319     {
320         ASSERT(!isUndefined());
321         return m_isFloat ? m_floatValue : m_intValue;
322     }
323     float nonNanCalculatedValue(int maxValue) const;
324 
325     Length subtractFromOneHundredPercent() const;
326 
327 private:
getIntValue()328     int getIntValue() const
329     {
330         ASSERT(!isUndefined());
331         return m_isFloat ? static_cast<int>(m_floatValue) : m_intValue;
332     }
333 
334     Length blendMixedTypes(const Length& from, double progress, ValueRange) const;
335 
calculationHandle()336     int calculationHandle() const
337     {
338         ASSERT(isCalculated());
339         return getIntValue();
340     }
341     void incrementCalculatedRef() const;
342     void decrementCalculatedRef() const;
343 
344     union {
345         int m_intValue;
346         float m_floatValue;
347     };
348     bool m_quirk;
349     unsigned char m_type;
350     bool m_isFloat;
351 };
352 
353 PLATFORM_EXPORT Vector<Length> parseHTMLAreaElementCoords(const String&);
354 
355 } // namespace WebCore
356 
357 #endif // Length_h
358