Add make_unique and start using it
[WebKit-https.git] / Source / WebCore / 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 "Length.h"
27
28 #include "CalculationValue.h"
29 #include <wtf/ASCIICType.h>
30 #include <wtf/Assertions.h>
31 #include <wtf/StdLibExtras.h>
32 #include <wtf/text/StringBuffer.h>
33 #include <wtf/text/WTFString.h>
34
35 using namespace WTF;
36
37 namespace WebCore {
38
39 static Length parseLength(const UChar* data, unsigned length)
40 {
41     if (length == 0)
42         return Length(1, Relative);
43
44     unsigned i = 0;
45     while (i < length && isSpaceOrNewline(data[i]))
46         ++i;
47     if (i < length && (data[i] == '+' || data[i] == '-'))
48         ++i;
49     while (i < length && isASCIIDigit(data[i]))
50         ++i;
51     unsigned intLength = i;
52     while (i < length && (isASCIIDigit(data[i]) || data[i] == '.'))
53         ++i;
54     unsigned doubleLength = i;
55
56     // IE quirk: Skip whitespace between the number and the % character (20 % => 20%).
57     while (i < length && isSpaceOrNewline(data[i]))
58         ++i;
59
60     bool ok;
61     UChar next = (i < length) ? data[i] : ' ';
62     if (next == '%') {
63         // IE quirk: accept decimal fractions for percentages.
64         double r = charactersToDouble(data, doubleLength, &ok);
65         if (ok)
66             return Length(r, Percent);
67         return Length(1, Relative);
68     }
69     int r = charactersToIntStrict(data, intLength, &ok);
70     if (next == '*') {
71         if (ok)
72             return Length(r, Relative);
73         return Length(1, Relative);
74     }
75     if (ok)
76         return Length(r, Fixed);
77     return Length(0, Relative);
78 }
79
80 static int countCharacter(const UChar* data, unsigned length, UChar character)
81 {
82     int count = 0;
83     for (int i = 0; i < static_cast<int>(length); ++i)
84         count += data[i] == character;
85     return count;
86 }
87
88 std::unique_ptr<Length[]> newCoordsArray(const String& string, int& len)
89 {
90     unsigned length = string.length();
91     const UChar* data = string.characters();
92     StringBuffer<UChar> spacified(length);
93     for (unsigned i = 0; i < length; i++) {
94         UChar cc = data[i];
95         if (cc > '9' || (cc < '0' && cc != '-' && cc != '*' && cc != '.'))
96             spacified[i] = ' ';
97         else
98             spacified[i] = cc;
99     }
100     RefPtr<StringImpl> str = StringImpl::adopt(spacified);
101
102     str = str->simplifyWhiteSpace();
103
104     len = countCharacter(str->characters(), str->length(), ' ') + 1;
105     auto r = std::make_unique<Length[]>(len);
106
107     int i = 0;
108     unsigned pos = 0;
109     size_t pos2;
110
111     while ((pos2 = str->find(' ', pos)) != notFound) {
112         r[i++] = parseLength(str->characters() + pos, pos2 - pos);
113         pos = pos2+1;
114     }
115     r[i] = parseLength(str->characters() + pos, str->length() - pos);
116
117     ASSERT(i == len - 1);
118
119     return r;
120 }
121
122 std::unique_ptr<Length[]> newLengthArray(const String& string, int& len)
123 {
124     RefPtr<StringImpl> str = string.impl()->simplifyWhiteSpace();
125     if (!str->length()) {
126         len = 1;
127         return nullptr;
128     }
129
130     len = countCharacter(str->characters(), str->length(), ',') + 1;
131     auto r = std::make_unique<Length[]>(len);
132
133     int i = 0;
134     unsigned pos = 0;
135     size_t pos2;
136
137     while ((pos2 = str->find(',', pos)) != notFound) {
138         r[i++] = parseLength(str->characters() + pos, pos2 - pos);
139         pos = pos2+1;
140     }
141
142     ASSERT(i == len - 1);
143
144     // IE Quirk: If the last comma is the last char skip it and reduce len by one.
145     if (str->length()-pos > 0)
146         r[i] = parseLength(str->characters() + pos, str->length() - pos);
147     else
148         len--;
149
150     return r;
151 }
152         
153 class CalculationValueHandleMap {
154     WTF_MAKE_FAST_ALLOCATED;
155 public:
156     CalculationValueHandleMap() 
157         : m_index(1) 
158     {
159     }
160     
161     int insert(PassRefPtr<CalculationValue> calcValue)
162     {
163         ASSERT(m_index);
164         // FIXME calc(): https://bugs.webkit.org/show_bug.cgi?id=80489
165         // This monotonically increasing handle generation scheme is potentially wasteful
166         // of the handle space. Consider reusing empty handles.
167         while (m_map.contains(m_index))
168             m_index++;
169         
170         m_map.set(m_index, calcValue);       
171         
172         return m_index;
173     }
174
175     void remove(int index)
176     {
177         ASSERT(m_map.contains(index));
178         m_map.remove(index);
179     }
180     
181     PassRefPtr<CalculationValue> get(int index)
182     {
183         ASSERT(m_map.contains(index));
184         return m_map.get(index);
185     }
186     
187 private:        
188     int m_index;
189     HashMap<int, RefPtr<CalculationValue> > m_map;
190 };
191     
192 static CalculationValueHandleMap& calcHandles()
193 {
194     DEFINE_STATIC_LOCAL(CalculationValueHandleMap, handleMap, ());
195     return handleMap;
196 }
197
198 Length::Length(PassRefPtr<CalculationValue> calc)
199     : m_quirk(false)
200     , m_type(Calculated)
201     , m_isFloat(false)
202 {
203     m_intValue = calcHandles().insert(calc);
204 }
205         
206 Length Length::blendMixedTypes(const Length& from, double progress) const
207 {
208     if (progress <= 0.0)
209         return from;
210         
211     if (progress >= 1.0)
212         return *this;
213         
214     OwnPtr<CalcExpressionNode> blend = adoptPtr(new CalcExpressionBlendLength(from, *this, progress));
215     return Length(CalculationValue::create(blend.release(), CalculationRangeAll));
216 }
217           
218 PassRefPtr<CalculationValue> Length::calculationValue() const
219 {
220     ASSERT(isCalculated());
221     return calcHandles().get(calculationHandle());
222 }
223     
224 void Length::incrementCalculatedRef() const
225 {
226     ASSERT(isCalculated());
227     calculationValue()->ref();
228 }
229
230 void Length::decrementCalculatedRef() const
231 {
232     ASSERT(isCalculated());
233     RefPtr<CalculationValue> calcLength = calculationValue();
234     if (calcLength->hasOneRef())
235         calcHandles().remove(calculationHandle());
236     calcLength->deref();
237 }    
238
239 float Length::nonNanCalculatedValue(int maxValue) const
240 {
241     ASSERT(isCalculated());
242     float result = calculationValue()->evaluate(maxValue);
243     if (std::isnan(result))
244         return 0;
245     return result;
246 }
247
248 bool Length::isCalculatedEqual(const Length& o) const
249 {
250     return isCalculated() && (calculationValue() == o.calculationValue() || *calculationValue() == *o.calculationValue());
251 }
252
253 struct SameSizeAsLength {
254     int32_t value;
255     int32_t metaData;
256 };
257 COMPILE_ASSERT(sizeof(Length) == sizeof(SameSizeAsLength), length_should_stay_small);
258
259 } // namespace WebCore