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 Vector<CharacterType> fractionNumbers; 66 while (position < endOfCurrentToken && (isASCIIDigit(characters[position]) || isASCIISpace(characters[position]))) { 67 if (isASCIIDigit(characters[position])) 68 fractionNumbers.append(characters[position]); 69 ++position; 70 } 71 72 if (fractionNumbers.size()) { 73 double fractionValue = charactersToUIntStrict(fractionNumbers.data(), fractionNumbers.size(), &ok); 74 ASSERT(ok); 75 76 value += fractionValue / pow(10., static_cast<double>(fractionNumbers.size())); 77 } 78 } 79 } 80 81 while (position < endOfCurrentToken && isASCIISpace(characters[position])) 82 ++position; 83 84 if (position < endOfCurrentToken) { 85 if (characters[position] == '*') 86 type = HTMLDimension::Relative; 87 else if (characters[position] == '%') 88 type = HTMLDimension::Percentage; 89 } 90 91 return HTMLDimension(value, type); 92 } 93 94 static HTMLDimension parseDimension(const String& rawToken, size_t lastParsedIndex, size_t endOfCurrentToken) 95 { 96 if (rawToken.is8Bit()) 97 return parseDimension<LChar>(rawToken.characters8(), lastParsedIndex, endOfCurrentToken); 98 return parseDimension<UChar>(rawToken.characters16(), lastParsedIndex, endOfCurrentToken); 99 } 100 101 // This implements the "rules for parsing a list of dimensions" per HTML5. 102 // http://www.whatwg.org/specs/web-apps/current-work/multipage/common-microsyntaxes.html#rules-for-parsing-a-list-of-dimensions 103 Vector<HTMLDimension> parseListOfDimensions(const String& input) 104 { 105 static const char comma = ','; 106 107 // Step 2. Remove the last character if it's a comma. 108 String trimmedString = input; 109 if (trimmedString.endsWith(comma)) 110 trimmedString.truncate(trimmedString.length() - 1); 111 112 // HTML5's split doesn't return a token for an empty string so 113 // we need to match them here. 114 if (trimmedString.isEmpty()) 115 return Vector<HTMLDimension>(); 116 117 // Step 3. To avoid String copies, we just look for commas instead of splitting. 118 Vector<HTMLDimension> parsedDimensions; 119 size_t lastParsedIndex = 0; 120 while (true) { 121 size_t nextComma = trimmedString.find(comma, lastParsedIndex); 122 if (nextComma == kNotFound) 123 break; 124 125 parsedDimensions.append(parseDimension(trimmedString, lastParsedIndex, nextComma)); 126 lastParsedIndex = nextComma + 1; 127 } 128 129 parsedDimensions.append(parseDimension(trimmedString, lastParsedIndex, trimmedString.length())); 130 return parsedDimensions; 131 } 132 133 } // namespace WebCore 134