Diff
Modified: trunk/LayoutTests/ChangeLog (153732 => 153733)
--- trunk/LayoutTests/ChangeLog 2013-08-06 00:41:08 UTC (rev 153732)
+++ trunk/LayoutTests/ChangeLog 2013-08-06 01:13:15 UTC (rev 153733)
@@ -1,3 +1,19 @@
+2013-08-05 Dean Jackson <[email protected]>
+
+ Update HTMLPreloadScanner to handle img srcset
+ https://bugs.webkit.org/show_bug.cgi?id=119360
+
+ Reviewed by Sam Weinig.
+
+ This patch is a merge of similar patches from Yoav Weiss <[email protected]>
+ and Dean Jackson.
+
+ New test to make sure the HTML preloader takes the
+ value of srcset if available.
+
+ * fast/preloader/image-srcset-expected.txt: Added.
+ * fast/preloader/image-srcset.html: Added.
+
2013-08-05 Alexey Proskuryakov <[email protected]>
<rdar://problem/13128990> chunked-progress-event-expectedLength.html is flaky on Mac
Added: trunk/LayoutTests/fast/preloader/image-srcset-expected.txt (0 => 153733)
--- trunk/LayoutTests/fast/preloader/image-srcset-expected.txt (rev 0)
+++ trunk/LayoutTests/fast/preloader/image-srcset-expected.txt 2013-08-06 01:13:15 UTC (rev 153733)
@@ -0,0 +1,4 @@
+base-image1.png has MIME type image/png
+PASS internals.isPreloaded("resources/image1.png") is false
+This test passes if the fallback image (defined in the src attribute) is not preloaded, but the 1x version (defined in srcset) is.
+
Property changes on: trunk/LayoutTests/fast/preloader/image-srcset-expected.txt
___________________________________________________________________
Added: svn:mime-type
Added: svn:keywords
Added: svn:eol-style
Added: trunk/LayoutTests/fast/preloader/image-srcset.html (0 => 153733)
--- trunk/LayoutTests/fast/preloader/image-srcset.html (rev 0)
+++ trunk/LayoutTests/fast/preloader/image-srcset.html 2013-08-06 01:13:15 UTC (rev 153733)
@@ -0,0 +1,22 @@
+<html>
+<head>
+<script src=""
+<script>
+ if (window.testRunner) {
+ testRunner.dumpAsText();
+ testRunner.dumpResourceResponseMIMETypes();
+ }
+
+ addEventListener("load", function() {
+ if (internals)
+ shouldBeFalse('internals.isPreloaded("resources/image1.png")');
+ }, false);
+</script>
+<script src=""
+</head>
+<body>
+<div>This test passes if the fallback image (defined in the src attribute) is not preloaded, but the 1x version (defined in srcset) is.</div>
+<img height="100" width="100" src="" srcset="resources/base-image1.png 1x, resources/base-image3.png 3x, resources/base-image2.png 2x"></img>
+</body>
+</html>
+
Property changes on: trunk/LayoutTests/fast/preloader/image-srcset.html
___________________________________________________________________
Added: svn:mime-type
Added: svn:keywords
Added: svn:eol-style
Modified: trunk/Source/WebCore/ChangeLog (153732 => 153733)
--- trunk/Source/WebCore/ChangeLog 2013-08-06 00:41:08 UTC (rev 153732)
+++ trunk/Source/WebCore/ChangeLog 2013-08-06 01:13:15 UTC (rev 153733)
@@ -1,3 +1,43 @@
+2013-08-05 Dean Jackson <[email protected]>
+
+ Update HTMLPreloadScanner to handle img srcset
+ https://bugs.webkit.org/show_bug.cgi?id=119360
+
+ Reviewed by Sam Weinig.
+
+ This patch is a merge of similar patches from Yoav Weiss <[email protected]>
+ and Dean Jackson.
+
+ Test: fast/preloader/image-srcset.html
+
+ * html/HTMLImageElement.cpp:
+ (WebCore::HTMLImageElement::parseAttribute): Move srcset parsing into
+ HTMLParserIdioms, and call it when we hit src or srcset.
+ * html/HTMLImageElement.h: Remove code that was moved to HTMLParserIdioms.
+
+ * html/parser/HTMLDocumentParser.cpp:
+ (WebCore::HTMLDocumentParser::pumpTokenizer): Pass device scale into preloader.
+ (WebCore::HTMLDocumentParser::insert):
+
+ * html/parser/HTMLPreloadScanner.cpp:
+ (WebCore::TokenPreloadScanner::StartTagScanner::StartTagScanner): Takes device scale as a parameter.
+ (WebCore::TokenPreloadScanner::StartTagScanner::processAttributes): Resolve between src and srcSet if necessary.
+ (WebCore::TokenPreloadScanner::StartTagScanner::processAttribute): Add support for srcset attribute.
+ (WebCore::TokenPreloadScanner::StartTagScanner::setUrlToLoad): New flag to indicate if we should
+ replace any existing value.
+ (WebCore::TokenPreloadScanner::TokenPreloadScanner): Takes device scale.
+ (WebCore::TokenPreloadScanner::scanCommon): Pass device scale.
+ (WebCore::HTMLPreloadScanner::HTMLPreloadScanner):
+ * html/parser/HTMLPreloadScanner.h: New attribute to constructor for device scale. New member
+ variable on TokenPreloadScanner that holds the srcset value.
+
+ * html/parser/HTMLParserIdioms.cpp:
+ (WebCore::ImageWithScale::operator==): Used for sorting.
+ (WebCore::compareByScaleFactor): Used for sorting.
+ (WebCore::bestFitSourceForImageAttributes): New method that takes the code from HTMLImageElement
+ for parsing src and srcset attributes, and finding the best match.
+ * html/parser/HTMLParserIdioms.h:
+
2013-08-05 Oliver Hunt <[email protected]>
Move TypedArray implementation into JSC
Modified: trunk/Source/WebCore/html/HTMLImageElement.cpp (153732 => 153733)
--- trunk/Source/WebCore/html/HTMLImageElement.cpp 2013-08-06 00:41:08 UTC (rev 153732)
+++ trunk/Source/WebCore/html/HTMLImageElement.cpp 2013-08-06 01:13:15 UTC (rev 153733)
@@ -115,85 +115,16 @@
return m_bestFitImageURL.isEmpty() ? fastGetAttribute(srcAttr) : m_bestFitImageURL;
}
-void HTMLImageElement::determineBestImageForScaleFactor()
-{
- m_imagesWithScale.clear();
- m_bestFitImageURL = nullAtom;
-
- collectImageCandidatesFromSrcSet();
- collectImageCandidateFromSrc();
- stable_sort(m_imagesWithScale.begin(), m_imagesWithScale.end(), compareByScaleFactor);
-
- for (size_t i = 1; i < m_imagesWithScale.size(); ++i) {
- if (m_imagesWithScale[i-1].scaleFactor == m_imagesWithScale[i].scaleFactor) {
- m_imagesWithScale.remove(i);
- i--;
- }
- }
-
- float pageScaleFactor = 1.0;
- if (Page* page = document()->page())
- pageScaleFactor = page->deviceScaleFactor();
-
- for (size_t i = 0; i < m_imagesWithScale.size(); ++i) {
- if (m_imagesWithScale[i].scaleFactor >= pageScaleFactor) {
- m_bestFitImageURL = m_imagesWithScale[i].imageURL;
- return;
- }
- }
-}
-
-void HTMLImageElement::collectImageCandidatesFromSrcSet()
-{
- const String& srcSetAttributeValue = fastGetAttribute(srcsetAttr).string().simplifyWhiteSpace(isHTMLSpace);
- Vector<String> srcSetTokens;
-
- srcSetAttributeValue.split(',', srcSetTokens);
- for (size_t i = 0; i < srcSetTokens.size(); ++i) {
- Vector<String> data;
- float imgScaleFactor = 1.0;
- bool validScaleFactor = false;
-
- srcSetTokens[i].stripWhiteSpace().split(' ', data);
- // There must be at least one candidate descriptor, and the last one must
- // be a scale factor. Since we don't support descriptors other than scale,
- // it's better to discard any rule with such descriptors rather than accept
- // only the scale data.
- if (data.size() != 2)
- continue;
- if (!data.last().endsWith('x'))
- continue;
-
- imgScaleFactor = data.last().substring(0, data.last().length() - 1).toFloat(&validScaleFactor);
- if (!validScaleFactor)
- continue;
-
- ImageWithScale image;
- image.imageURL = decodeURLEscapeSequences(data[0]);
- image.scaleFactor = imgScaleFactor;
-
- m_imagesWithScale.append(image);
- }
-}
-
-void HTMLImageElement::collectImageCandidateFromSrc()
-{
- const AtomicString& src = ""
- ImageWithScale image;
- if (!src.isEmpty()) {
- image.imageURL = decodeURLEscapeSequences(src);
- image.scaleFactor = 1.0;
- m_imagesWithScale.append(image);
- }
-}
-
void HTMLImageElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
{
if (name == altAttr) {
if (renderer() && renderer()->isImage())
toRenderImage(renderer())->updateAltText();
} else if (name == srcAttr || name == srcsetAttr) {
- determineBestImageForScaleFactor();
+ float deviceScaleFactor = 1.0;
+ if (Page* page = document()->page())
+ deviceScaleFactor = page->deviceScaleFactor();
+ m_bestFitImageURL = bestFitSourceForImageAttributes(deviceScaleFactor, fastGetAttribute(srcAttr), fastGetAttribute(srcsetAttr));
m_imageLoader.updateFromElementIgnoringPreviousError();
}
else if (name == usemapAttr)
Modified: trunk/Source/WebCore/html/HTMLImageElement.h (153732 => 153733)
--- trunk/Source/WebCore/html/HTMLImageElement.h 2013-08-06 00:41:08 UTC (rev 153732)
+++ trunk/Source/WebCore/html/HTMLImageElement.h 2013-08-06 01:13:15 UTC (rev 153733)
@@ -109,29 +109,10 @@
virtual void setItemValueText(const String&, ExceptionCode&) OVERRIDE;
#endif
- void collectImageCandidateFromSrc();
- void collectImageCandidatesFromSrcSet();
- void determineBestImageForScaleFactor();
-
- struct ImageWithScale {
- String imageURL;
- float scaleFactor;
- bool operator==(const ImageWithScale& image) const
- {
- return scaleFactor == image.scaleFactor && imageURL == image.imageURL;
- }
- };
-
- static inline bool compareByScaleFactor(const ImageWithScale& first, const ImageWithScale& second)
- {
- return first.scaleFactor < second.scaleFactor;
- }
-
HTMLImageLoader m_imageLoader;
HTMLFormElement* m_form;
CompositeOperator m_compositeOperator;
AtomicString m_bestFitImageURL;
- Vector<ImageWithScale> m_imagesWithScale;
};
inline bool isHTMLImageElement(Node* node)
Modified: trunk/Source/WebCore/html/parser/HTMLDocumentParser.cpp (153732 => 153733)
--- trunk/Source/WebCore/html/parser/HTMLDocumentParser.cpp 2013-08-06 00:41:08 UTC (rev 153732)
+++ trunk/Source/WebCore/html/parser/HTMLDocumentParser.cpp 2013-08-06 01:13:15 UTC (rev 153733)
@@ -565,7 +565,10 @@
if (isWaitingForScripts()) {
ASSERT(m_tokenizer->state() == HTMLTokenizer::DataState);
if (!m_preloadScanner) {
- m_preloadScanner = adoptPtr(new HTMLPreloadScanner(m_options, document()->url()));
+ float deviceScaleFactor = 1.0;
+ if (Page* page = document()->page())
+ deviceScaleFactor = page->deviceScaleFactor();
+ m_preloadScanner = adoptPtr(new HTMLPreloadScanner(m_options, document()->url(), deviceScaleFactor));
m_preloadScanner->appendToEnd(m_input.current());
}
m_preloadScanner->scan(m_preloader.get(), document()->baseElementURL());
@@ -645,8 +648,12 @@
if (isWaitingForScripts()) {
// Check the document.write() output with a separate preload scanner as
// the main scanner can't deal with insertions.
- if (!m_insertionPreloadScanner)
- m_insertionPreloadScanner = adoptPtr(new HTMLPreloadScanner(m_options, document()->url()));
+ if (!m_insertionPreloadScanner) {
+ float deviceScaleFactor = 1.0;
+ if (Page* page = document()->page())
+ deviceScaleFactor = page->deviceScaleFactor();
+ m_insertionPreloadScanner = adoptPtr(new HTMLPreloadScanner(m_options, document()->url(), deviceScaleFactor));
+ }
m_insertionPreloadScanner->appendToEnd(source);
m_insertionPreloadScanner->scan(m_preloader.get(), document()->baseElementURL());
}
Modified: trunk/Source/WebCore/html/parser/HTMLParserIdioms.cpp (153732 => 153733)
--- trunk/Source/WebCore/html/parser/HTMLParserIdioms.cpp 2013-08-06 00:41:08 UTC (rev 153732)
+++ trunk/Source/WebCore/html/parser/HTMLParserIdioms.cpp 2013-08-06 01:13:15 UTC (rev 153733)
@@ -27,6 +27,7 @@
#include "Decimal.h"
#include "HTMLIdentifier.h"
+#include "KURL.h"
#include "QualifiedName.h"
#include <limits>
#include <wtf/MathExtras.h>
@@ -298,4 +299,71 @@
}
#endif
+struct ImageWithScale {
+ String imageURL;
+ float scaleFactor;
+ bool operator==(const ImageWithScale& image) const
+ {
+ return scaleFactor == image.scaleFactor && imageURL == image.imageURL;
+ }
+};
+typedef Vector<ImageWithScale> ImageCandidates;
+
+static inline bool compareByScaleFactor(const ImageWithScale& first, const ImageWithScale& second)
+{
+ return first.scaleFactor < second.scaleFactor;
}
+
+String bestFitSourceForImageAttributes(float deviceScaleFactor, const String& srcAttribute, const String& srcSetAttribute)
+{
+ ImageCandidates imageCandidates;
+
+ const String srcSetAttributeValue = srcSetAttribute.simplifyWhiteSpace(isHTMLSpace);
+ Vector<String> srcSetTokens;
+
+ srcSetAttributeValue.split(',', srcSetTokens);
+ for (size_t i = 0; i < srcSetTokens.size(); ++i) {
+ Vector<String> data;
+ float imgScaleFactor = 1.0;
+ bool validScaleFactor = false;
+
+ srcSetTokens[i].stripWhiteSpace().split(' ', data);
+ // There must be at least one candidate descriptor, and the last one must
+ // be a scale factor. Since we don't support descriptors other than scale,
+ // it's better to discard any rule with such descriptors rather than accept
+ // only the scale data.
+ if (data.size() != 2)
+ continue;
+ if (!data.last().endsWith('x'))
+ continue;
+
+ imgScaleFactor = data.last().substring(0, data.last().length() - 1).toFloat(&validScaleFactor);
+ if (!validScaleFactor)
+ continue;
+
+ ImageWithScale image;
+ image.imageURL = decodeURLEscapeSequences(data[0]);
+ image.scaleFactor = imgScaleFactor;
+
+ imageCandidates.append(image);
+ }
+
+ const String src = ""
+ if (!src.isEmpty()) {
+ ImageWithScale image;
+ image.imageURL = decodeURLEscapeSequences(src);
+ image.scaleFactor = 1.0;
+
+ imageCandidates.append(image);
+ }
+
+ std::stable_sort(imageCandidates.begin(), imageCandidates.end(), compareByScaleFactor);
+
+ for (size_t i = 0; i < imageCandidates.size(); ++i) {
+ if (imageCandidates[i].scaleFactor >= deviceScaleFactor)
+ return imageCandidates[i].imageURL;
+ }
+ return String();
+}
+
+}
Modified: trunk/Source/WebCore/html/parser/HTMLParserIdioms.h (153732 => 153733)
--- trunk/Source/WebCore/html/parser/HTMLParserIdioms.h 2013-08-06 00:41:08 UTC (rev 153732)
+++ trunk/Source/WebCore/html/parser/HTMLParserIdioms.h 2013-08-06 01:13:15 UTC (rev 153733)
@@ -104,6 +104,8 @@
}
#endif
+String bestFitSourceForImageAttributes(float deviceScaleFactor, const String& srcAttribute, const String& sourceSetAttribute);
+
}
#endif
Modified: trunk/Source/WebCore/html/parser/HTMLPreloadScanner.cpp (153732 => 153733)
--- trunk/Source/WebCore/html/parser/HTMLPreloadScanner.cpp 2013-08-06 00:41:08 UTC (rev 153732)
+++ trunk/Source/WebCore/html/parser/HTMLPreloadScanner.cpp 2013-08-06 01:13:15 UTC (rev 153733)
@@ -105,10 +105,11 @@
class TokenPreloadScanner::StartTagScanner {
public:
- explicit StartTagScanner(TagId tagId)
+ explicit StartTagScanner(TagId tagId, float deviceScaleFactor = 1.0)
: m_tagId(tagId)
, m_linkIsStyleSheet(false)
, m_inputIsImage(false)
+ , m_deviceScaleFactor(deviceScaleFactor)
{
}
@@ -122,6 +123,13 @@
String attributeValue = StringImpl::create8BitIfPossible(iter->value);
processAttribute(attributeName, attributeValue);
}
+
+ // Resolve between src and srcSet if we have them.
+ if (!m_srcSetAttribute.isEmpty()) {
+ String srcMatchingScale = bestFitSourceForImageAttributes(m_deviceScaleFactor, m_urlToLoad, m_srcSetAttribute);
+ setUrlToLoad(srcMatchingScale, true);
+ }
+
}
#if ENABLE(THREADED_HTML_PARSER)
@@ -168,6 +176,8 @@
if (m_tagId == ScriptTagId || m_tagId == ImgTagId) {
if (match(attributeName, srcAttr))
setUrlToLoad(attributeValue);
+ else if (match(attributeName, srcsetAttr))
+ m_srcSetAttribute = attributeValue;
else if (match(attributeName, crossoriginAttr) && !attributeValue.isNull())
m_crossOriginMode = stripLeadingAndTrailingHTMLSpaces(attributeValue);
} else if (m_tagId == LinkTagId) {
@@ -191,13 +201,16 @@
return rel.m_isStyleSheet && !rel.m_isAlternate && rel.m_iconType == InvalidIcon && !rel.m_isDNSPrefetch;
}
- void setUrlToLoad(const String& attributeValue)
+ void setUrlToLoad(const String& value, bool allowReplacement = false)
{
// We only respect the first src/href, per HTML5:
// http://www.whatwg.org/specs/web-apps/current-work/multipage/tokenization.html#attribute-name-state
- if (!m_urlToLoad.isEmpty())
+ if (!allowReplacement && !m_urlToLoad.isEmpty())
return;
- m_urlToLoad = stripLeadingAndTrailingHTMLSpaces(attributeValue);
+ String url = ""
+ if (url.isEmpty())
+ return;
+ m_urlToLoad = url;
}
const String& charset() const
@@ -241,16 +254,19 @@
TagId m_tagId;
String m_urlToLoad;
+ String m_srcSetAttribute;
String m_charset;
String m_crossOriginMode;
bool m_linkIsStyleSheet;
String m_mediaAttribute;
bool m_inputIsImage;
+ float m_deviceScaleFactor;
};
-TokenPreloadScanner::TokenPreloadScanner(const KURL& documentURL)
+TokenPreloadScanner::TokenPreloadScanner(const KURL& documentURL, float deviceScaleFactor)
: m_documentURL(documentURL)
, m_inStyle(false)
+ , m_deviceScaleFactor(deviceScaleFactor)
#if ENABLE(TEMPLATE_ELEMENT)
, m_templateCount(0)
#endif
@@ -347,7 +363,7 @@
return;
}
- StartTagScanner scanner(tagId);
+ StartTagScanner scanner(tagId, m_deviceScaleFactor);
scanner.processAttributes(token.attributes());
OwnPtr<PreloadRequest> request = scanner.createPreloadRequest(m_predictedBaseElementURL);
if (request)
@@ -368,8 +384,8 @@
m_predictedBaseElementURL = KURL(m_documentURL, stripLeadingAndTrailingHTMLSpaces(hrefAttribute->value)).copy();
}
-HTMLPreloadScanner::HTMLPreloadScanner(const HTMLParserOptions& options, const KURL& documentURL)
- : m_scanner(documentURL)
+HTMLPreloadScanner::HTMLPreloadScanner(const HTMLParserOptions& options, const KURL& documentURL, float deviceScaleFactor)
+ : m_scanner(documentURL, deviceScaleFactor)
, m_tokenizer(HTMLTokenizer::create(options))
{
}
Modified: trunk/Source/WebCore/html/parser/HTMLPreloadScanner.h (153732 => 153733)
--- trunk/Source/WebCore/html/parser/HTMLPreloadScanner.h 2013-08-06 00:41:08 UTC (rev 153732)
+++ trunk/Source/WebCore/html/parser/HTMLPreloadScanner.h 2013-08-06 01:13:15 UTC (rev 153733)
@@ -44,7 +44,7 @@
class TokenPreloadScanner {
WTF_MAKE_NONCOPYABLE(TokenPreloadScanner); WTF_MAKE_FAST_ALLOCATED;
public:
- explicit TokenPreloadScanner(const KURL& documentURL);
+ explicit TokenPreloadScanner(const KURL& documentURL, float deviceScaleFactor = 1.0);
~TokenPreloadScanner();
void scan(const HTMLToken&, PreloadRequestStream& requests);
@@ -118,6 +118,7 @@
const KURL m_documentURL;
KURL m_predictedBaseElementURL;
bool m_inStyle;
+ float m_deviceScaleFactor;
#if ENABLE(TEMPLATE_ELEMENT)
size_t m_templateCount;
@@ -129,7 +130,7 @@
class HTMLPreloadScanner {
WTF_MAKE_NONCOPYABLE(HTMLPreloadScanner); WTF_MAKE_FAST_ALLOCATED;
public:
- HTMLPreloadScanner(const HTMLParserOptions&, const KURL& documentURL);
+ HTMLPreloadScanner(const HTMLParserOptions&, const KURL& documentURL, float deviceScaleFactor = 1.0);
~HTMLPreloadScanner();
void appendToEnd(const SegmentedString&);