зеркало из https://github.com/mozilla/pjs.git
Added code to interrupt the parser's processing of tokens if a threshold is exceeded to improve interactivity during long page loads. Turned OFF by default. Can be enabled through a pref. bug 76722 r=harishd@netscape.com,rickg@netscape.com sr=vidur@netscape.com,attinasi@netscape.com a=chofmann@netscape.com
This commit is contained in:
Родитель
208706e674
Коммит
e3ef64bd96
|
@ -102,6 +102,10 @@ public:
|
|||
NS_IMETHOD DoFragment(PRBool aFlag);
|
||||
NS_IMETHOD BeginContext(PRInt32 aPosition) { return NS_OK; }
|
||||
NS_IMETHOD EndContext(PRInt32 aPosition) { return NS_OK; }
|
||||
NS_IMETHOD WillProcessTokens(void) { return NS_OK; }
|
||||
NS_IMETHOD DidProcessTokens(void) { return NS_OK; }
|
||||
NS_IMETHOD WillProcessAToken(void) { return NS_OK; }
|
||||
NS_IMETHOD DidProcessAToken(void) { return NS_OK; }
|
||||
|
||||
// nsIHTMLToTextSink
|
||||
NS_IMETHOD Initialize(nsAWritableString* aOutString,
|
||||
|
|
|
@ -170,6 +170,35 @@ static PRLogModuleInfo* gSinkLogModuleInfo;
|
|||
|
||||
#define NS_SINK_FLAG_SCRIPT_ENABLED 0x8
|
||||
#define NS_SINK_FLAG_FRAMES_ENABLED 0x10
|
||||
#define NS_SINK_FLAG_CAN_INTERRUPT_PARSER 0x20 //Interrupt parsing when mMaxTokenProcessingTime is exceeded
|
||||
|
||||
// Timer used to determine how long the content sink
|
||||
// spends processing a tokens
|
||||
|
||||
class nsDelayTimer
|
||||
{
|
||||
public:
|
||||
|
||||
void Start(void) {
|
||||
mStart = PR_IntervalToMicroseconds(PR_IntervalNow());
|
||||
}
|
||||
|
||||
// Determine if the current time - start time is greater
|
||||
// then aMaxDelayInMicroseconds
|
||||
PRBool HasExceeded(PRUint32 aMaxDelayInMicroseconds) {
|
||||
PRUint32 stop = PR_IntervalToMicroseconds(PR_IntervalNow());
|
||||
if ((stop - mStart) > aMaxDelayInMicroseconds) {
|
||||
return PR_TRUE;
|
||||
}
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
private:
|
||||
PRUint32 mStart;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
class SinkContext;
|
||||
|
||||
|
@ -209,6 +238,11 @@ public:
|
|||
NS_IMETHOD AddComment(const nsIParserNode& aNode);
|
||||
NS_IMETHOD AddProcessingInstruction(const nsIParserNode& aNode);
|
||||
NS_IMETHOD AddDocTypeDecl(const nsIParserNode& aNode, PRInt32 aMode=0);
|
||||
NS_IMETHOD WillProcessTokens(void);
|
||||
NS_IMETHOD DidProcessTokens(void);
|
||||
NS_IMETHOD WillProcessAToken(void);
|
||||
NS_IMETHOD DidProcessAToken(void);
|
||||
|
||||
|
||||
// nsIHTMLContentSink
|
||||
NS_IMETHOD BeginContext(PRInt32 aID);
|
||||
|
@ -356,6 +390,7 @@ public:
|
|||
nsSupportsArray mScriptElements;
|
||||
PRBool mParserBlocked;
|
||||
PRBool mNeedToBlockParser;
|
||||
nsCOMPtr<nsIRequest> mDummyParserRequest;
|
||||
|
||||
nsCString mRef;
|
||||
|
||||
|
@ -368,6 +403,10 @@ public:
|
|||
PRInt32 mInMonolithicContainer;
|
||||
PRUint32 mFlags;
|
||||
|
||||
// Can interrupt parsing members
|
||||
nsDelayTimer mDelayTimer;
|
||||
PRInt32 mMaxTokenProcessingTime; // Interrupt parsing during token procesing after # of microseconds
|
||||
|
||||
void StartLayout();
|
||||
|
||||
void ScrollToRef();
|
||||
|
@ -410,13 +449,134 @@ public:
|
|||
nsIContent* aChildContent,
|
||||
PRInt32 aIndexInContainer);
|
||||
PRBool IsMonolithicContainer(nsHTMLTag aTag);
|
||||
|
||||
// CanInterrupt parsing related routines
|
||||
nsresult AddDummyParserRequest(void);
|
||||
nsresult RemoveDummyParserRequest(void);
|
||||
|
||||
#ifdef NS_DEBUG
|
||||
void ForceReflow();
|
||||
#endif
|
||||
|
||||
MOZ_TIMER_DECLARE(mWatch) // Measures content model creation time for current document
|
||||
|
||||
};
|
||||
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
//
|
||||
// DummyParserRequest
|
||||
//
|
||||
// This is a dummy request implementation that we add to the document's load
|
||||
// group. It ensures that EndDocumentLoad() in the docshell doesn't fire
|
||||
// before we've finished all of parsing and tokenizing of the document.
|
||||
//
|
||||
|
||||
class DummyParserRequest : public nsIChannel
|
||||
{
|
||||
protected:
|
||||
DummyParserRequest(nsIHTMLContentSink* aSink);
|
||||
virtual ~DummyParserRequest();
|
||||
|
||||
static PRInt32 gRefCnt;
|
||||
static nsIURI* gURI;
|
||||
|
||||
nsCOMPtr<nsILoadGroup> mLoadGroup;
|
||||
|
||||
nsIHTMLContentSink* mSink; // Weak reference
|
||||
|
||||
public:
|
||||
static nsresult
|
||||
Create(nsIRequest** aResult, nsIHTMLContentSink* aSink);
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
// nsIRequest
|
||||
NS_IMETHOD GetName(PRUnichar* *result) {
|
||||
*result = ToNewUnicode(NS_LITERAL_STRING("about:layout-dummy-request"));
|
||||
return NS_OK;
|
||||
}
|
||||
NS_IMETHOD IsPending(PRBool *_retval) { *_retval = PR_TRUE; return NS_OK; }
|
||||
NS_IMETHOD GetStatus(nsresult *status) { *status = NS_OK; return NS_OK; }
|
||||
NS_IMETHOD Cancel(nsresult status);
|
||||
NS_IMETHOD Suspend(void) { return NS_OK; }
|
||||
NS_IMETHOD Resume(void) { return NS_OK; }
|
||||
|
||||
// nsIChannel
|
||||
NS_IMETHOD GetOriginalURI(nsIURI* *aOriginalURI) { *aOriginalURI = gURI; NS_ADDREF(*aOriginalURI); return NS_OK; }
|
||||
NS_IMETHOD SetOriginalURI(nsIURI* aOriginalURI) { gURI = aOriginalURI; NS_ADDREF(gURI); return NS_OK; }
|
||||
NS_IMETHOD GetURI(nsIURI* *aURI) { *aURI = gURI; NS_ADDREF(*aURI); return NS_OK; }
|
||||
NS_IMETHOD SetURI(nsIURI* aURI) { gURI = aURI; NS_ADDREF(gURI); return NS_OK; }
|
||||
NS_IMETHOD Open(nsIInputStream **_retval) { *_retval = nsnull; return NS_OK; }
|
||||
NS_IMETHOD AsyncOpen(nsIStreamListener *listener, nsISupports *ctxt) { return NS_OK; }
|
||||
NS_IMETHOD GetLoadFlags(nsLoadFlags *aLoadFlags) { *aLoadFlags = nsIRequest::LOAD_NORMAL; return NS_OK; }
|
||||
NS_IMETHOD SetLoadFlags(nsLoadFlags aLoadFlags) { return NS_OK; }
|
||||
NS_IMETHOD GetOwner(nsISupports * *aOwner) { *aOwner = nsnull; return NS_OK; }
|
||||
NS_IMETHOD SetOwner(nsISupports * aOwner) { return NS_OK; }
|
||||
NS_IMETHOD GetLoadGroup(nsILoadGroup * *aLoadGroup) { *aLoadGroup = mLoadGroup; NS_IF_ADDREF(*aLoadGroup); return NS_OK; }
|
||||
NS_IMETHOD SetLoadGroup(nsILoadGroup * aLoadGroup) { mLoadGroup = aLoadGroup; return NS_OK; }
|
||||
NS_IMETHOD GetNotificationCallbacks(nsIInterfaceRequestor * *aNotificationCallbacks) { *aNotificationCallbacks = nsnull; return NS_OK; }
|
||||
NS_IMETHOD SetNotificationCallbacks(nsIInterfaceRequestor * aNotificationCallbacks) { return NS_OK; }
|
||||
NS_IMETHOD GetSecurityInfo(nsISupports * *aSecurityInfo) { *aSecurityInfo = nsnull; return NS_OK; }
|
||||
NS_IMETHOD GetContentType(char * *aContentType) { *aContentType = nsnull; return NS_OK; }
|
||||
NS_IMETHOD SetContentType(const char * aContentType) { return NS_OK; }
|
||||
NS_IMETHOD GetContentLength(PRInt32 *aContentLength) { return NS_OK; }
|
||||
NS_IMETHOD SetContentLength(PRInt32 aContentLength) { return NS_OK; }
|
||||
|
||||
};
|
||||
|
||||
PRInt32 DummyParserRequest::gRefCnt;
|
||||
nsIURI* DummyParserRequest::gURI;
|
||||
|
||||
NS_IMPL_ADDREF(DummyParserRequest);
|
||||
NS_IMPL_RELEASE(DummyParserRequest);
|
||||
NS_IMPL_QUERY_INTERFACE2(DummyParserRequest, nsIRequest, nsIChannel);
|
||||
|
||||
nsresult
|
||||
DummyParserRequest::Create(nsIRequest** aResult, nsIHTMLContentSink* aSink)
|
||||
{
|
||||
DummyParserRequest* request = new DummyParserRequest(aSink);
|
||||
if (!request)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
return request->QueryInterface(NS_GET_IID(nsIRequest), (void**) aResult);
|
||||
}
|
||||
|
||||
|
||||
DummyParserRequest::DummyParserRequest(nsIHTMLContentSink* aSink)
|
||||
{
|
||||
NS_INIT_REFCNT();
|
||||
|
||||
if (gRefCnt++ == 0) {
|
||||
nsresult rv;
|
||||
rv = NS_NewURI(&gURI, "about:parser-dummy-request", nsnull);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "unable to create about:parser-dummy-request");
|
||||
}
|
||||
|
||||
mSink = aSink;
|
||||
}
|
||||
|
||||
|
||||
DummyParserRequest::~DummyParserRequest()
|
||||
{
|
||||
if (--gRefCnt == 0) {
|
||||
NS_IF_RELEASE(gURI);
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
DummyParserRequest::Cancel(nsresult status)
|
||||
{
|
||||
// Cancel parser
|
||||
nsresult rv = NS_OK;
|
||||
HTMLContentSink* sink = NS_STATIC_CAST(HTMLContentSink*, mSink);
|
||||
if ((sink) && (sink->mParser)) {
|
||||
sink->mParser->CancelParsingEvents();
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
class SinkContext {
|
||||
public:
|
||||
SinkContext(HTMLContentSink* aSink);
|
||||
|
@ -2151,6 +2311,7 @@ HTMLContentSink::HTMLContentSink() {
|
|||
mFlags=0;
|
||||
mNeedToBlockParser = PR_FALSE;
|
||||
mParserBlocked = PR_FALSE;
|
||||
mDummyParserRequest = nsnull;
|
||||
}
|
||||
|
||||
HTMLContentSink::~HTMLContentSink()
|
||||
|
@ -2329,16 +2490,42 @@ HTMLContentSink::Init(nsIDocument* aDoc,
|
|||
|
||||
// The mNotificationInterval has a dramatic effect on how long it
|
||||
// takes to initially display content for slow connections.
|
||||
// The current value of 1/4 of second provides good
|
||||
// The current value provides good
|
||||
// incremental display of content without causing an increase
|
||||
// in page load time. If this value is set below 1/10 of second
|
||||
// it starts to impact page load performance.
|
||||
// see bugzilla bug 72138 for more info.
|
||||
mNotificationInterval = 250000;
|
||||
mNotificationInterval = 120000;
|
||||
if (prefs) {
|
||||
prefs->GetIntPref("content.notify.interval", &mNotificationInterval);
|
||||
}
|
||||
|
||||
// The mMaxTokenProcessingTime controls how long we stay away from
|
||||
// the event loop when processing token. A lower value
|
||||
// makes the app more responsive, but may increase page load time.
|
||||
// The content sink mNotificationInterval gates how frequently the content
|
||||
// is processed so it will also affect how interactive the app is during
|
||||
// page load also. The mNotification prevents contents flushes from happening
|
||||
// too frequently. while mMaxTokenProcessingTime prevents flushes from happening
|
||||
// too infrequently.
|
||||
|
||||
// The current ratio of 3 to 1 was determined to be the lowest mMaxTokenProcessingTime
|
||||
// which does not impact page load performance.
|
||||
// See bugzilla bug 76722 for details.
|
||||
|
||||
mMaxTokenProcessingTime = mNotificationInterval * 3;
|
||||
|
||||
PRBool enableInterruptParsing = PR_FALSE;
|
||||
|
||||
if (prefs) {
|
||||
prefs->GetBoolPref("content.interrupt.parsing", &enableInterruptParsing);
|
||||
prefs->GetIntPref("content.max.tokenizing.time", &mMaxTokenProcessingTime);
|
||||
}
|
||||
|
||||
if (enableInterruptParsing) {
|
||||
mFlags |= NS_SINK_FLAG_CAN_INTERRUPT_PARSER;
|
||||
}
|
||||
|
||||
// Changed from 8192 to greatly improve page loading performance on large
|
||||
// pages. See bugzilla bug 77540.
|
||||
mMaxTextRun = 8191;
|
||||
|
@ -2420,6 +2607,16 @@ HTMLContentSink::Init(nsIDocument* aDoc,
|
|||
NS_IMETHODIMP
|
||||
HTMLContentSink::WillBuildModel(void)
|
||||
{
|
||||
if (mFlags & NS_SINK_FLAG_CAN_INTERRUPT_PARSER) {
|
||||
nsresult rv = AddDummyParserRequest();
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Adding dummy parser request failed");
|
||||
if (NS_FAILED(rv)) {
|
||||
// Don't return the error result, just reset flag which indicates that it can
|
||||
// interrupt parsing. If AddDummyParserRequests fails it should not affect
|
||||
// WillBuildModel.
|
||||
mFlags &= ~NS_SINK_FLAG_CAN_INTERRUPT_PARSER;
|
||||
}
|
||||
}
|
||||
// Notify document that the load is beginning
|
||||
mDocument->BeginLoad();
|
||||
return NS_OK;
|
||||
|
@ -2428,6 +2625,7 @@ HTMLContentSink::WillBuildModel(void)
|
|||
NS_IMETHODIMP
|
||||
HTMLContentSink::DidBuildModel(PRInt32 aQualityLevel)
|
||||
{
|
||||
|
||||
// NRA Dump stopwatch stop info here
|
||||
#ifdef MOZ_PERF_METRICS
|
||||
MOZ_TIMER_DEBUGLOG(("Stop: nsHTMLContentSink::DidBuildModel(), this=%p\n", this));
|
||||
|
@ -2500,6 +2698,14 @@ HTMLContentSink::DidBuildModel(PRInt32 aQualityLevel)
|
|||
// Drop our reference to the parser to get rid of a circular
|
||||
// reference.
|
||||
NS_IF_RELEASE(mParser);
|
||||
|
||||
if (mFlags & NS_SINK_FLAG_CAN_INTERRUPT_PARSER) {
|
||||
// Note: Don't return value from RemoveDummyParserRequest,
|
||||
// If RemoveDummyParserRequests fails it should not affect
|
||||
// DidBuildModel. The remove can fail if the parser request
|
||||
// was already removed by a DummyParserRequest::Cancel
|
||||
RemoveDummyParserRequest();
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -3111,7 +3317,7 @@ HTMLContentSink::CloseMap(const nsIParserNode& aNode)
|
|||
NS_IMETHODIMP
|
||||
HTMLContentSink::GetPref(PRInt32 aTag,PRBool& aPref) {
|
||||
nsHTMLTag theHTMLTag = nsHTMLTag(aTag);
|
||||
|
||||
|
||||
if (theHTMLTag == eHTMLTag_script) {
|
||||
aPref = mFlags & NS_SINK_FLAG_SCRIPT_ENABLED;
|
||||
}
|
||||
|
@ -3494,6 +3700,33 @@ HTMLContentSink::AddDocTypeDecl(const nsIParserNode& aNode, PRInt32 aMode)
|
|||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP
|
||||
HTMLContentSink::WillProcessTokens(void) {
|
||||
if (mFlags & NS_SINK_FLAG_CAN_INTERRUPT_PARSER) {
|
||||
mDelayTimer.Start();
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
HTMLContentSink::DidProcessTokens(void) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
HTMLContentSink::WillProcessAToken(void) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
HTMLContentSink::DidProcessAToken(void) {
|
||||
if ((mFlags & NS_SINK_FLAG_CAN_INTERRUPT_PARSER) && (mDelayTimer.HasExceeded(mMaxTokenProcessingTime))) {
|
||||
return NS_ERROR_HTMLPARSER_INTERRUPTED;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
HTMLContentSink::StartLayout()
|
||||
{
|
||||
|
@ -4881,3 +5114,62 @@ HTMLContentSink::DumpContentModel()
|
|||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// If the content sink can interrupt the parser (@see mCanInteruptParsing)
|
||||
// then it needs to schedule a dummy parser request to delay the document
|
||||
// from firing onload handlers and other document done actions until all of the
|
||||
// parsing has completed.
|
||||
|
||||
nsresult
|
||||
HTMLContentSink::AddDummyParserRequest(void)
|
||||
{
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
NS_ASSERTION(nsnull == mDummyParserRequest,"Already have a dummy parser request");
|
||||
rv = DummyParserRequest::Create(getter_AddRefs(mDummyParserRequest), this);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
nsCOMPtr<nsILoadGroup> loadGroup;
|
||||
if (mDocument) {
|
||||
rv = mDocument->GetDocumentLoadGroup(getter_AddRefs(loadGroup));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
}
|
||||
|
||||
if (loadGroup) {
|
||||
nsCOMPtr<nsIChannel> channel = do_QueryInterface(mDummyParserRequest);
|
||||
if (channel) {
|
||||
rv = channel->SetLoadGroup(loadGroup);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
rv = loadGroup->AddRequest(mDummyParserRequest, nsnull);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
} else {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult
|
||||
HTMLContentSink::RemoveDummyParserRequest(void)
|
||||
{
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
nsCOMPtr<nsILoadGroup> loadGroup;
|
||||
if (mDocument) {
|
||||
rv = mDocument->GetDocumentLoadGroup(getter_AddRefs(loadGroup));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
}
|
||||
|
||||
if (loadGroup && mDummyParserRequest) {
|
||||
rv = loadGroup->RemoveRequest(mDummyParserRequest, nsnull, NS_OK);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
mDummyParserRequest = nsnull;
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
|
|
@ -96,6 +96,10 @@ public:
|
|||
NS_IMETHOD OpenMap(const nsIParserNode& aNode);
|
||||
NS_IMETHOD CloseMap(const nsIParserNode& aNode);
|
||||
NS_IMETHOD FlushPendingNotifications() { return NS_OK; }
|
||||
NS_IMETHOD WillProcessTokens(void) { return NS_OK; }
|
||||
NS_IMETHOD DidProcessTokens(void) { return NS_OK; }
|
||||
NS_IMETHOD WillProcessAToken(void) { return NS_OK; }
|
||||
NS_IMETHOD DidProcessAToken(void) { return NS_OK; }
|
||||
|
||||
NS_IMETHOD DoFragment(PRBool aFlag);
|
||||
|
||||
|
|
|
@ -86,6 +86,10 @@ public:
|
|||
NS_IMETHOD WillResume(void) { return NS_OK; }
|
||||
NS_IMETHOD SetParser(nsIParser* aParser) { return NS_OK; }
|
||||
NS_IMETHOD FlushPendingNotifications() { return NS_OK; }
|
||||
NS_IMETHOD WillProcessTokens(void) { return NS_OK; }
|
||||
NS_IMETHOD DidProcessTokens(void) { return NS_OK; }
|
||||
NS_IMETHOD WillProcessAToken(void) { return NS_OK; }
|
||||
NS_IMETHOD DidProcessAToken(void) { return NS_OK; }
|
||||
|
||||
NS_IMETHOD DoFragment(PRBool aFlag);
|
||||
NS_IMETHOD BeginContext(PRInt32 aPosition){ return NS_OK; }
|
||||
|
|
|
@ -520,8 +520,12 @@ nsresult CNavDTD::BuildModel(nsIParser* aParser,nsITokenizer* aTokenizer,nsIToke
|
|||
mTokenizer->PushTokenFront(theToken); //this token should get pushed on the context stack.
|
||||
}
|
||||
}
|
||||
|
||||
mSink->WillProcessTokens();
|
||||
|
||||
while(NS_SUCCEEDED(result)){
|
||||
//Currently nsIHTMLContentSink does nothing with a call to WillProcessAToken.
|
||||
//mSink->WillProcessAToken();
|
||||
|
||||
#if 0
|
||||
int n=aTokenizer->GetCount();
|
||||
|
@ -544,12 +548,34 @@ nsresult CNavDTD::BuildModel(nsIParser* aParser,nsITokenizer* aTokenizer,nsIToke
|
|||
result=mDTDState;
|
||||
break;
|
||||
}
|
||||
|
||||
if ((NS_ERROR_HTMLPARSER_INTERRUPTED == mSink->DidProcessAToken())) {
|
||||
// The content sink has requested that DTD interrupt processing tokens
|
||||
// So we need to make sure the parser is in a state where it can be
|
||||
// interrupted.
|
||||
// The mParser->CanInterrupt will return TRUE if BuildModel was called
|
||||
// from a place in the parser where it prepared to handle a return value of
|
||||
// NS_ERROR_HTMLPARSER_INTERRUPTED.
|
||||
// If the parser has mPrevContext then it may be processing
|
||||
// Script so we should not allow it to be interrupted.
|
||||
|
||||
if ((mParser->CanInterrupt()) &&
|
||||
(nsnull == mParser->PeekContext()->mPrevContext) &&
|
||||
(eHTMLTag_unknown==mSkipTarget)) {
|
||||
result = NS_ERROR_HTMLPARSER_INTERRUPTED;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}//while
|
||||
mTokenizer=oldTokenizer;
|
||||
//Currently nsIHTMLContentSink does nothing with a call to DidProcessATokens().
|
||||
//mSink->DidProcessTokens();
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
else result=NS_ERROR_HTMLPARSER_BADTOKENIZER;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -2219,7 +2245,6 @@ nsresult CNavDTD::HandleAttributeToken(CToken* aToken) {
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This method gets called when a script token has been
|
||||
* encountered in the parse process. n
|
||||
|
@ -2236,6 +2261,8 @@ nsresult CNavDTD::HandleScriptToken(const nsIParserNode *aNode) {
|
|||
|
||||
nsresult result=AddLeaf(aNode);
|
||||
|
||||
mParser->SetCanInterrupt(PR_FALSE);
|
||||
|
||||
MOZ_TIMER_DEBUGLOG(("Start: Parse Time: CNavDTD::HandleScriptToken(), this=%p\n", this));
|
||||
START_TIMER();
|
||||
|
||||
|
|
|
@ -108,7 +108,6 @@ class nsITokenizer;
|
|||
class nsCParserNode;
|
||||
class nsTokenAllocator;
|
||||
|
||||
|
||||
/***************************************************************
|
||||
Now the main event: CNavDTD.
|
||||
|
||||
|
|
|
@ -71,6 +71,10 @@ public:
|
|||
NS_IMETHOD OpenFrameset(const nsIParserNode& aNode);
|
||||
NS_IMETHOD CloseFrameset(const nsIParserNode& aNode);
|
||||
NS_IMETHOD GetPref(PRInt32 aTag,PRBool& aPref) { return NS_OK; }
|
||||
NS_IMETHOD WillProcessTokens(void) { return NS_OK; }
|
||||
NS_IMETHOD DidProcessTokens(void) { return NS_OK; }
|
||||
NS_IMETHOD WillProcessAToken(void) { return NS_OK; }
|
||||
NS_IMETHOD DidProcessAToken(void) { return NS_OK; }
|
||||
|
||||
NS_IMETHOD DoFragment(PRBool aFlag);
|
||||
NS_IMETHOD BeginContext(PRInt32 aPosition);
|
||||
|
|
|
@ -1,234 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public
|
||||
* License Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is Mozilla Communicator client code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*/
|
||||
#ifndef nsIHTMLContentSink_h___
|
||||
#define nsIHTMLContentSink_h___
|
||||
|
||||
/**
|
||||
* MODULE NOTES:
|
||||
* @update gess 4/1/98
|
||||
*
|
||||
* This file declares the concrete HTMLContentSink class.
|
||||
* This class is used during the parsing process as the
|
||||
* primary interface between the parser and the content
|
||||
* model.
|
||||
*
|
||||
* After the tokenizer completes, the parser iterates over
|
||||
* the known token list. As the parser identifies valid
|
||||
* elements, it calls the contentsink interface to notify
|
||||
* the content model that a new node or child node is being
|
||||
* created and added to the content model.
|
||||
*
|
||||
* The HTMLContentSink interface assumes 4 underlying
|
||||
* containers: HTML, HEAD, BODY and FRAMESET. Before
|
||||
* accessing any these, the parser will call the appropriate
|
||||
* OpennsIHTMLContentSink method: OpenHTML,OpenHead,OpenBody,OpenFrameSet;
|
||||
* likewise, the ClosensIHTMLContentSink version will be called when the
|
||||
* parser is done with a given section.
|
||||
*
|
||||
* IMPORTANT: The parser may Open each container more than
|
||||
* once! This is due to the irregular nature of HTML files.
|
||||
* For example, it is possible to encounter plain text at
|
||||
* the start of an HTML document (that preceeds the HTML tag).
|
||||
* Such text is treated as if it were part of the body.
|
||||
* In such cases, the parser will Open the body, pass the text-
|
||||
* node in and then Close the body. The body will likely be
|
||||
* re-Opened later when the actual <BODY> tag has been seen.
|
||||
*
|
||||
* Containers within the body are Opened and Closed
|
||||
* using the OpenContainer(...) and CloseContainer(...) calls.
|
||||
* It is assumed that the document or contentSink is
|
||||
* maintaining its state to manage where new content should
|
||||
* be added to the underlying document.
|
||||
*
|
||||
* NOTE: OpenHTML() and OpenBody() may get called multiple times
|
||||
* in the same document. That's fine, and it doesn't mean
|
||||
* that we have multiple bodies or HTML's.
|
||||
*
|
||||
* NOTE: I haven't figured out how sub-documents (non-frames)
|
||||
* are going to be handled. Stay tuned.
|
||||
*/
|
||||
#include "nsIParserNode.h"
|
||||
#include "nsIContentSink.h"
|
||||
|
||||
#define NS_IHTML_CONTENT_SINK_IID \
|
||||
{ 0xa6cf9051, 0x15b3, 0x11d2,{0x93, 0x2e, 0x00, 0x80, 0x5f, 0x8a, 0xdd, 0x32}}
|
||||
|
||||
|
||||
#ifdef XP_MAC
|
||||
#define MAX_REFLOW_DEPTH 75 //setting to 75 to prevent layout from crashing on mac. Bug 55095.
|
||||
#else
|
||||
#define MAX_REFLOW_DEPTH 200 //windows and linux (etc) can do much deeper structures.
|
||||
#endif
|
||||
|
||||
|
||||
class nsIHTMLContentSink : public nsIContentSink {
|
||||
public:
|
||||
|
||||
static const nsIID& GetIID() { static nsIID iid = NS_IHTML_CONTENT_SINK_IID; return iid; }
|
||||
|
||||
/**
|
||||
* This method gets called by the parser when it encounters
|
||||
* a title tag and wants to set the document title in the sink.
|
||||
*
|
||||
* @update 4/1/98 gess
|
||||
* @param nsString reference to new title value
|
||||
*/
|
||||
NS_IMETHOD SetTitle(const nsString& aValue)=0;
|
||||
|
||||
/**
|
||||
* This method is used to open the outer HTML container.
|
||||
*
|
||||
* @update 4/1/98 gess
|
||||
* @param nsIParserNode reference to parser node interface
|
||||
*/
|
||||
NS_IMETHOD OpenHTML(const nsIParserNode& aNode)=0;
|
||||
|
||||
/**
|
||||
* This method is used to close the outer HTML container.
|
||||
*
|
||||
* @update 4/1/98 gess
|
||||
* @param nsIParserNode reference to parser node interface
|
||||
*/
|
||||
NS_IMETHOD CloseHTML(const nsIParserNode& aNode)=0;
|
||||
|
||||
/**
|
||||
* This method is used to open the only HEAD container.
|
||||
*
|
||||
* @update 4/1/98 gess
|
||||
* @param nsIParserNode reference to parser node interface
|
||||
*/
|
||||
NS_IMETHOD OpenHead(const nsIParserNode& aNode)=0;
|
||||
|
||||
/**
|
||||
* This method is used to close the only HEAD container.
|
||||
*
|
||||
* @update 4/1/98 gess
|
||||
* @param nsIParserNode reference to parser node interface
|
||||
*/
|
||||
NS_IMETHOD CloseHead(const nsIParserNode& aNode)=0;
|
||||
|
||||
/**
|
||||
* This method is used to open the main BODY container.
|
||||
*
|
||||
* @update 4/1/98 gess
|
||||
* @param nsIParserNode reference to parser node interface
|
||||
*/
|
||||
NS_IMETHOD OpenBody(const nsIParserNode& aNode)=0;
|
||||
|
||||
/**
|
||||
* This method is used to close the main BODY container.
|
||||
*
|
||||
* @update 4/1/98 gess
|
||||
* @param nsIParserNode reference to parser node interface
|
||||
*/
|
||||
NS_IMETHOD CloseBody(const nsIParserNode& aNode)=0;
|
||||
|
||||
/**
|
||||
* This method is used to open a new FORM container.
|
||||
*
|
||||
* @update 4/1/98 gess
|
||||
* @param nsIParserNode reference to parser node interface
|
||||
*/
|
||||
NS_IMETHOD OpenForm(const nsIParserNode& aNode)=0;
|
||||
|
||||
/**
|
||||
* This method is used to close the outer FORM container.
|
||||
*
|
||||
* @update 4/1/98 gess
|
||||
* @param nsIParserNode reference to parser node interface
|
||||
*/
|
||||
NS_IMETHOD CloseForm(const nsIParserNode& aNode)=0;
|
||||
|
||||
/**
|
||||
* This method is used to open a new MAP container.
|
||||
*
|
||||
* @update 4/1/98 gess
|
||||
* @param nsIParserNode reference to parser node interface
|
||||
*/
|
||||
NS_IMETHOD OpenMap(const nsIParserNode& aNode)=0;
|
||||
|
||||
/**
|
||||
* This method is used to close the MAP container.
|
||||
*
|
||||
* @update 4/1/98 gess
|
||||
* @param nsIParserNode reference to parser node interface
|
||||
*/
|
||||
NS_IMETHOD CloseMap(const nsIParserNode& aNode)=0;
|
||||
|
||||
/**
|
||||
* This method is used to open the FRAMESET container.
|
||||
*
|
||||
* @update 4/1/98 gess
|
||||
* @param nsIParserNode reference to parser node interface
|
||||
*/
|
||||
NS_IMETHOD OpenFrameset(const nsIParserNode& aNode)=0;
|
||||
|
||||
/**
|
||||
* This method is used to close the FRAMESET container.
|
||||
*
|
||||
* @update 4/1/98 gess
|
||||
* @param nsIParserNode reference to parser node interface
|
||||
*/
|
||||
NS_IMETHOD CloseFrameset(const nsIParserNode& aNode)=0;
|
||||
|
||||
/**
|
||||
* This method tells the sink whether or not it is
|
||||
* encoding an HTML fragment or the whole document.
|
||||
* By default, the entire document is encoded.
|
||||
*
|
||||
* @update 03/14/99 gpk
|
||||
* @param aFlag set to true if only encoding a fragment
|
||||
*/
|
||||
|
||||
NS_IMETHOD DoFragment(PRBool aFlag)=0;
|
||||
|
||||
/**
|
||||
* This gets called when handling illegal contents, especially
|
||||
* in dealing with tables. This method creates a new context.
|
||||
*
|
||||
* @update 04/04/99 harishd
|
||||
* @param aPosition - The position from where the new context begins.
|
||||
*/
|
||||
NS_IMETHOD BeginContext(PRInt32 aPosition)=0;
|
||||
|
||||
/**
|
||||
* This method terminates any new context that got created by
|
||||
* BeginContext and switches back to the main context.
|
||||
*
|
||||
* @update 04/04/99 harishd
|
||||
* @param aPosition - Validates the end of a context.
|
||||
*/
|
||||
NS_IMETHOD EndContext(PRInt32 aPosition)=0;
|
||||
|
||||
/**
|
||||
* Use this method to retrieve pref. for the tag.
|
||||
*
|
||||
* @update 04/11/01 harishd
|
||||
* @param aTag - Check pref. for this tag.
|
||||
*/
|
||||
NS_IMETHOD GetPref(PRInt32 aTag,PRBool& aPref)=0;
|
||||
|
||||
};
|
||||
|
||||
extern NS_HTMLPARS nsresult NS_NewHTMLNullSink(nsIContentSink** aInstancePtrResult);
|
||||
|
||||
#endif /* nsIHTMLContentSink_h___ */
|
|
@ -110,7 +110,7 @@ public:
|
|||
virtual PRUint32 GetSize(void)=0;
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* FOR DEBUG PURPOSE ONLY
|
||||
*
|
||||
* Use this interface to query objects that contain content information.
|
||||
|
@ -233,6 +233,7 @@ class nsIParser : public nsISupports {
|
|||
virtual void UnblockParser() =0;
|
||||
|
||||
virtual PRBool IsParserEnabled() =0;
|
||||
virtual PRBool IsComplete() =0;
|
||||
|
||||
virtual nsresult Parse(nsIURI* aURL,nsIRequestObserver* aListener = nsnull,PRBool aEnableVerify=PR_FALSE, void* aKey=0,nsDTDMode aMode=eDTDMode_autodetect) = 0;
|
||||
virtual nsresult Parse(nsIInputStream& aStream, const nsString& aMimeType,PRBool aEnableVerify=PR_FALSE, void* aKey=0,nsDTDMode aMode=eDTDMode_autodetect) = 0;
|
||||
|
@ -276,6 +277,18 @@ class nsIParser : public nsISupports {
|
|||
eParserCommands aCommand,
|
||||
const nsString* aMimeType=nsnull,
|
||||
nsDTDMode aDTDMode=eDTDMode_unknown)=0;
|
||||
|
||||
/**
|
||||
* Call this method to cancel any pending parsing events.
|
||||
* Parsing events may be pending if all of the document's content
|
||||
* has been passed to the parser but the parser has been interrupted
|
||||
* because processing the tokens took too long.
|
||||
*
|
||||
* @update kmcclusk 05/18/01
|
||||
* @return NS_OK if succeeded else ERROR.
|
||||
*/
|
||||
|
||||
NS_IMETHOD CancelParsingEvents()=0;
|
||||
};
|
||||
|
||||
/* ===========================================================*
|
||||
|
@ -304,6 +317,7 @@ class nsIParser : public nsISupports {
|
|||
#define NS_ERROR_HTMLPARSER_UNTERMINATEDSTRINGLITERAL NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_HTMLPARSER,1016)
|
||||
#define NS_ERROR_HTMLPARSER_HIERARCHYTOODEEP NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_HTMLPARSER,1017)
|
||||
|
||||
|
||||
#define NS_ERROR_HTMLPARSER_CONTINUE NS_OK
|
||||
|
||||
|
||||
|
|
|
@ -76,6 +76,10 @@ public:
|
|||
NS_IMETHOD DoFragment(PRBool aFlag);
|
||||
NS_IMETHOD BeginContext(PRInt32 aPosition);
|
||||
NS_IMETHOD EndContext(PRInt32 aPosition);
|
||||
NS_IMETHOD WillProcessTokens(void) { return NS_OK; }
|
||||
NS_IMETHOD DidProcessTokens(void) { return NS_OK; }
|
||||
NS_IMETHOD WillProcessAToken(void) { return NS_OK; }
|
||||
NS_IMETHOD DidProcessAToken(void) { return NS_OK; }
|
||||
|
||||
// nsILoggingSink
|
||||
NS_IMETHOD SetOutputStream(PRFileDesc *aStream,PRBool autoDelete=PR_FALSE);
|
||||
|
|
|
@ -46,6 +46,8 @@
|
|||
#include "prenv.h"
|
||||
#include "nsParserCIID.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIEventQueue.h"
|
||||
#include "nsIEventQueueService.h"
|
||||
//#define rickgdebug
|
||||
|
||||
static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID);
|
||||
|
@ -57,6 +59,7 @@ static NS_DEFINE_CID(kWellFormedDTDCID, NS_WELLFORMEDDTD_CID);
|
|||
static NS_DEFINE_CID(kNavDTDCID, NS_CNAVDTD_CID);
|
||||
static NS_DEFINE_CID(kCOtherDTDCID, NS_COTHER_DTD_CID);
|
||||
static NS_DEFINE_CID(kViewSourceDTDCID, NS_VIEWSOURCE_DTD_CID);
|
||||
static NS_DEFINE_CID(kEventQueueServiceCID, NS_EVENTQUEUESERVICE_CID);
|
||||
|
||||
static const char* kNullURL = "Error: Null URL given";
|
||||
static const char* kOnStartNotCalled = "Error: OnStartRequest() must be called before OnDataAvailable()";
|
||||
|
@ -150,6 +153,99 @@ public:
|
|||
nsIDTD *mOtherDTD; //it's ok to leak this; the deque contains a copy too.
|
||||
};
|
||||
|
||||
|
||||
//-------------- Begin ParseContinue Event Definition ------------------------
|
||||
/*
|
||||
The parser can be explicitly interrupted by passing a return value of NS_ERROR_HTMLPARSER_INTERRUPTED
|
||||
from BuildModel on the DTD. This will cause the parser to stop processing and allow
|
||||
the application to return to the event loop. The data which was left at the time of
|
||||
interruption will be processed the next time OnDataAvailable is called. If the parser
|
||||
has received its final chunk of data then OnDataAvailable will no longer be called by the
|
||||
networking module, so the parser will schedule a nsParserContinueEvent which will call
|
||||
the parser to process the remaining data after returning to the event loop. If the parser
|
||||
is interrupted while processing the remaining data it will schedule another
|
||||
ParseContinueEvent. The processing of data followed by scheduling of the continue events
|
||||
will proceed until either:
|
||||
|
||||
1) All of the remaining data can be processed without interrupting
|
||||
2) The parser has been cancelled.
|
||||
|
||||
|
||||
This capability is currently used in CNavDTD and nsHTMLContentSink. The nsHTMLContentSink is
|
||||
notified by CNavDTD when a chunk of tokens is going to be processed and when each token
|
||||
is processed. The nsHTML content sink records the time when the chunk has started
|
||||
processing and will return NS_ERROR_HTMLPARSER_INTERRUPTED if the token processing time
|
||||
has exceeded a threshold called max tokenizing processing time. This allows the content
|
||||
sink to limit how much data is processed in a single chunk which in turn gates how much
|
||||
time is spent away from the event loop. Processing smaller chunks of data also reduces
|
||||
the time spent in subsequent reflows.
|
||||
|
||||
This capability is most apparent when loading large documents. If the maximum token
|
||||
processing time is set small enough the application will remain responsive during
|
||||
document load.
|
||||
|
||||
A side-effect of this capability is that document load is not complete when the last chunk
|
||||
of data is passed to OnDataAvailable since the parser may have been interrupted when
|
||||
the last chunk of data arrived. The document is complete when all of the document has
|
||||
been tokenized and there aren't any pending nsParserContinueEvents. This can cause
|
||||
problems if the application assumes that it can monitor the load requests to determine
|
||||
when the document load has been completed. This is what happens in Mozilla. The document
|
||||
is considered completely loaded when all of the load requests have been satisfied. To delay the
|
||||
document load until all of the parsing has been completed the nsHTMLContentSink adds a
|
||||
dummy parser load request which is not removed until the nsHTMLContentSink's DidBuildModel
|
||||
is called. The CNavDTD will not call DidBuildModel until the final chunk of data has been
|
||||
passed to the parser through the OnDataAvailable and there aren't any pending
|
||||
nsParserContineEvents.
|
||||
|
||||
Currently the parser is ignores requests to be interrupted during the processing of script.
|
||||
This is because a document.write followed by JavaScript calls to manipulate the DOM may
|
||||
fail if the parser was interrupted during the document.write.
|
||||
|
||||
|
||||
For more details @see bugzilla bug 76722
|
||||
*/
|
||||
|
||||
|
||||
struct nsParserContinueEvent : public PLEvent {
|
||||
|
||||
nsParserContinueEvent(nsIParser* aParser);
|
||||
~nsParserContinueEvent() { }
|
||||
|
||||
void HandleEvent() {
|
||||
if (mParser) {
|
||||
nsParser* parser = NS_STATIC_CAST(nsParser*, mParser);
|
||||
parser->HandleParserContinueEvent();
|
||||
NS_RELEASE(mParser);
|
||||
}
|
||||
};
|
||||
|
||||
nsIParser* mParser;
|
||||
};
|
||||
|
||||
static void PR_CALLBACK HandlePLEvent(nsParserContinueEvent* aEvent)
|
||||
{
|
||||
NS_ASSERTION(nsnull != aEvent,"Event is null");
|
||||
aEvent->HandleEvent();
|
||||
}
|
||||
|
||||
static void PR_CALLBACK DestroyPLEvent(nsParserContinueEvent* aEvent)
|
||||
{
|
||||
NS_ASSERTION(nsnull != aEvent,"Event is null");
|
||||
delete aEvent;
|
||||
}
|
||||
|
||||
nsParserContinueEvent::nsParserContinueEvent(nsIParser* aParser)
|
||||
{
|
||||
NS_ASSERTION(aParser, "null parameter");
|
||||
mParser = aParser;
|
||||
PL_InitEvent(this, aParser,
|
||||
(PLHandleEventProc) ::HandlePLEvent,
|
||||
(PLDestroyEventProc) ::DestroyPLEvent);
|
||||
}
|
||||
|
||||
//-------------- End ParseContinue Event Definition ------------------------
|
||||
|
||||
|
||||
static CSharedParserObjects* gSharedParserObjects=0;
|
||||
|
||||
|
||||
|
@ -247,11 +343,24 @@ nsParser::nsParser(nsITokenObserver* anObserver) {
|
|||
mCommand=eViewNormal;
|
||||
mParserEnabled=PR_TRUE;
|
||||
mBundle=nsnull;
|
||||
|
||||
mPendingContinueEvent=PR_FALSE;
|
||||
mCanInterrupt=PR_FALSE;
|
||||
|
||||
MOZ_TIMER_DEBUGLOG(("Reset: Parse Time: nsParser::nsParser(), this=%p\n", this));
|
||||
MOZ_TIMER_RESET(mParseTime);
|
||||
MOZ_TIMER_RESET(mDTDTime);
|
||||
MOZ_TIMER_RESET(mTokenizeTime);
|
||||
|
||||
nsresult rv = NS_OK;
|
||||
if (mEventQueue == nsnull) {
|
||||
// Cache the event queue of the current UI thread
|
||||
NS_WITH_SERVICE(nsIEventQueueService, eventService, kEventQueueServiceCID, &rv);
|
||||
if (NS_SUCCEEDED(rv) && (eventService)) { // XXX this implies that the UI is the current thread.
|
||||
rv = eventService->GetThreadEventQueue(NS_CURRENT_THREAD, getter_AddRefs(mEventQueue));
|
||||
}
|
||||
|
||||
NS_ASSERTION(mEventQueue, "event queue is null");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -286,6 +395,11 @@ nsParser::~nsParser() {
|
|||
//don't forget to add code here to delete
|
||||
//what may be several contexts...
|
||||
delete mParserContext;
|
||||
|
||||
if (mPendingContinueEvent) {
|
||||
NS_ASSERTION(mEventQueue != nsnull,"Event queue is null");
|
||||
mEventQueue->RevokeEvents(this);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -339,6 +453,24 @@ nsresult nsParser::QueryInterface(const nsIID& aIID, void** aInstancePtr)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
// The parser continue event is posted only if
|
||||
// all of the data to parse has been passed to ::OnDataAvailable
|
||||
// and the parser has been interrupted by the content sink
|
||||
// because the processing of tokens took too long.
|
||||
|
||||
nsresult
|
||||
nsParser::PostContinueEvent()
|
||||
{
|
||||
if ((! mPendingContinueEvent) && (mEventQueue)) {
|
||||
nsParserContinueEvent* ev = new nsParserContinueEvent(NS_STATIC_CAST(nsIParser*, this));
|
||||
NS_ENSURE_TRUE(ev,NS_ERROR_OUT_OF_MEMORY);
|
||||
NS_ADDREF(this);
|
||||
mEventQueue->PostEvent(ev);
|
||||
mPendingContinueEvent = PR_TRUE;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -1240,6 +1372,19 @@ NS_IMETHODIMP nsParser::CreateCompatibleDTD(nsIDTD** aDTD,
|
|||
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsParser::CancelParsingEvents() {
|
||||
if (mPendingContinueEvent) {
|
||||
NS_ASSERTION(mEventQueue,"Event queue is null");
|
||||
// Revoke all pending continue parsing events
|
||||
if (mEventQueue != nsnull) {
|
||||
mEventQueue->RevokeEvents(this);
|
||||
}
|
||||
mPendingContinueEvent=PR_FALSE;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//#define TEST_DOCTYPES
|
||||
#ifdef TEST_DOCTYPES
|
||||
static const char* doctypes[] = {
|
||||
|
@ -1433,13 +1578,15 @@ nsresult nsParser::DidBuildModel(nsresult anErrorCode) {
|
|||
//One last thing...close any open containers.
|
||||
nsresult result=anErrorCode;
|
||||
|
||||
if(mParserContext && !mParserContext->mPrevContext) {
|
||||
if(mParserContext->mDTD) {
|
||||
result=mParserContext->mDTD->DidBuildModel(anErrorCode,PRBool(0==mParserContext->mPrevContext),this,mSink);
|
||||
}
|
||||
//Ref. to bug 61462.
|
||||
NS_IF_RELEASE(mBundle);
|
||||
}//if
|
||||
if (IsComplete()) {
|
||||
if(mParserContext && !mParserContext->mPrevContext) {
|
||||
if(mParserContext->mDTD) {
|
||||
result=mParserContext->mDTD->DidBuildModel(anErrorCode,PRBool(0==mParserContext->mPrevContext),this,mSink);
|
||||
}
|
||||
//Ref. to bug 61462.
|
||||
NS_IF_RELEASE(mBundle);
|
||||
}//if
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
@ -1540,7 +1687,7 @@ nsresult nsParser::ContinueParsing(){
|
|||
|
||||
if(result!=NS_OK)
|
||||
result=mInternalState;
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -1582,6 +1729,29 @@ PRBool nsParser::IsParserEnabled() {
|
|||
return mParserEnabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Call this to query whether the parser thinks it's done with parsing.
|
||||
*
|
||||
* @update rickg 5/12/01
|
||||
* @return complete state
|
||||
*/
|
||||
PRBool nsParser::IsComplete() {
|
||||
return (! mPendingContinueEvent);
|
||||
}
|
||||
|
||||
|
||||
void nsParser::HandleParserContinueEvent() {
|
||||
mPendingContinueEvent = PR_FALSE;
|
||||
ContinueParsing();
|
||||
}
|
||||
|
||||
PRBool nsParser::CanInterrupt(void) {
|
||||
return mCanInterrupt;
|
||||
}
|
||||
|
||||
void nsParser::SetCanInterrupt(PRBool aCanInterrupt) {
|
||||
mCanInterrupt = aCanInterrupt;
|
||||
}
|
||||
|
||||
/**
|
||||
* This is the main controlling routine in the parsing process.
|
||||
|
@ -1679,7 +1849,16 @@ aMimeType,PRBool aVerifyEnabled,PRBool aLastCall,nsDTDMode aMode){
|
|||
//NOTE: Make sure that updates to this method don't cause
|
||||
// bug #2361 to break again!
|
||||
|
||||
nsresult result=NS_OK;
|
||||
nsresult result=NS_OK;
|
||||
|
||||
|
||||
if(aLastCall && (0==aSourceBuffer.Length())) {
|
||||
// Nothing is being passed to the parser so return
|
||||
// immediately. mUnusedInput will get processed when
|
||||
// some data is actually passed in.
|
||||
return result;
|
||||
}
|
||||
|
||||
nsParser* me = this;
|
||||
// Maintain a reference to ourselves so we don't go away
|
||||
// till we're completely done.
|
||||
|
@ -1687,7 +1866,7 @@ aMimeType,PRBool aVerifyEnabled,PRBool aLastCall,nsDTDMode aMode){
|
|||
|
||||
if(aSourceBuffer.Length() || mUnusedInput.Length()) {
|
||||
mDTDVerification=aVerifyEnabled;
|
||||
CParserContext* pc=0;
|
||||
CParserContext* pc=0;
|
||||
|
||||
if((!mParserContext) || (mParserContext->mKey!=aKey)) {
|
||||
//only make a new context if we dont have one, OR if we do, but has a different context key...
|
||||
|
@ -1867,10 +2046,19 @@ nsresult nsParser::ResumeParse(PRBool allowIteration, PRBool aIsFinalChunk) {
|
|||
}
|
||||
}
|
||||
|
||||
//Only allow parsing to be interuptted in the subsequent call
|
||||
//to build model.
|
||||
SetCanInterrupt(PR_TRUE);
|
||||
nsresult theTokenizerResult=Tokenize(aIsFinalChunk); // kEOF==2152596456
|
||||
result=BuildModel();
|
||||
|
||||
theIterationIsOk=PRBool(kEOF!=theTokenizerResult);
|
||||
if(result==NS_ERROR_HTMLPARSER_INTERRUPTED) {
|
||||
if(aIsFinalChunk)
|
||||
PostContinueEvent();
|
||||
}
|
||||
SetCanInterrupt(PR_FALSE);
|
||||
|
||||
theIterationIsOk=PRBool((kEOF!=theTokenizerResult) && (result!=NS_ERROR_HTMLPARSER_INTERRUPTED));
|
||||
|
||||
// Make sure not to stop parsing too early. Therefore, before shutting down the
|
||||
// parser, it's important to check whether the input buffer has been scanned to
|
||||
|
@ -1895,7 +2083,7 @@ nsresult nsParser::ResumeParse(PRBool allowIteration, PRBool aIsFinalChunk) {
|
|||
break;
|
||||
}
|
||||
|
||||
else if((NS_OK==result) && (theTokenizerResult==kEOF)){
|
||||
else if(((NS_OK==result) && (theTokenizerResult==kEOF)) || (result==NS_ERROR_HTMLPARSER_INTERRUPTED)){
|
||||
|
||||
PRBool theContextIsStringBased=PRBool(CParserContext::eCTString==mParserContext->mContextType);
|
||||
if( (eOnStop==mParserContext->mStreamListenerState) ||
|
||||
|
@ -1918,11 +2106,11 @@ nsresult nsParser::ResumeParse(PRBool allowIteration, PRBool aIsFinalChunk) {
|
|||
MOZ_TIMER_LOG(("Tokenize Time: "));
|
||||
MOZ_TIMER_PRINT(mTokenizeTime);
|
||||
|
||||
return result;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
}
|
||||
else {
|
||||
else {
|
||||
|
||||
CParserContext* theContext=PopContext();
|
||||
if(theContext) {
|
||||
|
@ -1933,6 +2121,8 @@ nsresult nsParser::ResumeParse(PRBool allowIteration, PRBool aIsFinalChunk) {
|
|||
delete theContext;
|
||||
}
|
||||
result = mInternalState;
|
||||
aIsFinalChunk=(mParserContext && mParserContext->mStreamListenerState==eOnStop)? PR_TRUE:PR_FALSE;
|
||||
|
||||
//...then intentionally fall through to WillInterruptParse()...
|
||||
}
|
||||
|
||||
|
@ -1940,10 +2130,12 @@ nsresult nsParser::ResumeParse(PRBool allowIteration, PRBool aIsFinalChunk) {
|
|||
|
||||
}
|
||||
|
||||
if(kEOF==theTokenizerResult) {
|
||||
if((kEOF==theTokenizerResult) || (result==NS_ERROR_HTMLPARSER_INTERRUPTED)) {
|
||||
result = (result == NS_ERROR_HTMLPARSER_INTERRUPTED) ? NS_OK : result;
|
||||
mParserContext->mDTD->WillInterruptParse();
|
||||
}
|
||||
|
||||
|
||||
}//while
|
||||
}//if
|
||||
else {
|
||||
|
@ -1954,7 +2146,7 @@ nsresult nsParser::ResumeParse(PRBool allowIteration, PRBool aIsFinalChunk) {
|
|||
MOZ_TIMER_DEBUGLOG(("Stop: Parse Time: nsParser::ResumeParse(), this=%p\n", this));
|
||||
MOZ_TIMER_STOP(mParseTime);
|
||||
|
||||
return result;
|
||||
return (result==NS_ERROR_HTMLPARSER_INTERRUPTED) ? NS_OK : result;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -70,6 +70,7 @@
|
|||
#include "nsDTDUtils.h"
|
||||
#include "nsTimer.h"
|
||||
#include "nsIProgressEventSink.h"
|
||||
#include "nsIEventQueue.h"
|
||||
|
||||
class IContentSink;
|
||||
class nsIDTD;
|
||||
|
@ -225,6 +226,14 @@ class nsParser : public nsIParser,
|
|||
*/
|
||||
virtual PRBool IsParserEnabled();
|
||||
|
||||
/**
|
||||
* Call this to query whether the parser thinks it's done with parsing.
|
||||
*
|
||||
* @update rickg 5/12/01
|
||||
* @return complete state
|
||||
*/
|
||||
virtual PRBool IsComplete();
|
||||
|
||||
/**
|
||||
* This rather arcane method (hack) is used as a signal between the
|
||||
* DTD and the parser. It allows the DTD to tell the parser that content
|
||||
|
@ -319,6 +328,44 @@ class nsParser : public nsIParser,
|
|||
const nsString* aMimeType=nsnull,
|
||||
nsDTDMode aDTDMode=eDTDMode_unknown);
|
||||
|
||||
/**
|
||||
* Removes continue parsing events
|
||||
* @update kmcclusk 5/18/98
|
||||
*/
|
||||
|
||||
NS_IMETHODIMP CancelParsingEvents();
|
||||
|
||||
/**
|
||||
* Indicates whether the parser is in a state where it
|
||||
* can be interrupted.
|
||||
* @return PR_TRUE if parser can be interrupted, PR_FALSE if it can not be interrupted.
|
||||
* @update kmcclusk 5/18/98
|
||||
*/
|
||||
PRBool CanInterrupt(void);
|
||||
|
||||
/**
|
||||
* Set to parser state to indicate whether parsing tokens can be interrupted
|
||||
* @param aCanInterrupt PR_TRUE if parser can be interrupted, PR_FALSE if it can not be interrupted.
|
||||
* @update kmcclusk 5/18/98
|
||||
*/
|
||||
void SetCanInterrupt(PRBool aCanInterrupt);
|
||||
|
||||
/**
|
||||
* This is called when the final chunk has been
|
||||
* passed to the parser and the content sink has
|
||||
* interrupted token processing. It schedules
|
||||
* a ParserContinue PL_Event which will ask the parser
|
||||
* to HandleParserContinueEvent when it is handled.
|
||||
* @update kmcclusk6/1/2001
|
||||
*/
|
||||
nsresult PostContinueEvent();
|
||||
|
||||
/**
|
||||
* Fired when the continue parse event is triggered.
|
||||
* @update kmcclusk 5/18/98
|
||||
*/
|
||||
void HandleParserContinueEvent(void);
|
||||
|
||||
protected:
|
||||
|
||||
/**
|
||||
|
@ -383,6 +430,8 @@ private:
|
|||
* @return TRUE if all went well
|
||||
*/
|
||||
PRBool DidTokenize(PRBool aIsFinalChunk = PR_FALSE);
|
||||
|
||||
|
||||
protected:
|
||||
//*********************************************
|
||||
// And now, some data members...
|
||||
|
@ -396,6 +445,7 @@ protected:
|
|||
nsIRequestObserver* mObserver;
|
||||
nsIProgressEventSink* mProgressEventSink;
|
||||
nsIContentSink* mSink;
|
||||
|
||||
nsIParserFilter* mParserFilter;
|
||||
PRBool mDTDVerification;
|
||||
eParserCommands mCommand;
|
||||
|
@ -412,7 +462,12 @@ protected:
|
|||
nsParserBundle* mBundle;
|
||||
nsTokenAllocator mTokenAllocator;
|
||||
|
||||
public:
|
||||
nsCOMPtr<nsIEventQueue> mEventQueue;
|
||||
PRPackedBool mPendingContinueEvent;
|
||||
PRPackedBool mCanInterrupt;
|
||||
|
||||
public:
|
||||
|
||||
MOZ_TIMER_DECLARE(mParseTime)
|
||||
MOZ_TIMER_DECLARE(mDTDTime)
|
||||
MOZ_TIMER_DECLARE(mTokenizeTime)
|
||||
|
|
|
@ -86,6 +86,10 @@ public:
|
|||
NS_IMETHOD WillResume(void) { return NS_OK; }
|
||||
NS_IMETHOD SetParser(nsIParser* aParser) { return NS_OK; }
|
||||
NS_IMETHOD FlushPendingNotifications() { return NS_OK; }
|
||||
NS_IMETHOD WillProcessTokens(void) { return NS_OK; }
|
||||
NS_IMETHOD DidProcessTokens(void) { return NS_OK; }
|
||||
NS_IMETHOD WillProcessAToken(void) { return NS_OK; }
|
||||
NS_IMETHOD DidProcessAToken(void) { return NS_OK; }
|
||||
|
||||
NS_IMETHOD DoFragment(PRBool aFlag);
|
||||
NS_IMETHOD BeginContext(PRInt32 aPosition){ return NS_OK; }
|
||||
|
|
|
@ -520,8 +520,12 @@ nsresult CNavDTD::BuildModel(nsIParser* aParser,nsITokenizer* aTokenizer,nsIToke
|
|||
mTokenizer->PushTokenFront(theToken); //this token should get pushed on the context stack.
|
||||
}
|
||||
}
|
||||
|
||||
mSink->WillProcessTokens();
|
||||
|
||||
while(NS_SUCCEEDED(result)){
|
||||
//Currently nsIHTMLContentSink does nothing with a call to WillProcessAToken.
|
||||
//mSink->WillProcessAToken();
|
||||
|
||||
#if 0
|
||||
int n=aTokenizer->GetCount();
|
||||
|
@ -544,12 +548,34 @@ nsresult CNavDTD::BuildModel(nsIParser* aParser,nsITokenizer* aTokenizer,nsIToke
|
|||
result=mDTDState;
|
||||
break;
|
||||
}
|
||||
|
||||
if ((NS_ERROR_HTMLPARSER_INTERRUPTED == mSink->DidProcessAToken())) {
|
||||
// The content sink has requested that DTD interrupt processing tokens
|
||||
// So we need to make sure the parser is in a state where it can be
|
||||
// interrupted.
|
||||
// The mParser->CanInterrupt will return TRUE if BuildModel was called
|
||||
// from a place in the parser where it prepared to handle a return value of
|
||||
// NS_ERROR_HTMLPARSER_INTERRUPTED.
|
||||
// If the parser has mPrevContext then it may be processing
|
||||
// Script so we should not allow it to be interrupted.
|
||||
|
||||
if ((mParser->CanInterrupt()) &&
|
||||
(nsnull == mParser->PeekContext()->mPrevContext) &&
|
||||
(eHTMLTag_unknown==mSkipTarget)) {
|
||||
result = NS_ERROR_HTMLPARSER_INTERRUPTED;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}//while
|
||||
mTokenizer=oldTokenizer;
|
||||
//Currently nsIHTMLContentSink does nothing with a call to DidProcessATokens().
|
||||
//mSink->DidProcessTokens();
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
else result=NS_ERROR_HTMLPARSER_BADTOKENIZER;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -2219,7 +2245,6 @@ nsresult CNavDTD::HandleAttributeToken(CToken* aToken) {
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This method gets called when a script token has been
|
||||
* encountered in the parse process. n
|
||||
|
@ -2236,6 +2261,8 @@ nsresult CNavDTD::HandleScriptToken(const nsIParserNode *aNode) {
|
|||
|
||||
nsresult result=AddLeaf(aNode);
|
||||
|
||||
mParser->SetCanInterrupt(PR_FALSE);
|
||||
|
||||
MOZ_TIMER_DEBUGLOG(("Start: Parse Time: CNavDTD::HandleScriptToken(), this=%p\n", this));
|
||||
START_TIMER();
|
||||
|
||||
|
|
|
@ -108,7 +108,6 @@ class nsITokenizer;
|
|||
class nsCParserNode;
|
||||
class nsTokenAllocator;
|
||||
|
||||
|
||||
/***************************************************************
|
||||
Now the main event: CNavDTD.
|
||||
|
||||
|
|
|
@ -71,6 +71,10 @@ public:
|
|||
NS_IMETHOD OpenFrameset(const nsIParserNode& aNode);
|
||||
NS_IMETHOD CloseFrameset(const nsIParserNode& aNode);
|
||||
NS_IMETHOD GetPref(PRInt32 aTag,PRBool& aPref) { return NS_OK; }
|
||||
NS_IMETHOD WillProcessTokens(void) { return NS_OK; }
|
||||
NS_IMETHOD DidProcessTokens(void) { return NS_OK; }
|
||||
NS_IMETHOD WillProcessAToken(void) { return NS_OK; }
|
||||
NS_IMETHOD DidProcessAToken(void) { return NS_OK; }
|
||||
|
||||
NS_IMETHOD DoFragment(PRBool aFlag);
|
||||
NS_IMETHOD BeginContext(PRInt32 aPosition);
|
||||
|
|
|
@ -1,234 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public
|
||||
* License Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is Mozilla Communicator client code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*/
|
||||
#ifndef nsIHTMLContentSink_h___
|
||||
#define nsIHTMLContentSink_h___
|
||||
|
||||
/**
|
||||
* MODULE NOTES:
|
||||
* @update gess 4/1/98
|
||||
*
|
||||
* This file declares the concrete HTMLContentSink class.
|
||||
* This class is used during the parsing process as the
|
||||
* primary interface between the parser and the content
|
||||
* model.
|
||||
*
|
||||
* After the tokenizer completes, the parser iterates over
|
||||
* the known token list. As the parser identifies valid
|
||||
* elements, it calls the contentsink interface to notify
|
||||
* the content model that a new node or child node is being
|
||||
* created and added to the content model.
|
||||
*
|
||||
* The HTMLContentSink interface assumes 4 underlying
|
||||
* containers: HTML, HEAD, BODY and FRAMESET. Before
|
||||
* accessing any these, the parser will call the appropriate
|
||||
* OpennsIHTMLContentSink method: OpenHTML,OpenHead,OpenBody,OpenFrameSet;
|
||||
* likewise, the ClosensIHTMLContentSink version will be called when the
|
||||
* parser is done with a given section.
|
||||
*
|
||||
* IMPORTANT: The parser may Open each container more than
|
||||
* once! This is due to the irregular nature of HTML files.
|
||||
* For example, it is possible to encounter plain text at
|
||||
* the start of an HTML document (that preceeds the HTML tag).
|
||||
* Such text is treated as if it were part of the body.
|
||||
* In such cases, the parser will Open the body, pass the text-
|
||||
* node in and then Close the body. The body will likely be
|
||||
* re-Opened later when the actual <BODY> tag has been seen.
|
||||
*
|
||||
* Containers within the body are Opened and Closed
|
||||
* using the OpenContainer(...) and CloseContainer(...) calls.
|
||||
* It is assumed that the document or contentSink is
|
||||
* maintaining its state to manage where new content should
|
||||
* be added to the underlying document.
|
||||
*
|
||||
* NOTE: OpenHTML() and OpenBody() may get called multiple times
|
||||
* in the same document. That's fine, and it doesn't mean
|
||||
* that we have multiple bodies or HTML's.
|
||||
*
|
||||
* NOTE: I haven't figured out how sub-documents (non-frames)
|
||||
* are going to be handled. Stay tuned.
|
||||
*/
|
||||
#include "nsIParserNode.h"
|
||||
#include "nsIContentSink.h"
|
||||
|
||||
#define NS_IHTML_CONTENT_SINK_IID \
|
||||
{ 0xa6cf9051, 0x15b3, 0x11d2,{0x93, 0x2e, 0x00, 0x80, 0x5f, 0x8a, 0xdd, 0x32}}
|
||||
|
||||
|
||||
#ifdef XP_MAC
|
||||
#define MAX_REFLOW_DEPTH 75 //setting to 75 to prevent layout from crashing on mac. Bug 55095.
|
||||
#else
|
||||
#define MAX_REFLOW_DEPTH 200 //windows and linux (etc) can do much deeper structures.
|
||||
#endif
|
||||
|
||||
|
||||
class nsIHTMLContentSink : public nsIContentSink {
|
||||
public:
|
||||
|
||||
static const nsIID& GetIID() { static nsIID iid = NS_IHTML_CONTENT_SINK_IID; return iid; }
|
||||
|
||||
/**
|
||||
* This method gets called by the parser when it encounters
|
||||
* a title tag and wants to set the document title in the sink.
|
||||
*
|
||||
* @update 4/1/98 gess
|
||||
* @param nsString reference to new title value
|
||||
*/
|
||||
NS_IMETHOD SetTitle(const nsString& aValue)=0;
|
||||
|
||||
/**
|
||||
* This method is used to open the outer HTML container.
|
||||
*
|
||||
* @update 4/1/98 gess
|
||||
* @param nsIParserNode reference to parser node interface
|
||||
*/
|
||||
NS_IMETHOD OpenHTML(const nsIParserNode& aNode)=0;
|
||||
|
||||
/**
|
||||
* This method is used to close the outer HTML container.
|
||||
*
|
||||
* @update 4/1/98 gess
|
||||
* @param nsIParserNode reference to parser node interface
|
||||
*/
|
||||
NS_IMETHOD CloseHTML(const nsIParserNode& aNode)=0;
|
||||
|
||||
/**
|
||||
* This method is used to open the only HEAD container.
|
||||
*
|
||||
* @update 4/1/98 gess
|
||||
* @param nsIParserNode reference to parser node interface
|
||||
*/
|
||||
NS_IMETHOD OpenHead(const nsIParserNode& aNode)=0;
|
||||
|
||||
/**
|
||||
* This method is used to close the only HEAD container.
|
||||
*
|
||||
* @update 4/1/98 gess
|
||||
* @param nsIParserNode reference to parser node interface
|
||||
*/
|
||||
NS_IMETHOD CloseHead(const nsIParserNode& aNode)=0;
|
||||
|
||||
/**
|
||||
* This method is used to open the main BODY container.
|
||||
*
|
||||
* @update 4/1/98 gess
|
||||
* @param nsIParserNode reference to parser node interface
|
||||
*/
|
||||
NS_IMETHOD OpenBody(const nsIParserNode& aNode)=0;
|
||||
|
||||
/**
|
||||
* This method is used to close the main BODY container.
|
||||
*
|
||||
* @update 4/1/98 gess
|
||||
* @param nsIParserNode reference to parser node interface
|
||||
*/
|
||||
NS_IMETHOD CloseBody(const nsIParserNode& aNode)=0;
|
||||
|
||||
/**
|
||||
* This method is used to open a new FORM container.
|
||||
*
|
||||
* @update 4/1/98 gess
|
||||
* @param nsIParserNode reference to parser node interface
|
||||
*/
|
||||
NS_IMETHOD OpenForm(const nsIParserNode& aNode)=0;
|
||||
|
||||
/**
|
||||
* This method is used to close the outer FORM container.
|
||||
*
|
||||
* @update 4/1/98 gess
|
||||
* @param nsIParserNode reference to parser node interface
|
||||
*/
|
||||
NS_IMETHOD CloseForm(const nsIParserNode& aNode)=0;
|
||||
|
||||
/**
|
||||
* This method is used to open a new MAP container.
|
||||
*
|
||||
* @update 4/1/98 gess
|
||||
* @param nsIParserNode reference to parser node interface
|
||||
*/
|
||||
NS_IMETHOD OpenMap(const nsIParserNode& aNode)=0;
|
||||
|
||||
/**
|
||||
* This method is used to close the MAP container.
|
||||
*
|
||||
* @update 4/1/98 gess
|
||||
* @param nsIParserNode reference to parser node interface
|
||||
*/
|
||||
NS_IMETHOD CloseMap(const nsIParserNode& aNode)=0;
|
||||
|
||||
/**
|
||||
* This method is used to open the FRAMESET container.
|
||||
*
|
||||
* @update 4/1/98 gess
|
||||
* @param nsIParserNode reference to parser node interface
|
||||
*/
|
||||
NS_IMETHOD OpenFrameset(const nsIParserNode& aNode)=0;
|
||||
|
||||
/**
|
||||
* This method is used to close the FRAMESET container.
|
||||
*
|
||||
* @update 4/1/98 gess
|
||||
* @param nsIParserNode reference to parser node interface
|
||||
*/
|
||||
NS_IMETHOD CloseFrameset(const nsIParserNode& aNode)=0;
|
||||
|
||||
/**
|
||||
* This method tells the sink whether or not it is
|
||||
* encoding an HTML fragment or the whole document.
|
||||
* By default, the entire document is encoded.
|
||||
*
|
||||
* @update 03/14/99 gpk
|
||||
* @param aFlag set to true if only encoding a fragment
|
||||
*/
|
||||
|
||||
NS_IMETHOD DoFragment(PRBool aFlag)=0;
|
||||
|
||||
/**
|
||||
* This gets called when handling illegal contents, especially
|
||||
* in dealing with tables. This method creates a new context.
|
||||
*
|
||||
* @update 04/04/99 harishd
|
||||
* @param aPosition - The position from where the new context begins.
|
||||
*/
|
||||
NS_IMETHOD BeginContext(PRInt32 aPosition)=0;
|
||||
|
||||
/**
|
||||
* This method terminates any new context that got created by
|
||||
* BeginContext and switches back to the main context.
|
||||
*
|
||||
* @update 04/04/99 harishd
|
||||
* @param aPosition - Validates the end of a context.
|
||||
*/
|
||||
NS_IMETHOD EndContext(PRInt32 aPosition)=0;
|
||||
|
||||
/**
|
||||
* Use this method to retrieve pref. for the tag.
|
||||
*
|
||||
* @update 04/11/01 harishd
|
||||
* @param aTag - Check pref. for this tag.
|
||||
*/
|
||||
NS_IMETHOD GetPref(PRInt32 aTag,PRBool& aPref)=0;
|
||||
|
||||
};
|
||||
|
||||
extern NS_HTMLPARS nsresult NS_NewHTMLNullSink(nsIContentSink** aInstancePtrResult);
|
||||
|
||||
#endif /* nsIHTMLContentSink_h___ */
|
|
@ -110,7 +110,7 @@ public:
|
|||
virtual PRUint32 GetSize(void)=0;
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* FOR DEBUG PURPOSE ONLY
|
||||
*
|
||||
* Use this interface to query objects that contain content information.
|
||||
|
@ -233,6 +233,7 @@ class nsIParser : public nsISupports {
|
|||
virtual void UnblockParser() =0;
|
||||
|
||||
virtual PRBool IsParserEnabled() =0;
|
||||
virtual PRBool IsComplete() =0;
|
||||
|
||||
virtual nsresult Parse(nsIURI* aURL,nsIRequestObserver* aListener = nsnull,PRBool aEnableVerify=PR_FALSE, void* aKey=0,nsDTDMode aMode=eDTDMode_autodetect) = 0;
|
||||
virtual nsresult Parse(nsIInputStream& aStream, const nsString& aMimeType,PRBool aEnableVerify=PR_FALSE, void* aKey=0,nsDTDMode aMode=eDTDMode_autodetect) = 0;
|
||||
|
@ -276,6 +277,18 @@ class nsIParser : public nsISupports {
|
|||
eParserCommands aCommand,
|
||||
const nsString* aMimeType=nsnull,
|
||||
nsDTDMode aDTDMode=eDTDMode_unknown)=0;
|
||||
|
||||
/**
|
||||
* Call this method to cancel any pending parsing events.
|
||||
* Parsing events may be pending if all of the document's content
|
||||
* has been passed to the parser but the parser has been interrupted
|
||||
* because processing the tokens took too long.
|
||||
*
|
||||
* @update kmcclusk 05/18/01
|
||||
* @return NS_OK if succeeded else ERROR.
|
||||
*/
|
||||
|
||||
NS_IMETHOD CancelParsingEvents()=0;
|
||||
};
|
||||
|
||||
/* ===========================================================*
|
||||
|
@ -304,6 +317,7 @@ class nsIParser : public nsISupports {
|
|||
#define NS_ERROR_HTMLPARSER_UNTERMINATEDSTRINGLITERAL NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_HTMLPARSER,1016)
|
||||
#define NS_ERROR_HTMLPARSER_HIERARCHYTOODEEP NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_HTMLPARSER,1017)
|
||||
|
||||
|
||||
#define NS_ERROR_HTMLPARSER_CONTINUE NS_OK
|
||||
|
||||
|
||||
|
|
|
@ -76,6 +76,10 @@ public:
|
|||
NS_IMETHOD DoFragment(PRBool aFlag);
|
||||
NS_IMETHOD BeginContext(PRInt32 aPosition);
|
||||
NS_IMETHOD EndContext(PRInt32 aPosition);
|
||||
NS_IMETHOD WillProcessTokens(void) { return NS_OK; }
|
||||
NS_IMETHOD DidProcessTokens(void) { return NS_OK; }
|
||||
NS_IMETHOD WillProcessAToken(void) { return NS_OK; }
|
||||
NS_IMETHOD DidProcessAToken(void) { return NS_OK; }
|
||||
|
||||
// nsILoggingSink
|
||||
NS_IMETHOD SetOutputStream(PRFileDesc *aStream,PRBool autoDelete=PR_FALSE);
|
||||
|
|
|
@ -46,6 +46,8 @@
|
|||
#include "prenv.h"
|
||||
#include "nsParserCIID.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIEventQueue.h"
|
||||
#include "nsIEventQueueService.h"
|
||||
//#define rickgdebug
|
||||
|
||||
static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID);
|
||||
|
@ -57,6 +59,7 @@ static NS_DEFINE_CID(kWellFormedDTDCID, NS_WELLFORMEDDTD_CID);
|
|||
static NS_DEFINE_CID(kNavDTDCID, NS_CNAVDTD_CID);
|
||||
static NS_DEFINE_CID(kCOtherDTDCID, NS_COTHER_DTD_CID);
|
||||
static NS_DEFINE_CID(kViewSourceDTDCID, NS_VIEWSOURCE_DTD_CID);
|
||||
static NS_DEFINE_CID(kEventQueueServiceCID, NS_EVENTQUEUESERVICE_CID);
|
||||
|
||||
static const char* kNullURL = "Error: Null URL given";
|
||||
static const char* kOnStartNotCalled = "Error: OnStartRequest() must be called before OnDataAvailable()";
|
||||
|
@ -150,6 +153,99 @@ public:
|
|||
nsIDTD *mOtherDTD; //it's ok to leak this; the deque contains a copy too.
|
||||
};
|
||||
|
||||
|
||||
//-------------- Begin ParseContinue Event Definition ------------------------
|
||||
/*
|
||||
The parser can be explicitly interrupted by passing a return value of NS_ERROR_HTMLPARSER_INTERRUPTED
|
||||
from BuildModel on the DTD. This will cause the parser to stop processing and allow
|
||||
the application to return to the event loop. The data which was left at the time of
|
||||
interruption will be processed the next time OnDataAvailable is called. If the parser
|
||||
has received its final chunk of data then OnDataAvailable will no longer be called by the
|
||||
networking module, so the parser will schedule a nsParserContinueEvent which will call
|
||||
the parser to process the remaining data after returning to the event loop. If the parser
|
||||
is interrupted while processing the remaining data it will schedule another
|
||||
ParseContinueEvent. The processing of data followed by scheduling of the continue events
|
||||
will proceed until either:
|
||||
|
||||
1) All of the remaining data can be processed without interrupting
|
||||
2) The parser has been cancelled.
|
||||
|
||||
|
||||
This capability is currently used in CNavDTD and nsHTMLContentSink. The nsHTMLContentSink is
|
||||
notified by CNavDTD when a chunk of tokens is going to be processed and when each token
|
||||
is processed. The nsHTML content sink records the time when the chunk has started
|
||||
processing and will return NS_ERROR_HTMLPARSER_INTERRUPTED if the token processing time
|
||||
has exceeded a threshold called max tokenizing processing time. This allows the content
|
||||
sink to limit how much data is processed in a single chunk which in turn gates how much
|
||||
time is spent away from the event loop. Processing smaller chunks of data also reduces
|
||||
the time spent in subsequent reflows.
|
||||
|
||||
This capability is most apparent when loading large documents. If the maximum token
|
||||
processing time is set small enough the application will remain responsive during
|
||||
document load.
|
||||
|
||||
A side-effect of this capability is that document load is not complete when the last chunk
|
||||
of data is passed to OnDataAvailable since the parser may have been interrupted when
|
||||
the last chunk of data arrived. The document is complete when all of the document has
|
||||
been tokenized and there aren't any pending nsParserContinueEvents. This can cause
|
||||
problems if the application assumes that it can monitor the load requests to determine
|
||||
when the document load has been completed. This is what happens in Mozilla. The document
|
||||
is considered completely loaded when all of the load requests have been satisfied. To delay the
|
||||
document load until all of the parsing has been completed the nsHTMLContentSink adds a
|
||||
dummy parser load request which is not removed until the nsHTMLContentSink's DidBuildModel
|
||||
is called. The CNavDTD will not call DidBuildModel until the final chunk of data has been
|
||||
passed to the parser through the OnDataAvailable and there aren't any pending
|
||||
nsParserContineEvents.
|
||||
|
||||
Currently the parser is ignores requests to be interrupted during the processing of script.
|
||||
This is because a document.write followed by JavaScript calls to manipulate the DOM may
|
||||
fail if the parser was interrupted during the document.write.
|
||||
|
||||
|
||||
For more details @see bugzilla bug 76722
|
||||
*/
|
||||
|
||||
|
||||
struct nsParserContinueEvent : public PLEvent {
|
||||
|
||||
nsParserContinueEvent(nsIParser* aParser);
|
||||
~nsParserContinueEvent() { }
|
||||
|
||||
void HandleEvent() {
|
||||
if (mParser) {
|
||||
nsParser* parser = NS_STATIC_CAST(nsParser*, mParser);
|
||||
parser->HandleParserContinueEvent();
|
||||
NS_RELEASE(mParser);
|
||||
}
|
||||
};
|
||||
|
||||
nsIParser* mParser;
|
||||
};
|
||||
|
||||
static void PR_CALLBACK HandlePLEvent(nsParserContinueEvent* aEvent)
|
||||
{
|
||||
NS_ASSERTION(nsnull != aEvent,"Event is null");
|
||||
aEvent->HandleEvent();
|
||||
}
|
||||
|
||||
static void PR_CALLBACK DestroyPLEvent(nsParserContinueEvent* aEvent)
|
||||
{
|
||||
NS_ASSERTION(nsnull != aEvent,"Event is null");
|
||||
delete aEvent;
|
||||
}
|
||||
|
||||
nsParserContinueEvent::nsParserContinueEvent(nsIParser* aParser)
|
||||
{
|
||||
NS_ASSERTION(aParser, "null parameter");
|
||||
mParser = aParser;
|
||||
PL_InitEvent(this, aParser,
|
||||
(PLHandleEventProc) ::HandlePLEvent,
|
||||
(PLDestroyEventProc) ::DestroyPLEvent);
|
||||
}
|
||||
|
||||
//-------------- End ParseContinue Event Definition ------------------------
|
||||
|
||||
|
||||
static CSharedParserObjects* gSharedParserObjects=0;
|
||||
|
||||
|
||||
|
@ -247,11 +343,24 @@ nsParser::nsParser(nsITokenObserver* anObserver) {
|
|||
mCommand=eViewNormal;
|
||||
mParserEnabled=PR_TRUE;
|
||||
mBundle=nsnull;
|
||||
|
||||
mPendingContinueEvent=PR_FALSE;
|
||||
mCanInterrupt=PR_FALSE;
|
||||
|
||||
MOZ_TIMER_DEBUGLOG(("Reset: Parse Time: nsParser::nsParser(), this=%p\n", this));
|
||||
MOZ_TIMER_RESET(mParseTime);
|
||||
MOZ_TIMER_RESET(mDTDTime);
|
||||
MOZ_TIMER_RESET(mTokenizeTime);
|
||||
|
||||
nsresult rv = NS_OK;
|
||||
if (mEventQueue == nsnull) {
|
||||
// Cache the event queue of the current UI thread
|
||||
NS_WITH_SERVICE(nsIEventQueueService, eventService, kEventQueueServiceCID, &rv);
|
||||
if (NS_SUCCEEDED(rv) && (eventService)) { // XXX this implies that the UI is the current thread.
|
||||
rv = eventService->GetThreadEventQueue(NS_CURRENT_THREAD, getter_AddRefs(mEventQueue));
|
||||
}
|
||||
|
||||
NS_ASSERTION(mEventQueue, "event queue is null");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -286,6 +395,11 @@ nsParser::~nsParser() {
|
|||
//don't forget to add code here to delete
|
||||
//what may be several contexts...
|
||||
delete mParserContext;
|
||||
|
||||
if (mPendingContinueEvent) {
|
||||
NS_ASSERTION(mEventQueue != nsnull,"Event queue is null");
|
||||
mEventQueue->RevokeEvents(this);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -339,6 +453,24 @@ nsresult nsParser::QueryInterface(const nsIID& aIID, void** aInstancePtr)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
// The parser continue event is posted only if
|
||||
// all of the data to parse has been passed to ::OnDataAvailable
|
||||
// and the parser has been interrupted by the content sink
|
||||
// because the processing of tokens took too long.
|
||||
|
||||
nsresult
|
||||
nsParser::PostContinueEvent()
|
||||
{
|
||||
if ((! mPendingContinueEvent) && (mEventQueue)) {
|
||||
nsParserContinueEvent* ev = new nsParserContinueEvent(NS_STATIC_CAST(nsIParser*, this));
|
||||
NS_ENSURE_TRUE(ev,NS_ERROR_OUT_OF_MEMORY);
|
||||
NS_ADDREF(this);
|
||||
mEventQueue->PostEvent(ev);
|
||||
mPendingContinueEvent = PR_TRUE;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -1240,6 +1372,19 @@ NS_IMETHODIMP nsParser::CreateCompatibleDTD(nsIDTD** aDTD,
|
|||
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsParser::CancelParsingEvents() {
|
||||
if (mPendingContinueEvent) {
|
||||
NS_ASSERTION(mEventQueue,"Event queue is null");
|
||||
// Revoke all pending continue parsing events
|
||||
if (mEventQueue != nsnull) {
|
||||
mEventQueue->RevokeEvents(this);
|
||||
}
|
||||
mPendingContinueEvent=PR_FALSE;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//#define TEST_DOCTYPES
|
||||
#ifdef TEST_DOCTYPES
|
||||
static const char* doctypes[] = {
|
||||
|
@ -1433,13 +1578,15 @@ nsresult nsParser::DidBuildModel(nsresult anErrorCode) {
|
|||
//One last thing...close any open containers.
|
||||
nsresult result=anErrorCode;
|
||||
|
||||
if(mParserContext && !mParserContext->mPrevContext) {
|
||||
if(mParserContext->mDTD) {
|
||||
result=mParserContext->mDTD->DidBuildModel(anErrorCode,PRBool(0==mParserContext->mPrevContext),this,mSink);
|
||||
}
|
||||
//Ref. to bug 61462.
|
||||
NS_IF_RELEASE(mBundle);
|
||||
}//if
|
||||
if (IsComplete()) {
|
||||
if(mParserContext && !mParserContext->mPrevContext) {
|
||||
if(mParserContext->mDTD) {
|
||||
result=mParserContext->mDTD->DidBuildModel(anErrorCode,PRBool(0==mParserContext->mPrevContext),this,mSink);
|
||||
}
|
||||
//Ref. to bug 61462.
|
||||
NS_IF_RELEASE(mBundle);
|
||||
}//if
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
@ -1540,7 +1687,7 @@ nsresult nsParser::ContinueParsing(){
|
|||
|
||||
if(result!=NS_OK)
|
||||
result=mInternalState;
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -1582,6 +1729,29 @@ PRBool nsParser::IsParserEnabled() {
|
|||
return mParserEnabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Call this to query whether the parser thinks it's done with parsing.
|
||||
*
|
||||
* @update rickg 5/12/01
|
||||
* @return complete state
|
||||
*/
|
||||
PRBool nsParser::IsComplete() {
|
||||
return (! mPendingContinueEvent);
|
||||
}
|
||||
|
||||
|
||||
void nsParser::HandleParserContinueEvent() {
|
||||
mPendingContinueEvent = PR_FALSE;
|
||||
ContinueParsing();
|
||||
}
|
||||
|
||||
PRBool nsParser::CanInterrupt(void) {
|
||||
return mCanInterrupt;
|
||||
}
|
||||
|
||||
void nsParser::SetCanInterrupt(PRBool aCanInterrupt) {
|
||||
mCanInterrupt = aCanInterrupt;
|
||||
}
|
||||
|
||||
/**
|
||||
* This is the main controlling routine in the parsing process.
|
||||
|
@ -1679,7 +1849,16 @@ aMimeType,PRBool aVerifyEnabled,PRBool aLastCall,nsDTDMode aMode){
|
|||
//NOTE: Make sure that updates to this method don't cause
|
||||
// bug #2361 to break again!
|
||||
|
||||
nsresult result=NS_OK;
|
||||
nsresult result=NS_OK;
|
||||
|
||||
|
||||
if(aLastCall && (0==aSourceBuffer.Length())) {
|
||||
// Nothing is being passed to the parser so return
|
||||
// immediately. mUnusedInput will get processed when
|
||||
// some data is actually passed in.
|
||||
return result;
|
||||
}
|
||||
|
||||
nsParser* me = this;
|
||||
// Maintain a reference to ourselves so we don't go away
|
||||
// till we're completely done.
|
||||
|
@ -1687,7 +1866,7 @@ aMimeType,PRBool aVerifyEnabled,PRBool aLastCall,nsDTDMode aMode){
|
|||
|
||||
if(aSourceBuffer.Length() || mUnusedInput.Length()) {
|
||||
mDTDVerification=aVerifyEnabled;
|
||||
CParserContext* pc=0;
|
||||
CParserContext* pc=0;
|
||||
|
||||
if((!mParserContext) || (mParserContext->mKey!=aKey)) {
|
||||
//only make a new context if we dont have one, OR if we do, but has a different context key...
|
||||
|
@ -1867,10 +2046,19 @@ nsresult nsParser::ResumeParse(PRBool allowIteration, PRBool aIsFinalChunk) {
|
|||
}
|
||||
}
|
||||
|
||||
//Only allow parsing to be interuptted in the subsequent call
|
||||
//to build model.
|
||||
SetCanInterrupt(PR_TRUE);
|
||||
nsresult theTokenizerResult=Tokenize(aIsFinalChunk); // kEOF==2152596456
|
||||
result=BuildModel();
|
||||
|
||||
theIterationIsOk=PRBool(kEOF!=theTokenizerResult);
|
||||
if(result==NS_ERROR_HTMLPARSER_INTERRUPTED) {
|
||||
if(aIsFinalChunk)
|
||||
PostContinueEvent();
|
||||
}
|
||||
SetCanInterrupt(PR_FALSE);
|
||||
|
||||
theIterationIsOk=PRBool((kEOF!=theTokenizerResult) && (result!=NS_ERROR_HTMLPARSER_INTERRUPTED));
|
||||
|
||||
// Make sure not to stop parsing too early. Therefore, before shutting down the
|
||||
// parser, it's important to check whether the input buffer has been scanned to
|
||||
|
@ -1895,7 +2083,7 @@ nsresult nsParser::ResumeParse(PRBool allowIteration, PRBool aIsFinalChunk) {
|
|||
break;
|
||||
}
|
||||
|
||||
else if((NS_OK==result) && (theTokenizerResult==kEOF)){
|
||||
else if(((NS_OK==result) && (theTokenizerResult==kEOF)) || (result==NS_ERROR_HTMLPARSER_INTERRUPTED)){
|
||||
|
||||
PRBool theContextIsStringBased=PRBool(CParserContext::eCTString==mParserContext->mContextType);
|
||||
if( (eOnStop==mParserContext->mStreamListenerState) ||
|
||||
|
@ -1918,11 +2106,11 @@ nsresult nsParser::ResumeParse(PRBool allowIteration, PRBool aIsFinalChunk) {
|
|||
MOZ_TIMER_LOG(("Tokenize Time: "));
|
||||
MOZ_TIMER_PRINT(mTokenizeTime);
|
||||
|
||||
return result;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
}
|
||||
else {
|
||||
else {
|
||||
|
||||
CParserContext* theContext=PopContext();
|
||||
if(theContext) {
|
||||
|
@ -1933,6 +2121,8 @@ nsresult nsParser::ResumeParse(PRBool allowIteration, PRBool aIsFinalChunk) {
|
|||
delete theContext;
|
||||
}
|
||||
result = mInternalState;
|
||||
aIsFinalChunk=(mParserContext && mParserContext->mStreamListenerState==eOnStop)? PR_TRUE:PR_FALSE;
|
||||
|
||||
//...then intentionally fall through to WillInterruptParse()...
|
||||
}
|
||||
|
||||
|
@ -1940,10 +2130,12 @@ nsresult nsParser::ResumeParse(PRBool allowIteration, PRBool aIsFinalChunk) {
|
|||
|
||||
}
|
||||
|
||||
if(kEOF==theTokenizerResult) {
|
||||
if((kEOF==theTokenizerResult) || (result==NS_ERROR_HTMLPARSER_INTERRUPTED)) {
|
||||
result = (result == NS_ERROR_HTMLPARSER_INTERRUPTED) ? NS_OK : result;
|
||||
mParserContext->mDTD->WillInterruptParse();
|
||||
}
|
||||
|
||||
|
||||
}//while
|
||||
}//if
|
||||
else {
|
||||
|
@ -1954,7 +2146,7 @@ nsresult nsParser::ResumeParse(PRBool allowIteration, PRBool aIsFinalChunk) {
|
|||
MOZ_TIMER_DEBUGLOG(("Stop: Parse Time: nsParser::ResumeParse(), this=%p\n", this));
|
||||
MOZ_TIMER_STOP(mParseTime);
|
||||
|
||||
return result;
|
||||
return (result==NS_ERROR_HTMLPARSER_INTERRUPTED) ? NS_OK : result;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -70,6 +70,7 @@
|
|||
#include "nsDTDUtils.h"
|
||||
#include "nsTimer.h"
|
||||
#include "nsIProgressEventSink.h"
|
||||
#include "nsIEventQueue.h"
|
||||
|
||||
class IContentSink;
|
||||
class nsIDTD;
|
||||
|
@ -225,6 +226,14 @@ class nsParser : public nsIParser,
|
|||
*/
|
||||
virtual PRBool IsParserEnabled();
|
||||
|
||||
/**
|
||||
* Call this to query whether the parser thinks it's done with parsing.
|
||||
*
|
||||
* @update rickg 5/12/01
|
||||
* @return complete state
|
||||
*/
|
||||
virtual PRBool IsComplete();
|
||||
|
||||
/**
|
||||
* This rather arcane method (hack) is used as a signal between the
|
||||
* DTD and the parser. It allows the DTD to tell the parser that content
|
||||
|
@ -319,6 +328,44 @@ class nsParser : public nsIParser,
|
|||
const nsString* aMimeType=nsnull,
|
||||
nsDTDMode aDTDMode=eDTDMode_unknown);
|
||||
|
||||
/**
|
||||
* Removes continue parsing events
|
||||
* @update kmcclusk 5/18/98
|
||||
*/
|
||||
|
||||
NS_IMETHODIMP CancelParsingEvents();
|
||||
|
||||
/**
|
||||
* Indicates whether the parser is in a state where it
|
||||
* can be interrupted.
|
||||
* @return PR_TRUE if parser can be interrupted, PR_FALSE if it can not be interrupted.
|
||||
* @update kmcclusk 5/18/98
|
||||
*/
|
||||
PRBool CanInterrupt(void);
|
||||
|
||||
/**
|
||||
* Set to parser state to indicate whether parsing tokens can be interrupted
|
||||
* @param aCanInterrupt PR_TRUE if parser can be interrupted, PR_FALSE if it can not be interrupted.
|
||||
* @update kmcclusk 5/18/98
|
||||
*/
|
||||
void SetCanInterrupt(PRBool aCanInterrupt);
|
||||
|
||||
/**
|
||||
* This is called when the final chunk has been
|
||||
* passed to the parser and the content sink has
|
||||
* interrupted token processing. It schedules
|
||||
* a ParserContinue PL_Event which will ask the parser
|
||||
* to HandleParserContinueEvent when it is handled.
|
||||
* @update kmcclusk6/1/2001
|
||||
*/
|
||||
nsresult PostContinueEvent();
|
||||
|
||||
/**
|
||||
* Fired when the continue parse event is triggered.
|
||||
* @update kmcclusk 5/18/98
|
||||
*/
|
||||
void HandleParserContinueEvent(void);
|
||||
|
||||
protected:
|
||||
|
||||
/**
|
||||
|
@ -383,6 +430,8 @@ private:
|
|||
* @return TRUE if all went well
|
||||
*/
|
||||
PRBool DidTokenize(PRBool aIsFinalChunk = PR_FALSE);
|
||||
|
||||
|
||||
protected:
|
||||
//*********************************************
|
||||
// And now, some data members...
|
||||
|
@ -396,6 +445,7 @@ protected:
|
|||
nsIRequestObserver* mObserver;
|
||||
nsIProgressEventSink* mProgressEventSink;
|
||||
nsIContentSink* mSink;
|
||||
|
||||
nsIParserFilter* mParserFilter;
|
||||
PRBool mDTDVerification;
|
||||
eParserCommands mCommand;
|
||||
|
@ -412,7 +462,12 @@ protected:
|
|||
nsParserBundle* mBundle;
|
||||
nsTokenAllocator mTokenAllocator;
|
||||
|
||||
public:
|
||||
nsCOMPtr<nsIEventQueue> mEventQueue;
|
||||
PRPackedBool mPendingContinueEvent;
|
||||
PRPackedBool mCanInterrupt;
|
||||
|
||||
public:
|
||||
|
||||
MOZ_TIMER_DECLARE(mParseTime)
|
||||
MOZ_TIMER_DECLARE(mDTDTime)
|
||||
MOZ_TIMER_DECLARE(mTokenizeTime)
|
||||
|
|
Загрузка…
Ссылка в новой задаче