Home | History | Annotate | Download | only in platform
      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