1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set sw=2 ts=2 et tw=78: */
3 /* ***** BEGIN LICENSE BLOCK *****
4 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 * The contents of this file are subject to the Mozilla Public License Version
7 * 1.1 (the "License"); you may not use this file except in compliance with
8 * the License. You may obtain a copy of the License at
9 * http://www.mozilla.org/MPL/
11 * Software distributed under the License is distributed on an "AS IS" basis,
12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 * for the specific language governing rights and limitations under the
16 * The Original Code is mozilla.org code.
18 * The Initial Developer of the Original Code is
19 * Netscape Communications Corporation.
20 * Portions created by the Initial Developer are Copyright (C) 1998
21 * the Initial Developer. All Rights Reserved.
24 * jce2@po.cwru.edu <Jason Eager>: Added pref to turn on/off
25 * Boris Zbarsky <bzbarsky@mit.edu>
27 * Andreas M. Schneider <clarence@clarence.de>
29 * Alternatively, the contents of this file may be used under the terms of
30 * either of the GNU General Public License Version 2 or later (the "GPL"),
31 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
32 * in which case the provisions of the GPL or the LGPL are applicable instead
33 * of those above. If you wish to allow use of your version of this file only
34 * under the terms of either the GPL or the LGPL, and not to allow others to
35 * use your version of this file under the terms of the MPL, indicate your
36 * decision by deleting the provisions above and replace them with the notice
37 * and other provisions required by the GPL or the LGPL. If you do not delete
38 * the provisions above, a recipient may use your version of this file under
39 * the terms of any one of the MPL, the GPL or the LGPL.
41 * ***** END LICENSE BLOCK ***** */
44 * Set NS_VIEWSOURCE_TOKENS_PER_BLOCK to 0 to disable multi-block
45 * output. Multi-block output helps reduce the amount of bidi
46 * processing we have to do on the resulting content model.
48 #define NS_VIEWSOURCE_TOKENS_PER_BLOCK 16
50 #ifdef RAPTOR_PERF_METRICS
51 # define START_TIMER() \
52 if(mParser) mParser->mParseTime.Start(PR_FALSE); \
53 if(mParser) mParser->mDTDTime.Start(PR_FALSE);
55 # define STOP_TIMER() \
56 if(mParser) mParser->mParseTime.Stop(); \
57 if(mParser) mParser->mDTDTime.Stop();
61 # define START_TIMER()
65 #include "nsViewSourceHTML.h"
68 #include "nsScanner.h"
69 #include "nsIParser.h"
70 #include "nsDTDUtils.h"
71 #include "nsIContentSink.h"
72 #include "nsIHTMLContentSink.h"
73 #include "nsHTMLTokenizer.h"
74 #include "nsIPrefService.h"
75 #include "nsIPrefBranch.h"
76 #include "nsUnicharUtils.h"
77 #include "nsPrintfCString.h"
79 #include "nsIServiceManager.h"
81 #include "nsElementTable.h"
83 #include "prenv.h" //this is here for debug reasons...
84 #include "prtypes.h" //this is here for debug reasons...
89 #ifdef RAPTOR_PERF_METRICS
90 #include "stopwatch.h"
96 // Define this to dump the viewsource stuff to a file
97 //#define DUMP_TO_FILE
101 static const char* gDumpFileName
= "/tmp/viewsource.html";
102 // static const char* gDumpFileName = "\\temp\\viewsource.html";
103 #endif // DUMP_TO_FILE
105 // bug 22022 - these are used to toggle 'Wrap Long Lines' on the viewsource
106 // window by selectively setting/unsetting the following class defined in
107 // viewsource.css; the setting is remembered between invocations using a pref.
108 static const char kBodyId
[] = "viewsource";
109 static const char kBodyClassWrap
[] = "wrap";
111 NS_IMPL_ISUPPORTS1(CViewSourceHTML
, nsIDTD
)
113 /********************************************
114 ********************************************/
130 static const char* const kElementClasses
[] = {
144 static const char* const kBeforeText
[] = {
158 static const char* const kAfterText
[] = {
173 static const char* const kDumpFileBeforeText
[] = {
187 static const char* const kDumpFileAfterText
[] = {
200 #endif // DUMP_TO_FILE
203 * Default constructor
205 * @update gess 4/9/98
209 CViewSourceHTML::CViewSourceHTML()
211 mSyntaxHighlight
= PR_FALSE
;
212 mWrapLongLines
= PR_FALSE
;
213 nsCOMPtr
<nsIPrefBranch
> prefBranch(do_GetService(NS_PREFSERVICE_CONTRACTID
));
217 rv
= prefBranch
->GetBoolPref("view_source.syntax_highlight", &temp
);
218 mSyntaxHighlight
= NS_SUCCEEDED(rv
) ? temp
: PR_TRUE
;
220 rv
= prefBranch
->GetBoolPref("view_source.wrap_long_lines", &temp
);
221 mWrapLongLines
= NS_SUCCEEDED(rv
) ? temp
: PR_FALSE
;
228 mDocType
=eHTML3_Quirks
; // why?
229 mHasOpenRoot
=PR_FALSE
;
230 mHasOpenBody
=PR_FALSE
;
235 gDumpFile
= fopen(gDumpFileName
,"w");
236 #endif // DUMP_TO_FILE
245 * @update gess 4/9/98
249 CViewSourceHTML::~CViewSourceHTML(){
250 mParser
=0; //just to prove we destructed...
254 * The parser uses a code sandwich to wrap the parsing process. Before
255 * the process begins, WillBuildModel() is called. Afterwards the parser
256 * calls DidBuildModel().
257 * @update rickg 03.20.2000
258 * @param aParserContext
260 * @return error code (almost always 0)
262 nsresult
CViewSourceHTML::WillBuildModel(const CParserContext
& aParserContext
,
263 nsITokenizer
* aTokenizer
,
264 nsIContentSink
* aSink
){
266 nsresult result
=NS_OK
;
268 #ifdef RAPTOR_PERF_METRICS
270 NS_START_STOPWATCH(vsTimer
);
274 mSink
=(nsIHTMLContentSink
*)aSink
;
276 if((!aParserContext
.mPrevContext
) && (mSink
)) {
278 nsAString
& contextFilename
= aParserContext
.mScanner
->GetFilename();
279 mFilename
= Substring(contextFilename
,
280 12, // The length of "view-source:"
281 contextFilename
.Length() - 12);
283 mDocType
=aParserContext
.mDocType
;
284 mMimeType
=aParserContext
.mMimeType
;
285 mDTDMode
=aParserContext
.mDTDMode
;
286 mParserCommand
=aParserContext
.mParserCommand
;
287 mTokenizer
= aTokenizer
;
292 fprintf(gDumpFile
, "<html>\n");
293 fprintf(gDumpFile
, "<head>\n");
294 fprintf(gDumpFile
, "<title>");
295 fprintf(gDumpFile
, "Source of: ");
296 fputs(NS_ConvertUTF16toUTF8(mFilename
).get(), gDumpFile
);
297 fprintf(gDumpFile
, "</title>\n");
298 fprintf(gDumpFile
, "<link rel=\"stylesheet\" type=\"text/css\" href=\"resource://gre/res/viewsource.css\">\n");
299 fprintf(gDumpFile
, "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">\n");
300 fprintf(gDumpFile
, "</head>\n");
301 fprintf(gDumpFile
, "<body id=\"viewsource\">\n");
302 fprintf(gDumpFile
, "<pre id=\"line1\">\n");
304 #endif //DUMP_TO_FILE
308 if(eViewSource
!=aParserContext
.mParserCommand
)
310 else mDocType
=aParserContext
.mDocType
;
313 // Munge the DTD mode so that the document will be in standards mode even if
314 // the original source was quirks. The CONST_CAST is evil, but the other
315 // options seem to be:
316 // 1) Change the WillBuildModel signature to take an nsIParser so that we can
317 // push a new parser context right here.
318 // 2) Make some assumptions about the exact class of mSink and get at the
319 // document that way.
320 // #1 doesn't seem worth it, and #2 is even more evil, since we plan to reset
321 // the DTD mode right back to what it was before, let's risk this.
322 CParserContext
& parserContext
= const_cast<CParserContext
&>(aParserContext
);
323 parserContext
.mDTDMode
= eDTDMode_full_standards
;
324 result
= mSink
->WillBuildModel();
325 // And reset the DTD mode back to the right one
326 parserContext
.mDTDMode
= mDTDMode
;
332 * The parser uses a code sandwich to wrap the parsing process. Before
333 * the process begins, WillBuildModel() is called. Afterwards the parser
334 * calls DidBuildModel().
335 * @update gess5/18/98
336 * @param aFilename is the name of the file being parsed.
337 * @return error code (almost always 0)
339 NS_IMETHODIMP
CViewSourceHTML::BuildModel(nsIParser
* aParser
,nsITokenizer
* aTokenizer
,nsITokenObserver
* anObserver
,nsIContentSink
* aSink
) {
340 nsresult result
=NS_OK
;
342 if(aTokenizer
&& aParser
) {
344 nsITokenizer
* oldTokenizer
=mTokenizer
;
345 mTokenizer
=aTokenizer
;
346 nsTokenAllocator
* theAllocator
=mTokenizer
->GetTokenAllocator();
349 // For the stack-allocated tokens below, it's safe to pass a null
350 // token allocator, because there are no attributes on the tokens.
351 CStartToken
htmlToken(NS_LITERAL_STRING("HTML"), eHTMLTag_html
);
352 nsCParserNode
htmlNode(&htmlToken
, 0/*stack token*/);
353 mSink
->OpenContainer(htmlNode
);
355 CStartToken
headToken(NS_LITERAL_STRING("HEAD"), eHTMLTag_head
);
356 nsCParserNode
headNode(&headToken
, 0/*stack token*/);
357 mSink
->OpenContainer(headNode
);
359 CStartToken
titleToken(NS_LITERAL_STRING("TITLE"), eHTMLTag_title
);
360 nsCParserNode
titleNode(&titleToken
, 0/*stack token*/);
361 mSink
->OpenContainer(titleNode
);
363 // Note that XUL will automatically add the prefix "Source of: "
364 if (StringBeginsWith(mFilename
, NS_LITERAL_STRING("data:")) &&
365 mFilename
.Length() > 50) {
366 nsAutoString
dataFilename(Substring(mFilename
, 0, 50));
367 dataFilename
.AppendLiteral("...");
368 CTextToken
titleText(dataFilename
);
369 nsCParserNode
titleTextNode(&titleText
, 0/*stack token*/);
370 mSink
->AddLeaf(titleTextNode
);
372 CTextToken
titleText(mFilename
);
373 nsCParserNode
titleTextNode(&titleText
, 0/*stack token*/);
374 mSink
->AddLeaf(titleTextNode
);
377 mSink
->CloseContainer(eHTMLTag_title
);
380 CStartToken
* theToken
=
381 static_cast<CStartToken
*>
382 (theAllocator
->CreateTokenOfType(eToken_start
,
384 NS_LITERAL_STRING("LINK")));
386 nsCParserStartNode
theNode(theToken
, theAllocator
);
388 AddAttrToNode(theNode
, theAllocator
,
389 NS_LITERAL_STRING("rel"),
390 NS_LITERAL_STRING("stylesheet"));
392 AddAttrToNode(theNode
, theAllocator
,
393 NS_LITERAL_STRING("type"),
394 NS_LITERAL_STRING("text/css"));
396 AddAttrToNode(theNode
, theAllocator
,
397 NS_LITERAL_STRING("href"),
398 NS_LITERAL_STRING("resource://gre/res/viewsource.css"));
400 mSink
->AddLeaf(theNode
);
402 IF_FREE(theToken
, theAllocator
);
405 result
= mSink
->CloseContainer(eHTMLTag_head
);
406 if(NS_SUCCEEDED(result
)) {
407 mHasOpenRoot
= PR_TRUE
;
410 if (NS_SUCCEEDED(result
) && !mHasOpenBody
) {
412 CStartToken
* bodyToken
=
413 static_cast<CStartToken
*>
414 (theAllocator
->CreateTokenOfType(eToken_start
,
416 NS_LITERAL_STRING("BODY")));
418 nsCParserStartNode
bodyNode(bodyToken
, theAllocator
);
420 AddAttrToNode(bodyNode
, theAllocator
,
421 NS_LITERAL_STRING("id"),
422 NS_ConvertASCIItoUTF16(kBodyId
));
424 if (mWrapLongLines
) {
425 AddAttrToNode(bodyNode
, theAllocator
,
426 NS_LITERAL_STRING("class"),
427 NS_ConvertASCIItoUTF16(kBodyClassWrap
));
429 result
= mSink
->OpenContainer(bodyNode
);
430 if(NS_SUCCEEDED(result
)) mHasOpenBody
=PR_TRUE
;
432 IF_FREE(bodyToken
, theAllocator
);
434 if (NS_SUCCEEDED(result
)) {
435 CStartToken
* preToken
=
436 static_cast<CStartToken
*>
437 (theAllocator
->CreateTokenOfType(eToken_start
,
439 NS_LITERAL_STRING("PRE")));
441 nsCParserStartNode
preNode(preToken
, theAllocator
);
442 AddAttrToNode(preNode
, theAllocator
,
443 NS_LITERAL_STRING("id"),
444 NS_LITERAL_STRING("line1"));
445 result
= mSink
->OpenContainer(preNode
);
447 result
= NS_ERROR_OUT_OF_MEMORY
;
449 IF_FREE(preToken
, theAllocator
);
454 mSink
->WillProcessTokens();
456 while(NS_SUCCEEDED(result
)){
457 CToken
* theToken
=mTokenizer
->PopToken();
459 result
=HandleToken(theToken
,aParser
);
460 if(NS_SUCCEEDED(result
)) {
461 IF_FREE(theToken
, mTokenizer
->GetTokenAllocator());
462 if (mParser
->CanInterrupt() &&
463 mSink
->DidProcessAToken() == NS_ERROR_HTMLPARSER_INTERRUPTED
) {
464 result
= NS_ERROR_HTMLPARSER_INTERRUPTED
;
468 mTokenizer
->PushTokenFront(theToken
);
474 mTokenizer
=oldTokenizer
;
476 else result
=NS_ERROR_HTMLPARSER_BADTOKENIZER
;
481 * Call this to start a new PRE block. See bug 86355 for why this
482 * makes some pages much faster.
484 void CViewSourceHTML::StartNewPreBlock(void){
485 CEndToken
endToken(eHTMLTag_pre
);
486 nsCParserNode
endNode(&endToken
, 0/*stack token*/);
487 mSink
->CloseContainer(eHTMLTag_pre
);
489 nsTokenAllocator
* theAllocator
= mTokenizer
->GetTokenAllocator();
494 CStartToken
* theToken
=
495 static_cast<CStartToken
*>
496 (theAllocator
->CreateTokenOfType(eToken_start
,
498 NS_LITERAL_STRING("PRE")));
503 nsCParserStartNode
startNode(theToken
, theAllocator
);
504 AddAttrToNode(startNode
, theAllocator
,
505 NS_LITERAL_STRING("id"),
506 NS_ConvertASCIItoUTF16(nsPrintfCString("line%d", mLineNumber
)));
507 mSink
->OpenContainer(startNode
);
508 IF_FREE(theToken
, theAllocator
);
512 fprintf(gDumpFile
, "</pre>\n");
513 fprintf(gDumpFile
, "<pre id=\"line%d\">\n", mLineNumber
);
515 #endif // DUMP_TO_FILE
520 void CViewSourceHTML::AddAttrToNode(nsCParserStartNode
& aNode
,
521 nsTokenAllocator
* aAllocator
,
522 const nsAString
& aAttrName
,
523 const nsAString
& aAttrValue
)
525 NS_PRECONDITION(aAllocator
, "Must have a token allocator!");
527 CAttributeToken
* theAttr
=
528 (CAttributeToken
*) aAllocator
->CreateTokenOfType(eToken_attribute
,
532 NS_ERROR("Failed to allocate attribute token");
536 theAttr
->SetKey(aAttrName
);
537 aNode
.AddAttribute(theAttr
);
539 // Parser nodes assume that they are being handed a ref when AddAttribute is
540 // called, unlike Init() and construction, when they actually addref the
541 // incoming token. Do NOT release here unless this setup changes.
546 * @update gess5/18/98
550 NS_IMETHODIMP
CViewSourceHTML::DidBuildModel(nsresult anErrorCode
,PRBool aNotifySink
,nsIParser
* aParser
,nsIContentSink
* aSink
){
551 nsresult result
= NS_OK
;
553 //ADD CODE HERE TO CLOSE OPEN CONTAINERS...
557 mParser
=(nsParser
*)aParser
; //debug XXX
560 mSink
=(nsIHTMLContentSink
*)aParser
->GetContentSink();
561 if((aNotifySink
) && (mSink
)) {
562 //now let's close automatically auto-opened containers...
566 fprintf(gDumpFile
, "</pre>\n");
567 fprintf(gDumpFile
, "</body>\n");
568 fprintf(gDumpFile
, "</html>\n");
571 #endif // DUMP_TO_FILE
573 if(ePlainText
!=mDocType
) {
574 mSink
->CloseContainer(eHTMLTag_pre
);
575 mSink
->CloseContainer(eHTMLTag_body
);
576 mSink
->CloseContainer(eHTMLTag_html
);
578 result
= mSink
->DidBuildModel();
585 #ifdef RAPTOR_PERF_METRICS
586 NS_STOP_STOPWATCH(vsTimer
);
587 printf("viewsource timer: ");
596 * Use this id you want to stop the building content model
597 * --------------[ Sets DTD to STOP mode ]----------------
598 * It's recommended to use this method in accordance with
599 * the parser's terminate() method.
601 * @update harishd 07/22/99
606 CViewSourceHTML::Terminate() {
609 NS_IMETHODIMP_(PRInt32
)
610 CViewSourceHTML::GetType() {
611 return NS_IPARSER_FLAG_HTML
;
616 * @update gess5/18/98
620 NS_IMETHODIMP
CViewSourceHTML::WillResumeParse(nsIContentSink
* aSink
){
621 nsresult result
= NS_OK
;
623 result
= mSink
->WillResume();
630 * @update gess5/18/98
634 NS_IMETHODIMP
CViewSourceHTML::WillInterruptParse(nsIContentSink
* aSink
){
635 nsresult result
= NS_OK
;
637 result
= mSink
->WillInterrupt();
643 * Called by the parser to enable/disable dtd verification of the
644 * internal context stack.
645 * @update gess 7/23/98
649 void CViewSourceHTML::SetVerification(PRBool aEnabled
)
654 * This method is called to determine whether or not a tag
655 * of one type can contain a tag of another type.
657 * @update gess 3/25/98
658 * @param aParent -- int tag of parent container
659 * @param aChild -- int tag of child container
660 * @return PR_TRUE if parent can contain child
662 PRBool
CViewSourceHTML::CanContain(PRInt32 aParent
,PRInt32 aChild
) const{
663 PRBool result
=PR_TRUE
;
668 * This method gets called to determine whether a given
669 * tag is itself a container
671 * @update gess 3/25/98
672 * @param aTag -- tag to test for containership
673 * @return PR_TRUE if given tag can contain other tags
675 PRBool
CViewSourceHTML::IsContainer(PRInt32 aTag
) const{
676 PRBool result
=PR_TRUE
;
681 * This method gets called when a tag needs to write it's attributes
683 * @update gess 3/25/98
685 * @return result status
687 nsresult
CViewSourceHTML::WriteAttributes(PRInt32 attrCount
, PRBool aOwnerInError
) {
688 nsresult result
=NS_OK
;
690 if(attrCount
){ //go collect the attributes...
692 for(attr
= 0; attr
< attrCount
; ++attr
){
693 CToken
* theToken
= mTokenizer
->PeekToken();
695 eHTMLTokenTypes theType
= eHTMLTokenTypes(theToken
->GetTokenType());
696 if(eToken_attribute
== theType
){
697 mTokenizer
->PopToken(); //pop it for real...
698 mTokenNode
.AddAttribute(theToken
); //and add it to the node.
700 CAttributeToken
* theAttrToken
= (CAttributeToken
*)theToken
;
701 const nsSubstring
& theKey
= theAttrToken
->GetKey();
703 // The attribute is only in error if its owner is NOT in error.
704 const PRBool attributeInError
=
705 !aOwnerInError
&& theAttrToken
->IsInError();
707 result
= WriteTag(kAttributeName
,theKey
,0,attributeInError
);
708 const nsSubstring
& theValue
= theAttrToken
->GetValue();
710 if(!theValue
.IsEmpty() || theAttrToken
->mHasEqualWithoutValue
){
711 result
= WriteTag(kAttributeValue
,theValue
,0,attributeInError
);
723 * This method gets called when a tag needs to be sent out
725 * @update gess 3/25/98
727 * @return result status
729 nsresult
CViewSourceHTML::WriteTag(PRInt32 aTagType
,const nsSubstring
& aText
,PRInt32 attrCount
,PRBool aTagInError
) {
730 nsresult result
=NS_OK
;
732 // adjust line number to what it will be after we finish writing this tag
733 // XXXbz life here sucks. We can't use the GetNewlineCount on the token,
734 // because Text tokens in <style>, <script>, etc lie through their teeth.
735 // On the other hand, the parser messes up newline counting in some token
736 // types (bug 137315). So our line numbers will disagree with the parser's
738 mLineNumber
+= aText
.CountChar(PRUnichar('\n'));
740 nsTokenAllocator
* theAllocator
=mTokenizer
->GetTokenAllocator();
741 NS_ASSERTION(0!=theAllocator
,"Error: no allocator");
743 return NS_ERROR_FAILURE
;
745 // Highlight all parts of all erroneous tags.
746 if (mSyntaxHighlight
&& aTagInError
) {
747 CStartToken
* theTagToken
=
748 static_cast<CStartToken
*>
749 (theAllocator
->CreateTokenOfType(eToken_start
,
751 NS_LITERAL_STRING("SPAN")));
752 NS_ENSURE_TRUE(theTagToken
, NS_ERROR_OUT_OF_MEMORY
);
753 mErrorNode
.Init(theTagToken
, theAllocator
);
754 AddAttrToNode(mErrorNode
, theAllocator
,
755 NS_LITERAL_STRING("class"),
756 NS_LITERAL_STRING("error"));
757 mSink
->OpenContainer(mErrorNode
);
758 IF_FREE(theTagToken
, theAllocator
);
761 fprintf(gDumpFile
, "<span class=\"error\">");
766 if (kBeforeText
[aTagType
][0] != 0) {
767 NS_ConvertASCIItoUTF16
beforeText(kBeforeText
[aTagType
]);
768 mITextToken
.SetIndirectString(beforeText
);
769 nsCParserNode
theNode(&mITextToken
, 0/*stack token*/);
770 mSink
->AddLeaf(theNode
);
773 if (gDumpFile
&& kDumpFileBeforeText
[aTagType
][0])
774 fprintf(gDumpFile
, kDumpFileBeforeText
[aTagType
]);
775 #endif // DUMP_TO_FILE
777 if (mSyntaxHighlight
&& aTagType
!= kText
) {
778 CStartToken
* theTagToken
=
779 static_cast<CStartToken
*>
780 (theAllocator
->CreateTokenOfType(eToken_start
,
782 NS_LITERAL_STRING("SPAN")));
783 NS_ENSURE_TRUE(theTagToken
, NS_ERROR_OUT_OF_MEMORY
);
784 mStartNode
.Init(theTagToken
, theAllocator
);
785 AddAttrToNode(mStartNode
, theAllocator
,
786 NS_LITERAL_STRING("class"),
787 NS_ConvertASCIItoUTF16(kElementClasses
[aTagType
]));
788 mSink
->OpenContainer(mStartNode
); //emit <starttag>...
789 IF_FREE(theTagToken
, theAllocator
);
792 fprintf(gDumpFile
, "<span class=\"");
793 fprintf(gDumpFile
, kElementClasses
[aTagType
]);
794 fprintf(gDumpFile
, "\">");
796 #endif // DUMP_TO_FILE
801 mITextToken
.SetIndirectString(aText
); //now emit the tag name...
803 nsCParserNode
theNode(&mITextToken
, 0/*stack token*/);
804 mSink
->AddLeaf(theNode
);
807 fputs(NS_ConvertUTF16toUTF8(aText
).get(), gDumpFile
);
809 #endif // DUMP_TO_FILE
811 if (mSyntaxHighlight
&& aTagType
!= kText
) {
812 mStartNode
.ReleaseAll();
813 mSink
->CloseContainer(eHTMLTag_span
); //emit </endtag>...
816 fprintf(gDumpFile
, "</span>");
817 #endif //DUMP_TO_FILE
821 result
=WriteAttributes(attrCount
, aTagInError
);
824 // Tokens are set in error if their ending > is not there, so don't output
826 if (!aTagInError
&& kAfterText
[aTagType
][0] != 0) {
827 NS_ConvertASCIItoUTF16
afterText(kAfterText
[aTagType
]);
828 mITextToken
.SetIndirectString(afterText
);
829 nsCParserNode
theNode(&mITextToken
, 0/*stack token*/);
830 mSink
->AddLeaf(theNode
);
833 if (!aTagInError
&& gDumpFile
&& kDumpFileAfterText
[aTagType
][0])
834 fprintf(gDumpFile
, kDumpFileAfterText
[aTagType
]);
835 #endif // DUMP_TO_FILE
837 if (mSyntaxHighlight
&& aTagInError
) {
838 mErrorNode
.ReleaseAll();
839 mSink
->CloseContainer(eHTMLTag_span
); //emit </endtag>...
842 fprintf(gDumpFile
, "</span>");
843 #endif //DUMP_TO_FILE
853 * @update gess 3/25/98
854 * @param aToken -- token object to be put into content model
855 * @return 0 if all is well; non-zero is an error
857 NS_IMETHODIMP
CViewSourceHTML::HandleToken(CToken
* aToken
,nsIParser
* aParser
)
859 nsresult result
=NS_OK
;
860 CHTMLToken
* theToken
= (CHTMLToken
*)(aToken
);
861 eHTMLTokenTypes theType
= (eHTMLTokenTypes
)theToken
->GetTokenType();
863 mParser
=(nsParser
*)aParser
;
864 mSink
=(nsIHTMLContentSink
*)aParser
->GetContentSink();
866 mTokenNode
.Init(theToken
, mTokenizer
->GetTokenAllocator());
872 const nsSubstring
& startValue
= aToken
->GetStringValue();
873 result
= WriteTag(kStartTag
,startValue
,aToken
->GetAttributeCount(),aToken
->IsInError());
875 if((ePlainText
!=mDocType
) && mParser
&& (NS_OK
==result
)) {
876 result
= mSink
->NotifyTagObservers(&mTokenNode
);
883 const nsSubstring
& endValue
= aToken
->GetStringValue();
884 result
= WriteTag(kEndTag
,endValue
,aToken
->GetAttributeCount(),aToken
->IsInError());
888 case eToken_cdatasection
:
891 theStr
.AssignLiteral("<!");
892 theStr
.Append(aToken
->GetStringValue());
893 if (!aToken
->IsInError()) {
894 theStr
.AppendLiteral(">");
896 result
=WriteTag(kCData
,theStr
,0,aToken
->IsInError());
900 case eToken_markupDecl
:
903 theStr
.AssignLiteral("<!");
904 theStr
.Append(aToken
->GetStringValue());
905 if (!aToken
->IsInError()) {
906 theStr
.AppendLiteral(">");
908 result
=WriteTag(kMarkupDecl
,theStr
,0,aToken
->IsInError());
915 aToken
->AppendSourceTo(theStr
);
916 result
=WriteTag(kComment
,theStr
,0,aToken
->IsInError());
920 case eToken_doctypeDecl
:
922 const nsSubstring
& doctypeValue
= aToken
->GetStringValue();
923 result
=WriteTag(kDoctype
,doctypeValue
,0,aToken
->IsInError());
929 const nsSubstring
& newlineValue
= aToken
->GetStringValue();
930 result
=WriteTag(kText
,newlineValue
,0,PR_FALSE
);
932 if (NS_VIEWSOURCE_TOKENS_PER_BLOCK
> 0 &&
933 mTokenCount
> NS_VIEWSOURCE_TOKENS_PER_BLOCK
) {
939 case eToken_whitespace
:
941 const nsSubstring
& wsValue
= aToken
->GetStringValue();
942 result
=WriteTag(kText
,wsValue
,0,PR_FALSE
);
944 if (NS_VIEWSOURCE_TOKENS_PER_BLOCK
> 0 &&
945 mTokenCount
> NS_VIEWSOURCE_TOKENS_PER_BLOCK
&&
946 !wsValue
.IsEmpty()) {
947 PRUnichar ch
= wsValue
.Last();
948 if (ch
== kLF
|| ch
== kCR
)
956 const nsSubstring
& str
= aToken
->GetStringValue();
957 result
=WriteTag(kText
,str
,aToken
->GetAttributeCount(),aToken
->IsInError());
959 if (NS_VIEWSOURCE_TOKENS_PER_BLOCK
> 0 &&
960 mTokenCount
> NS_VIEWSOURCE_TOKENS_PER_BLOCK
&& !str
.IsEmpty()) {
961 PRUnichar ch
= str
.Last();
962 if (ch
== kLF
|| ch
== kCR
)
970 result
=WriteTag(kEntity
,aToken
->GetStringValue(),0,aToken
->IsInError());
973 case eToken_instruction
:
974 result
=WriteTag(kPI
,aToken
->GetStringValue(),0,aToken
->IsInError());
981 mTokenNode
.ReleaseAll();