Heap-use-after-free in WTF::HashMap<int, WTF::RefPtr<WebCore::CalculationValue>,...
[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 "PlatformString.h"
30 #include <wtf/ASCIICType.h>
31 #include <wtf/Assertions.h>
32 #include <wtf/OwnArrayPtr.h>
33 #include <wtf/text/StringBuffer.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 PassOwnArrayPtr<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     OwnArrayPtr<Length> r = adoptArrayPtr(new 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.release();
120 }
121
122 PassOwnArrayPtr<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     OwnArrayPtr<Length> r = adoptArrayPtr(new 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.release();
151 }
152         
153 class CalculationValueHandleMap {
154 public:
155     CalculationValueHandleMap() 
156         : m_index(1) 
157     {
158     }
159     
160     int insert(PassRefPtr<CalculationValue> calcValue)
161     {
162         ASSERT(m_index);
163         // FIXME calc(): https://bugs.webkit.org/show_bug.cgi?id=80489
164         // This monotonically increasing handle generation scheme is potentially wasteful
165         // of the handle space. Consider reusing empty handles.
166         while (m_map.contains(m_index))
167             m_index++;
168         
169         m_map.set(m_index, calcValue);       
170         
171         return m_index;
172     }
173
174     void remove(int index)
175     {
176         ASSERT(m_map.contains(index));
177         m_map.remove(index);
178     }
179     
180     PassRefPtr<CalculationValue> get(int index)
181     {
182         ASSERT(m_map.contains(index));
183         return m_map.get(index);
184     }
185     
186 private:        
187     int m_index;
188     HashMap<int, RefPtr<CalculationValue> > m_map;
189 };
190     
191 static CalculationValueHandleMap& calcHandles()
192 {
193     DEFINE_STATIC_LOCAL(CalculationValueHandleMap, handleMap, ());
194     return handleMap;
195 }
196
197 Length::Length(PassRefPtr<CalculationValue> calc)
198     : m_quirk(false)
199     , m_type(Calculated)
200     , m_isFloat(false)
201 {
202     m_intValue = calcHandles().insert(calc);
203 }
204     
205 PassRefPtr<CalculationValue> Length::calculationValue() const
206 {
207     ASSERT(isCalculated());
208     return calcHandles().get(calculationHandle());
209 }
210     
211 void Length::incrementCalculatedRef() const
212 {
213     ASSERT(isCalculated());
214     calculationValue()->ref();
215 }
216
217 void Length::decrementCalculatedRef() const
218 {
219     ASSERT(isCalculated());
220     RefPtr<CalculationValue> calcLength = calculationValue();
221     if (calcLength->hasOneRef())
222         calcHandles().remove(calculationHandle());
223     calcLength->deref();
224 }    
225
226 float Length::nonNanCalculatedValue(int maxValue) const
227 {
228     ASSERT(isCalculated());
229     float result = calculationValue()->evaluate(maxValue);
230     if (isnan(result))
231         return 0;
232     return result;
233 }
234
235 bool Length::isCalculatedEqual(const Length& o) const
236 {
237     return isCalculated() && (calculationValue() == o.calculationValue() || *calculationValue() == *o.calculationValue());
238 }
239
240 class SameSizeAsLength {
241     int32_t value;
242     int32_t metaData;
243 };
244 COMPILE_ASSERT(sizeof(Length) == sizeof(SameSizeAsLength), length_should_stay_small);
245
246 } // namespace WebCore