1/*
2 Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3 Copyright (C) 2006, 2008, 2014 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 <memory>
28#include <string.h>
29#include <wtf/Assertions.h>
30#include <wtf/FastMalloc.h>
31#include <wtf/Forward.h>
32#include <wtf/UniqueArray.h>
33
34namespace WTF {
35class TextStream;
36}
37
38namespace WebCore {
39
40enum LengthType {
41 Auto, Relative, Percent, Fixed,
42 Intrinsic, MinIntrinsic,
43 MinContent, MaxContent, FillAvailable, FitContent,
44 Calculated,
45 Undefined
46};
47
48enum ValueRange {
49 ValueRangeAll,
50 ValueRangeNonNegative
51};
52
53class CalculationValue;
54
55struct Length {
56 WTF_MAKE_FAST_ALLOCATED;
57public:
58 Length(LengthType = Auto);
59
60 Length(int value, LengthType, bool hasQuirk = false);
61 Length(LayoutUnit value, LengthType, bool hasQuirk = false);
62 Length(float value, LengthType, bool hasQuirk = false);
63 Length(double value, LengthType, bool hasQuirk = false);
64
65 WEBCORE_EXPORT explicit Length(Ref<CalculationValue>&&);
66
67 Length(const Length&);
68 Length(Length&&);
69 Length& operator=(const Length&);
70 Length& operator=(Length&&);
71
72 ~Length();
73
74 void setValue(LengthType, int value);
75 void setValue(LengthType, float value);
76 void setValue(LengthType, LayoutUnit value);
77 Length& operator*=(float);
78
79 void setHasQuirk(bool);
80
81 bool operator==(const Length&) const;
82 bool operator!=(const Length&) const;
83
84 float value() const;
85 int intValue() const;
86 float percent() const;
87 CalculationValue& calculationValue() const;
88
89 LengthType type() const;
90
91 bool isAuto() const;
92 bool isCalculated() const;
93 bool isFixed() const;
94 bool isMaxContent() const;
95 bool isMinContent() const;
96 bool isPercent() const;
97 bool isRelative() const;
98 bool isUndefined() const;
99 bool isFillAvailable() const;
100 bool isFitContent() const;
101
102 bool hasQuirk() const;
103
104 // FIXME calc: https://bugs.webkit.org/show_bug.cgi?id=80357. A calculated Length
105 // always contains a percentage, and without a maxValue passed to these functions
106 // it's impossible to determine the sign or zero-ness. The following three functions
107 // act as if all calculated values are positive.
108 bool isZero() const;
109 bool isPositive() const;
110 bool isNegative() const;
111
112 bool isPercentOrCalculated() const; // Returns true for both Percent and Calculated.
113
114 bool isIntrinsic() const;
115 bool isIntrinsicOrAuto() const;
116 bool isSpecified() const;
117 bool isSpecifiedOrIntrinsic() const;
118
119 float nonNanCalculatedValue(int maxValue) const;
120
121private:
122 bool isLegacyIntrinsic() const;
123
124 bool isCalculatedEqual(const Length&) const;
125
126 WEBCORE_EXPORT void ref() const;
127 WEBCORE_EXPORT void deref() const;
128
129 union {
130 int m_intValue;
131 float m_floatValue;
132 unsigned m_calculationValueHandle;
133 };
134 bool m_hasQuirk;
135 unsigned char m_type;
136 bool m_isFloat;
137};
138
139// Blend two lengths to produce a new length that is in between them. Used for animation.
140Length blend(const Length& from, const Length& to, double progress);
141
142UniqueArray<Length> newCoordsArray(const String&, int& length);
143UniqueArray<Length> newLengthArray(const String&, int& length);
144
145inline Length::Length(LengthType type)
146 : m_intValue(0), m_hasQuirk(false), m_type(type), m_isFloat(false)
147{
148 ASSERT(type != Calculated);
149}
150
151inline Length::Length(int value, LengthType type, bool hasQuirk)
152 : m_intValue(value), m_hasQuirk(hasQuirk), m_type(type), m_isFloat(false)
153{
154 ASSERT(type != Calculated);
155}
156
157inline Length::Length(LayoutUnit value, LengthType type, bool hasQuirk)
158 : m_floatValue(value.toFloat()), m_hasQuirk(hasQuirk), m_type(type), m_isFloat(true)
159{
160 ASSERT(type != Calculated);
161}
162
163inline Length::Length(float value, LengthType type, bool hasQuirk)
164 : m_floatValue(value), m_hasQuirk(hasQuirk), m_type(type), m_isFloat(true)
165{
166 ASSERT(type != Calculated);
167}
168
169inline Length::Length(double value, LengthType type, bool hasQuirk)
170 : m_floatValue(static_cast<float>(value)), m_hasQuirk(hasQuirk), m_type(type), m_isFloat(true)
171{
172 ASSERT(type != Calculated);
173}
174
175inline Length::Length(const Length& other)
176{
177 if (other.isCalculated())
178 other.ref();
179
180 memcpy(static_cast<void*>(this), static_cast<void*>(const_cast<Length*>(&other)), sizeof(Length));
181}
182
183inline Length::Length(Length&& other)
184{
185 memcpy(static_cast<void*>(this), static_cast<void*>(&other), sizeof(Length));
186 other.m_type = Auto;
187}
188
189inline Length& Length::operator=(const Length& other)
190{
191 if (this == &other)
192 return *this;
193
194 if (other.isCalculated())
195 other.ref();
196 if (isCalculated())
197 deref();
198
199 memcpy(static_cast<void*>(this), static_cast<void*>(const_cast<Length*>(&other)), sizeof(Length));
200 return *this;
201}
202
203inline Length& Length::operator=(Length&& other)
204{
205 if (this == &other)
206 return *this;
207
208 if (isCalculated())
209 deref();
210
211 memcpy(static_cast<void*>(this), static_cast<void*>(&other), sizeof(Length));
212 other.m_type = Auto;
213 return *this;
214}
215
216inline Length::~Length()
217{
218 if (isCalculated())
219 deref();
220}
221
222inline bool Length::operator==(const Length& other) const
223{
224 // FIXME: This might be too long to be inline.
225 if (type() != other.type() || hasQuirk() != other.hasQuirk())
226 return false;
227 if (isUndefined())
228 return true;
229 if (isCalculated())
230 return isCalculatedEqual(other);
231 return value() == other.value();
232}
233
234inline bool Length::operator!=(const Length& other) const
235{
236 return !(*this == other);
237}
238
239inline Length& Length::operator*=(float value)
240{
241 ASSERT(!isCalculated());
242 if (isCalculated())
243 return *this;
244
245 if (m_isFloat)
246 m_floatValue *= value;
247 else
248 m_intValue *= value;
249
250 return *this;
251}
252
253inline float Length::value() const
254{
255 ASSERT(!isUndefined());
256 ASSERT(!isCalculated());
257 return m_isFloat ? m_floatValue : m_intValue;
258}
259
260inline int Length::intValue() const
261{
262 ASSERT(!isUndefined());
263 ASSERT(!isCalculated());
264 // FIXME: Makes no sense to return 0 here but not in the value() function above.
265 if (isCalculated())
266 return 0;
267 return m_isFloat ? static_cast<int>(m_floatValue) : m_intValue;
268}
269
270inline float Length::percent() const
271{
272 ASSERT(isPercent());
273 return value();
274}
275
276inline LengthType Length::type() const
277{
278 return static_cast<LengthType>(m_type);
279}
280
281inline bool Length::hasQuirk() const
282{
283 return m_hasQuirk;
284}
285
286inline void Length::setHasQuirk(bool hasQuirk)
287{
288 m_hasQuirk = hasQuirk;
289}
290
291inline void Length::setValue(LengthType type, int value)
292{
293 ASSERT(m_type != Calculated);
294 ASSERT(type != Calculated);
295 m_type = type;
296 m_intValue = value;
297 m_isFloat = false;
298}
299
300inline void Length::setValue(LengthType type, float value)
301{
302 ASSERT(m_type != Calculated);
303 ASSERT(type != Calculated);
304 m_type = type;
305 m_floatValue = value;
306 m_isFloat = true;
307}
308
309inline void Length::setValue(LengthType type, LayoutUnit value)
310{
311 ASSERT(m_type != Calculated);
312 ASSERT(type != Calculated);
313 m_type = type;
314 m_floatValue = value;
315 m_isFloat = true;
316}
317
318inline bool Length::isAuto() const
319{
320 return type() == Auto;
321}
322
323inline bool Length::isFixed() const
324{
325 return type() == Fixed;
326}
327
328inline bool Length::isMaxContent() const
329{
330 return type() == MaxContent;
331}
332
333inline bool Length::isMinContent() const
334{
335 return type() == MinContent;
336}
337
338inline bool Length::isNegative() const
339{
340 if (isUndefined() || isCalculated())
341 return false;
342 return m_isFloat ? (m_floatValue < 0) : (m_intValue < 0);
343}
344
345inline bool Length::isPercent() const
346{
347 return type() == Percent;
348}
349
350inline bool Length::isRelative() const
351{
352 return type() == Relative;
353}
354
355inline bool Length::isUndefined() const
356{
357 return type() == Undefined;
358}
359
360inline bool Length::isPercentOrCalculated() const
361{
362 return isPercent() || isCalculated();
363}
364
365inline bool Length::isPositive() const
366{
367 if (isUndefined())
368 return false;
369 if (isCalculated())
370 return true;
371 return m_isFloat ? (m_floatValue > 0) : (m_intValue > 0);
372}
373
374inline bool Length::isZero() const
375{
376 ASSERT(!isUndefined());
377 if (isCalculated())
378 return false;
379 return m_isFloat ? !m_floatValue : !m_intValue;
380}
381
382inline bool Length::isCalculated() const
383{
384 return type() == Calculated;
385}
386
387inline bool Length::isLegacyIntrinsic() const
388{
389 return type() == Intrinsic || type() == MinIntrinsic;
390}
391
392inline bool Length::isIntrinsic() const
393{
394 return type() == MinContent || type() == MaxContent || type() == FillAvailable || type() == FitContent;
395}
396
397inline bool Length::isIntrinsicOrAuto() const
398{
399 return isAuto() || isIntrinsic() || isLegacyIntrinsic();
400}
401
402inline bool Length::isSpecified() const
403{
404 return isFixed() || isPercentOrCalculated();
405}
406
407inline bool Length::isSpecifiedOrIntrinsic() const
408{
409 return isSpecified() || isIntrinsic();
410}
411
412inline bool Length::isFillAvailable() const
413{
414 return type() == FillAvailable;
415}
416
417inline bool Length::isFitContent() const
418{
419 return type() == FitContent;
420}
421
422Length convertTo100PercentMinusLength(const Length&);
423
424WTF::TextStream& operator<<(WTF::TextStream&, Length);
425
426} // namespace WebCore
427
428#endif // Length_h
429