Bug 534293 - Make speculative loads initiated by the HTML5 parser take <base> into account. r=jst, a=blocking2.0-betaN.
authorHenri Sivonen <hsivonen@iki.fi>
Mon, 26 Jul 2010 14:18:43 +0300
changeset 48403 44f910ba5741051daf06fbb5d4048e89793e0aeb
parent 48402 c5f35032f22df63a99d63bba7cf791ae309d0ab7
child 48404 e278b19aa8cad518c842729c4a0bb7bde035a3e6
push id14716
push userhsivonen@iki.fi
push dateFri, 30 Jul 2010 10:26:24 +0000
treeherderautoland@8832c82d90b9 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjst, blocking2
bugs534293
milestone2.0b3pre
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 534293 - Make speculative loads initiated by the HTML5 parser take <base> into account. r=jst, a=blocking2.0-betaN.
parser/html/nsHtml5SpeculativeLoad.cpp
parser/html/nsHtml5SpeculativeLoad.h
parser/html/nsHtml5TreeBuilderCppSupplement.h
parser/html/nsHtml5TreeOpExecutor.cpp
parser/html/nsHtml5TreeOpExecutor.h
--- a/parser/html/nsHtml5SpeculativeLoad.cpp
+++ b/parser/html/nsHtml5SpeculativeLoad.cpp
@@ -52,16 +52,19 @@ nsHtml5SpeculativeLoad::~nsHtml5Speculat
   NS_ASSERTION(mOpCode != eSpeculativeLoadUninitialized,
                "Uninitialized speculative load.");
 }
 
 void
 nsHtml5SpeculativeLoad::Perform(nsHtml5TreeOpExecutor* aExecutor)
 {
   switch (mOpCode) {
+    case eSpeculativeLoadBase:
+        aExecutor->SetSpeculationBase(mUrl);
+      break;
     case eSpeculativeLoadImage:
         aExecutor->PreloadImage(mUrl);
       break;
     case eSpeculativeLoadScript:
         aExecutor->PreloadScript(mUrl, mCharset, mType);
       break;
     case eSpeculativeLoadStyle:
         aExecutor->PreloadStyle(mUrl, mCharset);
--- a/parser/html/nsHtml5SpeculativeLoad.h
+++ b/parser/html/nsHtml5SpeculativeLoad.h
@@ -41,27 +41,35 @@
 #include "nsString.h"
 
 class nsHtml5TreeOpExecutor;
 
 enum eHtml5SpeculativeLoad {
 #ifdef DEBUG
   eSpeculativeLoadUninitialized,
 #endif
+  eSpeculativeLoadBase,
   eSpeculativeLoadImage,
   eSpeculativeLoadScript,
   eSpeculativeLoadStyle,
   eSpeculativeLoadManifest  
 };
 
 class nsHtml5SpeculativeLoad {
   public:
     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!");
       mOpCode = eSpeculativeLoadImage;
       mUrl.Assign(aUrl);
     }
 
     inline void InitScript(const nsAString& aUrl,
--- a/parser/html/nsHtml5TreeBuilderCppSupplement.h
+++ b/parser/html/nsHtml5TreeBuilderCppSupplement.h
@@ -144,16 +144,24 @@ nsHtml5TreeBuilder::createElement(PRInt3
           nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
           NS_ASSERTION(treeOp, "Tree op allocation failed.");
           treeOp->Init(eTreeOpSetStyleLineNumber, content, tokenizer->getLineNumber());
         } else if (nsHtml5Atoms::html == aName) {
           nsString* url = aAttributes->getValue(nsHtml5AttributeName::ATTR_MANIFEST);
           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:
         if (nsHtml5Atoms::image == aName) {
           nsString* url = aAttributes->getValue(nsHtml5AttributeName::ATTR_XLINK_HREF);
           if (url) {
             mSpeculativeLoadQueue.AppendElement()->InitImage(*url);
           }
--- a/parser/html/nsHtml5TreeOpExecutor.cpp
+++ b/parser/html/nsHtml5TreeOpExecutor.cpp
@@ -825,17 +825,28 @@ nsHtml5TreeOpExecutor::InitializeDocWrit
   static_cast<nsHtml5Parser*> (mParser.get())->InitializeDocWriteParserState(aState, aLine);
 }
 
 // Speculative loading
 
 already_AddRefed<nsIURI>
 nsHtml5TreeOpExecutor::ConvertIfNotPreloadedYet(const nsAString& aURL)
 {
-  nsIURI* base = mDocument->GetDocBaseURI();
+  // The URL of the document without <base>
+  nsIURI* documentURI = mDocument->GetDocumentURI();
+  // The URL of the document with non-speculative <base>
+  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 <base>, 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<nsIURI> uri;
   nsresult rv = NS_NewURI(getter_AddRefs(uri), aURL, charset.get(), base);
   if (NS_FAILED(rv)) {
     NS_WARNING("Failed to create a URI");
     return nsnull;
   }
   nsCAutoString spec;
@@ -877,15 +888,30 @@ nsHtml5TreeOpExecutor::PreloadImage(cons
 {
   nsCOMPtr<nsIURI> uri = ConvertIfNotPreloadedYet(aURL);
   if (!uri) {
     return;
   }
   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;
 PRUint32 nsHtml5TreeOpExecutor::sAppendBatchExaminations = 0;
 PRUint32 nsHtml5TreeOpExecutor::sLongestTimeOffTheEventLoop = 0;
 PRUint32 nsHtml5TreeOpExecutor::sTimesFlushLoopInterrupted = 0;
 #endif
--- a/parser/html/nsHtml5TreeOpExecutor.h
+++ b/parser/html/nsHtml5TreeOpExecutor.h
@@ -104,16 +104,18 @@ class nsHtml5TreeOpExecutor : public nsC
     nsHtml5StreamParser*                 mStreamParser;
     nsCOMArray<nsIContent>               mOwnedElements;
     
     /**
      * URLs already preloaded/preloading.
      */
     nsCStringHashSet mPreloadedURLs;
 
+    nsCOMPtr<nsIURI> mSpeculationBaseURI;
+
     /**
      * Whether the parser has started
      */
     PRBool                        mStarted;
 
     nsHtml5TreeOpStage            mStage;
 
     eHtml5FlushState              mFlushState;
@@ -390,16 +392,18 @@ class nsHtml5TreeOpExecutor : public nsC
     void PreloadScript(const nsAString& aURL,
                        const nsAString& aCharset,
                        const nsAString& aType);
 
     void PreloadStyle(const nsAString& aURL, const nsAString& aCharset);
 
     void PreloadImage(const nsAString& aURL);
 
+    void SetSpeculationBase(const nsAString& aURL);
+
   private:
 
     nsHtml5Tokenizer* GetTokenizer();
 
     /**
      * Get a nsIURI for an nsString if the URL hasn't been preloaded yet.
      */
     already_AddRefed<nsIURI> ConvertIfNotPreloadedYet(const nsAString& aURL);