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