summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLeon Clarke <leonclarke@google.com>2010-03-09 14:12:21 +0000
committerLeon Clarke <leonclarke@google.com>2010-05-04 10:59:37 +0100
commitf91ac8eab3399adb5325701bebe0590a77e49df7 (patch)
tree04ff055963cf2bfe147998ca3396134b243be38d
parentb97e8541004c77ec0c85f74b896b9d3bdb6de6b4 (diff)
downloadexternal_webkit-f91ac8eab3399adb5325701bebe0590a77e49df7.zip
external_webkit-f91ac8eab3399adb5325701bebe0590a77e49df7.tar.gz
external_webkit-f91ac8eab3399adb5325701bebe0590a77e49df7.tar.bz2
Link prefetch support
http://b/issue?id=2268353
-rw-r--r--LayoutTests/dom/html/level2/html/HTMLLinkElement10-expected.txt2
-rw-r--r--LayoutTests/dom/html/level2/html/HTMLLinkElement10-link.file12
-rw-r--r--LayoutTests/dom/html/level2/html/HTMLLinkElement10.html18
-rw-r--r--LayoutTests/dom/html/level2/html/HTMLLinkElement10.js51
-rw-r--r--LayoutTests/dom/html/level2/html/HTMLLinkElement11-expected.txt2
-rw-r--r--LayoutTests/dom/html/level2/html/HTMLLinkElement11.css1
-rw-r--r--LayoutTests/dom/html/level2/html/HTMLLinkElement11.html15
-rw-r--r--LayoutTests/dom/html/level2/html/HTMLLinkElement11.js51
-rw-r--r--WebCore/config.h3
-rw-r--r--WebCore/html/HTMLLinkElement.cpp110
-rw-r--r--WebCore/html/HTMLLinkElement.h52
-rw-r--r--WebCore/html/PreloadScanner.cpp16
-rw-r--r--WebCore/loader/Cache.cpp7
-rw-r--r--WebCore/loader/CachedCSSStyleSheet.cpp8
-rw-r--r--WebCore/loader/CachedLinkPrefetch.h67
-rw-r--r--WebCore/loader/CachedResource.h4
-rw-r--r--WebCore/loader/DocLoader.cpp26
-rw-r--r--WebCore/loader/DocLoader.h10
-rw-r--r--WebCore/loader/loader.cpp31
-rw-r--r--WebCore/loader/loader.h6
20 files changed, 402 insertions, 90 deletions
diff --git a/LayoutTests/dom/html/level2/html/HTMLLinkElement10-expected.txt b/LayoutTests/dom/html/level2/html/HTMLLinkElement10-expected.txt
new file mode 100644
index 0000000..6f009e8
--- /dev/null
+++ b/LayoutTests/dom/html/level2/html/HTMLLinkElement10-expected.txt
@@ -0,0 +1,2 @@
+Test: http://www.w3.org/2001/DOM-Test-Suite/level2/html/HTMLLinkElement10
+Status: Success
diff --git a/LayoutTests/dom/html/level2/html/HTMLLinkElement10-link.file b/LayoutTests/dom/html/level2/html/HTMLLinkElement10-link.file
new file mode 100644
index 0000000..4a94b89
--- /dev/null
+++ b/LayoutTests/dom/html/level2/html/HTMLLinkElement10-link.file
@@ -0,0 +1,12 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<HTML>
+<HEAD>
+<META HTTP-EQUIV="Content-Type" CONTENT="text/html; CHARSET=utf-8">
+<TITLE>NIST DOM HTML Test - LINK</TITLE>
+<BODY>
+<P>
+This is the test link that's pre-fetched by the prefetch test.
+</P>
+</BODY>
+</HTML>
+
diff --git a/LayoutTests/dom/html/level2/html/HTMLLinkElement10.html b/LayoutTests/dom/html/level2/html/HTMLLinkElement10.html
new file mode 100644
index 0000000..dcf20e1
--- /dev/null
+++ b/LayoutTests/dom/html/level2/html/HTMLLinkElement10.html
@@ -0,0 +1,18 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<HTML>
+<HEAD>
+<META HTTP-EQUIV="Content-Type" CONTENT="text/html; CHARSET=utf-8">
+<TITLE>NIST DOM HTML Test - LINK</TITLE>
+<script charset='UTF-8' type='text/javascript' src='selfhtml.js'></script>
+<script charset='UTF-8' type='text/javascript' src='HTMLLinkElement10.js'></script>
+<LINK CHARSET="Latin-1" HREF="HTMLLinkElement10-link.file" HREFLANG="en" MEDIA="screen" REL="prefetch" TYPE="text/html" onload="prefetchComplete()">
+<LINK CHARSET="Latin-1" HREF="./files/style1.css" HREFLANG="en" MEDIA="screen" REV="stylesheet" TYPE="text/css">
+<script type='text/javascript'>startTest10();
+</script></HEAD>
+<BODY onload="loadComplete()">
+<P>
+<BR>
+</P>
+</BODY>
+</HTML>
+
diff --git a/LayoutTests/dom/html/level2/html/HTMLLinkElement10.js b/LayoutTests/dom/html/level2/html/HTMLLinkElement10.js
new file mode 100644
index 0000000..c0ac4a7
--- /dev/null
+++ b/LayoutTests/dom/html/level2/html/HTMLLinkElement10.js
@@ -0,0 +1,51 @@
+
+
+ /**
+ * Gets URI that identifies the test.
+ * @return uri identifier of test
+ */
+function getTargetURI() {
+ return "http://www.w3.org/2001/DOM-Test-Suite/level2/html/HTMLLinkElement10";
+ }
+
+var docsLoaded = 0;
+var mainLoaded = false;
+var prefetchLoaded = false;
+
+function finishTest() {
+ if (mainLoaded && prefetchLoaded) {
+ setResult(null, null);
+ } else {
+ if (!prefetchLoaded) {
+ setResult("fail", "No prefetch onload fired");
+ } else {
+ setResult("fail", "Prefetch fired, but maybe the document onload didn't");
+ }
+ }
+ if (window.layoutTestController) {
+ layoutTestController.notifyDone();
+ }
+}
+
+function loadComplete() {
+ mainLoaded = true;
+ if (++docsLoaded == 2) {
+ finishTest();
+ }
+}
+
+function prefetchComplete() {
+ prefetchLoaded = true;
+ if (++docsLoaded == 2) {
+ finishTest();
+ }
+}
+
+
+
+function startTest10() {
+ if (window.layoutTestController) {
+ layoutTestController.dumpAsText();
+ layoutTestController.waitUntilDone();
+ }
+}
diff --git a/LayoutTests/dom/html/level2/html/HTMLLinkElement11-expected.txt b/LayoutTests/dom/html/level2/html/HTMLLinkElement11-expected.txt
new file mode 100644
index 0000000..d53710a
--- /dev/null
+++ b/LayoutTests/dom/html/level2/html/HTMLLinkElement11-expected.txt
@@ -0,0 +1,2 @@
+Test: http://www.w3.org/2001/DOM-Test-Suite/level2/html/HTMLLinkElement11
+Status: Success
diff --git a/LayoutTests/dom/html/level2/html/HTMLLinkElement11.css b/LayoutTests/dom/html/level2/html/HTMLLinkElement11.css
new file mode 100644
index 0000000..6a5dab8
--- /dev/null
+++ b/LayoutTests/dom/html/level2/html/HTMLLinkElement11.css
@@ -0,0 +1 @@
+div { font-family: Arial, Helvetica, sans-serif; color: red; }
diff --git a/LayoutTests/dom/html/level2/html/HTMLLinkElement11.html b/LayoutTests/dom/html/level2/html/HTMLLinkElement11.html
new file mode 100644
index 0000000..9b9a5e4
--- /dev/null
+++ b/LayoutTests/dom/html/level2/html/HTMLLinkElement11.html
@@ -0,0 +1,15 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<HTML>
+<HEAD>
+<META HTTP-EQUIV="Content-Type" CONTENT="text/html; CHARSET=utf-8">
+<TITLE>NIST DOM HTML Test - LINK</TITLE>
+<script charset='UTF-8' type='text/javascript' src='selfhtml.js'></script>
+<script charset='UTF-8' type='text/javascript' src='HTMLLinkElement11.js'></script><script type='text/javascript'>startTest11();</script></HEAD>
+<LINK CHARSET="Latin-1" HREF="HTMLLinkElement11.css" HREFLANG="en" MEDIA="screen" REL="stylesheet" TYPE="text/css" onload="cssComplete()">
+<BODY onload="loadComplete()">
+<P>
+<BR>
+</P>
+</BODY>
+</HTML>
+
diff --git a/LayoutTests/dom/html/level2/html/HTMLLinkElement11.js b/LayoutTests/dom/html/level2/html/HTMLLinkElement11.js
new file mode 100644
index 0000000..b8bf1cb
--- /dev/null
+++ b/LayoutTests/dom/html/level2/html/HTMLLinkElement11.js
@@ -0,0 +1,51 @@
+
+
+ /**
+ * Gets URI that identifies the test.
+ * @return uri identifier of test
+ */
+function getTargetURI() {
+ return "http://www.w3.org/2001/DOM-Test-Suite/level2/html/HTMLLinkElement11";
+ }
+
+var docsLoaded = 0;
+var mainLoaded = false;
+var cssLoaded = false;
+
+function finishTest() {
+ if (mainLoaded && cssLoaded) {
+ setResult(null, null);
+ } else {
+ if (!cssLoaded) {
+ setResult("fail", "No css onload fired");
+ } else {
+ setResult("fail", "Css fired, but maybe the document onload didn't");
+ }
+ }
+ if (window.layoutTestController) {
+ layoutTestController.notifyDone();
+ }
+}
+
+function loadComplete() {
+ mainLoaded = true;
+ if (++docsLoaded == 2) {
+ finishTest();
+ }
+}
+
+function cssComplete() {
+ cssLoaded = true;
+ if (++docsLoaded == 2) {
+ finishTest();
+ }
+}
+
+
+
+function startTest11() {
+ if (window.layoutTestController) {
+ layoutTestController.dumpAsText();
+ layoutTestController.waitUntilDone();
+ }
+}
diff --git a/WebCore/config.h b/WebCore/config.h
index 863423b..b61c2ad 100644
--- a/WebCore/config.h
+++ b/WebCore/config.h
@@ -194,6 +194,9 @@
// or if javascript tried to change the location.
#define ANDROID_USER_GESTURE
+// Enable prefetching when specified via the rel element of <link> elements.
+#define ENABLE_LINK_PREFETCH 1
+
#endif /* PLATFORM(ANDROID) */
#ifdef __cplusplus
diff --git a/WebCore/html/HTMLLinkElement.cpp b/WebCore/html/HTMLLinkElement.cpp
index 5376611..daa1702 100644
--- a/WebCore/html/HTMLLinkElement.cpp
+++ b/WebCore/html/HTMLLinkElement.cpp
@@ -41,6 +41,9 @@
#include "ScriptEventListener.h"
#include "Settings.h"
#include <wtf/StdLibExtras.h>
+#if ENABLE(LINK_PREFETCH)
+#include "CachedLinkPrefetch.h"
+#endif
namespace WebCore {
@@ -51,15 +54,8 @@ HTMLLinkElement::HTMLLinkElement(const QualifiedName& qName, Document *doc, bool
, m_cachedSheet(0)
, m_disabledState(0)
, m_loading(false)
- , m_alternate(false)
- , m_isStyleSheet(false)
- , m_isIcon(false)
-#ifdef ANDROID_APPLE_TOUCH_ICON
- , m_isTouchIcon(false)
- , m_isPrecomposedTouchIcon(false)
-#endif
- , m_isDNSPrefetch(false)
, m_createdByParser(createdByParser)
+ , m_timer(this, &HTMLLinkElement::timerFired)
{
ASSERT(hasTagName(linkTag));
}
@@ -84,11 +80,11 @@ void HTMLLinkElement::setDisabledState(bool _disabled)
// Check #1: If the sheet becomes disabled while it was loading, and if it was either
// a main sheet or a sheet that was previously enabled via script, then we need
// to remove it from the list of pending sheets.
- if (m_disabledState == 2 && (!m_alternate || oldDisabledState == 1))
+ if (m_disabledState == 2 && (!m_rel.m_isAlternate || oldDisabledState == 1))
document()->removePendingSheet();
// Check #2: An alternate sheet becomes enabled while it is still loading.
- if (m_alternate && m_disabledState == 1)
+ if (m_rel.m_isAlternate && m_disabledState == 1)
document()->addPendingSheet();
// Check #3: A main sheet becomes enabled while it was still loading and
@@ -96,7 +92,7 @@ void HTMLLinkElement::setDisabledState(bool _disabled)
// happen (a double toggle for no reason essentially). This happens on
// virtualplastic.net, which manages to do about 12 enable/disables on only 3
// sheets. :)
- if (!m_alternate && m_disabledState == 1 && oldDisabledState == 2)
+ if (!m_rel.m_isAlternate && m_disabledState == 1 && oldDisabledState == 2)
document()->addPendingSheet();
// If the sheet is already loading just bail.
@@ -119,11 +115,7 @@ StyleSheet* HTMLLinkElement::sheet() const
void HTMLLinkElement::parseMappedAttribute(MappedAttribute *attr)
{
if (attr->name() == relAttr) {
-#ifdef ANDROID_APPLE_TOUCH_ICON
- tokenizeRelAttribute(attr->value(), m_isStyleSheet, m_alternate, m_isIcon, m_isTouchIcon, m_isPrecomposedTouchIcon, m_isDNSPrefetch);
-#else
- tokenizeRelAttribute(attr->value(), m_isStyleSheet, m_alternate, m_isIcon, m_isDNSPrefetch);
-#endif
+ tokenizeRelAttribute(attr->value(), m_rel);
process();
} else if (attr->name() == hrefAttr) {
m_url = document()->completeURL(deprecatedParseURL(attr->value()));
@@ -136,44 +128,49 @@ void HTMLLinkElement::parseMappedAttribute(MappedAttribute *attr)
process();
} else if (attr->name() == disabledAttr) {
setDisabledState(!attr->isNull());
- } else if (attr->name() == onbeforeloadAttr)
+ } else if (attr->name() == onbeforeloadAttr) {
setAttributeEventListener(eventNames().beforeloadEvent, createAttributeEventListener(this, attr));
- else {
+ } else if (attr->name() == onloadAttr) {
+ setAttributeEventListener(eventNames().loadEvent, createAttributeEventListener(this, attr));
+ } else {
if (attr->name() == titleAttr && m_sheet)
m_sheet->setTitle(attr->value());
HTMLElement::parseMappedAttribute(attr);
}
}
-#ifdef ANDROID_APPLE_TOUCH_ICON
-void HTMLLinkElement::tokenizeRelAttribute(const AtomicString& rel, bool& styleSheet, bool& alternate, bool& icon, bool& touchIcon, bool& precomposedTouchIcon, bool& dnsPrefetch)
-#else
-void HTMLLinkElement::tokenizeRelAttribute(const AtomicString& rel, bool& styleSheet, bool& alternate, bool& icon, bool& dnsPrefetch)
-#endif
+void HTMLLinkElement::tokenizeRelAttribute(const AtomicString& rel, RelAttribute& attribute)
{
- styleSheet = false;
- icon = false;
- alternate = false;
- dnsPrefetch = false;
+ attribute.m_isStyleSheet = false;
+ attribute.m_isIcon = false;
+ attribute.m_isAlternate = false;
+ attribute.m_isDNSPrefetch = false;
+#if ENABLE(LINK_PREFETCH)
+ attribute.m_isLinkPrefetch = false;
+#endif
#ifdef ANDROID_APPLE_TOUCH_ICON
- touchIcon = false;
- precomposedTouchIcon = false;
+ attribute.m_isTouchIcon = false;
+ attribute.m_isPrecomposedTouchIcon = false;
#endif
if (equalIgnoringCase(rel, "stylesheet"))
- styleSheet = true;
+ attribute.m_isStyleSheet = true;
else if (equalIgnoringCase(rel, "icon") || equalIgnoringCase(rel, "shortcut icon"))
- icon = true;
+ attribute.m_isIcon = true;
#ifdef ANDROID_APPLE_TOUCH_ICON
else if (equalIgnoringCase(rel, "apple-touch-icon"))
- touchIcon = true;
+ attribute.m_isTouchIcon = true;
else if (equalIgnoringCase(rel, "apple-touch-icon-precomposed"))
- precomposedTouchIcon = true;
+ attribute.m_isPrecomposedTouchIcon = true;
#endif
else if (equalIgnoringCase(rel, "dns-prefetch"))
- dnsPrefetch = true;
+ attribute.m_isDNSPrefetch = true;
+#if ENABLE(LINK_PREFETCH)
+ else if (equalIgnoringCase(rel, "prefetch"))
+ attribute.m_isLinkPrefetch = true;
+#endif
else if (equalIgnoringCase(rel, "alternate stylesheet") || equalIgnoringCase(rel, "stylesheet alternate")) {
- styleSheet = true;
- alternate = true;
+ attribute.m_isStyleSheet = true;
+ attribute.m_isAlternate = true;
} else {
// Tokenize the rel attribute and set bits based on specific keywords that we find.
String relString = rel.string();
@@ -183,11 +180,11 @@ void HTMLLinkElement::tokenizeRelAttribute(const AtomicString& rel, bool& styleS
Vector<String>::const_iterator end = list.end();
for (Vector<String>::const_iterator it = list.begin(); it != end; ++it) {
if (equalIgnoringCase(*it, "stylesheet"))
- styleSheet = true;
+ attribute.m_isStyleSheet = true;
else if (equalIgnoringCase(*it, "alternate"))
- alternate = true;
+ attribute.m_isAlternate = true;
else if (equalIgnoringCase(*it, "icon"))
- icon = true;
+ attribute.m_isIcon = true;
}
}
}
@@ -201,25 +198,35 @@ void HTMLLinkElement::process()
// IE extension: location of small icon for locationbar / bookmarks
// We'll record this URL per document, even if we later only use it in top level frames
- if (m_isIcon && m_url.isValid() && !m_url.isEmpty())
+ if (m_rel.m_isIcon && m_url.isValid() && !m_url.isEmpty())
document()->setIconURL(m_url.string(), type);
#ifdef ANDROID_APPLE_TOUCH_ICON
- if ((m_isTouchIcon || m_isPrecomposedTouchIcon) && m_url.isValid()
+ if ((m_rel.m_isTouchIcon || m_rel.m_isPrecomposedTouchIcon) && m_url.isValid()
&& !m_url.isEmpty())
document()->frame()->loader()->client()
->dispatchDidReceiveTouchIconURL(m_url.string(),
- m_isPrecomposedTouchIcon);
+ m_rel.m_isPrecomposedTouchIcon);
#endif
- if (m_isDNSPrefetch && m_url.isValid() && !m_url.isEmpty())
+ if (m_rel.m_isDNSPrefetch && m_url.isValid() && !m_url.isEmpty())
prefetchDNS(m_url.host());
+#if ENABLE(LINK_PREFETCH)
+ if (m_rel.m_isLinkPrefetch && m_url.isValid()) {
+ m_cachedLinkPrefetch = document()->docLoader()->requestLinkPrefetch(m_url);
+ m_loading = true;
+
+ if (m_cachedLinkPrefetch)
+ m_cachedLinkPrefetch->addClient(this);
+ }
+#endif
+
bool acceptIfTypeContainsTextCSS = document()->page() && document()->page()->settings() && document()->page()->settings()->treatsAnyTextCSSLinkAsStylesheet();
// Stylesheet
// This was buggy and would incorrectly match <link rel="alternate">, which has a different specified meaning. -dwh
- if (m_disabledState != 2 && (m_isStyleSheet || (acceptIfTypeContainsTextCSS && type.contains("text/css"))) && document()->frame() && m_url.isValid()) {
+ if (m_disabledState != 2 && (m_rel.m_isStyleSheet || (acceptIfTypeContainsTextCSS && type.contains("text/css"))) && document()->frame() && m_url.isValid()) {
// also, don't load style sheets for standalone documents
String charset = getAttribute(charsetAttr);
@@ -353,6 +360,17 @@ bool HTMLLinkElement::isLoading() const
return static_cast<CSSStyleSheet *>(m_sheet.get())->isLoading();
}
+void HTMLLinkElement::notifyFinished(CachedResource*)
+{
+ if (!m_timer.isActive())
+ m_timer.startOneShot(0);
+}
+
+void HTMLLinkElement::timerFired(Timer<HTMLLinkElement>*)
+{
+ dispatchEvent(Event::create(eventNames().loadEvent, false, false));
+}
+
bool HTMLLinkElement::sheetLoaded()
{
if (!isLoading() && !isDisabled() && !isAlternate()) {
@@ -462,10 +480,10 @@ void HTMLLinkElement::addSubresourceAttributeURLs(ListHashSet<KURL>& urls) const
HTMLElement::addSubresourceAttributeURLs(urls);
// Favicons are handled by a special case in LegacyWebArchive::create()
- if (m_isIcon)
+ if (m_rel.m_isIcon)
return;
- if (!m_isStyleSheet)
+ if (!m_rel.m_isStyleSheet)
return;
// Append the URL of this link element.
diff --git a/WebCore/html/HTMLLinkElement.h b/WebCore/html/HTMLLinkElement.h
index 324c244..7ff47dc 100644
--- a/WebCore/html/HTMLLinkElement.h
+++ b/WebCore/html/HTMLLinkElement.h
@@ -27,14 +27,39 @@
#include "CachedResourceClient.h"
#include "CachedResourceHandle.h"
#include "HTMLElement.h"
+#include "Timer.h"
namespace WebCore {
class CachedCSSStyleSheet;
+class CachedLinkPrefetch;
class KURL;
class HTMLLinkElement : public HTMLElement, public CachedResourceClient {
public:
+ struct RelAttribute {
+ bool m_isStyleSheet;
+ bool m_isIcon;
+ bool m_isAlternate;
+ bool m_isDNSPrefetch;
+#ifdef ANDROID_APPLE_TOUCH_ICON
+ bool m_isTouchIcon;
+ bool m_isPrecomposedTouchIcon;
+#endif
+#if ENABLE(LINK_PREFETCH)
+ bool m_isLinkPrefetch;
+#endif
+
+ RelAttribute() : m_isStyleSheet(false), m_isIcon(false), m_isAlternate(false), m_isDNSPrefetch(false)
+#ifdef ANDROID_APPLE_TOUCH_ICON
+ , m_isTouchIcon(false), m_isPrecomposedTouchIcon(false)
+#endif
+#if ENABLE(LINK_PREFETCH)
+ , m_isLinkPrefetch(false)
+#endif
+ { };
+ };
+
HTMLLinkElement(const QualifiedName&, Document*, bool createdByParser);
~HTMLLinkElement();
@@ -80,24 +105,22 @@ public:
// from CachedResourceClient
virtual void setCSSStyleSheet(const String& href, const KURL& baseURL, const String& charset, const CachedCSSStyleSheet* sheet);
+ virtual void notifyFinished(CachedResource*);
+
bool isLoading() const;
virtual bool sheetLoaded();
- bool isAlternate() const { return m_disabledState == 0 && m_alternate; }
+ bool isAlternate() const { return m_disabledState == 0 && m_rel.m_isAlternate; }
bool isDisabled() const { return m_disabledState == 2; }
bool isEnabledViaScript() const { return m_disabledState == 1; }
- bool isIcon() const { return m_isIcon; }
+ bool isIcon() const { return m_rel.m_isIcon; }
int disabledState() { return m_disabledState; }
void setDisabledState(bool _disabled);
virtual bool isURLAttribute(Attribute*) const;
-#ifdef ANDROID_APPLE_TOUCH_ICON
- static void tokenizeRelAttribute(const AtomicString& value, bool& stylesheet, bool& alternate, bool& icon, bool& touchIcon, bool& precomposedTouchIcon, bool& dnsPrefetch);
-#else
- static void tokenizeRelAttribute(const AtomicString& value, bool& stylesheet, bool& alternate, bool& icon, bool& dnsPrefetch);
-#endif
+ static void tokenizeRelAttribute(const AtomicString& value, RelAttribute& attribute);
virtual void addSubresourceAttributeURLs(ListHashSet<KURL>&) const;
@@ -112,22 +135,21 @@ public:
#endif
protected:
+ void timerFired(Timer<HTMLLinkElement>*);
+
CachedResourceHandle<CachedCSSStyleSheet> m_cachedSheet;
RefPtr<CSSStyleSheet> m_sheet;
+#if ENABLE(LINK_PREFETCH)
+ CachedResourceHandle<CachedLinkPrefetch> m_cachedLinkPrefetch;
+#endif
KURL m_url;
String m_type;
String m_media;
int m_disabledState; // 0=unset(default), 1=enabled via script, 2=disabled
+ RelAttribute m_rel;
bool m_loading;
- bool m_alternate;
- bool m_isStyleSheet;
- bool m_isIcon;
-#ifdef ANDROID_APPLE_TOUCH_ICON
- bool m_isTouchIcon;
- bool m_isPrecomposedTouchIcon;
-#endif
- bool m_isDNSPrefetch;
bool m_createdByParser;
+ Timer<HTMLLinkElement> m_timer;
};
} //namespace
diff --git a/WebCore/html/PreloadScanner.cpp b/WebCore/html/PreloadScanner.cpp
index 624f2ae..527b9f8 100644
--- a/WebCore/html/PreloadScanner.cpp
+++ b/WebCore/html/PreloadScanner.cpp
@@ -703,19 +703,9 @@ void PreloadScanner::processAttribute()
if (attribute == hrefAttr && m_urlToLoad.isEmpty())
m_urlToLoad = deprecatedParseURL(value);
else if (attribute == relAttr) {
- bool styleSheet = false;
- bool alternate = false;
- bool icon = false;
- bool dnsPrefetch = false;
-#ifdef ANDROID_APPLE_TOUCH_ICON
- bool touchIcon = false;
- bool precomposedTouchIcon = false;
- HTMLLinkElement::tokenizeRelAttribute(value, styleSheet, alternate, icon, touchIcon, precomposedTouchIcon, dnsPrefetch);
- m_linkIsStyleSheet = styleSheet && !alternate && !icon && !touchIcon && !precomposedTouchIcon && !dnsPrefetch;
-#else
- HTMLLinkElement::tokenizeRelAttribute(value, styleSheet, alternate, icon, dnsPrefetch);
- m_linkIsStyleSheet = styleSheet && !alternate && !icon && !dnsPrefetch;
-#endif
+ HTMLLinkElement::RelAttribute rel;
+ HTMLLinkElement::tokenizeRelAttribute(value, rel);
+ m_linkIsStyleSheet = rel.m_isStyleSheet && !rel.m_isAlternate && !rel.m_isIcon && !rel.m_isDNSPrefetch;
} else if (attribute == charsetAttr)
m_charset = value;
}
diff --git a/WebCore/loader/Cache.cpp b/WebCore/loader/Cache.cpp
index fdd9b25..5f4d0e7 100644
--- a/WebCore/loader/Cache.cpp
+++ b/WebCore/loader/Cache.cpp
@@ -38,6 +38,9 @@
#include "SecurityOrigin.h"
#include <stdio.h>
#include <wtf/CurrentTime.h>
+#if ENABLE(LINK_PREFETCH)
+#include "CachedLinkPrefetch.h"
+#endif
using namespace std;
@@ -86,6 +89,10 @@ static CachedResource* createResource(CachedResource::Type type, const KURL& url
case CachedResource::XBLStyleSheet:
return new CachedXBLDocument(url.string());
#endif
+#if ENABLE(LINK_PREFETCH)
+ case CachedResource::LinkPrefetch:
+ return new CachedLinkPrefetch(url.string());
+#endif
default:
break;
}
diff --git a/WebCore/loader/CachedCSSStyleSheet.cpp b/WebCore/loader/CachedCSSStyleSheet.cpp
index b2e03b9..3fc28ff 100644
--- a/WebCore/loader/CachedCSSStyleSheet.cpp
+++ b/WebCore/loader/CachedCSSStyleSheet.cpp
@@ -51,8 +51,10 @@ CachedCSSStyleSheet::~CachedCSSStyleSheet()
void CachedCSSStyleSheet::didAddClient(CachedResourceClient *c)
{
- if (!m_loading)
+ if (!m_loading) {
c->setCSSStyleSheet(m_url, m_response.url(), m_decoder->encoding().name(), this);
+ c->notifyFinished(this);
+ }
}
void CachedCSSStyleSheet::allClientsRemoved()
@@ -103,6 +105,10 @@ void CachedCSSStyleSheet::data(PassRefPtr<SharedBuffer> data, bool allDataReceiv
checkNotify();
// Clear the decoded text as it is unlikely to be needed immediately again and is cheap to regenerate.
m_decodedSheetText = String();
+
+ CachedResourceClientWalker w(m_clients);
+ while (CachedResourceClient* c = w.next())
+ c->notifyFinished(this);
}
void CachedCSSStyleSheet::checkNotify()
diff --git a/WebCore/loader/CachedLinkPrefetch.h b/WebCore/loader/CachedLinkPrefetch.h
new file mode 100644
index 0000000..4ffa5fe
--- /dev/null
+++ b/WebCore/loader/CachedLinkPrefetch.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2010, The Android Open Source Project
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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 THE COPYRIGHT HOLDERS ``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 THE COPYRIGHT OWNER OR
+ * 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 CachedLinkPrefetch_h
+#define CachedLinkPrefetch_h
+
+#include "CachedResource.h"
+#include "CachedResourceClient.h"
+#include "CachedResourceClientWalker.h"
+
+namespace WebCore {
+
+class DocLoader;
+
+class CachedLinkPrefetch : public CachedResource {
+public:
+ CachedLinkPrefetch(const String& URL) : CachedResource(URL, LinkPrefetch) { };
+ virtual ~CachedLinkPrefetch() { };
+
+ virtual void didAddClient(CachedResourceClient* c) {
+ if (!m_loading)
+ c->notifyFinished(this);
+ };
+
+ virtual void data(PassRefPtr<SharedBuffer> data, bool allDataReceived) {
+ if (!allDataReceived)
+ return;
+
+ m_data = data;
+
+ CachedResourceClientWalker w(m_clients);
+ while (CachedResourceClient* c = w.next())
+ c->notifyFinished(this);
+ };
+ virtual void error() { };
+
+ virtual bool schedule() const { return true; }
+
+ virtual bool isPrefetch() const { return true; }
+};
+}
+
+#endif
+
diff --git a/WebCore/loader/CachedResource.h b/WebCore/loader/CachedResource.h
index 0f46a62..bad632b 100644
--- a/WebCore/loader/CachedResource.h
+++ b/WebCore/loader/CachedResource.h
@@ -63,6 +63,9 @@ public:
#if ENABLE(XBL)
, XBL
#endif
+#if ENABLE(LINK_PREFETCH)
+ , LinkPrefetch
+#endif
};
enum Status {
@@ -118,6 +121,7 @@ public:
void setLoading(bool b) { m_loading = b; }
virtual bool isImage() const { return false; }
+ virtual bool isPrefetch() const { return false; }
unsigned accessCount() const { return m_accessCount; }
void increaseAccessCount() { m_accessCount++; }
diff --git a/WebCore/loader/DocLoader.cpp b/WebCore/loader/DocLoader.cpp
index 8c0a1b2..08dfa33 100644
--- a/WebCore/loader/DocLoader.cpp
+++ b/WebCore/loader/DocLoader.cpp
@@ -44,6 +44,9 @@
#include "loader.h"
#include "SecurityOrigin.h"
#include "Settings.h"
+#if ENABLE(LINK_PREFETCH)
+#include "CachedLinkPrefetch.h"
+#endif
#define PRELOAD_DEBUG 0
@@ -176,6 +179,13 @@ CachedXBLDocument* DocLoader::requestXBLDocument(const String& url)
}
#endif
+#if ENABLE(LINK_PREFETCH)
+CachedLinkPrefetch* DocLoader::requestLinkPrefetch(const String& url)
+{
+ return static_cast<CachedLinkPrefetch*>(requestResource(CachedResource::LinkPrefetch, url, String()));
+}
+#endif
+
bool DocLoader::canRequest(CachedResource::Type type, const KURL& url)
{
// Some types of resources can be loaded only from the same origin. Other
@@ -186,6 +196,9 @@ bool DocLoader::canRequest(CachedResource::Type type, const KURL& url)
case CachedResource::CSSStyleSheet:
case CachedResource::Script:
case CachedResource::FontResource:
+#if ENABLE(LINK_PREFETCH)
+ case CachedResource::LinkPrefetch:
+#endif
// These types of resources can be loaded from any origin.
// FIXME: Are we sure about CachedResource::FontResource?
break;
@@ -228,6 +241,9 @@ bool DocLoader::canRequest(CachedResource::Type type, const KURL& url)
break;
case CachedResource::ImageResource:
case CachedResource::CSSStyleSheet:
+#if ENABLE(LINK_PREFETCH)
+ case CachedResource::LinkPrefetch:
+#endif
case CachedResource::FontResource: {
// These resources can corrupt only the frame's pixels.
if (Frame* f = frame()) {
@@ -402,13 +418,19 @@ void DocLoader::checkCacheObjectStatus(CachedResource* resource)
frame()->loader()->loadedResourceFromMemoryCache(resource);
}
-void DocLoader::incrementRequestCount()
+void DocLoader::incrementRequestCount(const CachedResource* res)
{
+ if (res->isPrefetch())
+ return;
+
++m_requestCount;
}
-void DocLoader::decrementRequestCount()
+void DocLoader::decrementRequestCount(const CachedResource* res)
{
+ if (res->isPrefetch())
+ return;
+
--m_requestCount;
ASSERT(m_requestCount > -1);
}
diff --git a/WebCore/loader/DocLoader.h b/WebCore/loader/DocLoader.h
index 06d8a47..2f8f639 100644
--- a/WebCore/loader/DocLoader.h
+++ b/WebCore/loader/DocLoader.h
@@ -45,6 +45,9 @@ class Document;
class Frame;
class ImageLoader;
class KURL;
+#if ENABLE(LINK_PREFETCH)
+class CachedLinkPrefetch;
+#endif
// The DocLoader manages the loading of scripts/images/stylesheets for a single document.
class DocLoader : public Noncopyable
@@ -68,6 +71,9 @@ public:
#if ENABLE(XBL)
CachedXBLDocument* requestXBLDocument(const String &url);
#endif
+#if ENABLE(LINK_PREFETCH)
+ CachedLinkPrefetch* requestLinkPrefetch(const String &url);
+#endif
// Logs an access denied message to the console for the specified URL.
void printAccessDeniedMessage(const KURL& url) const;
@@ -98,8 +104,8 @@ public:
void setAllowStaleResources(bool allowStaleResources) { m_allowStaleResources = allowStaleResources; }
- void incrementRequestCount();
- void decrementRequestCount();
+ void incrementRequestCount(const CachedResource*);
+ void decrementRequestCount(const CachedResource*);
int requestCount();
void clearPreloads();
diff --git a/WebCore/loader/loader.cpp b/WebCore/loader/loader.cpp
index 4d2b474..24f141f 100644
--- a/WebCore/loader/loader.cpp
+++ b/WebCore/loader/loader.cpp
@@ -88,7 +88,12 @@ static ResourceRequest::TargetType cachedResourceTypeToTargetType(CachedResource
return ResourceRequest::TargetIsFontResource;
case CachedResource::ImageResource:
return ResourceRequest::TargetIsImage;
+#if ENABLE(LINK_PREFETCH)
+ case CachedResource::LinkPrefetch:
+ return ResourceRequest::TargetIsSubresource;
+#endif
}
+ ASSERT_NOT_REACHED();
return ResourceRequest::TargetIsSubresource;
}
@@ -109,6 +114,10 @@ Loader::Priority Loader::determinePriority(const CachedResource* resource) const
return Medium;
case CachedResource::ImageResource:
return Low;
+#if ENABLE(LINK_PREFETCH)
+ case CachedResource::LinkPrefetch:
+ return VeryLow;
+#endif
}
ASSERT_NOT_REACHED();
return Low;
@@ -138,9 +147,9 @@ void Loader::load(DocLoader* docLoader, CachedResource* resource, bool increment
bool hadRequests = host->hasRequests();
Priority priority = determinePriority(resource);
host->addRequest(request, priority);
- docLoader->incrementRequestCount();
+ docLoader->incrementRequestCount(request->cachedResource());
- if (priority > Low || !url.protocolInHTTPFamily() || !hadRequests) {
+ if (priority > Low || !url.protocolInHTTPFamily() || (priority == Low && !hadRequests)) {
// Try to request important resources immediately
host->servePendingRequests(priority);
} else {
@@ -352,6 +361,12 @@ void Loader::Host::servePendingRequests(RequestQueue& requestsPending, bool& ser
}
}
+#if ENABLE(LINK_PREFETCH)
+ if (request->cachedResource()->type() == CachedResource::LinkPrefetch) {
+ resourceRequest.setHTTPHeaderField("X-Moz", "prefetch");
+ }
+#endif
+
RefPtr<SubresourceLoader> loader = SubresourceLoader::create(docLoader->doc()->frame(),
this, resourceRequest, request->shouldDoSecurityCheck(), request->sendResourceLoadCallbacks());
if (loader) {
@@ -361,7 +376,7 @@ void Loader::Host::servePendingRequests(RequestQueue& requestsPending, bool& ser
printf("HOST %s COUNT %d LOADING %s\n", resourceRequest.url().host().latin1().data(), m_requestsLoading.size(), request->cachedResource()->url().latin1().data());
#endif
} else {
- docLoader->decrementRequestCount();
+ docLoader->decrementRequestCount(request->cachedResource());
docLoader->setLoadInProgress(true);
request->cachedResource()->error();
docLoader->setLoadInProgress(false);
@@ -385,7 +400,7 @@ void Loader::Host::didFinishLoading(SubresourceLoader* loader)
// the docLoader that it will delete when the document gets deleted.
RefPtr<Document> protector(docLoader->doc());
if (!request->isMultipart())
- docLoader->decrementRequestCount();
+ docLoader->decrementRequestCount(request->cachedResource());
CachedResource* resource = request->cachedResource();
ASSERT(!resource->resourceToRevalidate());
@@ -433,7 +448,7 @@ void Loader::Host::didFail(SubresourceLoader* loader, bool cancelled)
// the docLoader that it will delete when the document gets deleted.
RefPtr<Document> protector(docLoader->doc());
if (!request->isMultipart())
- docLoader->decrementRequestCount();
+ docLoader->decrementRequestCount(request->cachedResource());
CachedResource* resource = request->cachedResource();
@@ -478,7 +493,7 @@ void Loader::Host::didReceiveResponse(SubresourceLoader* loader, const ResourceR
// 304 Not modified / Use local copy
m_requestsLoading.remove(loader);
loader->clearClient();
- request->docLoader()->decrementRequestCount();
+ request->docLoader()->decrementRequestCount(request->cachedResource());
// Existing resource is ok, just use it updating the expiration time.
cache()->revalidationSucceeded(resource, response);
@@ -510,7 +525,7 @@ void Loader::Host::didReceiveResponse(SubresourceLoader* loader, const ResourceR
request->setIsMultipart(true);
// We don't count multiParts in a DocLoader's request count
- request->docLoader()->decrementRequestCount();
+ request->docLoader()->decrementRequestCount(request->cachedResource());
// If we get a multipart response, we must have a handle
ASSERT(loader->handle());
@@ -559,7 +574,7 @@ void Loader::Host::cancelPendingRequests(RequestQueue& requestsPending, DocLoade
if (request->docLoader() == docLoader) {
cache()->remove(request->cachedResource());
delete request;
- docLoader->decrementRequestCount();
+ docLoader->decrementRequestCount(request->cachedResource());
} else
remaining.append(request);
}
diff --git a/WebCore/loader/loader.h b/WebCore/loader/loader.h
index a9de032..9393a60 100644
--- a/WebCore/loader/loader.h
+++ b/WebCore/loader/loader.h
@@ -48,8 +48,8 @@ namespace WebCore {
void cancelRequests(DocLoader*);
- enum Priority { Low, Medium, High };
- void servePendingRequests(Priority minimumPriority = Low);
+ enum Priority { VeryLow, Low, Medium, High };
+ void servePendingRequests(Priority minimumPriority = VeryLow);
bool isSuspendingPendingRequests() { return m_isSuspendingPendingRequests; }
void suspendPendingRequests();
@@ -76,7 +76,7 @@ namespace WebCore {
void addRequest(Request*, Priority);
void nonCacheRequestInFlight();
void nonCacheRequestComplete();
- void servePendingRequests(Priority minimumPriority = Low);
+ void servePendingRequests(Priority minimumPriority = VeryLow);
void cancelRequests(DocLoader*);
bool hasRequests() const;