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