Bug 541079 - Make app cache selection happen before speculative loads in the HTML5 parser. r=bnewman.

This commit is contained in:
Henri Sivonen 2010-02-02 09:43:18 +02:00
Родитель 287034c014
Коммит 6b8df8aef8
11 изменённых файлов: 119 добавлений и 67 удалений

Просмотреть файл

@ -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<nsIApplicationCache> 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<nsIURI> 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;

Просмотреть файл

@ -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:

Просмотреть файл

@ -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);
}

Просмотреть файл

@ -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<nsIURI>
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<nsIURI> 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<nsICSSLoaderObserver> 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);
}

Просмотреть файл

@ -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<nsIDocument> mDocument;
nsRefPtr<nsHtml5TreeOpExecutor> mExecutor;
/**
* URLs already preloaded/preloading.

Просмотреть файл

@ -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<nsIContentSink*> (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<nsIStreamListener*>(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<nsIContentSink*> (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<nsIRunnable> event = new nsHtml5StreamParserTimerFlusher(this);

Просмотреть файл

@ -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<nsIRunnable> mExecutorFlusher;
/**
* The document wrapped by the speculative loader.
*/
nsCOMPtr<nsIDocument> mDocument;
/**
* The chardet instance if chardet is enabled.
*/

Просмотреть файл

@ -50,7 +50,8 @@
// this really should be autogenerated...
jArray<PRUnichar,PRInt32> nsHtml5TreeBuilder::ISINDEX_PROMPT = jArray<PRUnichar,PRInt32>();
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<nsHtml5SpeculativeLoader> 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;

Просмотреть файл

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

Просмотреть файл

@ -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: {

Просмотреть файл

@ -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) {