Home | History | Annotate | Download | only in html
      1 /*
      2  * Copyright (C) 2013 Google Inc. All rights reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions are
      6  * met:
      7  *
      8  *     * Redistributions of source code must retain the above copyright
      9  * notice, this list of conditions and the following disclaimer.
     10  *     * Redistributions in binary form must reproduce the above
     11  * copyright notice, this list of conditions and the following disclaimer
     12  * in the documentation and/or other materials provided with the
     13  * distribution.
     14  *     * Neither the name of Google Inc. nor the names of its
     15  * contributors may be used to endorse or promote products derived from
     16  * this software without specific prior written permission.
     17  *
     18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     29  */
     30 
     31 #include "config.h"
     32 #include "core/html/HTMLDimension.h"
     33 
     34 #include "wtf/MathExtras.h"
     35 #include "wtf/text/WTFString.h"
     36 
     37 namespace WebCore {
     38 
     39 template <typename CharacterType>
     40 static HTMLDimension parseDimension(const CharacterType* characters, size_t lastParsedIndex, size_t endOfCurrentToken)
     41 {
     42     HTMLDimension::HTMLDimensionType type = HTMLDimension::Absolute;
     43     double value = 0.;
     44 
     45     // HTML5's split removes leading and trailing spaces so we need to skip the leading spaces here.
     46     while (lastParsedIndex < endOfCurrentToken && isASCIISpace((characters[lastParsedIndex])))
     47         ++lastParsedIndex;
     48 
     49     // This is Step 5.5. in the algorithm. Going to the last step would make the code less readable.
     50     if (lastParsedIndex >= endOfCurrentToken)
     51         return HTMLDimension(value, HTMLDimension::Relative);
     52 
     53     size_t position = lastParsedIndex;
     54     while (position < endOfCurrentToken && isASCIIDigit(characters[position]))
     55         ++position;
     56 
     57     if (position > lastParsedIndex) {
     58         bool ok = false;
     59         unsigned integerValue = charactersToUIntStrict(characters + lastParsedIndex, position - lastParsedIndex, &ok);
     60         ASSERT(ok);
     61         value += integerValue;
     62 
     63         if (position < endOfCurrentToken && characters[position] == '.') {
     64             ++position;
     65             size_t fractionStart = position;
     66             Vector<CharacterType> fractionNumbers;
     67             while (position < endOfCurrentToken && (isASCIIDigit(characters[position]) || isASCIISpace(characters[position]))) {
     68                 if (isASCIIDigit(characters[position]))
     69                     fractionNumbers.append(characters[position]);
     70                 ++position;
     71             }
     72 
     73             if (fractionNumbers.size()) {
     74                 double fractionValue = charactersToUIntStrict(fractionNumbers.data(), fractionNumbers.size(), &ok);
     75                 ASSERT(ok);
     76 
     77                 value += fractionValue / pow(10., static_cast<double>(fractionNumbers.size()));
     78             }
     79         }
     80     }
     81 
     82     while (position < endOfCurrentToken && isASCIISpace(characters[position]))
     83         ++position;
     84 
     85     if (position < endOfCurrentToken) {
     86         if (characters[position] == '*')
     87             type = HTMLDimension::Relative;
     88         else if (characters[position] == '%')
     89             type = HTMLDimension::Percentage;
     90     }
     91 
     92     return HTMLDimension(value, type);
     93 }
     94 
     95 static HTMLDimension parseDimension(const String& rawToken, size_t lastParsedIndex, size_t endOfCurrentToken)
     96 {
     97     if (rawToken.is8Bit())
     98         return parseDimension<LChar>(rawToken.characters8(), lastParsedIndex, endOfCurrentToken);
     99     return parseDimension<UChar>(rawToken.characters16(), lastParsedIndex, endOfCurrentToken);
    100 }
    101 
    102 // This implements the "rules for parsing a list of dimensions" per HTML5.
    103 // http://www.whatwg.org/specs/web-apps/current-work/multipage/common-microsyntaxes.html#rules-for-parsing-a-list-of-dimensions
    104 Vector<HTMLDimension> parseListOfDimensions(const String& input)
    105 {
    106     static const char comma = ',';
    107 
    108     // Step 2. Remove the last character if it's a comma.
    109     String trimmedString = input;
    110     if (trimmedString.endsWith(comma))
    111         trimmedString.truncate(trimmedString.length() - 1);
    112 
    113     // HTML5's split doesn't return a token for an empty string so
    114     // we need to match them here.
    115     if (trimmedString.isEmpty())
    116         return Vector<HTMLDimension>();
    117 
    118     // Step 3. To avoid String copies, we just look for commas instead of splitting.
    119     Vector<HTMLDimension> parsedDimensions;
    120     size_t lastParsedIndex = 0;
    121     while (true) {
    122         size_t nextComma = trimmedString.find(comma, lastParsedIndex);
    123         if (nextComma == notFound)
    124             break;
    125 
    126         parsedDimensions.append(parseDimension(trimmedString, lastParsedIndex, nextComma));
    127         lastParsedIndex = nextComma + 1;
    128     }
    129 
    130     parsedDimensions.append(parseDimension(trimmedString, lastParsedIndex, trimmedString.length()));
    131     return parsedDimensions;
    132 }
    133 
    134 } // namespace WebCore
    135