HTMLAreaElement's coords attributes parsing does not comply with the HTML specification
[WebKit-https.git] / Source / WebCore / html / parser / HTMLParserIdioms.cpp
index 8f057b1..ad332ee 100644 (file)
 #include "HTMLParserIdioms.h"
 
 #include "Decimal.h"
+#include "QualifiedName.h"
+#include "URL.h"
 #include <limits>
 #include <wtf/MathExtras.h>
+#include <wtf/NeverDestroyed.h>
 #include <wtf/dtoa.h>
-#include <wtf/text/AtomicString.h>
 #include <wtf/text/StringBuilder.h>
 
 namespace WebCore {
@@ -71,7 +73,7 @@ String stripLeadingAndTrailingHTMLSpaces(const String& string)
     if (string.is8Bit())
         return stripLeadingAndTrailingHTMLSpaces(string, string.characters8(), length);
 
-    return stripLeadingAndTrailingHTMLSpaces(string, string.characters(), length);
+    return stripLeadingAndTrailingHTMLSpaces(string, string.characters16(), length);
 }
 
 String serializeForNumberType(const Decimal& number)
@@ -87,8 +89,7 @@ String serializeForNumberType(double number)
 {
     // According to HTML5, "the best representation of the number n as a floating
     // point number" is a string produced by applying ToString() to n.
-    NumberToStringBuffer buffer;
-    return String(numberToString(number, buffer));
+    return String::numberToStringECMAScript(number);
 }
 
 Decimal parseToDecimalForNumberType(const String& string, const Decimal& fallbackValue)
@@ -135,7 +136,7 @@ double parseToDoubleForNumberType(const String& string, double fallbackValue)
         return fallbackValue;
 
     // NaN and infinity are considered valid by String::toDouble, but not valid here.
-    if (!isfinite(value))
+    if (!std::isfinite(value))
         return fallbackValue;
 
     // Numbers are considered finite IEEE 754 single-precision floating point values.
@@ -152,180 +153,148 @@ double parseToDoubleForNumberType(const String& string)
     return parseToDoubleForNumberType(string, std::numeric_limits<double>::quiet_NaN());
 }
 
-double parseToDoubleForNumberTypeWithDecimalPlaces(const String& string, unsigned *decimalPlaces, double fallbackValue)
+template <typename CharacterType>
+static Optional<int> parseHTMLIntegerInternal(const CharacterType* position, const CharacterType* end)
 {
-    if (decimalPlaces)
-        *decimalPlaces = 0;
+    while (position < end && isHTMLSpace(*position))
+        ++position;
 
-    double value = parseToDoubleForNumberType(string, std::numeric_limits<double>::quiet_NaN());
-    if (!isfinite(value))
-        return fallbackValue;
+    if (position == end)
+        return Nullopt;
 
-    if (!decimalPlaces)
-        return value;
+    bool isNegative = false;
+    if (*position == '-') {
+        isNegative = true;
+        ++position;
+    } else if (*position == '+')
+        ++position;
 
-    size_t dotIndex = string.find('.');
-    size_t eIndex = string.find('e');
-    if (eIndex == notFound) 
-        eIndex = string.find('E');
+    if (position == end || !isASCIIDigit(*position))
+        return Nullopt;
 
-    unsigned baseDecimalPlaces = 0;
-    if (dotIndex != notFound) {
-        if (eIndex == notFound)
-            baseDecimalPlaces = string.length() - dotIndex - 1;
-        else
-            baseDecimalPlaces = eIndex - dotIndex - 1;
-    }
+    constexpr int intMax = std::numeric_limits<int>::max();
+    constexpr int base = 10;
+    constexpr int maxMultiplier = intMax / base;
 
-    int exponent = 0;
-    if (eIndex != notFound) {
-        unsigned cursor = eIndex + 1, cursorSaved;
-        int digit, exponentSign;
-        int32_t exponent32;
-        size_t length = string.length();
-
-        // Not using String.toInt() in order to perform the same computation as dtoa() does.
-        exponentSign = 0;
-        switch (digit = string[cursor]) {
-        case '-':
-            exponentSign = 1;
-        case '+':
-            digit = string[++cursor];
-        }
-        if (digit >= '0' && digit <= '9') {
-            while (cursor < length && digit == '0')
-                digit = string[++cursor];
-            if (digit > '0' && digit <= '9') {
-                exponent32 = digit - '0';
-                cursorSaved = cursor;
-                while (cursor < length && (digit = string[++cursor]) >= '0' && digit <= '9')
-                    exponent32 = (10 * exponent32) + digit - '0';
-                if (cursor - cursorSaved > 8 || exponent32 > 19999)
-                    /* Avoid confusion from exponents
-                     * so large that e might overflow.
-                     */
-                    exponent = 19999; /* safe for 16 bit ints */
-                else
-                    exponent = static_cast<int>(exponent32);
-                if (exponentSign)
-                    exponent = -exponent;
-            } else
-                exponent = 0;
-        }
+    unsigned result = 0;
+    do {
+        int digitValue = *position - '0';
+
+        if (result > maxMultiplier || (result == maxMultiplier && digitValue > (intMax % base) + isNegative))
+            return Nullopt;
+
+        result = base * result + digitValue;
+        ++position;
+    } while (position < end && isASCIIDigit(*position));
+
+    return isNegative ? -result : result;
+}
+
+// https://html.spec.whatwg.org/multipage/infrastructure.html#rules-for-parsing-integers
+Optional<int> parseHTMLInteger(const String& input)
+{
+    unsigned length = input.length();
+    if (!length)
+        return Nullopt;
+
+    if (LIKELY(input.is8Bit())) {
+        auto* start = input.characters8();
+        return parseHTMLIntegerInternal(start, start + length);
     }
 
-    int intDecimalPlaces = baseDecimalPlaces - exponent;
-    if (intDecimalPlaces < 0)
-        *decimalPlaces = 0;
-    else if (intDecimalPlaces > 19999)
-        *decimalPlaces = 19999;
-    else
-        *decimalPlaces = static_cast<unsigned>(intDecimalPlaces);
+    auto* start = input.characters16();
+    return parseHTMLIntegerInternal(start, start + length);
+}
 
-    return value;
+// https://html.spec.whatwg.org/multipage/infrastructure.html#rules-for-parsing-non-negative-integers
+Optional<int> parseHTMLNonNegativeInteger(const String& input)
+{
+    Optional<int> signedValue = parseHTMLInteger(input);
+    if (!signedValue || signedValue.value() < 0)
+        return Nullopt;
+
+    return signedValue;
 }
 
-double parseToDoubleForNumberTypeWithDecimalPlaces(const String& string, unsigned *decimalPlaces)
+template <typename CharacterType>
+static inline bool isHTMLSpaceOrDelimiter(CharacterType character)
 {
-    return parseToDoubleForNumberTypeWithDecimalPlaces(string, decimalPlaces, std::numeric_limits<double>::quiet_NaN());
+    return isHTMLSpace(character) || character == ',' || character == ';';
 }
 
-// http://www.whatwg.org/specs/web-apps/current-work/#rules-for-parsing-integers
-bool parseHTMLInteger(const String& input, int& value)
+template <typename CharacterType>
+static inline bool isNumberStart(CharacterType character)
 {
-    // Step 1
-    // Step 2
-    const UChar* position = input.characters();
-    const UChar* end = position + input.length();
+    return isASCIIDigit(character) || character == '.' || character == '-';
+}
 
-    // Step 3
-    int sign = 1;
+// https://html.spec.whatwg.org/multipage/infrastructure.html#rules-for-parsing-floating-point-number-values
+template <typename CharacterType>
+static Vector<double> parseHTMLListOfOfFloatingPointNumberValuesInternal(const CharacterType* position, const CharacterType* end)
+{
+    Vector<double> numbers;
 
-    // Step 4
-    while (position < end) {
-        if (!isHTMLSpace(*position))
-            break;
+    // This skips past any leading delimiters.
+    while (position < end && isHTMLSpaceOrDelimiter(*position))
         ++position;
-    }
 
-    // Step 5
-    if (position == end)
-        return false;
-    ASSERT(position < end);
+    while (position < end) {
+        // This skips past leading garbage.
+        while (position < end && !(isHTMLSpaceOrDelimiter(*position) || isNumberStart(*position)))
+            ++position;
 
-    // Step 6
-    if (*position == '-') {
-        sign = -1;
-        ++position;
-    } else if (*position == '+')
-        ++position;
-    if (position == end)
-        return false;
-    ASSERT(position < end);
+        const CharacterType* numberStart = position;
+        while (position < end && !isHTMLSpaceOrDelimiter(*position))
+            ++position;
 
-    // Step 7
-    if (!isASCIIDigit(*position))
-        return false;
+        size_t parsedLength = 0;
+        double number = parseDouble(numberStart, position - numberStart, parsedLength);
+        numbers.append(parsedLength > 0 && std::isfinite(number) ? number : 0);
 
-    // Step 8
-    StringBuilder digits;
-    while (position < end) {
-        if (!isASCIIDigit(*position))
-            break;
-        digits.append(*position++);
+        // This skips past the delimiter.
+        while (position < end && isHTMLSpaceOrDelimiter(*position))
+            ++position;
     }
 
-    // Step 9
-    bool ok;
-    value = sign * charactersToIntStrict(digits.characters(), digits.length(), &ok);
-    return ok;
+    return numbers;
 }
 
-// http://www.whatwg.org/specs/web-apps/current-work/#rules-for-parsing-non-negative-integers
-bool parseHTMLNonNegativeInteger(const String& input, unsigned int& value)
+Vector<double> parseHTMLListOfOfFloatingPointNumberValues(const String& input)
 {
-    // Step 1
-    // Step 2
-    const UChar* position = input.characters();
-    const UChar* end = position + input.length();
+    unsigned length = input.length();
+    if (!length)
+        return { };
 
-    // Step 3
-    while (position < end) {
-        if (!isHTMLSpace(*position))
-            break;
-        ++position;
+    if (LIKELY(input.is8Bit())) {
+        auto* start = input.characters8();
+        return parseHTMLListOfOfFloatingPointNumberValuesInternal(start, start + length);
     }
 
-    // Step 4
-    if (position == end)
-        return false;
-    ASSERT(position < end);
-
-    // Step 5
-    if (*position == '+')
-        ++position;
-
-    // Step 6
-    if (position == end)
-        return false;
-    ASSERT(position < end);
+    auto* start = input.characters16();
+    return parseHTMLListOfOfFloatingPointNumberValuesInternal(start, start + length);
+}
 
-    // Step 7
-    if (!isASCIIDigit(*position))
+static bool threadSafeEqual(const StringImpl& a, const StringImpl& b)
+{
+    if (&a == &b)
+        return true;
+    if (a.hash() != b.hash())
         return false;
+    return equal(a, b);
+}
 
-    // Step 8
-    StringBuilder digits;
-    while (position < end) {
-        if (!isASCIIDigit(*position))
-            break;
-        digits.append(*position++);
-    }
+bool threadSafeMatch(const QualifiedName& a, const QualifiedName& b)
+{
+    return threadSafeEqual(*a.localName().impl(), *b.localName().impl());
+}
 
-    // Step 9
-    bool ok;
-    value = charactersToUIntStrict(digits.characters(), digits.length(), &ok);
-    return ok;
+String parseCORSSettingsAttribute(const AtomicString& value)
+{
+    if (value.isNull())
+        return String();
+    if (equalIgnoringASCIICase(value, "use-credentials"))
+        return ASCIILiteral("use-credentials");
+    return ASCIILiteral("anonymous");
 }
 
 }