2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3 * (C) 1999 Antti Koivisto (koivisto@kde.org)
4 * (C) 2001 Dirk Mueller ( mueller@kde.org )
5 * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
6 * Copyright (C) 2006 Andrew Wellington (proton@wiretapped.net)
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
18 * You should have received a copy of the GNU Library General Public License
19 * along with this library; see the file COPYING.LIB. If not, write to
20 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 * Boston, MA 02110-1301, USA.
26 #include "platform/Length.h"
28 #include "platform/CalculationValue.h"
29 #include "platform/animation/AnimationUtilities.h"
30 #include "wtf/ASCIICType.h"
31 #include "wtf/text/StringBuffer.h"
32 #include "wtf/text/WTFString.h"
38 template<typename CharType
>
39 static unsigned splitLength(const CharType
* data
, unsigned length
, unsigned& intLength
, unsigned& doubleLength
)
44 while (i
< length
&& isSpaceOrNewline(data
[i
]))
46 if (i
< length
&& (data
[i
] == '+' || data
[i
] == '-'))
48 while (i
< length
&& isASCIIDigit(data
[i
]))
51 while (i
< length
&& (isASCIIDigit(data
[i
]) || data
[i
] == '.'))
55 // IE quirk: Skip whitespace between the number and the % character (20 % => 20%).
56 while (i
< length
&& isSpaceOrNewline(data
[i
]))
62 template<typename CharType
>
63 static Length
parseHTMLAreaCoordinate(const CharType
* data
, unsigned length
)
66 unsigned doubleLength
;
67 splitLength(data
, length
, intLength
, doubleLength
);
69 return Length(charactersToIntStrict(data
, intLength
), Fixed
);
72 // FIXME: Per HTML5, this should follow the "rules for parsing a list of integers".
73 Vector
<Length
> parseHTMLAreaElementCoords(const String
& string
)
75 unsigned length
= string
.length();
76 StringBuffer
<LChar
> spacified(length
);
77 for (unsigned i
= 0; i
< length
; i
++) {
79 if (cc
> '9' || (cc
< '0' && cc
!= '-' && cc
!= '.'))
84 RefPtr
<StringImpl
> str
= spacified
.release();
85 str
= str
->simplifyWhiteSpace();
86 ASSERT(str
->is8Bit());
89 return Vector
<Length
>();
91 unsigned len
= str
->count(' ') + 1;
92 Vector
<Length
> r(len
);
98 while ((pos2
= str
->find(' ', pos
)) != kNotFound
) {
99 r
[i
++] = parseHTMLAreaCoordinate(str
->characters8() + pos
, pos2
- pos
);
102 r
[i
] = parseHTMLAreaCoordinate(str
->characters8() + pos
, str
->length() - pos
);
104 ASSERT(i
== len
- 1);
109 class CalculationValueHandleMap
{
110 WTF_MAKE_FAST_ALLOCATED(CalculationValueHandleMap
);
112 CalculationValueHandleMap()
117 int insert(PassRefPtr
<CalculationValue
> calcValue
)
120 // FIXME calc(): https://bugs.webkit.org/show_bug.cgi?id=80489
121 // This monotonically increasing handle generation scheme is potentially wasteful
122 // of the handle space. Consider reusing empty handles.
123 while (m_map
.contains(m_index
))
126 m_map
.set(m_index
, calcValue
);
131 void remove(int index
)
133 ASSERT(m_map
.contains(index
));
137 CalculationValue
& get(int index
)
139 ASSERT(m_map
.contains(index
));
140 return *m_map
.get(index
);
143 void decrementRef(int index
)
145 ASSERT(m_map
.contains(index
));
146 CalculationValue
* value
= m_map
.get(index
);
147 if (value
->hasOneRef()) {
148 // Force the CalculationValue destructor early to avoid a potential recursive call inside HashMap remove().
149 m_map
.set(index
, nullptr);
158 HashMap
<int, RefPtr
<CalculationValue
>> m_map
;
161 static CalculationValueHandleMap
& calcHandles()
163 DEFINE_STATIC_LOCAL(CalculationValueHandleMap
, handleMap
, ());
167 Length::Length(PassRefPtr
<CalculationValue
> calc
)
172 m_intValue
= calcHandles().insert(calc
);
175 Length
Length::blendMixedTypes(const Length
& from
, double progress
, ValueRange range
) const
177 ASSERT(from
.isSpecified());
178 ASSERT(isSpecified());
179 PixelsAndPercent fromPixelsAndPercent
= from
.pixelsAndPercent();
180 PixelsAndPercent toPixelsAndPercent
= pixelsAndPercent();
181 const float pixels
= blink::blend(fromPixelsAndPercent
.pixels
, toPixelsAndPercent
.pixels
, progress
);
182 const float percent
= blink::blend(fromPixelsAndPercent
.percent
, toPixelsAndPercent
.percent
, progress
);
183 return Length(CalculationValue::create(PixelsAndPercent(pixels
, percent
), range
));
186 PixelsAndPercent
Length::pixelsAndPercent() const
190 return PixelsAndPercent(value(), 0);
192 return PixelsAndPercent(0, value());
194 return calculationValue().pixelsAndPercent();
196 ASSERT_NOT_REACHED();
197 return PixelsAndPercent(0, 0);
201 Length
Length::subtractFromOneHundredPercent() const
203 PixelsAndPercent result
= pixelsAndPercent();
204 result
.pixels
= -result
.pixels
;
205 result
.percent
= 100 - result
.percent
;
206 if (result
.pixels
&& result
.percent
)
207 return Length(CalculationValue::create(result
, ValueRangeAll
));
209 return Length(result
.percent
, Percent
);
210 return Length(result
.pixels
, Fixed
);
213 Length
Length::zoom(double factor
) const
217 return Length(getFloatValue() * factor
, Fixed
);
219 PixelsAndPercent result
= pixelsAndPercent();
220 result
.pixels
*= factor
;
221 return Length(CalculationValue::create(result
, calculationValue().valueRange()));
228 CalculationValue
& Length::calculationValue() const
230 ASSERT(isCalculated());
231 return calcHandles().get(calculationHandle());
234 void Length::incrementCalculatedRef() const
236 ASSERT(isCalculated());
237 calculationValue().ref();
240 void Length::decrementCalculatedRef() const
242 ASSERT(isCalculated());
243 calcHandles().decrementRef(calculationHandle());
246 float Length::nonNanCalculatedValue(LayoutUnit maxValue
) const
248 ASSERT(isCalculated());
249 float result
= calculationValue().evaluate(maxValue
.toFloat());
250 if (std::isnan(result
))
255 bool Length::isCalculatedEqual(const Length
& o
) const
257 return isCalculated() && (&calculationValue() == &o
.calculationValue() || calculationValue() == o
.calculationValue());
260 struct SameSizeAsLength
{
264 static_assert(sizeof(Length
) == sizeof(SameSizeAsLength
), "length should stay small");