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