HTMLAreaElement's coords attributes parsing does not comply with the HTML specification
[WebKit-https.git] / Source / WebCore / html / parser / HTMLParserIdioms.cpp
index ea453d8..ad332ee 100644 (file)
 #include "HTMLParserIdioms.h"
 
 #include "Decimal.h"
+#include "QualifiedName.h"
 #include "URL.h"
 #include <limits>
 #include <wtf/MathExtras.h>
-#include <wtf/text/AtomicString.h>
+#include <wtf/NeverDestroyed.h>
+#include <wtf/dtoa.h>
 #include <wtf/text/StringBuilder.h>
 
 namespace WebCore {
@@ -152,283 +154,147 @@ double parseToDoubleForNumberType(const String& string)
 }
 
 template <typename CharacterType>
-static bool parseHTMLIntegerInternal(const CharacterType* position, const CharacterType* end, int& value)
+static Optional<int> parseHTMLIntegerInternal(const CharacterType* position, const CharacterType* end)
 {
-    // Step 3
-    int sign = 1;
-
-    // Step 4
-    while (position < end) {
-        if (!isHTMLSpace(*position))
-            break;
+    while (position < end && isHTMLSpace(*position))
         ++position;
-    }
 
-    // Step 5
     if (position == end)
-        return false;
-    ASSERT_WITH_SECURITY_IMPLICATION(position < end);
+        return Nullopt;
 
-    // Step 6
+    bool isNegative = false;
     if (*position == '-') {
-        sign = -1;
+        isNegative = true;
         ++position;
     } else if (*position == '+')
         ++position;
-    if (position == end)
-        return false;
-    ASSERT_WITH_SECURITY_IMPLICATION(position < end);
 
-    // Step 7
-    if (!isASCIIDigit(*position))
-        return false;
+    if (position == end || !isASCIIDigit(*position))
+        return Nullopt;
 
-    // Step 8
-    StringBuilder digits;
-    while (position < end) {
-        if (!isASCIIDigit(*position))
-            break;
-        digits.append(*position++);
-    }
+    constexpr int intMax = std::numeric_limits<int>::max();
+    constexpr int base = 10;
+    constexpr int maxMultiplier = intMax / base;
+
+    unsigned result = 0;
+    do {
+        int digitValue = *position - '0';
 
-    // Step 9
-    bool ok;
-    if (digits.is8Bit())
-        value = sign * charactersToIntStrict(digits.characters8(), digits.length(), &ok);
-    else
-        value = sign * charactersToIntStrict(digits.characters16(), digits.length(), &ok);
-    return ok;
+        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;
 }
 
-// http://www.whatwg.org/specs/web-apps/current-work/#rules-for-parsing-integers
-bool parseHTMLInteger(const String& input, int& value)
+// https://html.spec.whatwg.org/multipage/infrastructure.html#rules-for-parsing-integers
+Optional<int> parseHTMLInteger(const String& input)
 {
-    // Step 1
-    // Step 2
     unsigned length = input.length();
-    if (!length || input.is8Bit()) {
-        const LChar* start = input.characters8();
-        return parseHTMLIntegerInternal(start, start + length, value);
+    if (!length)
+        return Nullopt;
+
+    if (LIKELY(input.is8Bit())) {
+        auto* start = input.characters8();
+        return parseHTMLIntegerInternal(start, start + length);
     }
 
-    const UChar* start = input.characters16();
-    return parseHTMLIntegerInternal(start, start + length, value);
+    auto* start = input.characters16();
+    return parseHTMLIntegerInternal(start, start + length);
 }
 
-template <typename CharacterType>
-static bool parseHTMLNonNegativeIntegerInternal(const CharacterType* position, const CharacterType* end, unsigned& value)
+// https://html.spec.whatwg.org/multipage/infrastructure.html#rules-for-parsing-non-negative-integers
+Optional<int> parseHTMLNonNegativeInteger(const String& input)
 {
-    // Step 3
-    while (position < end) {
-        if (!isHTMLSpace(*position))
-            break;
-        ++position;
-    }
+    Optional<int> signedValue = parseHTMLInteger(input);
+    if (!signedValue || signedValue.value() < 0)
+        return Nullopt;
 
-    // Step 4
-    if (position == end)
-        return false;
-    ASSERT_WITH_SECURITY_IMPLICATION(position < end);
+    return signedValue;
+}
 
-    // Step 5
-    if (*position == '+')
-        ++position;
+template <typename CharacterType>
+static inline bool isHTMLSpaceOrDelimiter(CharacterType character)
+{
+    return isHTMLSpace(character) || character == ',' || character == ';';
+}
 
-    // Step 6
-    if (position == end)
-        return false;
-    ASSERT_WITH_SECURITY_IMPLICATION(position < end);
+template <typename CharacterType>
+static inline bool isNumberStart(CharacterType character)
+{
+    return isASCIIDigit(character) || character == '.' || character == '-';
+}
 
-    // Step 7
-    if (!isASCIIDigit(*position))
-        return false;
+// 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;
+
+    // This skips past any leading delimiters.
+    while (position < end && isHTMLSpaceOrDelimiter(*position))
+        ++position;
 
-    // Step 8
-    StringBuilder digits;
     while (position < end) {
-        if (!isASCIIDigit(*position))
-            break;
-        digits.append(*position++);
-    }
+        // This skips past leading garbage.
+        while (position < end && !(isHTMLSpaceOrDelimiter(*position) || isNumberStart(*position)))
+            ++position;
 
-    // Step 9
-    bool ok;
-    if (digits.is8Bit())
-        value = charactersToUIntStrict(digits.characters8(), digits.length(), &ok);
-    else
-        value = charactersToUIntStrict(digits.characters16(), digits.length(), &ok);
-    return ok;
-}
+        const CharacterType* numberStart = position;
+        while (position < end && !isHTMLSpaceOrDelimiter(*position))
+            ++position;
 
+        size_t parsedLength = 0;
+        double number = parseDouble(numberStart, position - numberStart, parsedLength);
+        numbers.append(parsedLength > 0 && std::isfinite(number) ? number : 0);
 
-// http://www.whatwg.org/specs/web-apps/current-work/#rules-for-parsing-non-negative-integers
-bool parseHTMLNonNegativeInteger(const String& input, unsigned& value)
-{
-    // Step 1
-    // Step 2
-    unsigned length = input.length();
-    if (input.isNull() || input.is8Bit()) {
-        const LChar* start = input.characters8();
-        return parseHTMLNonNegativeIntegerInternal(start, start + length, value);
+        // This skips past the delimiter.
+        while (position < end && isHTMLSpaceOrDelimiter(*position))
+            ++position;
     }
-    
-    const UChar* start = input.characters16();
-    return parseHTMLNonNegativeIntegerInternal(start, start + length, value);
-}
 
-static bool threadSafeEqual(const StringImpl* a, const StringImpl* b)
-{
-    if (a == b)
-        return true;
-    if (a->hash() != b->hash())
-        return false;
-    return equalNonNull(a, b);
+    return numbers;
 }
 
-bool threadSafeMatch(const QualifiedName& a, const QualifiedName& b)
+Vector<double> parseHTMLListOfOfFloatingPointNumberValues(const String& input)
 {
-    return threadSafeEqual(a.localName().impl(), b.localName().impl());
-}
-
-#if ENABLE(THREADED_HTML_PARSER)
-bool threadSafeMatch(const HTMLIdentifier& localName, const QualifiedName& qName)
-{
-    return threadSafeEqual(localName.asStringImpl(), qName.localName().impl());
-}
-#endif
-
-struct ImageWithScale {
-    unsigned imageURLStart;
-    unsigned imageURLLength;
-    float scaleFactor;
-
-    ImageWithScale()
-        : imageURLStart(0)
-        , imageURLLength(0)
-        , scaleFactor(1)
-    { 
-    }
+    unsigned length = input.length();
+    if (!length)
+        return { };
 
-    bool hasImageURL() const
-    {
-        return imageURLLength;
+    if (LIKELY(input.is8Bit())) {
+        auto* start = input.characters8();
+        return parseHTMLListOfOfFloatingPointNumberValuesInternal(start, start + length);
     }
-};
-typedef Vector<ImageWithScale> ImageCandidates;
 
-static inline bool compareByScaleFactor(const ImageWithScale& first, const ImageWithScale& second)
-{
-    return first.scaleFactor < second.scaleFactor;
+    auto* start = input.characters16();
+    return parseHTMLListOfOfFloatingPointNumberValuesInternal(start, start + length);
 }
 
-static inline bool isHTMLSpaceOrComma(UChar character)
+static bool threadSafeEqual(const StringImpl& a, const StringImpl& b)
 {
-    return isHTMLSpace(character) || character == ',';
+    if (&a == &b)
+        return true;
+    if (a.hash() != b.hash())
+        return false;
+    return equal(a, b);
 }
 
-// See the specifications for more details about the algorithm to follow.
-// http://www.w3.org/TR/2013/WD-html-srcset-20130228/#processing-the-image-candidates.
-static void parseImagesWithScaleFromSrcsetAttribute(const String& srcsetAttribute, ImageCandidates& imageCandidates)
+bool threadSafeMatch(const QualifiedName& a, const QualifiedName& b)
 {
-    ASSERT(imageCandidates.isEmpty());
-
-    size_t imageCandidateStart = 0;
-    unsigned srcsetAttributeLength = srcsetAttribute.length();
-
-    while (imageCandidateStart < srcsetAttributeLength) {
-        float imageScaleFactor = 1;
-        size_t separator;
-
-        // 4. Splitting loop: Skip whitespace.
-        size_t imageURLStart = srcsetAttribute.find(isNotHTMLSpace, imageCandidateStart);
-        if (imageURLStart == notFound)
-            break;
-        // If The current candidate is either totally empty or only contains space, skipping.
-        if (srcsetAttribute[imageURLStart] == ',') {
-            imageCandidateStart = imageURLStart + 1;
-            continue;
-        }
-        // 5. Collect a sequence of characters that are not space characters, and let that be url.
-        size_t imageURLEnd = srcsetAttribute.find(isHTMLSpace, imageURLStart + 1);
-        if (imageURLEnd == notFound) {
-            imageURLEnd = srcsetAttributeLength;
-            separator = srcsetAttributeLength;
-        } else if (srcsetAttribute[imageURLEnd - 1] == ',') {
-            --imageURLEnd;
-            separator = imageURLEnd;
-        } else {
-            // 7. Collect a sequence of characters that are not "," (U+002C) characters, and let that be descriptors.
-            size_t imageScaleStart = srcsetAttribute.find(isNotHTMLSpace, imageURLEnd + 1);
-            if (imageScaleStart == notFound)
-                separator = srcsetAttributeLength;
-            else if (srcsetAttribute[imageScaleStart] == ',')
-                separator = imageScaleStart;
-            else {
-                // This part differs from the spec as the current implementation only supports pixel density descriptors for now.
-                size_t imageScaleEnd = srcsetAttribute.find(isHTMLSpaceOrComma, imageScaleStart + 1);
-                imageScaleEnd = (imageScaleEnd == notFound) ? srcsetAttributeLength : imageScaleEnd;
-                size_t commaPosition = imageScaleEnd;
-                // Make sure there are no other descriptors.
-                while ((commaPosition < srcsetAttributeLength - 1) && isHTMLSpace(srcsetAttribute[commaPosition]))
-                    ++commaPosition;
-                // If the first not html space character after the scale modifier is not a comma,
-                // the current candidate is an invalid input.
-                if ((commaPosition < srcsetAttributeLength - 1) && srcsetAttribute[commaPosition] != ',') {
-                    // Find the nearest comma and skip the input.
-                    commaPosition = srcsetAttribute.find(',', commaPosition + 1);
-                    if (commaPosition == notFound)
-                        break;
-                    imageCandidateStart = commaPosition + 1;
-                    continue;
-                }
-                separator = commaPosition;
-                if (srcsetAttribute[imageScaleEnd - 1] != 'x') {
-                    imageCandidateStart = separator + 1;
-                    continue;
-                }
-                bool validScaleFactor = false;
-                size_t scaleFactorLengthWithoutUnit = imageScaleEnd - imageScaleStart - 1;
-                imageScaleFactor = charactersToFloat(srcsetAttribute.deprecatedCharacters() + imageScaleStart, scaleFactorLengthWithoutUnit, &validScaleFactor);
-
-                if (!validScaleFactor) {
-                    imageCandidateStart = separator + 1;
-                    continue;
-                }
-            }
-        }
-        ImageWithScale image;
-        image.imageURLStart = imageURLStart;
-        image.imageURLLength = imageURLEnd - imageURLStart;
-        image.scaleFactor = imageScaleFactor;
-
-        imageCandidates.append(image);
-        // 11. Return to the step labeled splitting loop.
-        imageCandidateStart = separator + 1;
-    }
+    return threadSafeEqual(*a.localName().impl(), *b.localName().impl());
 }
 
-String bestFitSourceForImageAttributes(float deviceScaleFactor, const String& srcAttribute, const String& srcsetAttribute)
+String parseCORSSettingsAttribute(const AtomicString& value)
 {
-    ImageCandidates imageCandidates;
-
-    parseImagesWithScaleFromSrcsetAttribute(srcsetAttribute, imageCandidates);
-
-    if (!srcAttribute.isEmpty()) {
-        ImageWithScale srcPlaceholderImage;
-        imageCandidates.append(srcPlaceholderImage);
-    }
-
-    if (imageCandidates.isEmpty())
+    if (value.isNull())
         return String();
-
-    std::stable_sort(imageCandidates.begin(), imageCandidates.end(), compareByScaleFactor);
-
-    for (size_t i = 0; i < imageCandidates.size() - 1; ++i) {
-        if (imageCandidates[i].scaleFactor >= deviceScaleFactor)
-            return imageCandidates[i].hasImageURL() ? srcsetAttribute.substringSharingImpl(imageCandidates[i].imageURLStart, imageCandidates[i].imageURLLength) : srcAttribute;
-    }
-    const ImageWithScale& lastCandidate = imageCandidates.last();
-    return lastCandidate.hasImageURL() ? srcsetAttribute.substringSharingImpl(lastCandidate.imageURLStart, lastCandidate.imageURLLength) : srcAttribute;
+    if (equalIgnoringASCIICase(value, "use-credentials"))
+        return ASCIILiteral("use-credentials");
+    return ASCIILiteral("anonymous");
 }
 
 }