96364 - Register html tag observers directly to parser service rather than nsObserverService. Doing so, reduces a lot of overhead. Also, the observers are now notified via sink. This eliminates the need for parser bundle.
r=dp,shanjian,sfraser, sr=rpotts. git-svn-id: svn://10.0.0.236/trunk@104152 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
@@ -59,7 +59,6 @@
|
||||
#include "nsTagHandler.h"
|
||||
#include "nsHTMLTokenizer.h"
|
||||
#include "nsTime.h"
|
||||
#include "nsIElementObserver.h"
|
||||
#include "nsViewSourceHTML.h"
|
||||
#include "nsParserNode.h"
|
||||
#include "nsHTMLEntities.h"
|
||||
@@ -189,7 +188,7 @@ CNavDTD::CNavDTD() : nsIDTD(),
|
||||
mLineNumber(1)
|
||||
{
|
||||
NS_INIT_REFCNT();
|
||||
|
||||
|
||||
mBodyContext=new nsDTDContext();
|
||||
|
||||
#ifdef RICKG_DEBUG
|
||||
@@ -198,7 +197,6 @@ CNavDTD::CNavDTD() : nsIDTD(),
|
||||
nsHTMLElement::DebugDumpMembership("c:/temp/membership.out");
|
||||
nsHTMLElement::DebugDumpContainType("c:/temp/ctnrules.out");
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1377,13 +1375,8 @@ nsresult CNavDTD::WillHandleStartTag(CToken* aToken,eHTMLTags aTag,nsIParserNode
|
||||
STOP_TIMER()
|
||||
MOZ_TIMER_DEBUGLOG(("Stop: Parse Time: CNavDTD::WillHandleStartTag(), this=%p\n", this));
|
||||
|
||||
if(mParser) {
|
||||
|
||||
CObserverService* theService=mParser->GetObserverService();
|
||||
if(theService) {
|
||||
const nsISupportsParserBundle* bundle=mParser->GetParserBundle();
|
||||
result=theService->Notify(aTag,aNode,(void*)bundle, mMimeType, mParser);
|
||||
}
|
||||
if (aTag <= NS_HTML_TAG_MAX) {
|
||||
result = mSink->NotifyTagObservers(&aNode);
|
||||
}
|
||||
|
||||
MOZ_TIMER_DEBUGLOG(("Start: Parse Time: CNavDTD::WillHandleStartTag(), this=%p\n", this));
|
||||
|
||||
@@ -57,7 +57,6 @@
|
||||
#include "nsTagHandler.h"
|
||||
#include "nsHTMLTokenizer.h"
|
||||
#include "nsTime.h"
|
||||
#include "nsIElementObserver.h"
|
||||
#include "nsViewSourceHTML.h"
|
||||
#include "nsParserNode.h"
|
||||
#include "nsHTMLEntities.h"
|
||||
@@ -70,7 +69,7 @@ static NS_DEFINE_IID(kIHTMLContentSinkIID, NS_IHTML_CONTENT_SINK_IID);
|
||||
static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID);
|
||||
static NS_DEFINE_IID(kIDTDIID, NS_IDTD_IID);
|
||||
static NS_DEFINE_IID(kClassIID, NS_IOTHERHTML_DTD_IID);
|
||||
|
||||
static NS_DEFINE_IID(kParserServiceCID, NS_PARSERSERVICE_CID);
|
||||
static char* kVerificationDir = "c:/temp";
|
||||
|
||||
|
||||
@@ -640,12 +639,7 @@ nsresult COtherDTD::WillHandleStartTag(CToken* aToken,eHTMLTags aTag,nsIParserNo
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
CObserverService* theService=mParser->GetObserverService();
|
||||
if(theService) {
|
||||
const nsISupportsParserBundle* bundle=mParser->GetParserBundle();
|
||||
result=theService->Notify(aTag,aNode,(void*)bundle, NS_ConvertASCIItoUCS2(kHTMLTextContentType), mParser);
|
||||
}
|
||||
mSink->NotifyTagObservers(&aNode);
|
||||
}
|
||||
|
||||
MOZ_TIMER_DEBUGLOG(("Start: Parse Time: COtherDTD::WillHandleStartTag(), this=%p\n", this));
|
||||
|
||||
@@ -68,6 +68,7 @@ CPPSRCS = \
|
||||
nsHTMLTokens.cpp \
|
||||
nsParser.cpp \
|
||||
CParserContext.cpp \
|
||||
nsParserService.cpp \
|
||||
nsParserModule.cpp \
|
||||
nsParserNode.cpp \
|
||||
nsScanner.cpp \
|
||||
|
||||
@@ -62,6 +62,7 @@ CPPSRCS = \
|
||||
nsToken.cpp \
|
||||
nsWellFormedDTD.cpp \
|
||||
nsViewSourceHTML.cpp\
|
||||
nsParserService.cpp \
|
||||
nsParserModule.cpp \
|
||||
nsParserMsgUtils.cpp \
|
||||
!ifdef MOZ_DEBUG
|
||||
@@ -87,6 +88,7 @@ CPP_OBJS = \
|
||||
.\$(OBJDIR)\nsToken.obj \
|
||||
.\$(OBJDIR)\nsWellFormedDTD.obj \
|
||||
.\$(OBJDIR)\nsViewSourceHTML.obj\
|
||||
.\$(OBJDIR)\nsParserService.obj \
|
||||
.\$(OBJDIR)\nsParserModule.obj \
|
||||
.\$(OBJDIR)\nsParserMsgUtils.obj \
|
||||
!ifdef MOZ_DEBUG
|
||||
|
||||
@@ -42,18 +42,14 @@
|
||||
#include "CNavDTD.h"
|
||||
#include "nsIParserNode.h"
|
||||
#include "nsParserNode.h"
|
||||
|
||||
#include "nsIChannel.h"
|
||||
#include "nsIServiceManager.h"
|
||||
|
||||
nsIObserverService *CObserverService::gObserverService = NULL;
|
||||
|
||||
MOZ_DECL_CTOR_COUNTER(nsEntryStack)
|
||||
MOZ_DECL_CTOR_COUNTER(nsDTDContext)
|
||||
MOZ_DECL_CTOR_COUNTER(nsTokenAllocator)
|
||||
MOZ_DECL_CTOR_COUNTER(CNodeRecycler)
|
||||
MOZ_DECL_CTOR_COUNTER(CObserverService)
|
||||
|
||||
|
||||
/**************************************************************************************
|
||||
A few notes about how residual style handling is performed:
|
||||
|
||||
@@ -1477,313 +1473,131 @@ PRUint32 AccumulateCRC(PRUint32 crc_accum, char *data_blk_ptr, int data_blk_size
|
||||
return crc_accum;
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************
|
||||
Define the nsIElementObserver release class...
|
||||
**************************************************************/
|
||||
class nsObserverReleaser: public nsDequeFunctor{
|
||||
public:
|
||||
virtual void* operator()(void* anObject) {
|
||||
nsIElementObserver* theObserver= (nsIElementObserver*)anObject;
|
||||
NS_RELEASE(theObserver);
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
/**************************************************************
|
||||
This defines the topic object used by the observer service.
|
||||
The observerService uses a list of these, 1 per topic when
|
||||
registering tags.
|
||||
**************************************************************/
|
||||
NS_IMPL_ISUPPORTS1(nsObserverEntry, nsIObserverEntry)
|
||||
|
||||
nsObserverTopic::nsObserverTopic(const nsString& aTopic) : mTopic(aTopic) {
|
||||
|
||||
nsCRT::zero(mObservers,sizeof(mObservers));
|
||||
mCharsetKey.AssignWithConversion("charset");
|
||||
mSourceKey.AssignWithConversion("charsetSource");
|
||||
mDTDKey.AssignWithConversion("X_COMMAND");
|
||||
nsObserverEntry::nsObserverEntry(const nsAString& aTopic) : mTopic(aTopic)
|
||||
{
|
||||
NS_INIT_ISUPPORTS();
|
||||
nsCRT::zero(mObservers,sizeof(mObservers));
|
||||
}
|
||||
|
||||
nsObserverTopic::~nsObserverTopic() {
|
||||
nsObserverReleaser theReleaser;
|
||||
|
||||
PRInt32 theIndex=0;
|
||||
for(theIndex=0;theIndex<=NS_HTML_TAG_MAX;theIndex++){
|
||||
if(mObservers[theIndex]){
|
||||
mObservers[theIndex]->ForEach(theReleaser);
|
||||
delete mObservers[theIndex];
|
||||
mObservers[theIndex]=0;
|
||||
nsObserverEntry::~nsObserverEntry() {
|
||||
for (PRInt32 i = 0; i <= NS_HTML_TAG_MAX; i++){
|
||||
if (mObservers[i]) {
|
||||
PRInt32 count = mObservers[i]->Count();
|
||||
for (PRInt32 j = 0; j < count; j++) {
|
||||
nsISupports* obs = (nsISupports*)mObservers[i]->ElementAt(j);
|
||||
NS_IF_RELEASE(obs);
|
||||
}
|
||||
delete mObservers[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PRBool nsObserverTopic::Matches(const nsString& aString) {
|
||||
PRBool result=aString.Equals(mTopic);
|
||||
return result;
|
||||
}
|
||||
NS_IMETHODIMP
|
||||
nsObserverEntry::Notify(nsIParserNode* aNode,
|
||||
nsIParser* aParser,
|
||||
nsISupports* aWebShell)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aNode);
|
||||
NS_ENSURE_ARG_POINTER(aParser);
|
||||
|
||||
nsDeque* nsObserverTopic::GetObserversForTag(eHTMLTags aTag) {
|
||||
if(aTag <= NS_HTML_TAG_MAX) {
|
||||
return mObservers[aTag];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
nsresult result = NS_OK;
|
||||
eHTMLTags theTag = (eHTMLTags)aNode->GetNodeType();
|
||||
|
||||
if (theTag <= NS_HTML_TAG_MAX) {
|
||||
nsVoidArray* theObservers = mObservers[theTag];
|
||||
if (theObservers) {
|
||||
nsAutoString theCharsetValue;
|
||||
nsCharsetSource theCharsetSource;
|
||||
aParser->GetDocumentCharset(theCharsetValue,theCharsetSource);
|
||||
|
||||
void nsObserverTopic::RegisterObserverForTag(nsIElementObserver *anObserver,eHTMLTags aTag) {
|
||||
if(anObserver) {
|
||||
if(mObservers[aTag] == nsnull) {
|
||||
mObservers[aTag] = new nsDeque(0);
|
||||
}
|
||||
NS_ADDREF(anObserver);
|
||||
mObservers[aTag]->Push(anObserver);
|
||||
}
|
||||
}
|
||||
PRInt32 theAttrCount = aNode->GetAttributeCount();
|
||||
PRInt32 theObserversCount = theObservers->Count();
|
||||
if (0 < theObserversCount){
|
||||
nsStringArray keys(theAttrCount+4), values(theAttrCount+4);
|
||||
|
||||
/**
|
||||
* This method will notify observers registered for specific tags.
|
||||
*
|
||||
* @update harishd 08/29/99
|
||||
* @param aTag - The tag for which observers could be waiting for.
|
||||
* @param aNode -
|
||||
* @param aUniqueID - The document ID.
|
||||
* @param aDTD - The current DTD.
|
||||
* @param aCharsetValue -
|
||||
* @param aCharsetSource -
|
||||
* @return if SUCCESS return NS_OK else return ERROR code.
|
||||
*/
|
||||
nsresult nsObserverTopic::Notify(eHTMLTags aTag,nsIParserNode& aNode,void* aUniqueID,nsIParser* aParser) {
|
||||
nsresult result=NS_OK;
|
||||
// XXX this and the following code may be a performance issue.
|
||||
// Every key and value is copied and added to an voidarray (causing at
|
||||
// least 2 allocations for mImpl, usually more, plus at least 1 per
|
||||
// string (total = 2*(keys+3) + 2(or more) array allocations )).
|
||||
PRInt32 index;
|
||||
for (index = 0; index < theAttrCount; index++) {
|
||||
keys.AppendString(aNode->GetKeyAt(index));
|
||||
values.AppendString(aNode->GetValueAt(index));
|
||||
}
|
||||
|
||||
nsDeque* theObservers=GetObserversForTag(aTag);
|
||||
if(theObservers){
|
||||
nsAutoString intValue;
|
||||
|
||||
nsAutoString theCharsetValue;
|
||||
nsCharsetSource theCharsetSource;
|
||||
aParser->GetDocumentCharset(theCharsetValue,theCharsetSource);
|
||||
|
||||
PRInt32 theAttrCount =aNode.GetAttributeCount();
|
||||
PRInt32 theObserversCount=theObservers->GetSize();
|
||||
if(0<theObserversCount){
|
||||
nsStringArray keys(theAttrCount+4),values(theAttrCount+4);
|
||||
|
||||
// XXX this and the following code may be a performance issue.
|
||||
// Every key and value is copied and added to an voidarray (causing at
|
||||
// least 2 allocations for mImpl, usually more, plus at least 1 per
|
||||
// string (total = 2*(keys+3) + 2(or more) array allocations )).
|
||||
PRInt32 index;
|
||||
for(index=0; index<theAttrCount; index++) {
|
||||
keys.AppendString(aNode.GetKeyAt(index));
|
||||
values.AppendString(aNode.GetValueAt(index));
|
||||
}
|
||||
|
||||
nsAutoString intValue;
|
||||
|
||||
keys.AppendString(mCharsetKey);
|
||||
values.AppendString(theCharsetValue);
|
||||
keys.AppendString(NS_LITERAL_STRING("charset"));
|
||||
values.AppendString(theCharsetValue);
|
||||
|
||||
keys.AppendString(mSourceKey);
|
||||
intValue.AppendInt(PRInt32(theCharsetSource),10);
|
||||
values.AppendString(intValue);
|
||||
keys.AppendString(NS_LITERAL_STRING("charsetSource"));
|
||||
intValue.AppendInt(PRInt32(theCharsetSource),10);
|
||||
values.AppendString(intValue);
|
||||
|
||||
keys.AppendString(mDTDKey);
|
||||
values.AppendString(mTopic);
|
||||
keys.AppendString(NS_LITERAL_STRING("X_COMMAND"));
|
||||
values.AppendString(NS_LITERAL_STRING("text/html"));
|
||||
|
||||
nsAutoString theTagStr; theTagStr.AssignWithConversion(nsHTMLTags::GetStringValue(aTag));
|
||||
|
||||
for(index=0;index<theObserversCount;index++) {
|
||||
nsIElementObserver* observer=NS_STATIC_CAST(nsIElementObserver*,theObservers->ObjectAt(index));
|
||||
if(observer) {
|
||||
result=observer->Notify((nsISupports*)aUniqueID,theTagStr.get(),&keys,&values);
|
||||
if(NS_FAILED(result)) {
|
||||
break;
|
||||
nsAutoString theTagStr;
|
||||
theTagStr.AssignWithConversion(nsHTMLTags::GetStringValue(theTag));
|
||||
|
||||
nsCOMPtr<nsIChannel> channel;
|
||||
aParser->GetChannel(getter_AddRefs(channel));
|
||||
|
||||
for (index=0;index<theObserversCount;index++) {
|
||||
nsIElementObserver* observer = NS_STATIC_CAST(nsIElementObserver*,theObservers->ElementAt(index));
|
||||
if (observer) {
|
||||
result = observer->Notify(aWebShell,channel,theTagStr.get(),&keys,&values);
|
||||
if (NS_FAILED(result)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}//if
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsObserverEntry::Matches(const nsAString& aString) {
|
||||
PRBool result = aString.Equals(mTopic);
|
||||
return result;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
This class is used to store ref's to tag observers during the parse phase.
|
||||
Note that for simplicity, this is a singleton that is constructed in the
|
||||
CNavDTD and shared for the duration of the application session. Later on it
|
||||
might be nice to use a more dynamic approach that would permit observers to
|
||||
come and go on a document basis.
|
||||
|
||||
I changed the observerservice to store topics so that we can distinguish
|
||||
observers by topic. Up till now, they've all just be thrown into the same
|
||||
observer list, which was wrong. This fixes bug #28825.
|
||||
******************************************************************************/
|
||||
nsresult
|
||||
CObserverService::InitGlobals() {
|
||||
if (!gObserverService) {
|
||||
nsresult rv = NS_OK;
|
||||
nsCOMPtr<nsIObserverService> obs(do_GetService(NS_OBSERVERSERVICE_CONTRACTID,&rv));
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
gObserverService = obs.get();
|
||||
NS_IF_ADDREF(gObserverService);
|
||||
nsObserverEntry::AddObserver(nsIElementObserver *aObserver,
|
||||
eHTMLTags aTag)
|
||||
{
|
||||
if (aObserver) {
|
||||
if (!mObservers[aTag]) {
|
||||
mObservers[aTag] = new nsAutoVoidArray();
|
||||
if (!mObservers[aTag]) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
}
|
||||
NS_ADDREF(aObserver);
|
||||
mObservers[aTag]->AppendElement(aObserver);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
CObserverService::ReleaseGlobals() {
|
||||
NS_IF_RELEASE(gObserverService);
|
||||
}
|
||||
|
||||
CObserverService::CObserverService() : mTopics(0) {
|
||||
|
||||
MOZ_COUNT_CTOR(CObserverService);
|
||||
|
||||
nsAutoString theHTMLTopic; theHTMLTopic.AssignWithConversion(kHTMLTextContentType);
|
||||
RegisterObservers(theHTMLTopic);
|
||||
|
||||
nsAutoString theXMLTopic; theXMLTopic.AssignWithConversion(kXMLTextContentType); //use the mimetype for the topic
|
||||
RegisterObservers(theXMLTopic);
|
||||
|
||||
theXMLTopic.AssignWithConversion(kXMLApplicationContentType);
|
||||
RegisterObservers(theXMLTopic);
|
||||
|
||||
theXMLTopic.AssignWithConversion(kXHTMLApplicationContentType);
|
||||
RegisterObservers(theXMLTopic);
|
||||
}
|
||||
|
||||
|
||||
CObserverService::~CObserverService() {
|
||||
|
||||
MOZ_COUNT_DTOR(CObserverService);
|
||||
|
||||
nsObserverTopic *theTopic=(nsObserverTopic*)mTopics.Pop();
|
||||
while(theTopic) {
|
||||
delete theTopic;
|
||||
theTopic=(nsObserverTopic*)mTopics.Pop();
|
||||
}
|
||||
}
|
||||
|
||||
// XXX This may be more efficient as a HashTable instead of linear search
|
||||
nsObserverTopic* CObserverService::GetTopic(const nsString& aTopic) {
|
||||
PRInt32 theIndex=0;
|
||||
nsObserverTopic *theTopic=(nsObserverTopic*)mTopics.ObjectAt(theIndex++);
|
||||
|
||||
while(theTopic) {
|
||||
if(theTopic->Matches(aTopic))
|
||||
return theTopic;
|
||||
theTopic=(nsObserverTopic*)mTopics.ObjectAt(theIndex++);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
nsObserverTopic* CObserverService::CreateTopic(const nsString& aTopic) {
|
||||
nsObserverTopic* theTopic=new nsObserverTopic(aTopic);
|
||||
mTopics.Push(theTopic);
|
||||
return theTopic;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method will maintain lists of observers registered for specific tags.
|
||||
*
|
||||
* @update rickg 03.23.2000
|
||||
* @param aTopic - The topic under which observers register for.
|
||||
* @return if SUCCESS return NS_OK else return ERROR code.
|
||||
*/
|
||||
|
||||
void CObserverService::RegisterObservers(const nsString& aTopic) {
|
||||
nsresult result = NS_OK;
|
||||
if (gObserverService) {
|
||||
nsIEnumerator* theEnum = nsnull;
|
||||
result = gObserverService->EnumerateObserverList(aTopic.get(), &theEnum);
|
||||
|
||||
if(result == NS_OK) {
|
||||
nsCOMPtr<nsIElementObserver> theElementObserver;
|
||||
nsISupports *inst = nsnull;
|
||||
|
||||
nsObserverTopic *theTopic=0;
|
||||
|
||||
for (theEnum->First(); theEnum->IsDone() != NS_OK; theEnum->Next()) {
|
||||
result = theEnum->CurrentItem(&inst);
|
||||
if (NS_SUCCEEDED(result)) {
|
||||
theElementObserver = do_QueryInterface(inst, &result);
|
||||
NS_RELEASE(inst);
|
||||
}
|
||||
if (result == NS_OK) {
|
||||
const char* theTagStr = nsnull;
|
||||
PRUint32 theTagIndex = 0;
|
||||
theTagStr = theElementObserver->GetTagNameAt(theTagIndex);
|
||||
while (theTagStr != nsnull) {
|
||||
eHTMLTags theTag = nsHTMLTags::LookupTag(nsCAutoString(theTagStr));
|
||||
if((eHTMLTag_userdefined!=theTag) && (theTag <= NS_HTML_TAG_MAX)){
|
||||
|
||||
theTopic=GetTopic(aTopic);
|
||||
if(!theTopic)
|
||||
theTopic=CreateTopic(aTopic);
|
||||
if(theTopic) {
|
||||
theTopic->RegisterObserverForTag(theElementObserver,theTag);
|
||||
}
|
||||
|
||||
}
|
||||
theTagIndex++;
|
||||
theTagStr = theElementObserver->GetTagNameAt(theTagIndex);
|
||||
}
|
||||
}
|
||||
void
|
||||
nsObserverEntry::RemoveObserver(nsIElementObserver *aObserver)
|
||||
{
|
||||
for (PRInt32 i=0; i <= NS_HTML_TAG_MAX; i++){
|
||||
if (mObservers[i]) {
|
||||
nsISupports* obs = aObserver;
|
||||
PRBool removed = mObservers[i]->RemoveElement(obs);
|
||||
if (removed) {
|
||||
NS_RELEASE(obs);
|
||||
}
|
||||
}
|
||||
NS_IF_RELEASE(theEnum);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method will maintain lists of observers registered for specific tags.
|
||||
*
|
||||
* @update rickg 03.23.2000
|
||||
* @param aTopic - The topic under which observers register for.
|
||||
* @return if SUCCESS return NS_OK else return ERROR code.
|
||||
*/
|
||||
|
||||
void CObserverService::UnregisterObservers(const nsString& aTopic) {
|
||||
}
|
||||
|
||||
/**
|
||||
* This method will notify observers registered for specific tags.
|
||||
*
|
||||
* @update rickg 03.23.2000
|
||||
* @param aTag - The tag for which observers could be waiting for.
|
||||
* @param aNode -
|
||||
* @param aUniqueID - The document ID.
|
||||
* @param aDTD - The current DTD.
|
||||
* @param aCharsetValue -
|
||||
* @param aCharsetSource -
|
||||
* @return if SUCCESS return NS_OK else return ERROR code.
|
||||
*/
|
||||
nsresult CObserverService::Notify( eHTMLTags aTag,
|
||||
nsIParserNode& aNode,
|
||||
void* aUniqueID,
|
||||
const nsString& aTopic,
|
||||
nsIParser* aParser) {
|
||||
nsresult result=NS_OK;
|
||||
nsObserverTopic *theTopic=GetTopic(aTopic);
|
||||
if(theTopic) {
|
||||
result=theTopic->Notify(aTag,aNode,aUniqueID,aParser);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method will look for the list of observers registered for
|
||||
* a specific tag.
|
||||
*
|
||||
* @update rickg 03.23.2000
|
||||
* @param aTag - The tag for which observers could be waiting for.
|
||||
* @return if FOUND return "observer list" else return nsnull;
|
||||
*
|
||||
*/
|
||||
|
||||
nsDeque* CObserverService::GetObserversForTagInTopic(eHTMLTags aTag,const nsString& aTopic) {
|
||||
nsObserverTopic *theTopic=GetTopic(aTopic);
|
||||
if(theTopic) {
|
||||
return theTopic->GetObserversForTag(aTag);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -56,11 +56,10 @@
|
||||
#include "nsIDTD.h"
|
||||
#include "nsITokenizer.h"
|
||||
#include "nsString.h"
|
||||
#include "nsIElementObserver.h"
|
||||
#include "nsIParserNode.h"
|
||||
#include "nsFixedSizeAllocator.h"
|
||||
#include "nsVoidArray.h"
|
||||
#include "nsIObserverService.h"
|
||||
#include "nsIParserService.h"
|
||||
|
||||
#define IF_HOLD(_ptr) \
|
||||
PR_BEGIN_MACRO \
|
||||
@@ -533,53 +532,23 @@ struct CRCStruct {
|
||||
registering tags.
|
||||
**************************************************************/
|
||||
|
||||
class nsObserverTopic {
|
||||
class nsObserverEntry : public nsIObserverEntry {
|
||||
public:
|
||||
nsObserverTopic(const nsString& aTopic);
|
||||
~nsObserverTopic();
|
||||
PRBool Matches(const nsString& aTopic);
|
||||
void RegisterObserverForTag(nsIElementObserver *anObserver,eHTMLTags aTag);
|
||||
nsDeque* GetObserversForTag(eHTMLTags aTag);
|
||||
nsresult Notify(eHTMLTags aTag,nsIParserNode& aNode,void* aUniqueID,nsIParser* aParser);
|
||||
NS_DECL_ISUPPORTS
|
||||
nsObserverEntry(const nsAString& aTopic);
|
||||
virtual ~nsObserverEntry();
|
||||
|
||||
nsString mTopic;
|
||||
nsString mCharsetKey;
|
||||
nsString mSourceKey;
|
||||
nsString mDTDKey;
|
||||
nsDeque* mObservers[NS_HTML_TAG_MAX + 1];
|
||||
};
|
||||
NS_IMETHOD Notify(nsIParserNode* aNode,
|
||||
nsIParser* aParser,
|
||||
nsISupports* aWebShell);
|
||||
|
||||
/******************************************************************************
|
||||
This class is used to store ref's to token observers during the parse phase.
|
||||
Note that for simplicity, this is a singleton that is constructed in the
|
||||
CNavDTD and shared for the duration of the application session. Later on it
|
||||
might be nice to use a more dynamic approach that would permit observers to
|
||||
come and go on a document basis.
|
||||
******************************************************************************/
|
||||
class CObserverService {
|
||||
public:
|
||||
CObserverService();
|
||||
~CObserverService();
|
||||
|
||||
nsDeque* GetObserversForTagInTopic(eHTMLTags aTag,const nsString& aTopic);
|
||||
nsresult Notify( eHTMLTags aTag,
|
||||
nsIParserNode& aNode,
|
||||
void* aUniqueID,
|
||||
const nsString& aTopic,
|
||||
nsIParser* aParser);
|
||||
nsObserverTopic* GetTopic(const nsString& aTopic);
|
||||
nsObserverTopic* CreateTopic(const nsString& aTopic);
|
||||
|
||||
// Do allocation and release of gObserverService
|
||||
// These are called from the module init and shutdown
|
||||
static nsresult InitGlobals();
|
||||
static void ReleaseGlobals();
|
||||
nsresult AddObserver(nsIElementObserver* aObserver,eHTMLTags aTag);
|
||||
void RemoveObserver(nsIElementObserver* aObserver);
|
||||
PRBool Matches(const nsAString& aTopic);
|
||||
|
||||
protected:
|
||||
void RegisterObservers(const nsString& aTopic);
|
||||
void UnregisterObservers(const nsString& aTopic);
|
||||
nsDeque mTopics; //each topic holds a list of observers per tag.
|
||||
static nsIObserverService *gObserverService;
|
||||
nsString mTopic;
|
||||
nsVoidArray* mObservers[NS_HTML_TAG_MAX + 1];
|
||||
};
|
||||
|
||||
/*********************************************************************************************/
|
||||
|
||||
@@ -72,6 +72,7 @@ public:
|
||||
NS_IMETHOD AddDocTypeDecl(const nsIParserNode& aNode, PRInt32 aMode=0);
|
||||
NS_IMETHOD FlushPendingNotifications() {return NS_OK; }
|
||||
NS_IMETHOD SetDocumentCharset(nsAWritableString& aCharset) {return NS_OK;}
|
||||
NS_IMETHOD NotifyTagObservers(nsIParserNode* aNode) { return NS_OK; }
|
||||
|
||||
// nsIHTMLContentSink
|
||||
NS_IMETHOD SetTitle(const nsString& aValue);
|
||||
|
||||
@@ -74,6 +74,7 @@ public:
|
||||
NS_IMETHOD AddDocTypeDecl(const nsIParserNode& aNode, PRInt32 aMode=0);
|
||||
NS_IMETHOD FlushPendingNotifications() { return NS_OK; }
|
||||
NS_IMETHOD SetDocumentCharset(nsAWritableString& aCharset) { return NS_OK; }
|
||||
NS_IMETHOD NotifyTagObservers(nsIParserNode* aNode) { return NS_OK; }
|
||||
|
||||
// nsIHTMLContentSink
|
||||
NS_IMETHOD SetTitle(const nsString& aValue);
|
||||
|
||||
@@ -356,7 +356,6 @@ nsParser::nsParser(nsITokenObserver* anObserver) {
|
||||
mObserversEnabled=PR_TRUE;
|
||||
mCommand=eViewNormal;
|
||||
mParserEnabled=PR_TRUE;
|
||||
mBundle=nsnull;
|
||||
mPendingContinueEvent=PR_FALSE;
|
||||
mCanInterrupt=PR_FALSE;
|
||||
|
||||
@@ -405,7 +404,6 @@ nsParser::~nsParser() {
|
||||
NS_IF_RELEASE(mProgressEventSink);
|
||||
NS_IF_RELEASE(mSink);
|
||||
NS_IF_RELEASE(mParserFilter);
|
||||
NS_IF_RELEASE(mBundle);
|
||||
|
||||
//don't forget to add code here to delete
|
||||
//what may be several contexts...
|
||||
@@ -456,9 +454,6 @@ nsresult nsParser::QueryInterface(const nsIID& aIID, void** aInstancePtr)
|
||||
else if(aIID.Equals(kCParserCID)) { //do this class...
|
||||
*aInstancePtr = (nsParser*)(this);
|
||||
}
|
||||
else if(aIID.Equals(NS_GET_IID(nsISupportsParserBundle))) {
|
||||
*aInstancePtr = (nsISupportsParserBundle*)(this);
|
||||
}
|
||||
else {
|
||||
*aInstancePtr=0;
|
||||
return NS_NOINTERFACE;
|
||||
@@ -1031,7 +1026,7 @@ static void VerifyPublicIDs()
|
||||
NS_NOTREACHED("doctype not lower case");
|
||||
printf("Doctype %s not lower case.\n", kPublicIDs[i].name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -1422,7 +1417,6 @@ nsresult nsParser::DidBuildModel(nsresult anErrorCode) {
|
||||
result = mParserContext->mDTD->DidBuildModel(anErrorCode,PRBool(0==mParserContext->mPrevContext),this,mSink);
|
||||
}
|
||||
//Ref. to bug 61462.
|
||||
NS_IF_RELEASE(mBundle);
|
||||
}//if
|
||||
}
|
||||
|
||||
@@ -2725,133 +2719,4 @@ nsParser::GetDTD(nsIDTD** aDTD)
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the observer service
|
||||
*
|
||||
* @update rickg 11/22/99
|
||||
* @return ptr to server or NULL
|
||||
*/
|
||||
CObserverService* nsParser::GetObserverService(void) {
|
||||
//XXX Hack! this should be XPCOM based!
|
||||
if(mObserversEnabled)
|
||||
return &mObserverService;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Store data into the bundle.
|
||||
*
|
||||
* @update harishd 05/10/00
|
||||
* @param aData - The data to be stored.
|
||||
* @return NS_OK if all went well else ERROR.
|
||||
*/
|
||||
NS_IMETHODIMP
|
||||
nsParser::SetDataIntoBundle(const nsString& aKey,nsISupports* anObject) {
|
||||
nsresult result=NS_OK;
|
||||
if(!mBundle) {
|
||||
mBundle = new nsParserBundle();
|
||||
if(mBundle==nsnull) return NS_ERROR_OUT_OF_MEMORY;
|
||||
NS_ADDREF(mBundle);
|
||||
}
|
||||
result=mBundle->SetDataIntoBundle(aKey,anObject);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve data from the bundle by IID.
|
||||
* NOTE: The object retireved should not be released
|
||||
*
|
||||
* @update harishd 05/10/00
|
||||
* @param aIID - The ID to identify the correct object in the bundle
|
||||
* @return Return object if found in bundle else return NULL.
|
||||
*/
|
||||
NS_IMETHODIMP
|
||||
nsParser::GetDataFromBundle(const nsString& aKey,nsISupports** anObject) {
|
||||
nsresult result=NS_OK;
|
||||
result=mBundle->GetDataFromBundle(aKey,anObject);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
NS_IMPL_ISUPPORTS1(nsParserBundle,
|
||||
nsISupportsParserBundle
|
||||
);
|
||||
|
||||
|
||||
/**
|
||||
* Release data from the Hash table
|
||||
*
|
||||
* @update harishd 05/10/00
|
||||
*/
|
||||
static PRBool PR_CALLBACK ReleaseData(nsHashKey* aKey, void* aData, void* aClosure) {
|
||||
nsISupports* object = (nsISupports*)aData;
|
||||
NS_RELEASE(object);
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @update harishd 05/10/00
|
||||
*/
|
||||
nsParserBundle::nsParserBundle (){
|
||||
NS_INIT_REFCNT();
|
||||
mData=new nsHashtable(5);
|
||||
}
|
||||
|
||||
/**
|
||||
* Release objects from the bundle.
|
||||
*
|
||||
* @update harishd 05/10/00
|
||||
*/
|
||||
nsParserBundle::~nsParserBundle () {
|
||||
mData->Enumerate(ReleaseData);
|
||||
delete mData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Store data into the bundle.
|
||||
*
|
||||
* @update harishd 05/10/00
|
||||
* @param aData - The data to be stored.
|
||||
* @return NS_OK if all went well else ERROR.
|
||||
*/
|
||||
NS_IMETHODIMP
|
||||
nsParserBundle::SetDataIntoBundle(const nsString& aKey,nsISupports* anObject) {
|
||||
nsresult result=NS_OK;
|
||||
if(anObject) {
|
||||
nsStringKey key(aKey);
|
||||
PRBool found=mData->Exists(&key);
|
||||
if(!found) {
|
||||
NS_ADDREF(anObject);
|
||||
mData->Put(&key,anObject);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve data from the bundle by IID.
|
||||
* NOTE: The object retrieved should not be released.
|
||||
*
|
||||
* @update harishd 05/10/00
|
||||
* @param aIID - The ID to identify the correct object in the bundle
|
||||
* @return Return object if found in bundle else return NULL.
|
||||
*/
|
||||
NS_IMETHODIMP
|
||||
nsParserBundle::GetDataFromBundle(const nsString& aKey,nsISupports** anObject) {
|
||||
nsresult result=NS_OK;
|
||||
|
||||
nsStringKey key(aKey);
|
||||
*anObject=(mData)? (nsISupports*)mData->Get(&key):nsnull;
|
||||
|
||||
if(*anObject) {
|
||||
NS_ADDREF(*anObject);
|
||||
}
|
||||
else{
|
||||
result=NS_ERROR_NULL_POINTER;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -93,7 +93,6 @@ class nsIDTD;
|
||||
class nsScanner;
|
||||
class nsIParserFilter;
|
||||
class nsIProgressEventSink;
|
||||
class nsParserBundle;
|
||||
|
||||
#ifdef XP_WIN
|
||||
#pragma warning( disable : 4275 )
|
||||
@@ -101,7 +100,6 @@ class nsParserBundle;
|
||||
|
||||
|
||||
class nsParser : public nsIParser,
|
||||
public nsISupportsParserBundle,
|
||||
public nsIStreamListener{
|
||||
|
||||
|
||||
@@ -287,8 +285,6 @@ class nsParser : public nsIParser,
|
||||
CParserContext* PopContext();
|
||||
CParserContext* PeekContext() {return mParserContext;}
|
||||
|
||||
const nsParserBundle* GetParserBundle() { return mBundle; }
|
||||
|
||||
/**
|
||||
*
|
||||
* @update gess 1/22/99
|
||||
@@ -320,20 +316,7 @@ class nsParser : public nsIParser,
|
||||
* @return NS_OK if successful, NS_ERROR_FAILURE for runtime error
|
||||
*/
|
||||
NS_IMETHOD GetDTD(nsIDTD** aDTD);
|
||||
|
||||
/**
|
||||
* Call this to access observer dictionary ( internal to parser )
|
||||
* @update harishd 06/27/99
|
||||
* @param
|
||||
* @return
|
||||
*/
|
||||
CObserverService* GetObserverService(void);
|
||||
|
||||
|
||||
// nsISupportsParserBundle
|
||||
NS_IMETHOD GetDataFromBundle(const nsString& aKey,nsISupports** anObject);
|
||||
NS_IMETHOD SetDataIntoBundle(const nsString& aKey,nsISupports* anObject);
|
||||
|
||||
|
||||
/**
|
||||
* Call this method to determine a DTD for a DOCTYPE
|
||||
*
|
||||
@@ -490,11 +473,9 @@ protected:
|
||||
nsString mCharset;
|
||||
nsCharsetSource mCharsetSource;
|
||||
nsresult mInternalState;
|
||||
CObserverService mObserverService;
|
||||
PRBool mObserversEnabled;
|
||||
nsString mCommandStr;
|
||||
PRBool mParserEnabled;
|
||||
nsParserBundle* mBundle;
|
||||
nsTokenAllocator mTokenAllocator;
|
||||
|
||||
nsCOMPtr<nsIEventQueue> mEventQueue;
|
||||
@@ -508,37 +489,5 @@ public:
|
||||
MOZ_TIMER_DECLARE(mTokenizeTime)
|
||||
};
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
|
||||
class nsParserBundle : public nsISupportsParserBundle {
|
||||
public:
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
nsParserBundle ();
|
||||
virtual ~nsParserBundle ();
|
||||
|
||||
/**
|
||||
* Retrieve data from the bundle by IID.
|
||||
*
|
||||
* @update harishd 05/10/00
|
||||
* @param aIID - The ID to identify the correct object in the bundle
|
||||
* @return Return object if found in bundle else return NULL.
|
||||
*/
|
||||
NS_IMETHOD GetDataFromBundle(const nsString& aKey,nsISupports** anObject);
|
||||
|
||||
/**
|
||||
* Store data into the bundle.
|
||||
*
|
||||
* @update harishd 05/10/00
|
||||
* @param aData - The data to be stored.
|
||||
* @return NS_OK if all went well else ERROR.
|
||||
*/
|
||||
NS_IMETHOD SetDataIntoBundle(const nsString& aKey,nsISupports* anObject);
|
||||
|
||||
protected:
|
||||
nsHashtable* mData;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -53,115 +53,13 @@
|
||||
#include "nsHTMLTokenizer.h"
|
||||
//#include "nsTextTokenizer.h"
|
||||
#include "nsExpatTokenizer.h"
|
||||
#include "nsIParserService.h"
|
||||
#include "nsElementTable.h"
|
||||
#include "nsParserService.h"
|
||||
|
||||
#ifdef NS_DEBUG
|
||||
#include "nsLoggingSink.h"
|
||||
#endif
|
||||
|
||||
class nsParserService : public nsIParserService {
|
||||
public:
|
||||
nsParserService();
|
||||
virtual ~nsParserService();
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
NS_IMETHOD HTMLAtomTagToId(nsIAtom* aAtom, PRInt32* aId) const;
|
||||
|
||||
NS_IMETHOD HTMLStringTagToId(const nsString &aTag, PRInt32* aId) const;
|
||||
|
||||
NS_IMETHOD HTMLIdToStringTag(PRInt32 aId, nsString& aTag) const;
|
||||
|
||||
NS_IMETHOD HTMLConvertEntityToUnicode(const nsString& aEntity,
|
||||
PRInt32* aUnicode) const;
|
||||
NS_IMETHOD HTMLConvertUnicodeToEntity(PRInt32 aUnicode,
|
||||
nsCString& aEntity) const;
|
||||
NS_IMETHOD IsContainer(PRInt32 aId, PRBool& aIsContainer) const;
|
||||
NS_IMETHOD IsBlock(PRInt32 aId, PRBool& aIsBlock) const;
|
||||
};
|
||||
|
||||
nsParserService::nsParserService()
|
||||
{
|
||||
NS_INIT_ISUPPORTS();
|
||||
}
|
||||
|
||||
nsParserService::~nsParserService()
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS1(nsParserService, nsIParserService)
|
||||
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsParserService::HTMLAtomTagToId(nsIAtom* aAtom, PRInt32* aId) const
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aAtom);
|
||||
|
||||
nsAutoString tagName;
|
||||
aAtom->ToString(tagName);
|
||||
*aId = nsHTMLTags::LookupTag(tagName);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsParserService::HTMLStringTagToId(const nsString &aTag, PRInt32* aId) const
|
||||
{
|
||||
*aId = nsHTMLTags::LookupTag(aTag);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsParserService::HTMLIdToStringTag(PRInt32 aId, nsString& aTag) const
|
||||
{
|
||||
aTag.AssignWithConversion( nsHTMLTags::GetStringValue((nsHTMLTag)aId) );
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsParserService::HTMLConvertEntityToUnicode(const nsString& aEntity,
|
||||
PRInt32* aUnicode) const
|
||||
{
|
||||
*aUnicode = nsHTMLEntities::EntityToUnicode(aEntity);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsParserService::HTMLConvertUnicodeToEntity(PRInt32 aUnicode,
|
||||
nsCString& aEntity) const
|
||||
{
|
||||
const char* str = nsHTMLEntities::UnicodeToEntity(aUnicode);
|
||||
if (str) {
|
||||
aEntity.Assign(str);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsParserService::IsContainer(PRInt32 aId, PRBool& aIsContainer) const
|
||||
{
|
||||
aIsContainer = nsHTMLElement::IsContainer((eHTMLTags)aId);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsParserService::IsBlock(PRInt32 aId, PRBool& aIsBlock) const
|
||||
{
|
||||
if((aId>eHTMLTag_unknown) && (aId<eHTMLTag_userdefined)) {
|
||||
aIsBlock=((gHTMLElements[aId].IsMemberOf(kBlock)) ||
|
||||
(gHTMLElements[aId].IsMemberOf(kBlockEntity)) ||
|
||||
(gHTMLElements[aId].IsMemberOf(kHeading)) ||
|
||||
(gHTMLElements[aId].IsMemberOf(kPreformatted))||
|
||||
(gHTMLElements[aId].IsMemberOf(kList)));
|
||||
}
|
||||
else {
|
||||
aIsBlock = PR_FALSE;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
#ifdef NS_DEBUG
|
||||
@@ -203,7 +101,6 @@ Initialize(nsIModule* aSelf)
|
||||
nsHTMLEntities::AddRefTable();
|
||||
InitializeElementTable();
|
||||
CNewlineToken::AllocNewline();
|
||||
CObserverService::InitGlobals();
|
||||
gInitialized = PR_TRUE;
|
||||
}
|
||||
return NS_OK;
|
||||
@@ -219,7 +116,6 @@ Shutdown(nsIModule* aSelf)
|
||||
nsParser::FreeSharedObjects();
|
||||
DeleteElementTable();
|
||||
CNewlineToken::FreeNewline();
|
||||
CObserverService::ReleaseGlobals();
|
||||
gInitialized = PR_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,17 +80,16 @@
|
||||
#include "prtypes.h" //this is here for debug reasons...
|
||||
#include "prio.h"
|
||||
#include "plstr.h"
|
||||
|
||||
#include "prmem.h"
|
||||
|
||||
|
||||
#ifdef RAPTOR_PERF_METRICS
|
||||
#include "stopwatch.h"
|
||||
Stopwatch vsTimer;
|
||||
#endif
|
||||
|
||||
|
||||
static NS_DEFINE_IID(kClassIID, NS_VIEWSOURCE_HTML_IID);
|
||||
static NS_DEFINE_IID(kClassIID, NS_VIEWSOURCE_HTML_IID);
|
||||
|
||||
static int gErrorThreshold = 10;
|
||||
|
||||
// Define this to dump the viewsource stuff to a file
|
||||
@@ -1099,12 +1098,7 @@ NS_IMETHODIMP CViewSourceHTML::HandleToken(CToken* aToken,nsIParser* aParser) {
|
||||
else result=WriteTag(mStartTag,startValue,aToken->GetAttributeCount(),PR_TRUE);
|
||||
|
||||
if((ePlainText!=mDocType) && mParser && (NS_OK==result)) {
|
||||
CObserverService* theService=mParser->GetObserverService();
|
||||
if(theService) {
|
||||
eHTMLTags theTag=(eHTMLTags)theToken->GetTypeID();
|
||||
const nsISupportsParserBundle* bundle=mParser->GetParserBundle();
|
||||
result=theService->Notify(theTag,theContext.mTokenNode,(void*)bundle, mMimeType, mParser);
|
||||
}
|
||||
result = mSink->NotifyTagObservers(&theContext.mTokenNode);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
Reference in New Issue
Block a user