1 /* 2 * Copyright (C) 1999 Lars Knoll (knoll (at) kde.org) 3 * (C) 1999 Antti Koivisto (koivisto (at) kde.org) 4 * (C) 2001 Dirk Mueller ( mueller (at) kde.org ) 5 * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. 6 * Copyright (C) 2006 Andrew Wellington (proton (at) 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> 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> 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". 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: 115 CalculationValueHandleMap() 116 : m_index(1) 117 { 118 } 119 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 134 void remove(int index) 135 { 136 ASSERT(m_map.contains(index)); 137 m_map.remove(index); 138 } 139 140 CalculationValue* get(int index) 141 { 142 ASSERT(m_map.contains(index)); 143 return m_map.get(index); 144 } 145 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 164 static CalculationValueHandleMap& calcHandles() 165 { 166 DEFINE_STATIC_LOCAL(CalculationValueHandleMap, handleMap, ()); 167 return handleMap; 168 } 169 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 178 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 183 CalculationValue* Length::calculationValue() const 184 { 185 ASSERT(isCalculated()); 186 return calcHandles().get(calculationHandle()); 187 } 188 189 void Length::incrementCalculatedRef() const 190 { 191 ASSERT(isCalculated()); 192 calculationValue()->ref(); 193 } 194 195 void Length::decrementCalculatedRef() const 196 { 197 ASSERT(isCalculated()); 198 calcHandles().decrementRef(calculationHandle()); 199 } 200 201 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 210 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