Bug 15146. Brutal sharing, Phase III. Turn on protoype, script, and style sheet caching. r=hyatt

This commit is contained in:
waterson%netscape.com 1999-11-02 01:14:07 +00:00
Родитель 649ac66265
Коммит 676716c335
16 изменённых файлов: 983 добавлений и 315 удалений

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

@ -27,6 +27,7 @@
#define nsIXULPrototypeCache_h__
#include "nsISupports.h"
class nsICSSStyleSheet;
class nsIURI;
class nsIXULPrototypeDocument;
@ -40,8 +41,20 @@ class nsIXULPrototypeCache : public nsISupports
public:
NS_DEFINE_STATIC_IID_ACCESSOR(NS_IXULPROTOTYPECACHE_IID);
NS_IMETHOD Get(nsIURI* aURI, nsIXULPrototypeDocument** _result) = 0;
NS_IMETHOD Put(nsIURI* aURI, nsIXULPrototypeDocument* aDocument) = 0;
NS_IMETHOD GetPrototype(nsIURI* aURI, nsIXULPrototypeDocument** _result) = 0;
NS_IMETHOD PutPrototype(nsIXULPrototypeDocument* aDocument) = 0;
NS_IMETHOD GetStyleSheet(nsIURI* aURI, nsICSSStyleSheet** _result) = 0;
NS_IMETHOD PutStyleSheet(nsICSSStyleSheet* aStyleSheet) = 0;
NS_IMETHOD GetScript(nsIURI* aURI, nsString& aScript, const char** aVersion) = 0;
NS_IMETHOD PutScript(nsIURI* aURI, const nsString& aScript, const char* aVersion) = 0;
/**
* Flush the cache; remove all XUL prototype documents, style
* sheets, and scripts.
*/
NS_IMETHOD Flush() = 0;
};

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

@ -71,6 +71,7 @@
#include "nsIXULDocument.h"
#include "nsIXULKeyListener.h"
#include "nsIXULPrototypeDocument.h"
#include "nsIXULPrototypeCache.h"
#include "nsLayoutCID.h"
#include "nsNeckoUtil.h"
#include "nsRDFCID.h"
@ -102,6 +103,8 @@ static const char kXULNameSpaceURI[] = XUL_NAMESPACE_URI;
static NS_DEFINE_CID(kCSSLoaderCID, NS_CSS_LOADER_CID);
static NS_DEFINE_CID(kCSSParserCID, NS_CSSPARSER_CID);
static NS_DEFINE_CID(kNameSpaceManagerCID, NS_NAMESPACEMANAGER_CID);
static NS_DEFINE_CID(kXULContentUtilsCID, NS_XULCONTENTUTILS_CID);
static NS_DEFINE_CID(kXULPrototypeCacheCID, NS_XULPROTOTYPECACHE_CID);
//----------------------------------------------------------------------
@ -142,6 +145,8 @@ protected:
// pseudo-constants
static nsrefcnt gRefCnt;
static nsINameSpaceManager* gNameSpaceManager;
static nsIXULContentUtils* gXULUtils;
static nsIXULPrototypeCache* gXULCache;
static nsIAtom* kClassAtom;
static nsIAtom* kIdAtom;
@ -240,6 +245,8 @@ protected:
nsrefcnt XULContentSinkImpl::gRefCnt;
nsINameSpaceManager* XULContentSinkImpl::gNameSpaceManager;
nsIXULContentUtils* XULContentSinkImpl::gXULUtils;
nsIXULPrototypeCache* XULContentSinkImpl::gXULCache;
nsIAtom* XULContentSinkImpl::kClassAtom;
nsIAtom* XULContentSinkImpl::kIdAtom;
@ -377,6 +384,15 @@ XULContentSinkImpl::XULContentSinkImpl(nsresult& rv)
kScriptAtom = NS_NewAtom("script");
kStyleAtom = NS_NewAtom("style");
kTemplateAtom = NS_NewAtom("template");
rv = nsServiceManager::GetService(kXULContentUtilsCID,
NS_GET_IID(nsIXULContentUtils),
(nsISupports**) &gXULUtils);
if (NS_FAILED(rv)) return;
rv = nsServiceManager::GetService(kXULPrototypeCacheCID,
NS_GET_IID(nsIXULPrototypeCache),
(nsISupports**) &gXULCache);
}
#ifdef PR_LOGGING
@ -390,11 +406,6 @@ XULContentSinkImpl::XULContentSinkImpl(nsresult& rv)
XULContentSinkImpl::~XULContentSinkImpl()
{
#ifdef DEBUG_REFS
--gInstanceCount;
fprintf(stdout, "%d - RDF: XULContentSinkImpl\n", gInstanceCount);
#endif
NS_IF_RELEASE(mParser); // XXX should've been released by now, unless error.
{
@ -475,6 +486,16 @@ XULContentSinkImpl::~XULContentSinkImpl()
NS_IF_RELEASE(kScriptAtom);
NS_IF_RELEASE(kStyleAtom);
NS_IF_RELEASE(kTemplateAtom);
if (gXULUtils) {
nsServiceManager::ReleaseService(kXULContentUtilsCID, gXULUtils);
gXULUtils = nsnull;
}
if (gXULCache) {
nsServiceManager::ReleaseService(kXULPrototypeCacheCID, gXULCache);
gXULCache = nsnull;
}
}
}
@ -821,7 +842,7 @@ XULContentSinkImpl::ProcessStyleLink(nsIContent* aElement,
{
static const char kCSSType[] = "text/css";
nsresult result = NS_OK;
nsresult rv = NS_OK;
if (aAlternate) { // if alternate, does it have title?
if (0 == aTitle.Length()) { // alternates must have title
@ -835,11 +856,35 @@ XULContentSinkImpl::ProcessStyleLink(nsIContent* aElement,
if ((0 == mimeType.Length()) || mimeType.EqualsIgnoreCase(kCSSType)) {
nsCOMPtr<nsIURI> url;
result = NS_NewURI(getter_AddRefs(url), aHref, mDocumentURL);
if (NS_OK != result) {
rv = NS_NewURI(getter_AddRefs(url), aHref, mDocumentURL);
if (NS_OK != rv) {
return NS_OK; // The URL is bad, move along, don't propagate the error (for now)
}
// Add the style sheet reference to the prototype
mPrototype->AddStyleSheetReference(url);
// See if the style sheet is in the style sheet cache. If so,
// just use it.
if (gXULUtils->UseXULCache()) {
nsCOMPtr<nsICSSStyleSheet> sheet;
rv = gXULCache->GetStyleSheet(url, getter_AddRefs(sheet));
if (NS_SUCCEEDED(rv) && sheet) {
nsCOMPtr<nsICSSStyleSheet> newsheet;
rv = sheet->Clone(*getter_AddRefs(newsheet));
if (NS_SUCCEEDED(rv) && newsheet) {
nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocument);
if (doc) {
doc->AddStyleSheet(newsheet);
return NS_OK;
}
}
}
}
// Nope, we need to load it asynchronously
PRBool blockParser = PR_FALSE;
if (! aAlternate) {
if (0 < aTitle.Length()) { // possibly preferred sheet
@ -862,16 +907,16 @@ XULContentSinkImpl::ProcessStyleLink(nsIContent* aElement,
// sheet in a fairly random location if we're loading an
// overlay. Should we just use a Very Large Number?
PRBool doneLoading;
result = mCSSLoader->LoadStyleLink(aElement, url, aTitle, aMedia, kNameSpaceID_Unknown,
mStyleSheetCount++,
((blockParser) ? mParser : nsnull),
doneLoading);
if (NS_SUCCEEDED(result) && blockParser && (! doneLoading)) {
result = NS_ERROR_HTMLPARSER_BLOCK;
rv = mCSSLoader->LoadStyleLink(aElement, url, aTitle, aMedia, kNameSpaceID_Unknown,
mStyleSheetCount++,
((blockParser) ? mParser : nsnull),
doneLoading);
if (NS_SUCCEEDED(rv) && blockParser && (! doneLoading)) {
rv = NS_ERROR_HTMLPARSER_BLOCK;
}
}
return result;
return rv;
}

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

@ -53,6 +53,7 @@
#include "nsIChromeRegistry.h"
#include "nsIComponentManager.h"
#include "nsIContentViewer.h"
#include "nsICSSStyleSheet.h"
#include "nsIDOMEvent.h"
#include "nsIDOMEventListener.h"
#include "nsIDOMEventReceiver.h"
@ -196,7 +197,7 @@ nsINameSpaceManager* nsXULDocument::gNameSpaceManager;
PRInt32 nsXULDocument::kNameSpaceID_XUL;
nsIXULContentUtils* nsXULDocument::gXULUtils;
nsIXULPrototypeCache* nsXULDocument::gXULPrototypeCache;
nsIXULPrototypeCache* nsXULDocument::gXULCache;
PRLogModuleInfo* nsXULDocument::gXULLog;
@ -330,9 +331,9 @@ nsXULDocument::~nsXULDocument()
gXULUtils = nsnull;
}
if (gXULPrototypeCache) {
nsServiceManager::ReleaseService(kXULPrototypeCacheCID, gXULPrototypeCache);
gXULPrototypeCache = nsnull;
if (gXULCache) {
nsServiceManager::ReleaseService(kXULPrototypeCacheCID, gXULCache);
gXULCache = nsnull;
}
}
}
@ -518,6 +519,10 @@ nsXULDocument::StartDocumentLoad(const char* aCommand,
{
nsresult rv;
#if defined(DEBUG_waterson) || defined(DEBUG_hyatt)
mLoadStart = PR_Now();
#endif
nsCOMPtr<nsIURI> url;
rv = aChannel->GetURI(getter_AddRefs(url));
if (NS_FAILED(rv)) return rv;
@ -866,6 +871,15 @@ nsXULDocument::AddStyleSheet(nsIStyleSheet* aSheet)
else {
mStyleSheets.AppendElement(aSheet);
}
// Put the style sheet into the XUL cache if the XUL cache is
// actually enabled and the document is chrome.
if (gXULUtils->UseXULCache() && IsChromeURI(mDocumentURL)) {
nsCOMPtr<nsICSSStyleSheet> css = do_QueryInterface(aSheet);
if (css) {
gXULCache->PutStyleSheet(css);
}
}
}
NS_ADDREF(aSheet);
@ -902,6 +916,16 @@ NS_IMETHODIMP
nsXULDocument::InsertStyleSheetAt(nsIStyleSheet* aSheet, PRInt32 aIndex, PRBool aNotify)
{
NS_PRECONDITION(nsnull != aSheet, "null ptr");
// Put the style sheet into the XUL cache if the XUL cache is
// actually enabled and the document is chrome.
if (gXULUtils->UseXULCache() && IsChromeURI(mDocumentURL)) {
nsCOMPtr<nsICSSStyleSheet> css = do_QueryInterface(aSheet);
if (css) {
gXULCache->PutStyleSheet(css);
}
}
mStyleSheets.InsertElementAt(aSheet, aIndex + 1); // offset by one for attribute sheet
NS_ADDREF(aSheet);
@ -932,6 +956,7 @@ nsXULDocument::InsertStyleSheetAt(nsIStyleSheet* aSheet, PRInt32 aIndex, PRBool
}
}
}
return NS_OK;
}
@ -1055,6 +1080,22 @@ NS_IMETHODIMP
nsXULDocument::EndLoad()
{
nsresult rv;
// Whack the prototype document into the cache so that the next
// time somebody asks for it, they don't need to load it by hand.
nsCOMPtr<nsIURI> uri;
rv = mCurrentPrototype->GetURI(getter_AddRefs(uri));
if (NS_FAILED(rv)) return rv;
if (gXULUtils->UseXULCache() && IsChromeURI(mDocumentURL)) {
// If it's a 'chrome:' prototype document, then put it into
// the prototype cache; other XUL documents will be reloaded
// each time.
rv = gXULCache->PutPrototype(mCurrentPrototype);
if (NS_FAILED(rv)) return rv;
}
// Now walk the prototype to build content.
rv = PrepareToWalk();
if (NS_FAILED(rv)) return rv;
@ -1856,10 +1897,12 @@ nsXULDocument::CreateFromPrototype(const char* aCommand,
rv = PrepareStyleSheets(mDocumentURL);
if (NS_FAILED(rv)) return rv;
return NS_OK;
mCommand = aCommand;
rv = AddPrototypeSheets();
if (NS_FAILED(rv)) return rv;
// Now create the delegates from the prototype
rv = PrepareToWalk();
if (NS_FAILED(rv)) return rv;
@ -3097,7 +3140,7 @@ static const char kXULNameSpaceURI[] = XUL_NAMESPACE_URI;
rv = nsServiceManager::GetService(kXULPrototypeCacheCID,
NS_GET_IID(nsIXULPrototypeCache),
(nsISupports**) &gXULPrototypeCache);
(nsISupports**) &gXULCache);
if (NS_FAILED(rv)) return rv;
}
@ -4102,14 +4145,17 @@ nsXULDocument::PrepareToWalk()
// Push the overlay references onto our overlay processing
// stack. GetOverlayReferences() will return an ordered array of
// overlay references...
nsVoidArray overlays;
rv = mCurrentPrototype->GetOverlayReferences(overlays);
nsCOMPtr<nsISupportsArray> overlays;
rv = mCurrentPrototype->GetOverlayReferences(getter_AddRefs(overlays));
if (NS_FAILED(rv)) return rv;
// ...and we preserve this ordering by appending to our
// mUnloadedOverlays array in reverse order
for (PRInt32 i = overlays.Count() - 1; i >= 0; --i) {
mUnloadedOverlays->AppendElement(NS_REINTERPRET_CAST(nsIURI*, overlays[i]));
PRUint32 count;
overlays->Count(&count);
for (PRInt32 i = count - 1; i >= 0; --i) {
nsCOMPtr<nsISupports> isupports = dont_AddRef(overlays->ElementAt(i));
mUnloadedOverlays->AppendElement(isupports);
}
@ -4422,11 +4468,15 @@ nsXULDocument::ResumeWalk()
// Look in the prototype cache for the prototype document with
// the specified URI.
rv = gXULPrototypeCache->Get(uri, getter_AddRefs(mCurrentPrototype));
rv = gXULCache->GetPrototype(uri, getter_AddRefs(mCurrentPrototype));
if (NS_FAILED(rv)) return rv;
if (mCurrentPrototype) {
// Found the overlay's prototype in the cache: walk it!
if (gXULUtils->UseXULCache() && mCurrentPrototype) {
// Found the overlay's prototype in the cache.
rv = AddPrototypeSheets();
if (NS_FAILED(rv)) return rv;
// Now prepare to walk the prototype to create its content
rv = PrepareToWalk();
if (NS_FAILED(rv)) return rv;
@ -4460,6 +4510,15 @@ nsXULDocument::ResumeWalk()
// If we get here, there is nothing left for us to walk. The content
// model is built and ready for layout.
#if defined(DEBUG_waterson) || defined(DEBUG_hyatt)
{
nsTime finish = PR_Now();
nsInt64 diff64 = finish - mLoadStart;
PRInt32 diff = PRInt32(diff64 / nsInt64(1000));
printf("***** XUL document loaded in %ldmsec\n", diff);
}
#endif
rv = ResolveForwardReferences();
if (NS_FAILED(rv)) return rv;
@ -4476,6 +4535,21 @@ nsXULDocument::ResumeWalk()
}
}
#if defined(DEBUG_waterson) || defined(DEBUG_hyatt)
{
nsTime finish = PR_Now();
nsInt64 diff64 = finish - mLoadStart;
PRInt32 diff = PRInt32(diff64 / nsInt64(1000));
printf("***** XUL document flowed in %ldmsec\n", diff);
}
{
nsInt64 now(PR_Now());
now /= nsInt64(1000);
printf("### ResumeWalk complete %ld\n", PRInt32(now));
}
#endif
return rv;
}
@ -4487,11 +4561,17 @@ nsXULDocument::LoadScript(nsIURI* aURI, const char* aVersion, PRBool* aBlock)
nsresult rv;
// XXX Look in a script cache to see if we already have it
nsAutoString script;
const char* version;
rv = gXULCache->GetScript(aURI, script, &version);
if (NS_FAILED(rv)) return rv;
if (gXULUtils->UseXULCache() && script.Length()) {
// We've found it in the cache. Just re-evaluate it.
rv = EvaluateScript(aURI, script, 1, version);
if (NS_FAILED(rv)) return rv;
if (/* cached */ PR_FALSE) {
*aBlock = PR_FALSE;
// XXX brendan, shaver: do some magic here
}
else {
// Set the current script URL so that the DoneLoadingScript()
@ -4538,6 +4618,12 @@ nsXULDocument::DoneLoadingScript(nsIUnicharStreamLoader* aLoader,
if (NS_SUCCEEDED(aStatus)) {
rv = doc->EvaluateScript(doc->mCurrentScriptURL, aData, 1,
doc->mCurrentScriptLanguageVersion);
if (IsChromeURI(doc->mDocumentURL)) {
gXULCache->PutScript(doc->mCurrentScriptURL,
aData,
doc->mCurrentScriptLanguageVersion);
}
}
// balance the addref we added in LoadScript()
@ -4842,10 +4928,23 @@ nsXULDocument::CheckTemplateBuilder(nsIContent* aElement)
NS_ASSERTION(NS_SUCCEEDED(rv), "unable to set builder's database");
if (NS_FAILED(rv)) return rv;
// Force construction of immediate template sub-content _now_.
rv = builder->CreateContents(aElement);
NS_ASSERTION(NS_SUCCEEDED(rv), "unable to create template contents");
if (NS_FAILED(rv)) return rv;
nsCOMPtr<nsIXULContent> xulcontent = do_QueryInterface(aElement);
if (xulcontent) {
// Mark the XUL element as being lazy, so the template builder
// will run when layout first asks for these nodes.
//
//rv = xulcontent->ClearLazyState(eTemplateContentsBuilt | eContainerContentsBuilt);
//if (NS_FAILED(rv)) return rv;
xulcontent->SetLazyState(nsIXULContent::eChildrenMustBeRebuilt);
if (NS_FAILED(rv)) return rv;
}
else {
// Force construction of immediate template sub-content _now_.
rv = builder->CreateContents(aElement);
NS_ASSERTION(NS_SUCCEEDED(rv), "unable to create template contents");
if (NS_FAILED(rv)) return rv;
}
return NS_OK;
}
@ -4895,6 +4994,45 @@ nsXULDocument::CheckBroadcasterHookup(nsIContent* aElement)
}
nsresult
nsXULDocument::AddPrototypeSheets()
{
// Add mCurrentPrototype's style sheets to the document.
nsresult rv;
nsCOMPtr<nsISupportsArray> sheets;
rv = mCurrentPrototype->GetStyleSheetReferences(getter_AddRefs(sheets));
if (NS_FAILED(rv)) return rv;
PRUint32 count;
sheets->Count(&count);
for (PRUint32 i = 0; i < count; ++i) {
nsCOMPtr<nsISupports> isupports = dont_AddRef(sheets->ElementAt(i));
nsCOMPtr<nsIURI> uri = do_QueryInterface(isupports);
NS_ASSERTION(uri != nsnull, "not a URI!!!");
if (! uri)
return NS_ERROR_UNEXPECTED;
nsCOMPtr<nsICSSStyleSheet> sheet;
rv = gXULCache->GetStyleSheet(uri, getter_AddRefs(sheet));
if (NS_FAILED(rv)) return rv;
NS_ASSERTION(sheet != nsnull, "uh oh, sheet wasn't in the cache. go reload it");
if (! sheet)
return NS_ERROR_UNEXPECTED;
nsCOMPtr<nsICSSStyleSheet> newsheet;
rv = sheet->Clone(*getter_AddRefs(newsheet));
if (NS_FAILED(rv)) return rv;
AddStyleSheet(newsheet);
}
return NS_OK;
}
//----------------------------------------------------------------------
//
// nsXULDocument::OverlayForwardReference
@ -5324,3 +5462,19 @@ nsXULDocument::ProcessCommonAttributes(nsIContent* aElement)
return NS_OK;
}
PRBool
nsXULDocument::IsChromeURI(nsIURI* aURI)
{
nsresult rv;
nsXPIDLCString protocol;
rv = aURI->GetScheme(getter_Copies(protocol));
if (NS_SUCCEEDED(rv)) {
if (PL_strcmp(protocol, "chrome") == 0) {
return PR_TRUE;
}
}
return PR_FALSE;
}

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

@ -51,6 +51,7 @@
#include "nsIXULDocument.h"
#include "nsIXULPrototypeDocument.h"
#include "nsRDFDOMNodeList.h"
#include "nsTime.h"
#include "nsVoidArray.h"
#include "nsWeakPtr.h"
#include "nsWeakReference.h"
@ -459,7 +460,7 @@ protected:
static PRInt32 kNameSpaceID_XUL;
static nsIXULContentUtils* gXULUtils;
static nsIXULPrototypeCache* gXULPrototypeCache;
static nsIXULPrototypeCache* gXULCache;
static PRLogModuleInfo* gXULLog;
@ -632,6 +633,11 @@ protected:
*/
nsresult CheckBroadcasterHookup(nsIContent* aElement);
/**
* Add the current prototype's style sheets to the document.
*/
nsresult AddPrototypeSheets();
/**
* Used to resolve broadcaster references
*/
@ -686,6 +692,10 @@ protected:
nsresult
ProcessCommonAttributes(nsIContent* aElement);
static
PRBool
IsChromeURI(nsIURI* aURI);
/**
* The current prototype that we are walking to construct the
* content model.
@ -714,6 +724,11 @@ protected:
* prototype walk.
*/
nsresult ResumeWalk();
#if defined(DEBUG_waterson) || defined(DEBUG_hyatt)
// timing
nsTime mLoadStart;
#endif
};

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

@ -25,10 +25,14 @@
#include "nsCOMPtr.h"
#include "nsXPIDLString.h"
#include "nsICSSStyleSheet.h"
#include "nsIXULPrototypeCache.h"
#include "nsIXULPrototypeDocument.h"
#include "nsIURI.h"
#include "plhash.h"
#include "nsHashtable.h"
#include "nsXPIDLString.h"
#include "plstr.h"
class nsXULPrototypeCache : public nsIXULPrototypeCache
{
@ -36,8 +40,16 @@ public:
// nsISupports
NS_DECL_ISUPPORTS
NS_IMETHOD Get(nsIURI* aURI, nsIXULPrototypeDocument** _result);
NS_IMETHOD Put(nsIURI* aURI, nsIXULPrototypeDocument* aDocument);
NS_IMETHOD GetPrototype(nsIURI* aURI, nsIXULPrototypeDocument** _result);
NS_IMETHOD PutPrototype(nsIXULPrototypeDocument* aDocument);
NS_IMETHOD GetStyleSheet(nsIURI* aURI, nsICSSStyleSheet** _result);
NS_IMETHOD PutStyleSheet(nsICSSStyleSheet* aStyleSheet);
NS_IMETHOD GetScript(nsIURI* aURI, nsString& aScript, const char** aVersion);
NS_IMETHOD PutScript(nsIURI* aURI, const nsString& aScript, const char* aVersion);
NS_IMETHOD Flush();
protected:
friend NS_IMETHODIMP
@ -45,13 +57,45 @@ protected:
nsXULPrototypeCache();
virtual ~nsXULPrototypeCache();
static PRIntn ReleaseTableEntry(PLHashEntry* aHashEntry, PRIntn aIndex, void* aClosure);
nsresult Init();
static PLHashNumber Hash(const void* aKey);
static PRIntn CompareKeys(const void* aKey1, const void* aKey2);
static PRBool
ReleaseScriptEntryEnumFunc(nsHashKey* aKey, void* aData, void* aClosure);
PLHashTable* mTable;
nsSupportsHashtable mPrototypeTable;
nsSupportsHashtable mStyleSheetTable;
nsHashtable mScriptTable;
class nsIURIKey : public nsHashKey {
protected:
nsCOMPtr<nsIURI> mKey;
public:
nsIURIKey(nsIURI* key) : mKey(key) {}
~nsIURIKey(void) {}
PRUint32 HashValue(void) const {
nsXPIDLCString spec;
mKey->GetSpec(getter_Copies(spec));
return (PRUint32) PL_HashString(spec);
}
PRBool Equals(const nsHashKey *aKey) const {
PRBool eq;
mKey->Equals( ((nsIURIKey*) aKey)->mKey, &eq );
return eq;
}
nsHashKey *Clone(void) const {
return new nsIURIKey(mKey);
}
};
class ScriptEntry {
public:
nsString mScript;
const char* mVersion;
};
};
@ -64,36 +108,18 @@ nsXULPrototypeCache::nsXULPrototypeCache()
nsXULPrototypeCache::~nsXULPrototypeCache()
{
if (mTable) {
PL_HashTableEnumerateEntries(mTable, ReleaseTableEntry, nsnull);
PL_HashTableDestroy(mTable);
}
mScriptTable.Enumerate(ReleaseScriptEntryEnumFunc, nsnull);
}
PRIntn
nsXULPrototypeCache::ReleaseTableEntry(PLHashEntry* aHashEntry, PRIntn aIndex, void* aClosure)
PRBool
nsXULPrototypeCache::ReleaseScriptEntryEnumFunc(nsHashKey* aKey, void* aData, void* aClosure)
{
nsIURI* key = NS_REINTERPRET_CAST(nsIURI*, NS_CONST_CAST(void*, aHashEntry->key));
NS_RELEASE(key);
nsIXULPrototypeDocument* value = NS_REINTERPRET_CAST(nsIXULPrototypeDocument*, aHashEntry->value);
NS_RELEASE(value);
return HT_ENUMERATE_REMOVE;
ScriptEntry* entry = NS_REINTERPRET_CAST(ScriptEntry*, aData);
delete entry;
return PR_TRUE;
}
nsresult
nsXULPrototypeCache::Init()
{
mTable = PL_NewHashTable(16, Hash, CompareKeys, PL_CompareValues, nsnull, nsnull);
if (! mTable)
return NS_ERROR_OUT_OF_MEMORY;
return NS_OK;
}
NS_IMPL_ISUPPORTS1(nsXULPrototypeCache, nsIXULPrototypeCache);
@ -109,11 +135,6 @@ NS_NewXULPrototypeCache(nsISupports* aOuter, REFNSIID aIID, void** aResult)
return NS_ERROR_OUT_OF_MEMORY;
nsresult rv;
rv = result->Init();
if (NS_FAILED(rv)) {
delete result;
return rv;
}
NS_ADDREF(result);
rv = result->QueryInterface(aIID, aResult);
@ -122,36 +143,98 @@ NS_NewXULPrototypeCache(nsISupports* aOuter, REFNSIID aIID, void** aResult)
return rv;
}
PLHashNumber
nsXULPrototypeCache::Hash(const void* aKey)
{
nsIURI* uri = NS_REINTERPRET_CAST(nsIURI*, NS_CONST_CAST(void*, aKey));
nsXPIDLCString spec;
uri->GetSpec(getter_Copies(spec));
return PL_HashString(spec);
}
PRIntn
nsXULPrototypeCache::CompareKeys(const void* aKey1, const void* aKey2)
{
nsIURI* uri1 = NS_REINTERPRET_CAST(nsIURI*, NS_CONST_CAST(void*, aKey1));
nsIURI* uri2 = NS_REINTERPRET_CAST(nsIURI*, NS_CONST_CAST(void*, aKey2));
PRBool eq;
uri1->Equals(uri2, &eq);
return eq;
}
//----------------------------------------------------------------------
NS_IMETHODIMP
nsXULPrototypeCache::Get(nsIURI* aURI, nsIXULPrototypeDocument** _result)
nsXULPrototypeCache::GetPrototype(nsIURI* aURI, nsIXULPrototypeDocument** _result)
{
nsIURIKey key(aURI);
*_result = NS_STATIC_CAST(nsIXULPrototypeDocument*, mPrototypeTable.Get(&key));
return NS_OK;
}
NS_IMETHODIMP
nsXULPrototypeCache::Put(nsIURI* aURI, nsIXULPrototypeDocument* aDocument)
nsXULPrototypeCache::PutPrototype(nsIXULPrototypeDocument* aDocument)
{
nsresult rv;
nsCOMPtr<nsIURI> uri;
rv = aDocument->GetURI(getter_AddRefs(uri));
nsIURIKey key(uri);
mPrototypeTable.Put(&key, aDocument);
return NS_OK;
}
NS_IMETHODIMP
nsXULPrototypeCache::GetStyleSheet(nsIURI* aURI, nsICSSStyleSheet** _result)
{
nsIURIKey key(aURI);
*_result = NS_STATIC_CAST(nsICSSStyleSheet*, mStyleSheetTable.Get(&key));
return NS_OK;
}
NS_IMETHODIMP
nsXULPrototypeCache::PutStyleSheet(nsICSSStyleSheet* aStyleSheet)
{
nsresult rv;
nsCOMPtr<nsIURI> uri;
rv = aStyleSheet->GetURL(*getter_AddRefs(uri));
nsIURIKey key(uri);
mStyleSheetTable.Put(&key, aStyleSheet);
return NS_OK;
}
NS_IMETHODIMP
nsXULPrototypeCache::GetScript(nsIURI* aURI, nsString& aScript, const char** aVersion)
{
nsIURIKey key(aURI);
const ScriptEntry* entry = NS_REINTERPRET_CAST(const ScriptEntry*, mScriptTable.Get(&key));
if (entry) {
aScript = entry->mScript;
*aVersion = entry->mVersion;
}
else {
aScript.Truncate();
*aVersion = nsnull;
}
return NS_OK;
}
NS_IMETHODIMP
nsXULPrototypeCache::PutScript(nsIURI* aURI, const nsString& aScript, const char* aVersion)
{
ScriptEntry* newentry = new ScriptEntry();
if (! newentry)
return NS_ERROR_OUT_OF_MEMORY;
newentry->mScript = aScript;
newentry->mVersion = aVersion;
nsIURIKey key(aURI);
ScriptEntry* oldentry = NS_REINTERPRET_CAST(ScriptEntry*, mScriptTable.Put(&key, newentry));
delete oldentry;
return NS_OK;
}
NS_IMETHODIMP
nsXULPrototypeCache::Flush()
{
mPrototypeTable.Reset();
mStyleSheetTable.Reset();
mScriptTable.Reset(ReleaseScriptEntryEnumFunc, nsnull);
return NS_OK;
}

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

@ -25,7 +25,6 @@
#include "nsCOMPtr.h"
#include "nsISupportsArray.h"
#include "nsIStyleSheet.h"
#include "nsIXULPrototypeDocument.h"
#include "nsIURI.h"
#include "nsString2.h"
@ -48,11 +47,11 @@ public:
NS_IMETHOD GetRootElement(nsXULPrototypeElement** aResult);
NS_IMETHOD SetRootElement(nsXULPrototypeElement* aElement);
NS_IMETHOD AddStyleSheet(nsIStyleSheet* aStyleSheet);
NS_IMETHOD GetStyleSheets(nsVoidArray& aResult);
NS_IMETHOD AddStyleSheetReference(nsIURI* aStyleSheet);
NS_IMETHOD GetStyleSheetReferences(nsISupportsArray** aResult);
NS_IMETHOD AddOverlayReference(nsIURI* aURI);
NS_IMETHOD GetOverlayReferences(nsVoidArray& aResult);
NS_IMETHOD GetOverlayReferences(nsISupportsArray** aResult);
NS_IMETHOD GetHeaderData(nsIAtom* aField, nsString& aData) const;
NS_IMETHOD SetHeaderData(nsIAtom* aField, const nsString& aData);
@ -60,7 +59,7 @@ public:
protected:
nsCOMPtr<nsIURI> mURI;
nsXULPrototypeElement* mRoot;
nsCOMPtr<nsISupportsArray> mStyleSheets;
nsCOMPtr<nsISupportsArray> mStyleSheetReferences;
nsCOMPtr<nsISupportsArray> mOverlayReferences;
nsXULPrototypeDocument();
@ -86,7 +85,7 @@ nsXULPrototypeDocument::Init()
{
nsresult rv;
rv = NS_NewISupportsArray(getter_AddRefs(mStyleSheets));
rv = NS_NewISupportsArray(getter_AddRefs(mStyleSheetReferences));
if (NS_FAILED(rv)) return rv;
rv = NS_NewISupportsArray(getter_AddRefs(mOverlayReferences));
@ -166,33 +165,22 @@ nsXULPrototypeDocument::SetRootElement(nsXULPrototypeElement* aElement)
NS_IMETHODIMP
nsXULPrototypeDocument::AddStyleSheet(nsIStyleSheet* aStyleSheet)
nsXULPrototypeDocument::AddStyleSheetReference(nsIURI* aURI)
{
NS_PRECONDITION(aStyleSheet != nsnull, "null ptr");
if (! aStyleSheet)
NS_PRECONDITION(aURI != nsnull, "null ptr");
if (! aURI)
return NS_ERROR_NULL_POINTER;
mStyleSheets->AppendElement(aStyleSheet);
mStyleSheetReferences->AppendElement(aURI);
return NS_OK;
}
NS_IMETHODIMP
nsXULPrototypeDocument::GetStyleSheets(nsVoidArray& aResult)
nsXULPrototypeDocument::GetStyleSheetReferences(nsISupportsArray** aResult)
{
nsresult rv;
aResult.Clear();
PRUint32 cnt;
rv = mStyleSheets->Count(&cnt);
if (NS_FAILED(rv)) return rv;
for (PRInt32 i = 0; i < PRInt32(cnt); ++i) {
nsIStyleSheet* sheet = NS_REINTERPRET_CAST(nsIStyleSheet*, mStyleSheets->ElementAt(i));
aResult.AppendElement(sheet);
NS_RELEASE(sheet);
}
*aResult = mStyleSheetReferences;
NS_ADDREF(*aResult);
return NS_OK;
}
@ -211,21 +199,10 @@ nsXULPrototypeDocument::AddOverlayReference(nsIURI* aURI)
NS_IMETHODIMP
nsXULPrototypeDocument::GetOverlayReferences(nsVoidArray& aResult)
nsXULPrototypeDocument::GetOverlayReferences(nsISupportsArray** aResult)
{
nsresult rv;
aResult.Clear();
PRUint32 cnt;
rv = mOverlayReferences->Count(&cnt);
if (NS_FAILED(rv)) return rv;
for (PRInt32 i = 0; i < PRInt32(cnt); ++i) {
nsIURI* ref = NS_REINTERPRET_CAST(nsIURI*, mOverlayReferences->ElementAt(i));
aResult.AppendElement(ref);
NS_RELEASE(ref);
}
*aResult = mOverlayReferences;
NS_ADDREF(*aResult);
return NS_OK;
}

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

@ -43,12 +43,14 @@
#include "nsIRDFNode.h"
#include "nsINameSpace.h"
#include "nsINameSpaceManager.h"
#include "nsIPref.h"
#include "nsIRDFService.h"
#include "nsIServiceManager.h"
#include "nsITextContent.h"
#include "nsIURL.h"
#include "nsIXMLContent.h"
#include "nsIXULContentUtils.h"
#include "nsIXULPrototypeCache.h"
#include "nsLayoutCID.h"
#include "nsNeckoUtil.h"
#include "nsRDFCID.h"
@ -67,23 +69,15 @@
#include "nsDateTimeFormatCID.h"
#include "nsIScriptableDateFormat.h"
static NS_DEFINE_IID(kIContentIID, NS_ICONTENT_IID);
static NS_DEFINE_IID(kIRDFResourceIID, NS_IRDFRESOURCE_IID);
static NS_DEFINE_IID(kIRDFLiteralIID, NS_IRDFLITERAL_IID);
static NS_DEFINE_IID(kIRDFIntIID, NS_IRDFINT_IID);
static NS_DEFINE_IID(kIRDFDateIID, NS_IRDFDATE_IID);
static NS_DEFINE_IID(kITextContentIID, NS_ITEXT_CONTENT_IID); // XXX grr...
static NS_DEFINE_CID(kTextNodeCID, NS_TEXTNODE_CID);
static NS_DEFINE_CID(kRDFServiceCID, NS_RDFSERVICE_CID);
static NS_DEFINE_CID(kLocaleFactoryCID, NS_LOCALEFACTORY_CID);
static NS_DEFINE_IID(kILocaleFactoryIID, NS_ILOCALEFACTORY_IID);
static NS_DEFINE_CID(kLocaleCID, NS_LOCALE_CID);
static NS_DEFINE_IID(kILocaleIID, NS_ILOCALE_IID);
static NS_DEFINE_CID(kNameSpaceManagerCID, NS_NAMESPACEMANAGER_CID);
static NS_DEFINE_CID(kDateTimeFormatCID, NS_DATETIMEFORMAT_CID);
static NS_DEFINE_CID(kDateTimeFormatIID, NS_IDATETIMEFORMAT_IID);
static NS_DEFINE_CID(kDateTimeFormatCID, NS_DATETIMEFORMAT_CID);
static NS_DEFINE_CID(kDateTimeFormatIID, NS_IDATETIMEFORMAT_IID);
static NS_DEFINE_CID(kLocaleCID, NS_LOCALE_CID);
static NS_DEFINE_CID(kLocaleFactoryCID, NS_LOCALEFACTORY_CID);
static NS_DEFINE_CID(kNameSpaceManagerCID, NS_NAMESPACEMANAGER_CID);
static NS_DEFINE_CID(kRDFServiceCID, NS_RDFSERVICE_CID);
static NS_DEFINE_CID(kTextNodeCID, NS_TEXTNODE_CID);
static NS_DEFINE_CID(kXULPrototypeCacheCID, NS_XULPROTOTYPECACHE_CID);
//------------------------------------------------------------------------
@ -113,6 +107,11 @@ protected:
static EventHandlerMapEntry kEventHandlerMap[];
static PRBool gDisableXULCache;
static int
DisableXULCacheChangedCallback(const char* aPrefName, void* aClosure);
public:
// nsISupports methods
NS_DECL_ISUPPORTS
@ -170,6 +169,9 @@ public:
NS_IMETHOD
GetEventHandlerIID(nsIAtom* aName, nsIID* aIID, PRBool* aFound);
NS_IMETHOD_(PRBool)
UseXULCache();
};
nsrefcnt nsXULContentUtils::gRefCnt;
@ -227,9 +229,15 @@ nsXULContentUtils::kEventHandlerMap[] = {
};
// Enabled by default. Must be over-ridden to disable
PRBool nsXULContentUtils::gDisableXULCache = PR_FALSE;
static const char kDisableXULCachePref[] = "nglayout.debug.disable_xul_cache";
//------------------------------------------------------------------------
// Constructors n' stuff
//
nsXULContentUtils::nsXULContentUtils()
{
@ -242,19 +250,19 @@ nsXULContentUtils::Init()
if (gRefCnt++ == 0) {
nsresult rv;
rv = nsServiceManager::GetService(kRDFServiceCID,
nsCOMTypeInfo<nsIRDFService>::GetIID(),
NS_GET_IID(nsIRDFService),
(nsISupports**) &gRDF);
if (NS_FAILED(rv)) return rv;
rv = nsComponentManager::CreateInstance(kNameSpaceManagerCID,
nsnull,
nsCOMTypeInfo<nsINameSpaceManager>::GetIID(),
NS_GET_IID(nsINameSpaceManager),
(void**) &gNameSpaceManager);
if (NS_FAILED(rv)) return rv;
rv = nsComponentManager::CreateInstance(kDateTimeFormatCID,
nsnull,
nsCOMTypeInfo<nsIDateTimeFormat>::GetIID(),
NS_GET_IID(nsIDateTimeFormat),
(void**) &gFormat);
if (NS_FAILED(rv)) return rv;
@ -267,6 +275,13 @@ nsXULContentUtils::Init()
entry->mAttributeAtom = NS_NewAtom(entry->mAttributeName);
++entry;
}
NS_WITH_SERVICE(nsIPref, prefs, NS_PREF_PROGID, &rv);
if (NS_SUCCEEDED(rv)) {
// XXX Ignore return values.
prefs->GetBoolPref(kDisableXULCachePref, &gDisableXULCache);
prefs->RegisterCallback(kDisableXULCachePref, DisableXULCacheChangedCallback, nsnull);
}
}
return NS_OK;
}
@ -332,7 +347,7 @@ NS_NewXULContentUtils(nsISupports* aOuter, const nsIID& aIID, void** aResult)
//------------------------------------------------------------------------
// nsISupports methods
NS_IMPL_ISUPPORTS(nsXULContentUtils, nsCOMTypeInfo<nsIXULContentUtils>::GetIID());
NS_IMPL_ISUPPORTS(nsXULContentUtils, NS_GET_IID(nsIXULContentUtils));
//------------------------------------------------------------------------
// nsIXULContentUtils methods
@ -349,7 +364,7 @@ nsXULContentUtils::AttachTextNode(nsIContent* parent, nsIRDFNode* value)
nsCOMPtr<nsITextContent> text;
rv = nsComponentManager::CreateInstance(kTextNodeCID,
nsnull,
nsITextContent::GetIID(),
NS_GET_IID(nsITextContent),
getter_AddRefs(text));
if (NS_FAILED(rv)) return rv;
@ -948,3 +963,32 @@ nsXULContentUtils::GetEventHandlerIID(nsIAtom* aName, nsIID* aIID, PRBool* aFoun
return NS_OK;
}
NS_IMETHODIMP_(PRBool)
nsXULContentUtils::UseXULCache()
{
return !gDisableXULCache;
}
//----------------------------------------------------------------------
int
nsXULContentUtils::DisableXULCacheChangedCallback(const char* aPref, void* aClosure)
{
nsresult rv;
NS_WITH_SERVICE(nsIPref, prefs, NS_PREF_PROGID, &rv);
if (NS_SUCCEEDED(rv)) {
prefs->GetBoolPref(kDisableXULCachePref, &gDisableXULCache);
}
// Flush the cache, regardless
NS_WITH_SERVICE(nsIXULPrototypeCache, cache, kXULPrototypeCacheCID, &rv);
if (NS_SUCCEEDED(rv)) {
cache->Flush();
}
return 0;
}

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

@ -98,6 +98,12 @@ public:
NS_IMETHOD
GetEventHandlerIID(nsIAtom* aName, nsIID* aIID, PRBool* aFound) = 0;
/**
* Returns <code>PR_TRUE</code> if the XUL cache should be used
*/
NS_IMETHOD_(PRBool)
UseXULCache() = 0;
};

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

@ -27,6 +27,7 @@
#define nsIXULPrototypeCache_h__
#include "nsISupports.h"
class nsICSSStyleSheet;
class nsIURI;
class nsIXULPrototypeDocument;
@ -40,8 +41,20 @@ class nsIXULPrototypeCache : public nsISupports
public:
NS_DEFINE_STATIC_IID_ACCESSOR(NS_IXULPROTOTYPECACHE_IID);
NS_IMETHOD Get(nsIURI* aURI, nsIXULPrototypeDocument** _result) = 0;
NS_IMETHOD Put(nsIURI* aURI, nsIXULPrototypeDocument* aDocument) = 0;
NS_IMETHOD GetPrototype(nsIURI* aURI, nsIXULPrototypeDocument** _result) = 0;
NS_IMETHOD PutPrototype(nsIXULPrototypeDocument* aDocument) = 0;
NS_IMETHOD GetStyleSheet(nsIURI* aURI, nsICSSStyleSheet** _result) = 0;
NS_IMETHOD PutStyleSheet(nsICSSStyleSheet* aStyleSheet) = 0;
NS_IMETHOD GetScript(nsIURI* aURI, nsString& aScript, const char** aVersion) = 0;
NS_IMETHOD PutScript(nsIURI* aURI, const nsString& aScript, const char* aVersion) = 0;
/**
* Flush the cache; remove all XUL prototype documents, style
* sheets, and scripts.
*/
NS_IMETHOD Flush() = 0;
};

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

@ -57,11 +57,11 @@ public:
NS_IMETHOD GetRootElement(nsXULPrototypeElement** aResult) = 0;
NS_IMETHOD SetRootElement(nsXULPrototypeElement* aElement) = 0;
NS_IMETHOD AddStyleSheet(nsIStyleSheet* aStyleSheet) = 0;
NS_IMETHOD GetStyleSheets(nsVoidArray& aResult) = 0;
NS_IMETHOD AddStyleSheetReference(nsIURI* aStyleSheet) = 0;
NS_IMETHOD GetStyleSheetReferences(nsISupportsArray** aResult) = 0;
NS_IMETHOD AddOverlayReference(nsIURI* aURI) = 0;
NS_IMETHOD GetOverlayReferences(nsVoidArray& aResult) = 0;
NS_IMETHOD GetOverlayReferences(nsISupportsArray** aResult) = 0;
NS_IMETHOD GetHeaderData(nsIAtom* aField, nsString& aData) const = 0;
NS_IMETHOD SetHeaderData(nsIAtom* aField, const nsString& aData) = 0;

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

@ -71,6 +71,7 @@
#include "nsIXULDocument.h"
#include "nsIXULKeyListener.h"
#include "nsIXULPrototypeDocument.h"
#include "nsIXULPrototypeCache.h"
#include "nsLayoutCID.h"
#include "nsNeckoUtil.h"
#include "nsRDFCID.h"
@ -102,6 +103,8 @@ static const char kXULNameSpaceURI[] = XUL_NAMESPACE_URI;
static NS_DEFINE_CID(kCSSLoaderCID, NS_CSS_LOADER_CID);
static NS_DEFINE_CID(kCSSParserCID, NS_CSSPARSER_CID);
static NS_DEFINE_CID(kNameSpaceManagerCID, NS_NAMESPACEMANAGER_CID);
static NS_DEFINE_CID(kXULContentUtilsCID, NS_XULCONTENTUTILS_CID);
static NS_DEFINE_CID(kXULPrototypeCacheCID, NS_XULPROTOTYPECACHE_CID);
//----------------------------------------------------------------------
@ -142,6 +145,8 @@ protected:
// pseudo-constants
static nsrefcnt gRefCnt;
static nsINameSpaceManager* gNameSpaceManager;
static nsIXULContentUtils* gXULUtils;
static nsIXULPrototypeCache* gXULCache;
static nsIAtom* kClassAtom;
static nsIAtom* kIdAtom;
@ -240,6 +245,8 @@ protected:
nsrefcnt XULContentSinkImpl::gRefCnt;
nsINameSpaceManager* XULContentSinkImpl::gNameSpaceManager;
nsIXULContentUtils* XULContentSinkImpl::gXULUtils;
nsIXULPrototypeCache* XULContentSinkImpl::gXULCache;
nsIAtom* XULContentSinkImpl::kClassAtom;
nsIAtom* XULContentSinkImpl::kIdAtom;
@ -377,6 +384,15 @@ XULContentSinkImpl::XULContentSinkImpl(nsresult& rv)
kScriptAtom = NS_NewAtom("script");
kStyleAtom = NS_NewAtom("style");
kTemplateAtom = NS_NewAtom("template");
rv = nsServiceManager::GetService(kXULContentUtilsCID,
NS_GET_IID(nsIXULContentUtils),
(nsISupports**) &gXULUtils);
if (NS_FAILED(rv)) return;
rv = nsServiceManager::GetService(kXULPrototypeCacheCID,
NS_GET_IID(nsIXULPrototypeCache),
(nsISupports**) &gXULCache);
}
#ifdef PR_LOGGING
@ -390,11 +406,6 @@ XULContentSinkImpl::XULContentSinkImpl(nsresult& rv)
XULContentSinkImpl::~XULContentSinkImpl()
{
#ifdef DEBUG_REFS
--gInstanceCount;
fprintf(stdout, "%d - RDF: XULContentSinkImpl\n", gInstanceCount);
#endif
NS_IF_RELEASE(mParser); // XXX should've been released by now, unless error.
{
@ -475,6 +486,16 @@ XULContentSinkImpl::~XULContentSinkImpl()
NS_IF_RELEASE(kScriptAtom);
NS_IF_RELEASE(kStyleAtom);
NS_IF_RELEASE(kTemplateAtom);
if (gXULUtils) {
nsServiceManager::ReleaseService(kXULContentUtilsCID, gXULUtils);
gXULUtils = nsnull;
}
if (gXULCache) {
nsServiceManager::ReleaseService(kXULPrototypeCacheCID, gXULCache);
gXULCache = nsnull;
}
}
}
@ -821,7 +842,7 @@ XULContentSinkImpl::ProcessStyleLink(nsIContent* aElement,
{
static const char kCSSType[] = "text/css";
nsresult result = NS_OK;
nsresult rv = NS_OK;
if (aAlternate) { // if alternate, does it have title?
if (0 == aTitle.Length()) { // alternates must have title
@ -835,11 +856,35 @@ XULContentSinkImpl::ProcessStyleLink(nsIContent* aElement,
if ((0 == mimeType.Length()) || mimeType.EqualsIgnoreCase(kCSSType)) {
nsCOMPtr<nsIURI> url;
result = NS_NewURI(getter_AddRefs(url), aHref, mDocumentURL);
if (NS_OK != result) {
rv = NS_NewURI(getter_AddRefs(url), aHref, mDocumentURL);
if (NS_OK != rv) {
return NS_OK; // The URL is bad, move along, don't propagate the error (for now)
}
// Add the style sheet reference to the prototype
mPrototype->AddStyleSheetReference(url);
// See if the style sheet is in the style sheet cache. If so,
// just use it.
if (gXULUtils->UseXULCache()) {
nsCOMPtr<nsICSSStyleSheet> sheet;
rv = gXULCache->GetStyleSheet(url, getter_AddRefs(sheet));
if (NS_SUCCEEDED(rv) && sheet) {
nsCOMPtr<nsICSSStyleSheet> newsheet;
rv = sheet->Clone(*getter_AddRefs(newsheet));
if (NS_SUCCEEDED(rv) && newsheet) {
nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocument);
if (doc) {
doc->AddStyleSheet(newsheet);
return NS_OK;
}
}
}
}
// Nope, we need to load it asynchronously
PRBool blockParser = PR_FALSE;
if (! aAlternate) {
if (0 < aTitle.Length()) { // possibly preferred sheet
@ -862,16 +907,16 @@ XULContentSinkImpl::ProcessStyleLink(nsIContent* aElement,
// sheet in a fairly random location if we're loading an
// overlay. Should we just use a Very Large Number?
PRBool doneLoading;
result = mCSSLoader->LoadStyleLink(aElement, url, aTitle, aMedia, kNameSpaceID_Unknown,
mStyleSheetCount++,
((blockParser) ? mParser : nsnull),
doneLoading);
if (NS_SUCCEEDED(result) && blockParser && (! doneLoading)) {
result = NS_ERROR_HTMLPARSER_BLOCK;
rv = mCSSLoader->LoadStyleLink(aElement, url, aTitle, aMedia, kNameSpaceID_Unknown,
mStyleSheetCount++,
((blockParser) ? mParser : nsnull),
doneLoading);
if (NS_SUCCEEDED(rv) && blockParser && (! doneLoading)) {
rv = NS_ERROR_HTMLPARSER_BLOCK;
}
}
return result;
return rv;
}

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

@ -43,12 +43,14 @@
#include "nsIRDFNode.h"
#include "nsINameSpace.h"
#include "nsINameSpaceManager.h"
#include "nsIPref.h"
#include "nsIRDFService.h"
#include "nsIServiceManager.h"
#include "nsITextContent.h"
#include "nsIURL.h"
#include "nsIXMLContent.h"
#include "nsIXULContentUtils.h"
#include "nsIXULPrototypeCache.h"
#include "nsLayoutCID.h"
#include "nsNeckoUtil.h"
#include "nsRDFCID.h"
@ -67,23 +69,15 @@
#include "nsDateTimeFormatCID.h"
#include "nsIScriptableDateFormat.h"
static NS_DEFINE_IID(kIContentIID, NS_ICONTENT_IID);
static NS_DEFINE_IID(kIRDFResourceIID, NS_IRDFRESOURCE_IID);
static NS_DEFINE_IID(kIRDFLiteralIID, NS_IRDFLITERAL_IID);
static NS_DEFINE_IID(kIRDFIntIID, NS_IRDFINT_IID);
static NS_DEFINE_IID(kIRDFDateIID, NS_IRDFDATE_IID);
static NS_DEFINE_IID(kITextContentIID, NS_ITEXT_CONTENT_IID); // XXX grr...
static NS_DEFINE_CID(kTextNodeCID, NS_TEXTNODE_CID);
static NS_DEFINE_CID(kRDFServiceCID, NS_RDFSERVICE_CID);
static NS_DEFINE_CID(kLocaleFactoryCID, NS_LOCALEFACTORY_CID);
static NS_DEFINE_IID(kILocaleFactoryIID, NS_ILOCALEFACTORY_IID);
static NS_DEFINE_CID(kLocaleCID, NS_LOCALE_CID);
static NS_DEFINE_IID(kILocaleIID, NS_ILOCALE_IID);
static NS_DEFINE_CID(kNameSpaceManagerCID, NS_NAMESPACEMANAGER_CID);
static NS_DEFINE_CID(kDateTimeFormatCID, NS_DATETIMEFORMAT_CID);
static NS_DEFINE_CID(kDateTimeFormatIID, NS_IDATETIMEFORMAT_IID);
static NS_DEFINE_CID(kDateTimeFormatCID, NS_DATETIMEFORMAT_CID);
static NS_DEFINE_CID(kDateTimeFormatIID, NS_IDATETIMEFORMAT_IID);
static NS_DEFINE_CID(kLocaleCID, NS_LOCALE_CID);
static NS_DEFINE_CID(kLocaleFactoryCID, NS_LOCALEFACTORY_CID);
static NS_DEFINE_CID(kNameSpaceManagerCID, NS_NAMESPACEMANAGER_CID);
static NS_DEFINE_CID(kRDFServiceCID, NS_RDFSERVICE_CID);
static NS_DEFINE_CID(kTextNodeCID, NS_TEXTNODE_CID);
static NS_DEFINE_CID(kXULPrototypeCacheCID, NS_XULPROTOTYPECACHE_CID);
//------------------------------------------------------------------------
@ -113,6 +107,11 @@ protected:
static EventHandlerMapEntry kEventHandlerMap[];
static PRBool gDisableXULCache;
static int
DisableXULCacheChangedCallback(const char* aPrefName, void* aClosure);
public:
// nsISupports methods
NS_DECL_ISUPPORTS
@ -170,6 +169,9 @@ public:
NS_IMETHOD
GetEventHandlerIID(nsIAtom* aName, nsIID* aIID, PRBool* aFound);
NS_IMETHOD_(PRBool)
UseXULCache();
};
nsrefcnt nsXULContentUtils::gRefCnt;
@ -227,9 +229,15 @@ nsXULContentUtils::kEventHandlerMap[] = {
};
// Enabled by default. Must be over-ridden to disable
PRBool nsXULContentUtils::gDisableXULCache = PR_FALSE;
static const char kDisableXULCachePref[] = "nglayout.debug.disable_xul_cache";
//------------------------------------------------------------------------
// Constructors n' stuff
//
nsXULContentUtils::nsXULContentUtils()
{
@ -242,19 +250,19 @@ nsXULContentUtils::Init()
if (gRefCnt++ == 0) {
nsresult rv;
rv = nsServiceManager::GetService(kRDFServiceCID,
nsCOMTypeInfo<nsIRDFService>::GetIID(),
NS_GET_IID(nsIRDFService),
(nsISupports**) &gRDF);
if (NS_FAILED(rv)) return rv;
rv = nsComponentManager::CreateInstance(kNameSpaceManagerCID,
nsnull,
nsCOMTypeInfo<nsINameSpaceManager>::GetIID(),
NS_GET_IID(nsINameSpaceManager),
(void**) &gNameSpaceManager);
if (NS_FAILED(rv)) return rv;
rv = nsComponentManager::CreateInstance(kDateTimeFormatCID,
nsnull,
nsCOMTypeInfo<nsIDateTimeFormat>::GetIID(),
NS_GET_IID(nsIDateTimeFormat),
(void**) &gFormat);
if (NS_FAILED(rv)) return rv;
@ -267,6 +275,13 @@ nsXULContentUtils::Init()
entry->mAttributeAtom = NS_NewAtom(entry->mAttributeName);
++entry;
}
NS_WITH_SERVICE(nsIPref, prefs, NS_PREF_PROGID, &rv);
if (NS_SUCCEEDED(rv)) {
// XXX Ignore return values.
prefs->GetBoolPref(kDisableXULCachePref, &gDisableXULCache);
prefs->RegisterCallback(kDisableXULCachePref, DisableXULCacheChangedCallback, nsnull);
}
}
return NS_OK;
}
@ -332,7 +347,7 @@ NS_NewXULContentUtils(nsISupports* aOuter, const nsIID& aIID, void** aResult)
//------------------------------------------------------------------------
// nsISupports methods
NS_IMPL_ISUPPORTS(nsXULContentUtils, nsCOMTypeInfo<nsIXULContentUtils>::GetIID());
NS_IMPL_ISUPPORTS(nsXULContentUtils, NS_GET_IID(nsIXULContentUtils));
//------------------------------------------------------------------------
// nsIXULContentUtils methods
@ -349,7 +364,7 @@ nsXULContentUtils::AttachTextNode(nsIContent* parent, nsIRDFNode* value)
nsCOMPtr<nsITextContent> text;
rv = nsComponentManager::CreateInstance(kTextNodeCID,
nsnull,
nsITextContent::GetIID(),
NS_GET_IID(nsITextContent),
getter_AddRefs(text));
if (NS_FAILED(rv)) return rv;
@ -948,3 +963,32 @@ nsXULContentUtils::GetEventHandlerIID(nsIAtom* aName, nsIID* aIID, PRBool* aFoun
return NS_OK;
}
NS_IMETHODIMP_(PRBool)
nsXULContentUtils::UseXULCache()
{
return !gDisableXULCache;
}
//----------------------------------------------------------------------
int
nsXULContentUtils::DisableXULCacheChangedCallback(const char* aPref, void* aClosure)
{
nsresult rv;
NS_WITH_SERVICE(nsIPref, prefs, NS_PREF_PROGID, &rv);
if (NS_SUCCEEDED(rv)) {
prefs->GetBoolPref(kDisableXULCachePref, &gDisableXULCache);
}
// Flush the cache, regardless
NS_WITH_SERVICE(nsIXULPrototypeCache, cache, kXULPrototypeCacheCID, &rv);
if (NS_SUCCEEDED(rv)) {
cache->Flush();
}
return 0;
}

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

@ -53,6 +53,7 @@
#include "nsIChromeRegistry.h"
#include "nsIComponentManager.h"
#include "nsIContentViewer.h"
#include "nsICSSStyleSheet.h"
#include "nsIDOMEvent.h"
#include "nsIDOMEventListener.h"
#include "nsIDOMEventReceiver.h"
@ -196,7 +197,7 @@ nsINameSpaceManager* nsXULDocument::gNameSpaceManager;
PRInt32 nsXULDocument::kNameSpaceID_XUL;
nsIXULContentUtils* nsXULDocument::gXULUtils;
nsIXULPrototypeCache* nsXULDocument::gXULPrototypeCache;
nsIXULPrototypeCache* nsXULDocument::gXULCache;
PRLogModuleInfo* nsXULDocument::gXULLog;
@ -330,9 +331,9 @@ nsXULDocument::~nsXULDocument()
gXULUtils = nsnull;
}
if (gXULPrototypeCache) {
nsServiceManager::ReleaseService(kXULPrototypeCacheCID, gXULPrototypeCache);
gXULPrototypeCache = nsnull;
if (gXULCache) {
nsServiceManager::ReleaseService(kXULPrototypeCacheCID, gXULCache);
gXULCache = nsnull;
}
}
}
@ -518,6 +519,10 @@ nsXULDocument::StartDocumentLoad(const char* aCommand,
{
nsresult rv;
#if defined(DEBUG_waterson) || defined(DEBUG_hyatt)
mLoadStart = PR_Now();
#endif
nsCOMPtr<nsIURI> url;
rv = aChannel->GetURI(getter_AddRefs(url));
if (NS_FAILED(rv)) return rv;
@ -866,6 +871,15 @@ nsXULDocument::AddStyleSheet(nsIStyleSheet* aSheet)
else {
mStyleSheets.AppendElement(aSheet);
}
// Put the style sheet into the XUL cache if the XUL cache is
// actually enabled and the document is chrome.
if (gXULUtils->UseXULCache() && IsChromeURI(mDocumentURL)) {
nsCOMPtr<nsICSSStyleSheet> css = do_QueryInterface(aSheet);
if (css) {
gXULCache->PutStyleSheet(css);
}
}
}
NS_ADDREF(aSheet);
@ -902,6 +916,16 @@ NS_IMETHODIMP
nsXULDocument::InsertStyleSheetAt(nsIStyleSheet* aSheet, PRInt32 aIndex, PRBool aNotify)
{
NS_PRECONDITION(nsnull != aSheet, "null ptr");
// Put the style sheet into the XUL cache if the XUL cache is
// actually enabled and the document is chrome.
if (gXULUtils->UseXULCache() && IsChromeURI(mDocumentURL)) {
nsCOMPtr<nsICSSStyleSheet> css = do_QueryInterface(aSheet);
if (css) {
gXULCache->PutStyleSheet(css);
}
}
mStyleSheets.InsertElementAt(aSheet, aIndex + 1); // offset by one for attribute sheet
NS_ADDREF(aSheet);
@ -932,6 +956,7 @@ nsXULDocument::InsertStyleSheetAt(nsIStyleSheet* aSheet, PRInt32 aIndex, PRBool
}
}
}
return NS_OK;
}
@ -1055,6 +1080,22 @@ NS_IMETHODIMP
nsXULDocument::EndLoad()
{
nsresult rv;
// Whack the prototype document into the cache so that the next
// time somebody asks for it, they don't need to load it by hand.
nsCOMPtr<nsIURI> uri;
rv = mCurrentPrototype->GetURI(getter_AddRefs(uri));
if (NS_FAILED(rv)) return rv;
if (gXULUtils->UseXULCache() && IsChromeURI(mDocumentURL)) {
// If it's a 'chrome:' prototype document, then put it into
// the prototype cache; other XUL documents will be reloaded
// each time.
rv = gXULCache->PutPrototype(mCurrentPrototype);
if (NS_FAILED(rv)) return rv;
}
// Now walk the prototype to build content.
rv = PrepareToWalk();
if (NS_FAILED(rv)) return rv;
@ -1856,10 +1897,12 @@ nsXULDocument::CreateFromPrototype(const char* aCommand,
rv = PrepareStyleSheets(mDocumentURL);
if (NS_FAILED(rv)) return rv;
return NS_OK;
mCommand = aCommand;
rv = AddPrototypeSheets();
if (NS_FAILED(rv)) return rv;
// Now create the delegates from the prototype
rv = PrepareToWalk();
if (NS_FAILED(rv)) return rv;
@ -3097,7 +3140,7 @@ static const char kXULNameSpaceURI[] = XUL_NAMESPACE_URI;
rv = nsServiceManager::GetService(kXULPrototypeCacheCID,
NS_GET_IID(nsIXULPrototypeCache),
(nsISupports**) &gXULPrototypeCache);
(nsISupports**) &gXULCache);
if (NS_FAILED(rv)) return rv;
}
@ -4102,14 +4145,17 @@ nsXULDocument::PrepareToWalk()
// Push the overlay references onto our overlay processing
// stack. GetOverlayReferences() will return an ordered array of
// overlay references...
nsVoidArray overlays;
rv = mCurrentPrototype->GetOverlayReferences(overlays);
nsCOMPtr<nsISupportsArray> overlays;
rv = mCurrentPrototype->GetOverlayReferences(getter_AddRefs(overlays));
if (NS_FAILED(rv)) return rv;
// ...and we preserve this ordering by appending to our
// mUnloadedOverlays array in reverse order
for (PRInt32 i = overlays.Count() - 1; i >= 0; --i) {
mUnloadedOverlays->AppendElement(NS_REINTERPRET_CAST(nsIURI*, overlays[i]));
PRUint32 count;
overlays->Count(&count);
for (PRInt32 i = count - 1; i >= 0; --i) {
nsCOMPtr<nsISupports> isupports = dont_AddRef(overlays->ElementAt(i));
mUnloadedOverlays->AppendElement(isupports);
}
@ -4422,11 +4468,15 @@ nsXULDocument::ResumeWalk()
// Look in the prototype cache for the prototype document with
// the specified URI.
rv = gXULPrototypeCache->Get(uri, getter_AddRefs(mCurrentPrototype));
rv = gXULCache->GetPrototype(uri, getter_AddRefs(mCurrentPrototype));
if (NS_FAILED(rv)) return rv;
if (mCurrentPrototype) {
// Found the overlay's prototype in the cache: walk it!
if (gXULUtils->UseXULCache() && mCurrentPrototype) {
// Found the overlay's prototype in the cache.
rv = AddPrototypeSheets();
if (NS_FAILED(rv)) return rv;
// Now prepare to walk the prototype to create its content
rv = PrepareToWalk();
if (NS_FAILED(rv)) return rv;
@ -4460,6 +4510,15 @@ nsXULDocument::ResumeWalk()
// If we get here, there is nothing left for us to walk. The content
// model is built and ready for layout.
#if defined(DEBUG_waterson) || defined(DEBUG_hyatt)
{
nsTime finish = PR_Now();
nsInt64 diff64 = finish - mLoadStart;
PRInt32 diff = PRInt32(diff64 / nsInt64(1000));
printf("***** XUL document loaded in %ldmsec\n", diff);
}
#endif
rv = ResolveForwardReferences();
if (NS_FAILED(rv)) return rv;
@ -4476,6 +4535,21 @@ nsXULDocument::ResumeWalk()
}
}
#if defined(DEBUG_waterson) || defined(DEBUG_hyatt)
{
nsTime finish = PR_Now();
nsInt64 diff64 = finish - mLoadStart;
PRInt32 diff = PRInt32(diff64 / nsInt64(1000));
printf("***** XUL document flowed in %ldmsec\n", diff);
}
{
nsInt64 now(PR_Now());
now /= nsInt64(1000);
printf("### ResumeWalk complete %ld\n", PRInt32(now));
}
#endif
return rv;
}
@ -4487,11 +4561,17 @@ nsXULDocument::LoadScript(nsIURI* aURI, const char* aVersion, PRBool* aBlock)
nsresult rv;
// XXX Look in a script cache to see if we already have it
nsAutoString script;
const char* version;
rv = gXULCache->GetScript(aURI, script, &version);
if (NS_FAILED(rv)) return rv;
if (gXULUtils->UseXULCache() && script.Length()) {
// We've found it in the cache. Just re-evaluate it.
rv = EvaluateScript(aURI, script, 1, version);
if (NS_FAILED(rv)) return rv;
if (/* cached */ PR_FALSE) {
*aBlock = PR_FALSE;
// XXX brendan, shaver: do some magic here
}
else {
// Set the current script URL so that the DoneLoadingScript()
@ -4538,6 +4618,12 @@ nsXULDocument::DoneLoadingScript(nsIUnicharStreamLoader* aLoader,
if (NS_SUCCEEDED(aStatus)) {
rv = doc->EvaluateScript(doc->mCurrentScriptURL, aData, 1,
doc->mCurrentScriptLanguageVersion);
if (IsChromeURI(doc->mDocumentURL)) {
gXULCache->PutScript(doc->mCurrentScriptURL,
aData,
doc->mCurrentScriptLanguageVersion);
}
}
// balance the addref we added in LoadScript()
@ -4842,10 +4928,23 @@ nsXULDocument::CheckTemplateBuilder(nsIContent* aElement)
NS_ASSERTION(NS_SUCCEEDED(rv), "unable to set builder's database");
if (NS_FAILED(rv)) return rv;
// Force construction of immediate template sub-content _now_.
rv = builder->CreateContents(aElement);
NS_ASSERTION(NS_SUCCEEDED(rv), "unable to create template contents");
if (NS_FAILED(rv)) return rv;
nsCOMPtr<nsIXULContent> xulcontent = do_QueryInterface(aElement);
if (xulcontent) {
// Mark the XUL element as being lazy, so the template builder
// will run when layout first asks for these nodes.
//
//rv = xulcontent->ClearLazyState(eTemplateContentsBuilt | eContainerContentsBuilt);
//if (NS_FAILED(rv)) return rv;
xulcontent->SetLazyState(nsIXULContent::eChildrenMustBeRebuilt);
if (NS_FAILED(rv)) return rv;
}
else {
// Force construction of immediate template sub-content _now_.
rv = builder->CreateContents(aElement);
NS_ASSERTION(NS_SUCCEEDED(rv), "unable to create template contents");
if (NS_FAILED(rv)) return rv;
}
return NS_OK;
}
@ -4895,6 +4994,45 @@ nsXULDocument::CheckBroadcasterHookup(nsIContent* aElement)
}
nsresult
nsXULDocument::AddPrototypeSheets()
{
// Add mCurrentPrototype's style sheets to the document.
nsresult rv;
nsCOMPtr<nsISupportsArray> sheets;
rv = mCurrentPrototype->GetStyleSheetReferences(getter_AddRefs(sheets));
if (NS_FAILED(rv)) return rv;
PRUint32 count;
sheets->Count(&count);
for (PRUint32 i = 0; i < count; ++i) {
nsCOMPtr<nsISupports> isupports = dont_AddRef(sheets->ElementAt(i));
nsCOMPtr<nsIURI> uri = do_QueryInterface(isupports);
NS_ASSERTION(uri != nsnull, "not a URI!!!");
if (! uri)
return NS_ERROR_UNEXPECTED;
nsCOMPtr<nsICSSStyleSheet> sheet;
rv = gXULCache->GetStyleSheet(uri, getter_AddRefs(sheet));
if (NS_FAILED(rv)) return rv;
NS_ASSERTION(sheet != nsnull, "uh oh, sheet wasn't in the cache. go reload it");
if (! sheet)
return NS_ERROR_UNEXPECTED;
nsCOMPtr<nsICSSStyleSheet> newsheet;
rv = sheet->Clone(*getter_AddRefs(newsheet));
if (NS_FAILED(rv)) return rv;
AddStyleSheet(newsheet);
}
return NS_OK;
}
//----------------------------------------------------------------------
//
// nsXULDocument::OverlayForwardReference
@ -5324,3 +5462,19 @@ nsXULDocument::ProcessCommonAttributes(nsIContent* aElement)
return NS_OK;
}
PRBool
nsXULDocument::IsChromeURI(nsIURI* aURI)
{
nsresult rv;
nsXPIDLCString protocol;
rv = aURI->GetScheme(getter_Copies(protocol));
if (NS_SUCCEEDED(rv)) {
if (PL_strcmp(protocol, "chrome") == 0) {
return PR_TRUE;
}
}
return PR_FALSE;
}

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

@ -51,6 +51,7 @@
#include "nsIXULDocument.h"
#include "nsIXULPrototypeDocument.h"
#include "nsRDFDOMNodeList.h"
#include "nsTime.h"
#include "nsVoidArray.h"
#include "nsWeakPtr.h"
#include "nsWeakReference.h"
@ -459,7 +460,7 @@ protected:
static PRInt32 kNameSpaceID_XUL;
static nsIXULContentUtils* gXULUtils;
static nsIXULPrototypeCache* gXULPrototypeCache;
static nsIXULPrototypeCache* gXULCache;
static PRLogModuleInfo* gXULLog;
@ -632,6 +633,11 @@ protected:
*/
nsresult CheckBroadcasterHookup(nsIContent* aElement);
/**
* Add the current prototype's style sheets to the document.
*/
nsresult AddPrototypeSheets();
/**
* Used to resolve broadcaster references
*/
@ -686,6 +692,10 @@ protected:
nsresult
ProcessCommonAttributes(nsIContent* aElement);
static
PRBool
IsChromeURI(nsIURI* aURI);
/**
* The current prototype that we are walking to construct the
* content model.
@ -714,6 +724,11 @@ protected:
* prototype walk.
*/
nsresult ResumeWalk();
#if defined(DEBUG_waterson) || defined(DEBUG_hyatt)
// timing
nsTime mLoadStart;
#endif
};

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

@ -25,10 +25,14 @@
#include "nsCOMPtr.h"
#include "nsXPIDLString.h"
#include "nsICSSStyleSheet.h"
#include "nsIXULPrototypeCache.h"
#include "nsIXULPrototypeDocument.h"
#include "nsIURI.h"
#include "plhash.h"
#include "nsHashtable.h"
#include "nsXPIDLString.h"
#include "plstr.h"
class nsXULPrototypeCache : public nsIXULPrototypeCache
{
@ -36,8 +40,16 @@ public:
// nsISupports
NS_DECL_ISUPPORTS
NS_IMETHOD Get(nsIURI* aURI, nsIXULPrototypeDocument** _result);
NS_IMETHOD Put(nsIURI* aURI, nsIXULPrototypeDocument* aDocument);
NS_IMETHOD GetPrototype(nsIURI* aURI, nsIXULPrototypeDocument** _result);
NS_IMETHOD PutPrototype(nsIXULPrototypeDocument* aDocument);
NS_IMETHOD GetStyleSheet(nsIURI* aURI, nsICSSStyleSheet** _result);
NS_IMETHOD PutStyleSheet(nsICSSStyleSheet* aStyleSheet);
NS_IMETHOD GetScript(nsIURI* aURI, nsString& aScript, const char** aVersion);
NS_IMETHOD PutScript(nsIURI* aURI, const nsString& aScript, const char* aVersion);
NS_IMETHOD Flush();
protected:
friend NS_IMETHODIMP
@ -45,13 +57,45 @@ protected:
nsXULPrototypeCache();
virtual ~nsXULPrototypeCache();
static PRIntn ReleaseTableEntry(PLHashEntry* aHashEntry, PRIntn aIndex, void* aClosure);
nsresult Init();
static PLHashNumber Hash(const void* aKey);
static PRIntn CompareKeys(const void* aKey1, const void* aKey2);
static PRBool
ReleaseScriptEntryEnumFunc(nsHashKey* aKey, void* aData, void* aClosure);
PLHashTable* mTable;
nsSupportsHashtable mPrototypeTable;
nsSupportsHashtable mStyleSheetTable;
nsHashtable mScriptTable;
class nsIURIKey : public nsHashKey {
protected:
nsCOMPtr<nsIURI> mKey;
public:
nsIURIKey(nsIURI* key) : mKey(key) {}
~nsIURIKey(void) {}
PRUint32 HashValue(void) const {
nsXPIDLCString spec;
mKey->GetSpec(getter_Copies(spec));
return (PRUint32) PL_HashString(spec);
}
PRBool Equals(const nsHashKey *aKey) const {
PRBool eq;
mKey->Equals( ((nsIURIKey*) aKey)->mKey, &eq );
return eq;
}
nsHashKey *Clone(void) const {
return new nsIURIKey(mKey);
}
};
class ScriptEntry {
public:
nsString mScript;
const char* mVersion;
};
};
@ -64,36 +108,18 @@ nsXULPrototypeCache::nsXULPrototypeCache()
nsXULPrototypeCache::~nsXULPrototypeCache()
{
if (mTable) {
PL_HashTableEnumerateEntries(mTable, ReleaseTableEntry, nsnull);
PL_HashTableDestroy(mTable);
}
mScriptTable.Enumerate(ReleaseScriptEntryEnumFunc, nsnull);
}
PRIntn
nsXULPrototypeCache::ReleaseTableEntry(PLHashEntry* aHashEntry, PRIntn aIndex, void* aClosure)
PRBool
nsXULPrototypeCache::ReleaseScriptEntryEnumFunc(nsHashKey* aKey, void* aData, void* aClosure)
{
nsIURI* key = NS_REINTERPRET_CAST(nsIURI*, NS_CONST_CAST(void*, aHashEntry->key));
NS_RELEASE(key);
nsIXULPrototypeDocument* value = NS_REINTERPRET_CAST(nsIXULPrototypeDocument*, aHashEntry->value);
NS_RELEASE(value);
return HT_ENUMERATE_REMOVE;
ScriptEntry* entry = NS_REINTERPRET_CAST(ScriptEntry*, aData);
delete entry;
return PR_TRUE;
}
nsresult
nsXULPrototypeCache::Init()
{
mTable = PL_NewHashTable(16, Hash, CompareKeys, PL_CompareValues, nsnull, nsnull);
if (! mTable)
return NS_ERROR_OUT_OF_MEMORY;
return NS_OK;
}
NS_IMPL_ISUPPORTS1(nsXULPrototypeCache, nsIXULPrototypeCache);
@ -109,11 +135,6 @@ NS_NewXULPrototypeCache(nsISupports* aOuter, REFNSIID aIID, void** aResult)
return NS_ERROR_OUT_OF_MEMORY;
nsresult rv;
rv = result->Init();
if (NS_FAILED(rv)) {
delete result;
return rv;
}
NS_ADDREF(result);
rv = result->QueryInterface(aIID, aResult);
@ -122,36 +143,98 @@ NS_NewXULPrototypeCache(nsISupports* aOuter, REFNSIID aIID, void** aResult)
return rv;
}
PLHashNumber
nsXULPrototypeCache::Hash(const void* aKey)
{
nsIURI* uri = NS_REINTERPRET_CAST(nsIURI*, NS_CONST_CAST(void*, aKey));
nsXPIDLCString spec;
uri->GetSpec(getter_Copies(spec));
return PL_HashString(spec);
}
PRIntn
nsXULPrototypeCache::CompareKeys(const void* aKey1, const void* aKey2)
{
nsIURI* uri1 = NS_REINTERPRET_CAST(nsIURI*, NS_CONST_CAST(void*, aKey1));
nsIURI* uri2 = NS_REINTERPRET_CAST(nsIURI*, NS_CONST_CAST(void*, aKey2));
PRBool eq;
uri1->Equals(uri2, &eq);
return eq;
}
//----------------------------------------------------------------------
NS_IMETHODIMP
nsXULPrototypeCache::Get(nsIURI* aURI, nsIXULPrototypeDocument** _result)
nsXULPrototypeCache::GetPrototype(nsIURI* aURI, nsIXULPrototypeDocument** _result)
{
nsIURIKey key(aURI);
*_result = NS_STATIC_CAST(nsIXULPrototypeDocument*, mPrototypeTable.Get(&key));
return NS_OK;
}
NS_IMETHODIMP
nsXULPrototypeCache::Put(nsIURI* aURI, nsIXULPrototypeDocument* aDocument)
nsXULPrototypeCache::PutPrototype(nsIXULPrototypeDocument* aDocument)
{
nsresult rv;
nsCOMPtr<nsIURI> uri;
rv = aDocument->GetURI(getter_AddRefs(uri));
nsIURIKey key(uri);
mPrototypeTable.Put(&key, aDocument);
return NS_OK;
}
NS_IMETHODIMP
nsXULPrototypeCache::GetStyleSheet(nsIURI* aURI, nsICSSStyleSheet** _result)
{
nsIURIKey key(aURI);
*_result = NS_STATIC_CAST(nsICSSStyleSheet*, mStyleSheetTable.Get(&key));
return NS_OK;
}
NS_IMETHODIMP
nsXULPrototypeCache::PutStyleSheet(nsICSSStyleSheet* aStyleSheet)
{
nsresult rv;
nsCOMPtr<nsIURI> uri;
rv = aStyleSheet->GetURL(*getter_AddRefs(uri));
nsIURIKey key(uri);
mStyleSheetTable.Put(&key, aStyleSheet);
return NS_OK;
}
NS_IMETHODIMP
nsXULPrototypeCache::GetScript(nsIURI* aURI, nsString& aScript, const char** aVersion)
{
nsIURIKey key(aURI);
const ScriptEntry* entry = NS_REINTERPRET_CAST(const ScriptEntry*, mScriptTable.Get(&key));
if (entry) {
aScript = entry->mScript;
*aVersion = entry->mVersion;
}
else {
aScript.Truncate();
*aVersion = nsnull;
}
return NS_OK;
}
NS_IMETHODIMP
nsXULPrototypeCache::PutScript(nsIURI* aURI, const nsString& aScript, const char* aVersion)
{
ScriptEntry* newentry = new ScriptEntry();
if (! newentry)
return NS_ERROR_OUT_OF_MEMORY;
newentry->mScript = aScript;
newentry->mVersion = aVersion;
nsIURIKey key(aURI);
ScriptEntry* oldentry = NS_REINTERPRET_CAST(ScriptEntry*, mScriptTable.Put(&key, newentry));
delete oldentry;
return NS_OK;
}
NS_IMETHODIMP
nsXULPrototypeCache::Flush()
{
mPrototypeTable.Reset();
mStyleSheetTable.Reset();
mScriptTable.Reset(ReleaseScriptEntryEnumFunc, nsnull);
return NS_OK;
}

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

@ -25,7 +25,6 @@
#include "nsCOMPtr.h"
#include "nsISupportsArray.h"
#include "nsIStyleSheet.h"
#include "nsIXULPrototypeDocument.h"
#include "nsIURI.h"
#include "nsString2.h"
@ -48,11 +47,11 @@ public:
NS_IMETHOD GetRootElement(nsXULPrototypeElement** aResult);
NS_IMETHOD SetRootElement(nsXULPrototypeElement* aElement);
NS_IMETHOD AddStyleSheet(nsIStyleSheet* aStyleSheet);
NS_IMETHOD GetStyleSheets(nsVoidArray& aResult);
NS_IMETHOD AddStyleSheetReference(nsIURI* aStyleSheet);
NS_IMETHOD GetStyleSheetReferences(nsISupportsArray** aResult);
NS_IMETHOD AddOverlayReference(nsIURI* aURI);
NS_IMETHOD GetOverlayReferences(nsVoidArray& aResult);
NS_IMETHOD GetOverlayReferences(nsISupportsArray** aResult);
NS_IMETHOD GetHeaderData(nsIAtom* aField, nsString& aData) const;
NS_IMETHOD SetHeaderData(nsIAtom* aField, const nsString& aData);
@ -60,7 +59,7 @@ public:
protected:
nsCOMPtr<nsIURI> mURI;
nsXULPrototypeElement* mRoot;
nsCOMPtr<nsISupportsArray> mStyleSheets;
nsCOMPtr<nsISupportsArray> mStyleSheetReferences;
nsCOMPtr<nsISupportsArray> mOverlayReferences;
nsXULPrototypeDocument();
@ -86,7 +85,7 @@ nsXULPrototypeDocument::Init()
{
nsresult rv;
rv = NS_NewISupportsArray(getter_AddRefs(mStyleSheets));
rv = NS_NewISupportsArray(getter_AddRefs(mStyleSheetReferences));
if (NS_FAILED(rv)) return rv;
rv = NS_NewISupportsArray(getter_AddRefs(mOverlayReferences));
@ -166,33 +165,22 @@ nsXULPrototypeDocument::SetRootElement(nsXULPrototypeElement* aElement)
NS_IMETHODIMP
nsXULPrototypeDocument::AddStyleSheet(nsIStyleSheet* aStyleSheet)
nsXULPrototypeDocument::AddStyleSheetReference(nsIURI* aURI)
{
NS_PRECONDITION(aStyleSheet != nsnull, "null ptr");
if (! aStyleSheet)
NS_PRECONDITION(aURI != nsnull, "null ptr");
if (! aURI)
return NS_ERROR_NULL_POINTER;
mStyleSheets->AppendElement(aStyleSheet);
mStyleSheetReferences->AppendElement(aURI);
return NS_OK;
}
NS_IMETHODIMP
nsXULPrototypeDocument::GetStyleSheets(nsVoidArray& aResult)
nsXULPrototypeDocument::GetStyleSheetReferences(nsISupportsArray** aResult)
{
nsresult rv;
aResult.Clear();
PRUint32 cnt;
rv = mStyleSheets->Count(&cnt);
if (NS_FAILED(rv)) return rv;
for (PRInt32 i = 0; i < PRInt32(cnt); ++i) {
nsIStyleSheet* sheet = NS_REINTERPRET_CAST(nsIStyleSheet*, mStyleSheets->ElementAt(i));
aResult.AppendElement(sheet);
NS_RELEASE(sheet);
}
*aResult = mStyleSheetReferences;
NS_ADDREF(*aResult);
return NS_OK;
}
@ -211,21 +199,10 @@ nsXULPrototypeDocument::AddOverlayReference(nsIURI* aURI)
NS_IMETHODIMP
nsXULPrototypeDocument::GetOverlayReferences(nsVoidArray& aResult)
nsXULPrototypeDocument::GetOverlayReferences(nsISupportsArray** aResult)
{
nsresult rv;
aResult.Clear();
PRUint32 cnt;
rv = mOverlayReferences->Count(&cnt);
if (NS_FAILED(rv)) return rv;
for (PRInt32 i = 0; i < PRInt32(cnt); ++i) {
nsIURI* ref = NS_REINTERPRET_CAST(nsIURI*, mOverlayReferences->ElementAt(i));
aResult.AppendElement(ref);
NS_RELEASE(ref);
}
*aResult = mOverlayReferences;
NS_ADDREF(*aResult);
return NS_OK;
}