diff --git a/content/base/src/nsContentSink.cpp b/content/base/src/nsContentSink.cpp index cf319e122e01..cbd38b7653e2 100644 --- a/content/base/src/nsContentSink.cpp +++ b/content/base/src/nsContentSink.cpp @@ -1087,11 +1087,22 @@ nsContentSink::ProcessOfflineManifest(nsIContent *aElement) return; } - nsresult rv; - // Check for a manifest= attribute. nsAutoString manifestSpec; aElement->GetAttr(kNameSpaceID_None, nsGkAtoms::manifest, manifestSpec); + ProcessOfflineManifest(manifestSpec); +} + +void +nsContentSink::ProcessOfflineManifest(const nsAString& aManifestSpec) +{ + // Don't bother processing offline manifest for documents + // without a docshell + if (!mDocShell) { + return; + } + + nsresult rv; // Grab the application cache the document was loaded from, if any. nsCOMPtr applicationCache; @@ -1115,7 +1126,7 @@ nsContentSink::ProcessOfflineManifest(nsIContent *aElement) } } - if (manifestSpec.IsEmpty() && !applicationCache) { + if (aManifestSpec.IsEmpty() && !applicationCache) { // Not loaded from an application cache, and no manifest // attribute. Nothing to do here. return; @@ -1124,12 +1135,12 @@ nsContentSink::ProcessOfflineManifest(nsIContent *aElement) CacheSelectionAction action = CACHE_SELECTION_NONE; nsCOMPtr manifestURI; - if (manifestSpec.IsEmpty()) { + if (aManifestSpec.IsEmpty()) { action = CACHE_SELECTION_RESELECT_WITHOUT_MANIFEST; } else { nsContentUtils::NewURIWithDocumentCharset(getter_AddRefs(manifestURI), - manifestSpec, mDocument, + aManifestSpec, mDocument, mDocumentURI); if (!manifestURI) { return; diff --git a/content/base/src/nsContentSink.h b/content/base/src/nsContentSink.h index 91e45e01459b..d4ac8f1c69f9 100644 --- a/content/base/src/nsContentSink.h +++ b/content/base/src/nsContentSink.h @@ -247,6 +247,10 @@ public: // of the above defined methods to select the document's application // cache, let it be associated with the document and eventually // schedule the cache update process. + void ProcessOfflineManifest(const nsAString& aManifestSpec); + + // Extracts the manifest attribute from the element if it is the root + // element and calls the above method. void ProcessOfflineManifest(nsIContent *aElement); protected: diff --git a/parser/html/nsHtml5Parser.cpp b/parser/html/nsHtml5Parser.cpp index 036263375af5..d4a5be187c02 100644 --- a/parser/html/nsHtml5Parser.cpp +++ b/parser/html/nsHtml5Parser.cpp @@ -85,7 +85,7 @@ nsHtml5Parser::nsHtml5Parser() : mFirstBuffer(new nsHtml5UTF16Buffer(0)) , mLastBuffer(mFirstBuffer) , mExecutor(new nsHtml5TreeOpExecutor()) - , mTreeBuilder(new nsHtml5TreeBuilder(mExecutor)) + , mTreeBuilder(new nsHtml5TreeBuilder(mExecutor, nsnull)) , mTokenizer(new nsHtml5Tokenizer(mTreeBuilder)) , mRootContextLineNumber(1) { @@ -662,9 +662,6 @@ nsHtml5Parser::Initialize(nsIDocument* aDoc, nsISupports* aContainer, nsIChannel* aChannel) { - if (mStreamParser && aDoc) { - mStreamParser->SetSpeculativeLoaderWithDocument(aDoc); - } return mExecutor->Init(aDoc, aURI, aContainer, aChannel); } diff --git a/parser/html/nsHtml5SpeculativeLoader.cpp b/parser/html/nsHtml5SpeculativeLoader.cpp index e3fc36a6359a..1663807d9691 100644 --- a/parser/html/nsHtml5SpeculativeLoader.cpp +++ b/parser/html/nsHtml5SpeculativeLoader.cpp @@ -43,6 +43,7 @@ #include "nsNetUtil.h" #include "nsScriptLoader.h" #include "nsICSSLoaderObserver.h" +#include "nsIDocument.h" /** * Used if we need to pass an nsICSSLoaderObserver as parameter, @@ -59,8 +60,8 @@ public: NS_IMPL_ISUPPORTS1(nsHtml5DummyCSSLoaderObserver, nsICSSLoaderObserver) -nsHtml5SpeculativeLoader::nsHtml5SpeculativeLoader(nsIDocument* aDocument) - : mDocument(aDocument) +nsHtml5SpeculativeLoader::nsHtml5SpeculativeLoader(nsHtml5TreeOpExecutor* aExecutor) + : mExecutor(aExecutor) { MOZ_COUNT_CTOR(nsHtml5SpeculativeLoader); mPreloadedURLs.Init(23); // Mean # of preloadable resources per page on dmoz @@ -78,8 +79,12 @@ NS_IMPL_THREADSAFE_RELEASE(nsHtml5SpeculativeLoader) already_AddRefed nsHtml5SpeculativeLoader::ConvertIfNotPreloadedYet(const nsAString& aURL) { - nsIURI* base = mDocument->GetBaseURI(); - const nsCString& charset = mDocument->GetDocumentCharacterSet(); + nsIDocument* doc = mExecutor->GetDocument(); + if (!doc) { + return nsnull; + } + nsIURI* base = doc->GetBaseURI(); + const nsCString& charset = doc->GetDocumentCharacterSet(); nsCOMPtr uri; nsresult rv = NS_NewURI(getter_AddRefs(uri), aURL, charset.get(), base); if (NS_FAILED(rv)) { @@ -106,7 +111,10 @@ nsHtml5SpeculativeLoader::PreloadScript(const nsAString& aURL, if (!uri) { return; } - mDocument->ScriptLoader()->PreloadURI(uri, aCharset, aType); + nsIDocument* doc = mExecutor->GetDocument(); + if (doc) { + doc->ScriptLoader()->PreloadURI(uri, aCharset, aType); + } } void @@ -118,9 +126,13 @@ nsHtml5SpeculativeLoader::PreloadStyle(const nsAString& aURL, return; } nsCOMPtr obs = new nsHtml5DummyCSSLoaderObserver(); - mDocument->CSSLoader()->LoadSheet(uri, mDocument->NodePrincipal(), - NS_LossyConvertUTF16toASCII(aCharset), - obs); + nsIDocument* doc = mExecutor->GetDocument(); + if (doc) { + doc->CSSLoader()->LoadSheet(uri, + doc->NodePrincipal(), + NS_LossyConvertUTF16toASCII(aCharset), + obs); + } } void @@ -130,5 +142,14 @@ nsHtml5SpeculativeLoader::PreloadImage(const nsAString& aURL) if (!uri) { return; } - mDocument->MaybePreLoadImage(uri); + nsIDocument* doc = mExecutor->GetDocument(); + if (doc) { + doc->MaybePreLoadImage(uri); + } +} + +void +nsHtml5SpeculativeLoader::ProcessManifest(const nsAString& aURL) +{ + mExecutor->ProcessOfflineManifest(aURL); } diff --git a/parser/html/nsHtml5SpeculativeLoader.h b/parser/html/nsHtml5SpeculativeLoader.h index f29e7714cd9f..a6a8d2f9c9f2 100644 --- a/parser/html/nsHtml5SpeculativeLoader.h +++ b/parser/html/nsHtml5SpeculativeLoader.h @@ -42,13 +42,13 @@ #include "nsIURI.h" #include "nsString.h" #include "nsCOMPtr.h" -#include "nsIDocument.h" +#include "nsHtml5TreeOpExecutor.h" #include "nsHashSets.h" class nsHtml5SpeculativeLoader { public: - nsHtml5SpeculativeLoader(nsIDocument* aDocument); + nsHtml5SpeculativeLoader(nsHtml5TreeOpExecutor* aExecutor); ~nsHtml5SpeculativeLoader(); NS_IMETHOD_(nsrefcnt) AddRef(void); @@ -62,6 +62,8 @@ class nsHtml5SpeculativeLoader void PreloadImage(const nsAString& aURL); + void ProcessManifest(const nsAString& aURL); + private: /** @@ -72,9 +74,9 @@ class nsHtml5SpeculativeLoader nsAutoRefCnt mRefCnt; /** - * The document to use as the context for preloading. + * The executor to use as the context for preloading. */ - nsCOMPtr mDocument; + nsRefPtr mExecutor; /** * URLs already preloaded/preloading. diff --git a/parser/html/nsHtml5StreamParser.cpp b/parser/html/nsHtml5StreamParser.cpp index 50161cb5f918..2a9969c2c5fb 100644 --- a/parser/html/nsHtml5StreamParser.cpp +++ b/parser/html/nsHtml5StreamParser.cpp @@ -50,6 +50,7 @@ #include "nsHtml5AtomTable.h" #include "nsHtml5Module.h" #include "nsHtml5RefPtr.h" +#include "nsHtml5SpeculativeLoader.h" static NS_DEFINE_CID(kCharsetAliasCID, NS_CHARSETALIAS_CID); @@ -91,7 +92,6 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsHtml5StreamParser) tmp->mOwner = nsnull; tmp->mExecutorFlusher = nsnull; tmp->mExecutor = nsnull; - NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mDocument) NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mChardet) tmp->mTreeBuilder->DropSpeculativeLoader(); NS_IMPL_CYCLE_COLLECTION_UNLINK_END @@ -108,7 +108,6 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsHtml5StreamParser) NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mExecutorFlusher->mExecutor"); cb.NoteXPCOMChild(static_cast (tmp->mExecutor)); } - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mDocument) // hack: count self if held by mChardet if (tmp->mChardet) { NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, @@ -116,10 +115,10 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsHtml5StreamParser) cb.NoteXPCOMChild(static_cast(tmp)); } // hack: count the strongly owned edge wrapped in the speculative loader - if (tmp->mDocument) { + if (tmp->mTreeBuilder->HasSpeculativeLoader()) { NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, - "mTreeBuilder->mSpeculativeLoader->mDocument"); - cb.NoteXPCOMChild(tmp->mDocument); + "mTreeBuilder->mSpeculativeLoader->mExecutor"); + cb.NoteXPCOMChild(static_cast (tmp->mExecutor)); } NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END @@ -143,7 +142,8 @@ nsHtml5StreamParser::nsHtml5StreamParser(nsHtml5TreeOpExecutor* aExecutor, : mFirstBuffer(new nsHtml5UTF16Buffer(NS_HTML5_STREAM_PARSER_READ_BUFFER_SIZE)) , mLastBuffer(mFirstBuffer) , mExecutor(aExecutor) - , mTreeBuilder(new nsHtml5TreeBuilder(mExecutor->GetStage())) + , mTreeBuilder(new nsHtml5TreeBuilder(mExecutor->GetStage(), + new nsHtml5SpeculativeLoader(mExecutor))) , mTokenizer(new nsHtml5Tokenizer(mTreeBuilder)) , mTokenizerMutex("nsHtml5StreamParser mTokenizerMutex") , mOwner(aOwner) @@ -199,13 +199,6 @@ nsHtml5StreamParser::~nsHtml5StreamParser() } } -void -nsHtml5StreamParser::SetSpeculativeLoaderWithDocument(nsIDocument* aDocument) { - NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); - mDocument = aDocument; - mTreeBuilder->SetSpeculativeLoaderWithDocument(aDocument); -} - nsresult nsHtml5StreamParser::GetChannel(nsIChannel** aChannel) { @@ -1039,7 +1032,7 @@ nsHtml5StreamParser::PostTimerFlush() sTimerInterval, nsITimer::TYPE_ONE_SHOT); - // TODO: (If mDocument isn't in the frontmost tab or If the user isn't + // TODO: (If the document isn't in the frontmost tab or If the user isn't // interacting with the browser) and this isn't every nth timer flush, return nsCOMPtr event = new nsHtml5StreamParserTimerFlusher(this); diff --git a/parser/html/nsHtml5StreamParser.h b/parser/html/nsHtml5StreamParser.h index 15e809628fed..09ea0c1ae84f 100644 --- a/parser/html/nsHtml5StreamParser.h +++ b/parser/html/nsHtml5StreamParser.h @@ -161,8 +161,6 @@ class nsHtml5StreamParser : public nsIStreamListener, mObserver = aObserver; } - void SetSpeculativeLoaderWithDocument(nsIDocument* aDocument); - nsresult GetChannel(nsIChannel** aChannel); /** @@ -453,11 +451,6 @@ class nsHtml5StreamParser : public nsIStreamListener, nsCOMPtr mExecutorFlusher; - /** - * The document wrapped by the speculative loader. - */ - nsCOMPtr mDocument; - /** * The chardet instance if chardet is enabled. */ diff --git a/parser/html/nsHtml5TreeBuilderCppSupplement.h b/parser/html/nsHtml5TreeBuilderCppSupplement.h index fc84920e52c0..833d634b6af8 100644 --- a/parser/html/nsHtml5TreeBuilderCppSupplement.h +++ b/parser/html/nsHtml5TreeBuilderCppSupplement.h @@ -50,7 +50,8 @@ // this really should be autogenerated... jArray nsHtml5TreeBuilder::ISINDEX_PROMPT = jArray(); -nsHtml5TreeBuilder::nsHtml5TreeBuilder(nsAHtml5TreeOpSink* aOpSink) +nsHtml5TreeBuilder::nsHtml5TreeBuilder(nsAHtml5TreeOpSink* aOpSink, + nsHtml5SpeculativeLoader* aSpeculativeLoader) : scriptingEnabled(PR_FALSE) , fragment(PR_FALSE) , contextNode(nsnull) @@ -59,6 +60,7 @@ nsHtml5TreeBuilder::nsHtml5TreeBuilder(nsAHtml5TreeOpSink* aOpSink) , mOpSink(aOpSink) , mHandles(new nsIContent*[NS_HTML5_TREE_BUILDER_HANDLE_ARRAY_LENGTH]) , mHandlesUsed(0) + , mSpeculativeLoader(aSpeculativeLoader) , mCurrentHtmlScriptIsAsyncOrDefer(PR_FALSE) #ifdef DEBUG , mActive(PR_FALSE) @@ -137,6 +139,24 @@ public: } }; +class nsHtml5SpeculativeManifest : public nsRunnable +{ +private: + nsRefPtr mSpeculativeLoader; + nsString mURL; +public: + nsHtml5SpeculativeManifest(nsHtml5SpeculativeLoader* aSpeculativeLoader, + const nsAString& aURL) + : mSpeculativeLoader(aSpeculativeLoader) + , mURL(aURL) + {} + NS_IMETHODIMP Run() + { + mSpeculativeLoader->ProcessManifest(mURL); + return NS_OK; + } +}; + nsIContent** nsHtml5TreeBuilder::createElement(PRInt32 aNamespace, nsIAtom* aName, nsHtml5HtmlAttributes* aAttributes) { @@ -201,6 +221,11 @@ nsHtml5TreeBuilder::createElement(PRInt32 aNamespace, nsIAtom* aName, nsHtml5Htm 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) { + Dispatch(new nsHtml5SpeculativeManifest(mSpeculativeLoader, *url)); + } } break; case kNameSpaceID_SVG: @@ -252,6 +277,13 @@ nsHtml5TreeBuilder::createElement(PRInt32 aNamespace, nsIAtom* aName, nsHtml5Htm (aAttributes->contains(nsHtml5AttributeName::ATTR_ASYNC) || aAttributes->contains(nsHtml5AttributeName::ATTR_DEFER)); } + } else if (aNamespace == kNameSpaceID_XHTML && nsHtml5Atoms::html == aName) { + nsString* url = aAttributes->getValue(nsHtml5AttributeName::ATTR_MANIFEST); + if (url) { + nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(); + NS_ASSERTION(treeOp, "Tree op allocation failed."); + treeOp->Init(eTreeOpProcessOfflineManifest, *url); + } } } @@ -439,18 +471,6 @@ nsHtml5TreeBuilder::appendDoctypeToDocument(nsIAtom* aName, nsString* aPublicId, void nsHtml5TreeBuilder::elementPushed(PRInt32 aNamespace, nsIAtom* aName, nsIContent** aElement) { - NS_ASSERTION(aNamespace == kNameSpaceID_XHTML || aNamespace == kNameSpaceID_SVG || aNamespace == kNameSpaceID_MathML, "Element isn't HTML, SVG or MathML!"); - NS_ASSERTION(aName, "Element doesn't have local name!"); - NS_ASSERTION(aElement, "No element!"); - // Give autoloading links a chance to fire - if (aNamespace == kNameSpaceID_XHTML) { - if (aName == nsHtml5Atoms::html) { - nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(); - NS_ASSERTION(treeOp, "Tree op allocation failed."); - treeOp->Init(eTreeOpProcessOfflineManifest, aElement); - return; - } - } } void @@ -664,12 +684,6 @@ nsHtml5TreeBuilder::AddSnapshotToScript(nsAHtml5TreeBuilderState* aSnapshot, PRI mOpQueue.ElementAt(mOpQueue.Length() - 1).SetSnapshot(aSnapshot, aLine); } -void -nsHtml5TreeBuilder::SetSpeculativeLoaderWithDocument(nsIDocument* aDocument) { - NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); - mSpeculativeLoader = new nsHtml5SpeculativeLoader(aDocument); -} - void nsHtml5TreeBuilder::DropSpeculativeLoader() { mSpeculativeLoader = nsnull; diff --git a/parser/html/nsHtml5TreeBuilderHSupplement.h b/parser/html/nsHtml5TreeBuilderHSupplement.h index bff38d1354db..dfba9ac0fcf8 100644 --- a/parser/html/nsHtml5TreeBuilderHSupplement.h +++ b/parser/html/nsHtml5TreeBuilderHSupplement.h @@ -60,7 +60,8 @@ public: - nsHtml5TreeBuilder(nsAHtml5TreeOpSink* aOpSink); + nsHtml5TreeBuilder(nsAHtml5TreeOpSink* aOpSink, + nsHtml5SpeculativeLoader* aSpeculativeLoader); ~nsHtml5TreeBuilder(); @@ -76,8 +77,10 @@ mOpQueue.Clear(); } - void SetSpeculativeLoaderWithDocument(nsIDocument* aDocument); - + PRBool HasSpeculativeLoader() { + return !!mSpeculativeLoader; + } + void DropSpeculativeLoader(); PRBool Flush(); diff --git a/parser/html/nsHtml5TreeOperation.cpp b/parser/html/nsHtml5TreeOperation.cpp index ebd4f08bbc7f..f9770238dddc 100644 --- a/parser/html/nsHtml5TreeOperation.cpp +++ b/parser/html/nsHtml5TreeOperation.cpp @@ -119,6 +119,9 @@ nsHtml5TreeOperation::~nsHtml5TreeOperation() case eTreeOpNeedsCharsetSwitchTo: delete[] mOne.charPtr; break; + case eTreeOpProcessOfflineManifest: + nsMemory::Free(mOne.unicharPtr); + break; default: // keep the compiler happy break; } @@ -554,8 +557,9 @@ nsHtml5TreeOperation::Perform(nsHtml5TreeOpExecutor* aBuilder, return rv; } case eTreeOpProcessOfflineManifest: { - nsIContent* node = *(mOne.node); - aBuilder->ProcessOfflineManifest(node); + PRUnichar* str = mOne.unicharPtr; + nsDependentString dependentString(str); + aBuilder->ProcessOfflineManifest(dependentString); return rv; } case eTreeOpMarkMalformedIfScript: { diff --git a/parser/html/nsHtml5TreeOperation.h b/parser/html/nsHtml5TreeOperation.h index 51c31fbfc463..5edafb5affed 100644 --- a/parser/html/nsHtml5TreeOperation.h +++ b/parser/html/nsHtml5TreeOperation.h @@ -41,6 +41,7 @@ #include "nsIContent.h" #include "nsHtml5DocumentMode.h" #include "nsHtml5HtmlAttributes.h" +#include "nsXPCOMStrings.h" class nsHtml5TreeOpExecutor; class nsHtml5StateSnapshot; @@ -263,6 +264,15 @@ class nsHtml5TreeOperation { mOne.charPtr = str; } + inline void Init(eHtml5TreeOperation aOpCode, const nsAString& aString) { + NS_PRECONDITION(mOpCode == eTreeOpUninitialized, + "Op code must be uninitialized when initializing."); + + PRUnichar* str = NS_StringCloneData(aString); + mOpCode = aOpCode; + mOne.unicharPtr = str; + } + inline void Init(eHtml5TreeOperation aOpCode, nsIContent** aNode, PRInt32 aInt) {