Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / platform / Length.cpp
1 /*
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)
7  *
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.
12  *
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.
17  *
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.
22  *
23  */
24
25 #include "config.h"
26 #include "platform/Length.h"
27
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"
33
34 using namespace WTF;
35
36 namespace WebCore {
37
38 template<typename CharType>
39 static unsigned splitLength(const CharType* data, unsigned length, unsigned& intLength, unsigned& doubleLength)
40 {
41     ASSERT(length);
42
43     unsigned i = 0;
44     while (i < length && isSpaceOrNewline(data[i]))
45         ++i;
46     if (i < length && (data[i] == '+' || data[i] == '-'))
47         ++i;
48     while (i < length && isASCIIDigit(data[i]))
49         ++i;
50     intLength = i;
51     while (i < length && (isASCIIDigit(data[i]) || data[i] == '.'))
52         ++i;
53     doubleLength = i;
54
55     // IE quirk: Skip whitespace between the number and the % character (20 % => 20%).
56     while (i < length && isSpaceOrNewline(data[i]))
57         ++i;
58
59     return i;
60 }
61
62 template<typename CharType>
63 static Length parseHTMLAreaCoordinate(const CharType* data, unsigned length)
64 {
65     unsigned intLength;
66     unsigned doubleLength;
67     splitLength(data, length, intLength, doubleLength);
68
69     bool ok;
70     int r = charactersToIntStrict(data, intLength, &ok);
71     if (ok)
72         return Length(r, Fixed);
73     return Length(0, Fixed);
74 }
75
76 // FIXME: Per HTML5, this should follow the "rules for parsing a list of integers".
77 Vector<Length> parseHTMLAreaElementCoords(const String& string)
78 {
79     unsigned length = string.length();
80     StringBuffer<LChar> spacified(length);
81     for (unsigned i = 0; i < length; i++) {
82         UChar cc = string[i];
83         if (cc > '9' || (cc < '0' && cc != '-' && cc != '.'))
84             spacified[i] = ' ';
85         else
86             spacified[i] = cc;
87     }
88     RefPtr<StringImpl> str = spacified.release();
89     str = str->simplifyWhiteSpace();
90     ASSERT(str->is8Bit());
91
92     if (!str->length())
93         return Vector<Length>();
94
95     unsigned len = str->count(' ') + 1;
96     Vector<Length> r(len);
97
98     unsigned i = 0;
99     unsigned pos = 0;
100     size_t pos2;
101
102     while ((pos2 = str->find(' ', pos)) != kNotFound) {
103         r[i++] = parseHTMLAreaCoordinate(str->characters8() + pos, pos2 - pos);
104         pos = pos2 + 1;
105     }
106     r[i] = parseHTMLAreaCoordinate(str->characters8() + pos, str->length() - pos);
107
108     ASSERT(i == len - 1);
109
110     return r;
111 }
112
113 class CalculationValueHandleMap {
114     WTF_MAKE_FAST_ALLOCATED;
115 public:
116     CalculationValueHandleMap()
117         : m_index(1)
118     {
119     }
120
121     int insert(PassRefPtr<CalculationValue> calcValue)
122     {
123         ASSERT(m_index);
124         // FIXME calc(): https://bugs.webkit.org/show_bug.cgi?id=80489
125         // This monotonically increasing handle generation scheme is potentially wasteful
126         // of the handle space. Consider reusing empty handles.
127         while (m_map.contains(m_index))
128             m_index++;
129
130         m_map.set(m_index, calcValue);
131
132         return m_index;
133     }
134
135     void remove(int index)
136     {
137         ASSERT(m_map.contains(index));
138         m_map.remove(index);
139     }
140
141     CalculationValue& get(int index)
142     {
143         ASSERT(m_map.contains(index));
144         return *m_map.get(index);
145     }
146
147     void decrementRef(int index)
148     {
149         ASSERT(m_map.contains(index));
150         CalculationValue* value = m_map.get(index);
151         if (value->hasOneRef()) {
152             // Force the CalculationValue destructor early to avoid a potential recursive call inside HashMap remove().
153             m_map.set(index, nullptr);
154             m_map.remove(index);
155         } else {
156             value->deref();
157         }
158     }
159
160 private:
161     int m_index;
162     HashMap<int, RefPtr<CalculationValue> > m_map;
163 };
164
165 static CalculationValueHandleMap& calcHandles()
166 {
167     DEFINE_STATIC_LOCAL(CalculationValueHandleMap, handleMap, ());
168     return handleMap;
169 }
170
171 Length::Length(PassRefPtr<CalculationValue> calc)
172     : m_quirk(false)
173     , m_type(Calculated)
174     , m_isFloat(false)
175 {
176     m_intValue = calcHandles().insert(calc);
177 }
178
179 Length Length::blendMixedTypes(const Length& from, double progress, ValueRange range) const
180 {
181     ASSERT(from.isSpecified());
182     ASSERT(isSpecified());
183     PixelsAndPercent fromPixelsAndPercent = from.pixelsAndPercent();
184     PixelsAndPercent toPixelsAndPercent = pixelsAndPercent();
185     const float pixels = WebCore::blend(fromPixelsAndPercent.pixels, toPixelsAndPercent.pixels, progress);
186     const float percent = WebCore::blend(fromPixelsAndPercent.percent, toPixelsAndPercent.percent, progress);
187     return Length(CalculationValue::create(PixelsAndPercent(pixels, percent), range));
188 }
189
190 PixelsAndPercent Length::pixelsAndPercent() const
191 {
192     switch (type()) {
193     case Fixed:
194         return PixelsAndPercent(value(), 0);
195     case Percent:
196         return PixelsAndPercent(0, value());
197     case Calculated:
198         return calculationValue().pixelsAndPercent();
199     default:
200         ASSERT_NOT_REACHED();
201         return PixelsAndPercent(0, 0);
202     }
203 }
204
205 Length Length::subtractFromOneHundredPercent() const
206 {
207     PixelsAndPercent result = pixelsAndPercent();
208     result.pixels = -result.pixels;
209     result.percent = 100 - result.percent;
210     if (result.pixels && result.percent)
211         return Length(CalculationValue::create(result, ValueRangeAll));
212     if (result.percent)
213         return Length(result.percent, Percent);
214     return Length(result.pixels, Fixed);
215 }
216
217 CalculationValue& Length::calculationValue() const
218 {
219     ASSERT(isCalculated());
220     return calcHandles().get(calculationHandle());
221 }
222
223 void Length::incrementCalculatedRef() const
224 {
225     ASSERT(isCalculated());
226     calculationValue().ref();
227 }
228
229 void Length::decrementCalculatedRef() const
230 {
231     ASSERT(isCalculated());
232     calcHandles().decrementRef(calculationHandle());
233 }
234
235 float Length::nonNanCalculatedValue(int maxValue) const
236 {
237     ASSERT(isCalculated());
238     float result = calculationValue().evaluate(maxValue);
239     if (std::isnan(result))
240         return 0;
241     return result;
242 }
243
244 bool Length::isCalculatedEqual(const Length& o) const
245 {
246     return isCalculated() && (&calculationValue() == &o.calculationValue() || calculationValue() == o.calculationValue());
247 }
248
249 struct SameSizeAsLength {
250     int32_t value;
251     int32_t metaData;
252 };
253 COMPILE_ASSERT(sizeof(Length) == sizeof(SameSizeAsLength), length_should_stay_small);
254
255 } // namespace WebCore