Refactor the srcset parser into its own file
authoryoav@yoav.ws <yoav@yoav.ws@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 3 Jun 2014 22:44:26 +0000 (22:44 +0000)
committeryoav@yoav.ws <yoav@yoav.ws@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 3 Jun 2014 22:44:26 +0000 (22:44 +0000)
https://bugs.webkit.org/show_bug.cgi?id=133480

Reviewed by Andreas Kling.

No new tests, since this patch doesn't change the parser's behavior.

This patch moves the srcset parser into its own file,
in order to prepare the code for alignment with recent spec changes.

* CMakeLists.txt:
* html/HTMLImageElement.cpp:
* html/parser/HTMLParserIdioms.cpp:
(WebCore::compareByScaleFactor): Deleted.
(WebCore::parseDescriptors): Deleted.
(WebCore::parseImagesWithScaleFromSrcsetAttribute): Deleted.
(WebCore::bestFitSourceForImageAttributes): Deleted.
* html/parser/HTMLParserIdioms.h:
(WebCore::ImageWithScale::ImageWithScale): Deleted.
(WebCore::ImageWithScale::imageURL): Deleted.
(WebCore::ImageWithScale::scaleFactor): Deleted.
* html/parser/HTMLPreloadScanner.cpp:
* html/parser/HTMLSrcsetParser.cpp: Added.
(WebCore::compareByScaleFactor):
(WebCore::parseDescriptors):
(WebCore::parseImagesWithScaleFromSrcsetAttribute):
(WebCore::bestFitSourceForImageAttributes):
* html/parser/HTMLSrcsetParser.h: Added.
(WebCore::ImageWithScale::ImageWithScale):
(WebCore::ImageWithScale::imageURL):
(WebCore::ImageWithScale::scaleFactor):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@169573 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/WebCore/CMakeLists.txt
Source/WebCore/ChangeLog
Source/WebCore/WebCore.vcxproj/WebCore.vcxproj
Source/WebCore/WebCore.vcxproj/WebCore.vcxproj.filters
Source/WebCore/WebCore.xcodeproj/project.pbxproj
Source/WebCore/html/HTMLImageElement.cpp
Source/WebCore/html/parser/HTMLParserIdioms.cpp
Source/WebCore/html/parser/HTMLParserIdioms.h
Source/WebCore/html/parser/HTMLPreloadScanner.cpp
Source/WebCore/html/parser/HTMLSrcsetParser.cpp [new file with mode: 0644]
Source/WebCore/html/parser/HTMLSrcsetParser.h [new file with mode: 0644]

index bd4d7b2..b8fad23 100644 (file)
@@ -1706,6 +1706,7 @@ set(WebCore_SOURCES
     html/parser/HTMLResourcePreloader.cpp
     html/parser/HTMLScriptRunner.cpp
     html/parser/HTMLSourceTracker.cpp
+    html/parser/HTMLSrcsetParser.cpp
     html/parser/HTMLTokenizer.cpp
     html/parser/HTMLTreeBuilder.cpp
     html/parser/TextDocumentParser.cpp
index fa8fa78..6b376d8 100644 (file)
@@ -1,3 +1,37 @@
+2014-06-03  Yoav Weiss  <yoav@yoav.ws>
+
+        Refactor the srcset parser into its own file
+        https://bugs.webkit.org/show_bug.cgi?id=133480
+
+        Reviewed by Andreas Kling.
+
+        No new tests, since this patch doesn't change the parser's behavior.
+
+        This patch moves the srcset parser into its own file,
+        in order to prepare the code for alignment with recent spec changes.
+
+        * CMakeLists.txt:
+        * html/HTMLImageElement.cpp:
+        * html/parser/HTMLParserIdioms.cpp:
+        (WebCore::compareByScaleFactor): Deleted.
+        (WebCore::parseDescriptors): Deleted.
+        (WebCore::parseImagesWithScaleFromSrcsetAttribute): Deleted.
+        (WebCore::bestFitSourceForImageAttributes): Deleted.
+        * html/parser/HTMLParserIdioms.h:
+        (WebCore::ImageWithScale::ImageWithScale): Deleted.
+        (WebCore::ImageWithScale::imageURL): Deleted.
+        (WebCore::ImageWithScale::scaleFactor): Deleted.
+        * html/parser/HTMLPreloadScanner.cpp:
+        * html/parser/HTMLSrcsetParser.cpp: Added.
+        (WebCore::compareByScaleFactor):
+        (WebCore::parseDescriptors):
+        (WebCore::parseImagesWithScaleFromSrcsetAttribute):
+        (WebCore::bestFitSourceForImageAttributes):
+        * html/parser/HTMLSrcsetParser.h: Added.
+        (WebCore::ImageWithScale::ImageWithScale):
+        (WebCore::ImageWithScale::imageURL):
+        (WebCore::ImageWithScale::scaleFactor):
+
 2014-06-03  Mario Sanchez Prada  <mario.prada@samsung.com>
 
         [ATK] accessibility/textarea-selected-text-range.html is failing
index 5db3e66..80a7183 100644 (file)
     <ClCompile Include="..\html\parser\HTMLResourcePreloader.cpp" />
     <ClCompile Include="..\html\parser\HTMLScriptRunner.cpp" />
     <ClCompile Include="..\html\parser\HTMLSourceTracker.cpp" />
+    <ClCompile Include="..\html\parser\HTMLSrcsetParser.cpp" />
     <ClCompile Include="..\html\parser\HTMLTokenizer.cpp" />
     <ClCompile Include="..\html\parser\HTMLTreeBuilder.cpp" />
     <ClCompile Include="..\html\parser\TextDocumentParser.cpp" />
     <ClInclude Include="..\html\parser\HTMLScriptRunner.h" />
     <ClInclude Include="..\html\parser\HTMLScriptRunnerHost.h" />
     <ClInclude Include="..\html\parser\HTMLSourceTracker.h" />
+    <ClInclude Include="..\html\parser\HTMLSrcsetParser.h" />
     <ClInclude Include="..\html\parser\HTMLStackItem.h" />
     <ClInclude Include="..\html\parser\HTMLToken.h" />
     <ClInclude Include="..\html\parser\HTMLTokenizer.h" />
index 7888c81..fd80a4e 100644 (file)
     <ClCompile Include="..\html\parser\HTMLSourceTracker.cpp">
       <Filter>html\parser</Filter>
     </ClCompile>
+    <ClCompile Include="..\html\parser\HTMLSrcsetParser.cpp">
+      <Filter>html\parser</Filter>
+    </ClCompile>
     <ClCompile Include="..\html\parser\HTMLTokenizer.cpp">
       <Filter>html\parser</Filter>
     </ClCompile>
     <ClInclude Include="..\html\parser\HTMLSourceTracker.h">
       <Filter>html\parser</Filter>
     </ClInclude>
+    <ClInclude Include="..\html\parser\HTMLSrcsetParser.h">
+      <Filter>html\parser</Filter>
+    </ClInclude>
     <ClInclude Include="..\html\parser\HTMLStackItem.h">
       <Filter>html\parser</Filter>
     </ClInclude>
index 856963c..f1299ba 100644 (file)
                52F52E1114A0134F00ACC397 /* NSScrollerImpDetails.mm in Sources */ = {isa = PBXBuildFile; fileRef = 52F52E1014A0134F00ACC397 /* NSScrollerImpDetails.mm */; };
                5317612213C516690026E454 /* StyleFlexibleBoxData.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5317612013C516690026E454 /* StyleFlexibleBoxData.cpp */; };
                5317612313C516690026E454 /* StyleFlexibleBoxData.h in Headers */ = {isa = PBXBuildFile; fileRef = 5317612113C516690026E454 /* StyleFlexibleBoxData.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               536D5A20193E18E900CE4CAB /* HTMLSrcsetParser.h in Headers */ = {isa = PBXBuildFile; fileRef = 536D5A1F193E18E900CE4CAB /* HTMLSrcsetParser.h */; };
+               536D5A21193E18EE00CE4CAB /* HTMLSrcsetParser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 536D5A1E193E18D000CE4CAB /* HTMLSrcsetParser.cpp */; };
                53C8298D13D8D92700DE2DEB /* RenderFlexibleBox.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 53C8298B13D8D92700DE2DEB /* RenderFlexibleBox.cpp */; };
                53C8298E13D8D92700DE2DEB /* RenderFlexibleBox.h in Headers */ = {isa = PBXBuildFile; fileRef = 53C8298C13D8D92700DE2DEB /* RenderFlexibleBox.h */; settings = {ATTRIBUTES = (Private, ); }; };
                53E29E5E167A8A1900586D3D /* InternalSettingsGenerated.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 53E29E5C167A8A1900586D3D /* InternalSettingsGenerated.cpp */; };
                52F52E1014A0134F00ACC397 /* NSScrollerImpDetails.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = NSScrollerImpDetails.mm; sourceTree = "<group>"; };
                5317612013C516690026E454 /* StyleFlexibleBoxData.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = StyleFlexibleBoxData.cpp; path = style/StyleFlexibleBoxData.cpp; sourceTree = "<group>"; };
                5317612113C516690026E454 /* StyleFlexibleBoxData.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = StyleFlexibleBoxData.h; path = style/StyleFlexibleBoxData.h; sourceTree = "<group>"; };
+               536D5A1E193E18D000CE4CAB /* HTMLSrcsetParser.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = HTMLSrcsetParser.cpp; path = parser/HTMLSrcsetParser.cpp; sourceTree = "<group>"; };
+               536D5A1F193E18E900CE4CAB /* HTMLSrcsetParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = HTMLSrcsetParser.h; path = parser/HTMLSrcsetParser.h; sourceTree = "<group>"; };
                53C8298B13D8D92700DE2DEB /* RenderFlexibleBox.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RenderFlexibleBox.cpp; sourceTree = "<group>"; };
                53C8298C13D8D92700DE2DEB /* RenderFlexibleBox.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RenderFlexibleBox.h; sourceTree = "<group>"; };
                53E29E5C167A8A1900586D3D /* InternalSettingsGenerated.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = InternalSettingsGenerated.cpp; sourceTree = "<group>"; };
                                977B385D122883E900B81FF8 /* HTMLScriptRunnerHost.h */,
                                977E2DCB12F0E28300C13379 /* HTMLSourceTracker.cpp */,
                                977E2DCC12F0E28300C13379 /* HTMLSourceTracker.h */,
+                               536D5A1F193E18E900CE4CAB /* HTMLSrcsetParser.h */,
+                               536D5A1E193E18D000CE4CAB /* HTMLSrcsetParser.cpp */,
                                97C1F552122855CB00EDE615 /* HTMLStackItem.h */,
                                97C1F552122855CB00EDE616 /* HTMLToken.h */,
                                977B385E122883E900B81FF8 /* HTMLTokenizer.cpp */,
                                A14832BA187F63E900DA63A6 /* WAKViewPrivate.h in Headers */,
                                A14832BB187F643200DA63A6 /* WAKWindow.h in Headers */,
                                FD7F299213D4C0CB00AD9535 /* WaveShaperDSPKernel.h in Headers */,
+                               536D5A20193E18E900CE4CAB /* HTMLSrcsetParser.h in Headers */,
                                FD7F299413D4C0CB00AD9535 /* WaveShaperNode.h in Headers */,
                                FD7F299713D4C0CB00AD9535 /* WaveShaperProcessor.h in Headers */,
                                29A812490FBB9CA900510293 /* WebAccessibilityObjectWrapperBase.h in Headers */,
                                B27535790B053814002CE64F /* FloatRectMac.mm in Sources */,
                                6E0E569B183BFFE600E0E8D5 /* FloatRoundedRect.cpp in Sources */,
                                B275356C0B053814002CE64F /* FloatSize.cpp in Sources */,
+                               536D5A21193E18EE00CE4CAB /* HTMLSrcsetParser.cpp in Sources */,
                                B275355B0B053814002CE64F /* FloatSizeCG.cpp in Sources */,
                                B275357A0B053814002CE64F /* FloatSizeMac.mm in Sources */,
                                D72F6D79153159A3001EE44E /* FlowThreadController.cpp in Sources */,
index 6c341bc..ea782e5 100644 (file)
@@ -33,6 +33,7 @@
 #include "HTMLDocument.h"
 #include "HTMLFormElement.h"
 #include "HTMLParserIdioms.h"
+#include "HTMLSrcsetParser.h"
 #include "Page.h"
 #include "RenderImage.h"
 #include "Settings.h"
index a2186b1..91a6606 100644 (file)
@@ -290,132 +290,4 @@ bool threadSafeMatch(const QualifiedName& a, const QualifiedName& b)
     return threadSafeEqual(*a.localName().impl(), *b.localName().impl());
 }
 
-typedef Vector<ImageWithScale> ImageCandidates;
-
-static inline bool compareByScaleFactor(const ImageWithScale& first, const ImageWithScale& second)
-{
-    return first.scaleFactor() < second.scaleFactor();
-}
-
-static bool parseDescriptors(const String& attribute, size_t start, size_t end, float& imageScaleFactor)
-{
-    size_t descriptorStart;
-    size_t descriptorEnd;
-    size_t position = start;
-    bool isFoundScaleFactor = false;
-    bool isEmptyDescriptor = !(end > start);
-    bool isValid = false;
-
-    while (position < end) {
-        while (isHTMLSpace(attribute[position]) && position < end)
-            ++position;
-        descriptorStart = position;
-        while (isNotHTMLSpace(attribute[position]) && position < end)
-            ++position;
-        descriptorEnd = position;
-
-        // Leave if there is only whitespace at the end of the descriptors
-        if (descriptorEnd <= descriptorStart)
-            break;
-
-        --descriptorEnd;
-        // This part differs from the spec as the current implementation only supports pixel density descriptors.
-        if (attribute[descriptorEnd] != 'x')
-            continue;
-
-        if (isFoundScaleFactor)
-            return false;
-
-        if (attribute.is8Bit())
-            imageScaleFactor = charactersToFloat(attribute.characters8() + descriptorStart, descriptorEnd - descriptorStart, &isValid);
-        else
-            imageScaleFactor = charactersToFloat(attribute.characters16() + descriptorStart, descriptorEnd - descriptorStart, &isValid);
-        isFoundScaleFactor = true;
-    }
-
-    return isEmptyDescriptor || isValid;
-}
-
-// 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)
-{
-    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);
-            imageScaleStart = (imageScaleStart == notFound) ? srcsetAttributeLength : imageScaleStart;
-            size_t imageScaleEnd = srcsetAttribute.find(',' , imageScaleStart + 1);
-            imageScaleEnd = (imageScaleEnd == notFound) ? srcsetAttributeLength : imageScaleEnd;
-
-            if (!parseDescriptors(srcsetAttribute, imageScaleStart, imageScaleEnd, imageScaleFactor)) {
-                imageCandidateStart = imageScaleEnd + 1;
-                continue;
-            }
-            separator = imageScaleEnd;
-        }
-        ImageWithScale image(imageURLStart, imageURLEnd - imageURLStart, imageScaleFactor);
-        imageCandidates.append(image);
-        // 11. Return to the step labeled splitting loop.
-        imageCandidateStart = separator + 1;
-    }
-}
-
-ImageWithScale bestFitSourceForImageAttributes(float deviceScaleFactor, const String& srcAttribute, const String& srcsetAttribute)
-{
-    ImageCandidates imageCandidates;
-
-    parseImagesWithScaleFromSrcsetAttribute(srcsetAttribute, imageCandidates);
-
-    if (!srcAttribute.isEmpty()) {
-        ImageWithScale srcPlaceholderImage;
-        imageCandidates.append(srcPlaceholderImage);
-    }
-
-    if (imageCandidates.isEmpty())
-        return ImageWithScale();
-
-    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];
-    }
-
-    // 16. If an entry b in candidates has the same associated ... pixel density as an earlier entry a in candidates,
-    // then remove entry b
-    size_t winner = imageCandidates.size() - 1;
-    size_t previousCandidate = winner;
-    float winningScaleFactor = imageCandidates.last().scaleFactor();
-    while ((previousCandidate > 0) && (imageCandidates[--previousCandidate].scaleFactor() == winningScaleFactor))
-        winner = previousCandidate;
-
-    return imageCandidates[winner];
-}
-
 }
index 82eba6d..6573113 100644 (file)
@@ -33,38 +33,6 @@ namespace WebCore {
 
 class Decimal;
 
-class ImageWithScale {
-public:
-    ImageWithScale()
-        : m_imageURLStart(0)
-        , m_imageURLLength(0)
-        , m_scaleFactor(1)
-    {
-    }
-
-    ImageWithScale(unsigned start, unsigned length, float scaleFactor)
-        : m_imageURLStart(start)
-        , m_imageURLLength(length)
-        , m_scaleFactor(scaleFactor)
-    {
-    }
-
-    String imageURL(const String& srcAttribute, const String& srcsetAttribute) const
-    {
-        return m_imageURLLength ? srcsetAttribute.substringSharingImpl(m_imageURLStart, m_imageURLLength) : srcAttribute;
-    }
-
-    float scaleFactor() const
-    {
-        return m_scaleFactor;
-    }
-
-private:
-    unsigned m_imageURLStart;
-    unsigned m_imageURLLength;
-    float m_scaleFactor;
-};
-
 // Space characters as defined by the HTML specification.
 bool isHTMLSpace(UChar);
 bool isHTMLLineBreak(UChar);
@@ -131,8 +99,6 @@ inline bool isHTMLSpaceButNotLineBreak(UChar character)
 
 bool threadSafeMatch(const QualifiedName&, const QualifiedName&);
 
-ImageWithScale bestFitSourceForImageAttributes(float deviceScaleFactor, const String& srcAttribute, const String& sourceSetAttribute);
-
 }
 
 #endif
index e100364..a4a3a15 100644 (file)
@@ -30,6 +30,7 @@
 
 #include "HTMLNames.h"
 #include "HTMLParserIdioms.h"
+#include "HTMLSrcsetParser.h"
 #include "HTMLTokenizer.h"
 #include "InputTypeNames.h"
 #include "LinkRelAttribute.h"
diff --git a/Source/WebCore/html/parser/HTMLSrcsetParser.cpp b/Source/WebCore/html/parser/HTMLSrcsetParser.cpp
new file mode 100644 (file)
index 0000000..434743e
--- /dev/null
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2013 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1.  Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ * 2.  Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "HTMLSrcsetParser.h"
+
+namespace WebCore {
+
+typedef Vector<ImageWithScale> ImageCandidates;
+
+static inline bool compareByScaleFactor(const ImageWithScale& first, const ImageWithScale& second)
+{
+    return first.scaleFactor() < second.scaleFactor();
+}
+
+static bool parseDescriptors(const String& attribute, size_t start, size_t end, float& imageScaleFactor)
+{
+    size_t descriptorStart;
+    size_t descriptorEnd;
+    size_t position = start;
+    bool isFoundScaleFactor = false;
+    bool isEmptyDescriptor = !(end > start);
+    bool isValid = false;
+
+    while (position < end) {
+        while (isHTMLSpace(attribute[position]) && position < end)
+            ++position;
+        descriptorStart = position;
+        while (isNotHTMLSpace(attribute[position]) && position < end)
+            ++position;
+        descriptorEnd = position;
+
+        // Leave if there is only whitespace at the end of the descriptors
+        if (descriptorEnd <= descriptorStart)
+            break;
+
+        --descriptorEnd;
+        // This part differs from the spec as the current implementation only supports pixel density descriptors.
+        if (attribute[descriptorEnd] != 'x')
+            continue;
+
+        if (isFoundScaleFactor)
+            return false;
+
+        if (attribute.is8Bit())
+            imageScaleFactor = charactersToFloat(attribute.characters8() + descriptorStart, descriptorEnd - descriptorStart, &isValid);
+        else
+            imageScaleFactor = charactersToFloat(attribute.characters16() + descriptorStart, descriptorEnd - descriptorStart, &isValid);
+        isFoundScaleFactor = true;
+    }
+
+    return isEmptyDescriptor || isValid;
+}
+
+// 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)
+{
+    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);
+            imageScaleStart = (imageScaleStart == notFound) ? srcsetAttributeLength : imageScaleStart;
+            size_t imageScaleEnd = srcsetAttribute.find(',' , imageScaleStart + 1);
+            imageScaleEnd = (imageScaleEnd == notFound) ? srcsetAttributeLength : imageScaleEnd;
+
+            if (!parseDescriptors(srcsetAttribute, imageScaleStart, imageScaleEnd, imageScaleFactor)) {
+                imageCandidateStart = imageScaleEnd + 1;
+                continue;
+            }
+            separator = imageScaleEnd;
+        }
+        ImageWithScale image(imageURLStart, imageURLEnd - imageURLStart, imageScaleFactor);
+        imageCandidates.append(image);
+        // 11. Return to the step labeled splitting loop.
+        imageCandidateStart = separator + 1;
+    }
+}
+
+ImageWithScale bestFitSourceForImageAttributes(float deviceScaleFactor, const String& srcAttribute, const String& srcsetAttribute)
+{
+    ImageCandidates imageCandidates;
+
+    parseImagesWithScaleFromSrcsetAttribute(srcsetAttribute, imageCandidates);
+
+    if (!srcAttribute.isEmpty()) {
+        ImageWithScale srcPlaceholderImage;
+        imageCandidates.append(srcPlaceholderImage);
+    }
+
+    if (imageCandidates.isEmpty())
+        return ImageWithScale();
+
+    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];
+    }
+
+    // 16. If an entry b in candidates has the same associated ... pixel density as an earlier entry a in candidates,
+    // then remove entry b
+    size_t winner = imageCandidates.size() - 1;
+    size_t previousCandidate = winner;
+    float winningScaleFactor = imageCandidates.last().scaleFactor();
+    while ((previousCandidate > 0) && (imageCandidates[--previousCandidate].scaleFactor() == winningScaleFactor))
+        winner = previousCandidate;
+
+    return imageCandidates[winner];
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/html/parser/HTMLSrcsetParser.h b/Source/WebCore/html/parser/HTMLSrcsetParser.h
new file mode 100644 (file)
index 0000000..3458b59
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2013 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1.  Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ * 2.  Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef HTMLSrcsetParser_h
+#define HTMLSrcsetParser_h
+
+#include <wtf/text/WTFString.h>
+
+namespace WebCore {
+
+class ImageWithScale {
+public:
+    ImageWithScale()
+        : m_imageURLStart(0)
+        , m_imageURLLength(0)
+        , m_scaleFactor(1)
+    {
+    }
+
+    ImageWithScale(unsigned start, unsigned length, float scaleFactor)
+        : m_imageURLStart(start)
+        , m_imageURLLength(length)
+        , m_scaleFactor(scaleFactor)
+    {
+    }
+
+    String imageURL(const String& srcAttribute, const String& srcsetAttribute) const
+    {
+        return m_imageURLLength ? srcsetAttribute.substringSharingImpl(m_imageURLStart, m_imageURLLength) : srcAttribute;
+    }
+
+    float scaleFactor() const
+    {
+        return m_scaleFactor;
+    }
+
+private:
+    unsigned m_imageURLStart;
+    unsigned m_imageURLLength;
+    float m_scaleFactor;
+};
+
+// Space characters as defined by the HTML specification.
+bool isHTMLSpace(UChar);
+bool isHTMLLineBreak(UChar);
+bool isNotHTMLSpace(UChar);
+bool isHTMLSpaceButNotLineBreak(UChar character);
+
+ImageWithScale bestFitSourceForImageAttributes(float deviceScaleFactor, const String& srcAttribute, const String& sourceSetAttribute);
+
+}
+
+#endif