• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "wtf/ASCIICType.h"
30 #include "wtf/text/StringBuffer.h"
31 #include "wtf/text/WTFString.h"
32 
33 using namespace WTF;
34 
35 namespace WebCore {
36 
37 template<typename CharType>
splitLength(const CharType * data,unsigned length,unsigned & intLength,unsigned & doubleLength)38 static unsigned splitLength(const CharType* data, unsigned length, unsigned& intLength, unsigned& doubleLength)
39 {
40     ASSERT(length);
41 
42     unsigned i = 0;
43     while (i < length && isSpaceOrNewline(data[i]))
44         ++i;
45     if (i < length && (data[i] == '+' || data[i] == '-'))
46         ++i;
47     while (i < length && isASCIIDigit(data[i]))
48         ++i;
49     intLength = i;
50     while (i < length && (isASCIIDigit(data[i]) || data[i] == '.'))
51         ++i;
52     doubleLength = i;
53 
54     // IE quirk: Skip whitespace between the number and the % character (20 % => 20%).
55     while (i < length && isSpaceOrNewline(data[i]))
56         ++i;
57 
58     return i;
59 }
60 
61 template<typename CharType>
parseHTMLAreaCoordinate(const CharType * data,unsigned length)62 static Length parseHTMLAreaCoordinate(const CharType* data, unsigned length)
63 {
64     unsigned intLength;
65     unsigned doubleLength;
66     splitLength(data, length, intLength, doubleLength);
67 
68     bool ok;
69     int r = charactersToIntStrict(data, intLength, &ok);
70     if (ok)
71         return Length(r, Fixed);
72     return Length(0, Fixed);
73 }
74 
75 // FIXME: Per HTML5, this should follow the "rules for parsing a list of integers".
parseHTMLAreaElementCoords(const String & string)76 Vector<Length> parseHTMLAreaElementCoords(const String& string)
77 {
78     unsigned length = string.length();
79     StringBuffer<LChar> spacified(length);
80     for (unsigned i = 0; i < length; i++) {
81         UChar cc = string[i];
82         if (cc > '9' || (cc < '0' && cc != '-' && cc != '.'))
83             spacified[i] = ' ';
84         else
85             spacified[i] = cc;
86     }
87     RefPtr<StringImpl> str = spacified.release();
88     str = str->simplifyWhiteSpace();
89     ASSERT(str->is8Bit());
90 
91     if (!str->length())
92         return Vector<Length>();
93 
94     unsigned len = str->count(' ') + 1;
95     Vector<Length> r(len);
96 
97     unsigned i = 0;
98     unsigned pos = 0;
99     size_t pos2;
100 
101     while ((pos2 = str->find(' ', pos)) != kNotFound) {
102         r[i++] = parseHTMLAreaCoordinate(str->characters8() + pos, pos2 - pos);
103         pos = pos2 + 1;
104     }
105     r[i] = parseHTMLAreaCoordinate(str->characters8() + pos, str->length() - pos);
106 
107     ASSERT(i == len - 1);
108 
109     return r;
110 }
111 
112 class CalculationValueHandleMap {
113     WTF_MAKE_FAST_ALLOCATED;
114 public:
CalculationValueHandleMap()115     CalculationValueHandleMap()
116         : m_index(1)
117     {
118     }
119 
insert(PassRefPtr<CalculationValue> calcValue)120     int insert(PassRefPtr<CalculationValue> calcValue)
121     {
122         ASSERT(m_index);
123         // FIXME calc(): https://bugs.webkit.org/show_bug.cgi?id=80489
124         // This monotonically increasing handle generation scheme is potentially wasteful
125         // of the handle space. Consider reusing empty handles.
126         while (m_map.contains(m_index))
127             m_index++;
128 
129         m_map.set(m_index, calcValue);
130 
131         return m_index;
132     }
133 
remove(int index)134     void remove(int index)
135     {
136         ASSERT(m_map.contains(index));
137         m_map.remove(index);
138     }
139 
get(int index)140     CalculationValue* get(int index)
141     {
142         ASSERT(m_map.contains(index));
143         return m_map.get(index);
144     }
145 
decrementRef(int index)146     void decrementRef(int index)
147     {
148         ASSERT(m_map.contains(index));
149         CalculationValue* value = m_map.get(index);
150         if (value->hasOneRef()) {
151             // Force the CalculationValue destructor early to avoid a potential recursive call inside HashMap remove().
152             m_map.set(index, 0);
153             m_map.remove(index);
154         } else {
155             value->deref();
156         }
157     }
158 
159 private:
160     int m_index;
161     HashMap<int, RefPtr<CalculationValue> > m_map;
162 };
163 
calcHandles()164 static CalculationValueHandleMap& calcHandles()
165 {
166     DEFINE_STATIC_LOCAL(CalculationValueHandleMap, handleMap, ());
167     return handleMap;
168 }
169 
Length(PassRefPtr<CalculationValue> calc)170 Length::Length(PassRefPtr<CalculationValue> calc)
171     : m_quirk(false)
172     , m_type(Calculated)
173     , m_isFloat(false)
174 {
175     m_intValue = calcHandles().insert(calc);
176 }
177 
blendMixedTypes(const Length & from,double progress,ValueRange range) const178 Length Length::blendMixedTypes(const Length& from, double progress, ValueRange range) const
179 {
180     return Length(CalculationValue::create(adoptPtr(new CalcExpressionBlendLength(from, *this, progress)), range));
181 }
182 
calculationValue() const183 CalculationValue* Length::calculationValue() const
184 {
185     ASSERT(isCalculated());
186     return calcHandles().get(calculationHandle());
187 }
188 
incrementCalculatedRef() const189 void Length::incrementCalculatedRef() const
190 {
191     ASSERT(isCalculated());
192     calculationValue()->ref();
193 }
194 
decrementCalculatedRef() const195 void Length::decrementCalculatedRef() const
196 {
197     ASSERT(isCalculated());
198     calcHandles().decrementRef(calculationHandle());
199 }
200 
nonNanCalculatedValue(int maxValue) const201 float Length::nonNanCalculatedValue(int maxValue) const
202 {
203     ASSERT(isCalculated());
204     float result = calculationValue()->evaluate(maxValue);
205     if (std::isnan(result))
206         return 0;
207     return result;
208 }
209 
isCalculatedEqual(const Length & o) const210 bool Length::isCalculatedEqual(const Length& o) const
211 {
212     return isCalculated() && (calculationValue() == o.calculationValue() || *calculationValue() == *o.calculationValue());
213 }
214 
215 struct SameSizeAsLength {
216     int32_t value;
217     int32_t metaData;
218 };
219 COMPILE_ASSERT(sizeof(Length) == sizeof(SameSizeAsLength), length_should_stay_small);
220 
221 } // namespace WebCore
222