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();