diff --git a/parser/html/nsHtml5SpeculativeLoad.cpp b/parser/html/nsHtml5SpeculativeLoad.cpp
index 5dacb2e2753..733842b5815 100644
--- a/parser/html/nsHtml5SpeculativeLoad.cpp
+++ b/parser/html/nsHtml5SpeculativeLoad.cpp
@@ -57,6 +57,9 @@ void
nsHtml5SpeculativeLoad::Perform(nsHtml5TreeOpExecutor* aExecutor)
{
switch (mOpCode) {
+ case eSpeculativeLoadBase:
+ aExecutor->SetSpeculationBase(mUrl);
+ break;
case eSpeculativeLoadImage:
aExecutor->PreloadImage(mUrl);
break;
diff --git a/parser/html/nsHtml5SpeculativeLoad.h b/parser/html/nsHtml5SpeculativeLoad.h
index 17334f1d4b8..d6c8c0ba87e 100644
--- a/parser/html/nsHtml5SpeculativeLoad.h
+++ b/parser/html/nsHtml5SpeculativeLoad.h
@@ -46,6 +46,7 @@ enum eHtml5SpeculativeLoad {
#ifdef DEBUG
eSpeculativeLoadUninitialized,
#endif
+ eSpeculativeLoadBase,
eSpeculativeLoadImage,
eSpeculativeLoadScript,
eSpeculativeLoadStyle,
@@ -57,6 +58,13 @@ class nsHtml5SpeculativeLoad {
nsHtml5SpeculativeLoad();
~nsHtml5SpeculativeLoad();
+ inline void InitBase(const nsAString& aUrl) {
+ NS_PRECONDITION(mOpCode == eSpeculativeLoadUninitialized,
+ "Trying to reinitialize a speculative load!");
+ mOpCode = eSpeculativeLoadBase;
+ mUrl.Assign(aUrl);
+ }
+
inline void InitImage(const nsAString& aUrl) {
NS_PRECONDITION(mOpCode == eSpeculativeLoadUninitialized,
"Trying to reinitialize a speculative load!");
diff --git a/parser/html/nsHtml5TreeBuilderCppSupplement.h b/parser/html/nsHtml5TreeBuilderCppSupplement.h
index 9699fb3bdb4..1f4311eb8da 100644
--- a/parser/html/nsHtml5TreeBuilderCppSupplement.h
+++ b/parser/html/nsHtml5TreeBuilderCppSupplement.h
@@ -149,6 +149,14 @@ nsHtml5TreeBuilder::createElement(PRInt32 aNamespace, nsIAtom* aName, nsHtml5Htm
if (url) {
mSpeculativeLoadQueue.AppendElement()->InitManifest(*url);
}
+ } else if (nsHtml5Atoms::base == aName &&
+ (mode == NS_HTML5TREE_BUILDER_IN_HEAD ||
+ mode == NS_HTML5TREE_BUILDER_AFTER_HEAD)) {
+ nsString* url =
+ aAttributes->getValue(nsHtml5AttributeName::ATTR_HREF);
+ if (url) {
+ mSpeculativeLoadQueue.AppendElement()->InitBase(*url);
+ }
}
break;
case kNameSpaceID_SVG:
diff --git a/parser/html/nsHtml5TreeOpExecutor.cpp b/parser/html/nsHtml5TreeOpExecutor.cpp
index 02b62e9dded..0ef3a076b36 100644
--- a/parser/html/nsHtml5TreeOpExecutor.cpp
+++ b/parser/html/nsHtml5TreeOpExecutor.cpp
@@ -830,7 +830,18 @@ nsHtml5TreeOpExecutor::InitializeDocWriteParserState(nsAHtml5TreeBuilderState* a
already_AddRefed
nsHtml5TreeOpExecutor::ConvertIfNotPreloadedYet(const nsAString& aURL)
{
- nsIURI* base = mDocument->GetDocBaseURI();
+ // The URL of the document without
+ nsIURI* documentURI = mDocument->GetDocumentURI();
+ // The URL of the document with non-speculative
+ nsIURI* documentBaseURI = mDocument->GetDocBaseURI();
+
+ // If the two above are different, use documentBaseURI. If they are the
+ // same, the document object isn't aware of a , so attempt to use the
+ // mSpeculationBaseURI or, failing, that, documentURI.
+ nsIURI* base = (documentURI == documentBaseURI) ?
+ (mSpeculationBaseURI ?
+ mSpeculationBaseURI.get() : documentURI)
+ : documentBaseURI;
const nsCString& charset = mDocument->GetDocumentCharacterSet();
nsCOMPtr uri;
nsresult rv = NS_NewURI(getter_AddRefs(uri), aURL, charset.get(), base);
@@ -882,6 +893,21 @@ nsHtml5TreeOpExecutor::PreloadImage(const nsAString& aURL)
mDocument->MaybePreLoadImage(uri);
}
+void
+nsHtml5TreeOpExecutor::SetSpeculationBase(const nsAString& aURL)
+{
+ if (mSpeculationBaseURI) {
+ // the first one wins
+ return;
+ }
+ const nsCString& charset = mDocument->GetDocumentCharacterSet();
+ nsresult rv = NS_NewURI(getter_AddRefs(mSpeculationBaseURI), aURL,
+ charset.get(), mDocument->GetDocumentURI());
+ if (NS_FAILED(rv)) {
+ NS_WARNING("Failed to create a URI");
+ }
+}
+
#ifdef DEBUG_NS_HTML5_TREE_OP_EXECUTOR_FLUSH
PRUint32 nsHtml5TreeOpExecutor::sAppendBatchMaxSize = 0;
PRUint32 nsHtml5TreeOpExecutor::sAppendBatchSlotsExamined = 0;
diff --git a/parser/html/nsHtml5TreeOpExecutor.h b/parser/html/nsHtml5TreeOpExecutor.h
index 5a44f4f4189..02814e32d2a 100644
--- a/parser/html/nsHtml5TreeOpExecutor.h
+++ b/parser/html/nsHtml5TreeOpExecutor.h
@@ -109,6 +109,8 @@ class nsHtml5TreeOpExecutor : public nsContentSink,
*/
nsCStringHashSet mPreloadedURLs;
+ nsCOMPtr mSpeculationBaseURI;
+
/**
* Whether the parser has started
*/
@@ -395,6 +397,8 @@ class nsHtml5TreeOpExecutor : public nsContentSink,
void PreloadImage(const nsAString& aURL);
+ void SetSpeculationBase(const nsAString& aURL);
+
private:
nsHtml5Tokenizer* GetTokenizer();