2 //------------------------------------------------------------------------------
3 // <copyright file="HtmlRawTextWriterGenerator.cxx" company="Microsoft">
4 // Copyright (c) Microsoft Corporation. All rights reserved.
6 // <owner current="true" primary="true">Microsoft</owner>
7 //------------------------------------------------------------------------------
9 // WARNING: This file is generated and should not be modified directly. Instead,
10 // modify XmlTextWriterGenerator.cxx and run gen.bat in the same directory.
11 // This batch file will execute the following commands:
13 // cl.exe /C /EP /D _XML_UTF8_TEXT_WRITER HtmlTextWriterGenerator.cxx > HtmlUtf8TextWriter.cs
14 // cl.exe /C /EP /D _XML_ENCODED_TEXT_WRITER HtmlTextWriterGenerator.cxx > HtmlEncodedTextWriter.cs
16 // Because these two implementations of XmlTextWriter are so similar, the C++ preprocessor
17 // is used to generate each implementation from one template file, using macros and ifdefs.
47 using System
.Xml
.Schema
;
48 //using System.Xml.Query;
49 using System
.Diagnostics
;
50 using MS
.Internal
.Xml
;
52 namespace System
.Xml
{
54 internal class HtmlUtf8RawTextWriter
: XmlUtf8RawTextWriter
{
58 protected ByteStack elementScope
;
59 protected ElementProperties currentElementProperties
;
60 private AttributeProperties currentAttributeProperties
;
62 private bool endsWithAmpersand
;
63 private byte [] uriEscapingBuffer
;
66 private string mediaType
;
67 private bool doNotEscapeUriAttributes
;
72 protected static TernaryTreeReadOnly elementPropertySearch
;
73 protected static TernaryTreeReadOnly attributePropertySearch
;
78 private const int StackIncrement
= 10;
91 public HtmlUtf8RawTextWriter( Stream stream
, XmlWriterSettings settings
) : base( stream
, settings
) {
96 // XmlRawWriter implementation
98 internal override void WriteXmlDeclaration( XmlStandalone standalone
) {
99 // Ignore xml declaration
102 internal override void WriteXmlDeclaration( string xmldecl
) {
103 // Ignore xml declaration
106 /// Html rules allow public ID without system ID and always output "html"
107 public override void WriteDocType( string name
, string pubid
, string sysid
, string subset
) {
108 Debug
.Assert( name
!= null && name
.Length
> 0 );
112 RawText( "<!DOCTYPE ");
114 // Bug 114337: Always output "html" or "HTML" in doc-type, even if "name" is something else
115 if ( name
== "HTML" )
120 if ( pubid
!= null ) {
121 RawText( " PUBLIC \"" );
123 if ( sysid
!= null ) {
127 bufBytes
[bufPos
++] = (byte) '"';
129 else if ( sysid
!= null ) {
130 RawText( " SYSTEM \"" );
132 bufBytes
[bufPos
++] = (byte) '"';
135 bufBytes
[bufPos
++] = (byte) ' ';
138 if ( subset
!= null ) {
139 bufBytes
[bufPos
++] = (byte) '[';
141 bufBytes
[bufPos
++] = (byte) ']';
144 bufBytes
[this.bufPos
++] = (byte) '>';
147 // For the HTML element, it should call this method with ns and prefix as String.Empty
148 public override void WriteStartElement( string prefix
, string localName
, string ns
) {
149 Debug
.Assert( localName
!= null && localName
.Length
!= 0 && prefix
!= null && ns
!= null );
151 elementScope
.Push( (byte)currentElementProperties
);
153 if ( ns
.Length
== 0 ) {
154 Debug
.Assert( prefix
.Length
== 0 );
157 currentElementProperties
= (ElementProperties
)elementPropertySearch
.FindCaseInsensitiveString( localName
);
158 base.bufBytes
[bufPos
++] = (byte) '<';
159 base.RawText( localName
);
160 base.attrEndPos
= bufPos
;
163 // Since the HAS_NS has no impact to the ElementTextBlock behavior,
164 // we don't need to push it into the stack.
165 currentElementProperties
= ElementProperties
.HAS_NS
;
166 base.WriteStartElement( prefix
, localName
, ns
);
170 // Output >. For HTML needs to output META info
171 internal override void StartElementContent() {
172 base.bufBytes
[base.bufPos
++] = (byte) '>';
174 // Detect whether content is output
175 this.contentPos
= this.bufPos
;
177 if ( ( currentElementProperties
& ElementProperties
.HEAD
) != 0 ) {
182 // end element with />
183 // for HTML(ns.Length == 0)
184 // not an empty tag <h1></h1>
185 // empty tag <basefont>
186 internal override void WriteEndElement( string prefix
, string localName
, string ns
) {
187 if ( ns
.Length
== 0 ) {
188 Debug
.Assert( prefix
.Length
== 0 );
192 if ( ( currentElementProperties
& ElementProperties
.EMPTY
) == 0 ) {
193 bufBytes
[base.bufPos
++] = (byte) '<';
194 bufBytes
[base.bufPos
++] = (byte) '/';
195 base.RawText( localName
);
196 bufBytes
[base.bufPos
++] = (byte) '>';
201 base.WriteEndElement( prefix
, localName
, ns
);
204 currentElementProperties
= (ElementProperties
)elementScope
.Pop();
207 internal override void WriteFullEndElement( string prefix
, string localName
, string ns
) {
208 if ( ns
.Length
== 0 ) {
209 Debug
.Assert( prefix
.Length
== 0 );
213 if ( ( currentElementProperties
& ElementProperties
.EMPTY
) == 0 ) {
214 bufBytes
[base.bufPos
++] = (byte) '<';
215 bufBytes
[base.bufPos
++] = (byte) '/';
216 base.RawText( localName
);
217 bufBytes
[base.bufPos
++] = (byte) '>';
222 base.WriteFullEndElement( prefix
, localName
, ns
);
225 currentElementProperties
= (ElementProperties
)elementScope
.Pop();
228 // 1. How the outputBooleanAttribute(fBOOL) and outputHtmlUriText(fURI) being set?
229 // When SA is called.
231 // BOOL_PARENT URI_PARENT Others
233 // URI att false true false
236 // BOOL att true false false
238 // How they change the attribute output behaviors?
240 // 1) fURI=true fURI=false
242 // AT HtmlURIText HtmlText
245 // 2) fBOOL=true fBOOL=false
247 // AT HtmlText output nothing
248 // EA output nothing "
250 // When they get reset?
251 // At the end of attribute.
253 // 2. How the outputXmlTextElementScoped(fENs) and outputXmlTextattributeScoped(fANs) are set?
254 // fANs is in the scope of the fENs.
256 // SE(localName) SE(ns, pre, localName) SA(localName) SA(ns, pre, localName)
257 // fENs false(default) true(action)
258 // fANs false(default) false(default) false(default) true(action)
260 // how they get reset?
262 // EE(localName) EE(ns, pre, localName) EENC(ns, pre, localName) EA(localName) EA(ns, pre, localName)
263 // fENs false(action)
264 // fANs false(action)
266 // How they change the TextOutput?
269 // AT XmlText HtmlText
272 // 3. Flags for processing &{ split situations
274 // When the flag is set?
276 // AT src[lastchar]='&' flag&{ = true;
278 // when it get result?
282 // How it changes the behaviors?
286 // AT if (src[0] == '{') {
296 // SA if (flagBOOL == false) { output =";}
298 // AT if (flagBOOL) { return};
299 // if (flagNS) {XmlText;} {
301 // else if (flagURI) {
309 // AT if (flagNS) {XmlText;} {
311 // else if (flagURI) {
314 // else if (!flagBOOL) {
315 // HtmlText; //flag&{ handling
319 // EA if (flagBOOL == false) { output "
321 // else if (flag&{) {
325 public override void WriteStartAttribute( string prefix
, string localName
, string ns
) {
326 Debug
.Assert( localName
!= null && localName
.Length
!= 0 && prefix
!= null && ns
!= null );
328 if ( ns
.Length
== 0 ) {
329 Debug
.Assert( prefix
.Length
== 0 );
332 if ( base.attrEndPos
== bufPos
) {
333 base.bufBytes
[bufPos
++] = (byte) ' ';
335 base.RawText( localName
);
337 if ( ( currentElementProperties
& ( ElementProperties
.BOOL_PARENT
| ElementProperties
.URI_PARENT
| ElementProperties
.NAME_PARENT
) ) != 0 ) {
338 currentAttributeProperties
= (AttributeProperties
)attributePropertySearch
.FindCaseInsensitiveString( localName
) &
339 (AttributeProperties
)currentElementProperties
;
341 if ( ( currentAttributeProperties
& AttributeProperties
.BOOLEAN
) != 0 ) {
342 base.inAttributeValue
= true;
347 currentAttributeProperties
= AttributeProperties
.DEFAULT
;
350 base.bufBytes
[bufPos
++] = (byte) '=';
351 base.bufBytes
[bufPos
++] = (byte) '"';
354 base.WriteStartAttribute( prefix
, localName
, ns
);
355 currentAttributeProperties
= AttributeProperties
.DEFAULT
;
358 base.inAttributeValue
= true;
361 // Output the amp; at end of EndAttribute
362 public override void WriteEndAttribute() {
364 if ( ( currentAttributeProperties
& AttributeProperties
.BOOLEAN
) != 0 ) {
365 base.attrEndPos
= bufPos
;
368 if ( endsWithAmpersand
) {
370 endsWithAmpersand
= false;
375 base.bufBytes
[bufPos
++] = (byte) '"';
377 base.inAttributeValue
= false;
378 base.attrEndPos
= bufPos
;
381 // HTML PI's use ">" to terminate rather than "?>".
382 public override void WriteProcessingInstruction( string target
, string text
) {
383 Debug
.Assert( target
!= null && target
.Length
!= 0 && text
!= null );
387 bufBytes
[base.bufPos
++] = (byte) '<';
388 bufBytes
[base.bufPos
++] = (byte) '?';
389 base.RawText( target
);
390 bufBytes
[base.bufPos
++] = (byte) ' ';
392 base.WriteCommentOrPi( text
, '?' );
394 base.bufBytes
[base.bufPos
++] = (byte) '>';
396 if ( base.bufPos
> base.bufLen
) {
401 // Serialize either attribute or element text using HTML rules.
402 public override unsafe void WriteString( string text
) {
403 Debug
.Assert( text
!= null );
407 fixed ( char * pSrc
= text
) {
408 char * pSrcEnd
= pSrc
+ text
.Length
;
409 if ( base.inAttributeValue
) {
410 WriteHtmlAttributeTextBlock( pSrc
, pSrcEnd
);
413 WriteHtmlElementTextBlock( pSrc
, pSrcEnd
);
418 public override void WriteEntityRef( string name
) {
419 throw new InvalidOperationException( Res
.GetString( Res
.Xml_InvalidOperation
) );
422 public override void WriteCharEntity( char ch
) {
423 throw new InvalidOperationException( Res
.GetString( Res
.Xml_InvalidOperation
) );
426 public override void WriteSurrogateCharEntity( char lowChar
, char highChar
) {
427 throw new InvalidOperationException( Res
.GetString( Res
.Xml_InvalidOperation
) );
430 public override unsafe void WriteChars( char[] buffer
, int index
, int count
) {
431 Debug
.Assert( buffer
!= null );
432 Debug
.Assert( index
>= 0 );
433 Debug
.Assert( count
>= 0 && index
+ count
<= buffer
.Length
);
437 fixed ( char * pSrcBegin
= &buffer
[index
] ) {
438 if ( inAttributeValue
) {
439 WriteAttributeTextBlock( pSrcBegin
, pSrcBegin
+ count
);
442 WriteElementTextBlock( pSrcBegin
, pSrcBegin
+ count
);
451 private void Init( XmlWriterSettings settings
) {
452 Debug
.Assert( (int)ElementProperties
.URI_PARENT
== (int)AttributeProperties
.URI
);
453 Debug
.Assert( (int)ElementProperties
.BOOL_PARENT
== (int)AttributeProperties
.BOOLEAN
);
454 Debug
.Assert( (int)ElementProperties
.NAME_PARENT
== (int)AttributeProperties
.NAME
);
456 if ( elementPropertySearch
== null ) {
457 //elementPropertySearch should be init last for the mutli thread safe situation.
458 attributePropertySearch
= new TernaryTreeReadOnly(HtmlTernaryTree
.htmlAttributes
);
459 elementPropertySearch
= new TernaryTreeReadOnly( HtmlTernaryTree
.htmlElements
);
462 elementScope
= new ByteStack( StackIncrement
);
463 uriEscapingBuffer
= new byte[5];
464 currentElementProperties
= ElementProperties
.DEFAULT
;
466 mediaType
= settings
.MediaType
;
467 doNotEscapeUriAttributes
= settings
.DoNotEscapeUriAttributes
;
470 protected void WriteMetaElement() {
471 base.RawText("<META http-equiv=\"Content-Type\"");
473 if ( mediaType
== null ) {
474 mediaType
= "text/html";
477 base.RawText( " content=\"" );
478 base.RawText( mediaType
);
479 base.RawText( "; charset=" );
480 base.RawText( base.encoding
.WebName
);
481 base.RawText( "\">" );
484 // Justify the stack usage:
486 // Nested elements has following possible position combinations
487 // 1. <E1>Content1<E2>Content2</E2></E1>
488 // 2. <E1><E2>Content2</E2>Content1</E1>
489 // 3. <E1>Content<E2>Cotent2</E2>Content1</E1>
491 // In the situation 2 and 3, the stored currentElementProrperties will be E2's,
492 // only the top of the stack is the real E1 element properties.
493 protected unsafe void WriteHtmlElementTextBlock( char * pSrc
, char * pSrcEnd
) {
494 if ( ( currentElementProperties
& ElementProperties
.NO_ENTITIES
) != 0 ) {
495 base.RawText( pSrc
, pSrcEnd
);
497 base.WriteElementTextBlock( pSrc
, pSrcEnd
);
502 protected unsafe void WriteHtmlAttributeTextBlock( char * pSrc
, char * pSrcEnd
) {
503 if ( ( currentAttributeProperties
& ( AttributeProperties
.BOOLEAN
| AttributeProperties
.URI
| AttributeProperties
.NAME
) ) != 0 ) {
504 if ( ( currentAttributeProperties
& AttributeProperties
.BOOLEAN
) != 0 ) {
505 //if output boolean attribute, ignore this call.
509 if ( ( currentAttributeProperties
& ( AttributeProperties
.URI
| AttributeProperties
.NAME
) ) != 0 && !doNotEscapeUriAttributes
) {
510 WriteUriAttributeText( pSrc
, pSrcEnd
);
513 WriteHtmlAttributeText( pSrc
, pSrcEnd
);
516 else if ( ( currentElementProperties
& ElementProperties
.HAS_NS
) != 0 ) {
517 base.WriteAttributeTextBlock( pSrc
, pSrcEnd
);
520 WriteHtmlAttributeText( pSrc
, pSrcEnd
);
526 // 1). HtmlAttributeText("a&");
527 // HtmlAttributeText("{b}");
529 // 2). HtmlAttributeText("a&");
532 // 3).split with Flush by the user
533 // HtmlAttributeText("a&");
535 // HtmlAttributeText("{b}");
539 // case 1)hold the & output as &
540 // if the next income character is {, output {
544 private unsafe void WriteHtmlAttributeText( char * pSrc
, char *pSrcEnd
) {
545 if ( endsWithAmpersand
) {
546 if ( pSrcEnd
- pSrc
> 0 && pSrc
[0] != '{' ) {
549 endsWithAmpersand
= false;
552 fixed ( byte * pDstBegin
= bufBytes
) {
553 byte * pDst
= pDstBegin
+ this.bufPos
;
557 byte * pDstEnd
= pDst
+ ( pSrcEnd
- pSrc
);
558 if ( pDstEnd
> pDstBegin
+ bufLen
) {
559 pDstEnd
= pDstBegin
+ bufLen
;
563 while ( pDst
< pDstEnd
&& ( ( ( xmlCharType
.charProperties
[( ch
= *pSrc
)] & XmlCharType
.fAttrValue
) != 0 ) && ch
<= 0x7F ) ) {
570 Debug
.Assert( pSrc
<= pSrcEnd
);
573 if ( pSrc
>= pSrcEnd
) {
578 if ( pDst
>= pDstEnd
) {
579 bufPos
= (int)(pDst
- pDstBegin
);
581 pDst
= pDstBegin
+ 1;
585 // some character needs to be escaped
588 if ( pSrc
+ 1 == pSrcEnd
) {
589 endsWithAmpersand
= true;
591 else if ( pSrc
[1] != '{' ) {
592 pDst
= XmlUtf8RawTextWriter
.AmpEntity(pDst
);
598 pDst
= QuoteEntity( pDst
);
607 // do not normalize new lines in attributes - just escape them
608 pDst
= CarriageReturnEntity( pDst
);
611 // do not normalize new lines in attributes - just escape them
612 pDst
= LineFeedEntity( pDst
);
615 EncodeChar( ref pSrc
, pSrcEnd
, ref pDst
);
620 bufPos
= (int)(pDst
- pDstBegin
);
624 private unsafe void WriteUriAttributeText( char * pSrc
, char * pSrcEnd
) {
625 if ( endsWithAmpersand
) {
626 if ( pSrcEnd
- pSrc
> 0 && pSrc
[0] != '{' ) {
629 this.endsWithAmpersand
= false;
632 fixed ( byte * pDstBegin
= bufBytes
) {
633 byte * pDst
= pDstBegin
+ this.bufPos
;
637 byte * pDstEnd
= pDst
+ ( pSrcEnd
- pSrc
);
638 if ( pDstEnd
> pDstBegin
+ bufLen
) {
639 pDstEnd
= pDstBegin
+ bufLen
;
642 while ( pDst
< pDstEnd
&& ( ( ( xmlCharType
.charProperties
[( ch
= *pSrc
)] & XmlCharType
.fAttrValue
) != 0 ) && ch
< 0x80 ) ) {
646 Debug
.Assert( pSrc
<= pSrcEnd
);
649 if ( pSrc
>= pSrcEnd
) {
654 if ( pDst
>= pDstEnd
) {
655 bufPos
= (int)(pDst
- pDstBegin
);
657 pDst
= pDstBegin
+ 1;
661 // some character needs to be escaped
664 if ( pSrc
+ 1 == pSrcEnd
) {
665 endsWithAmpersand
= true;
667 else if ( pSrc
[1] != '{' ) {
668 pDst
= XmlUtf8RawTextWriter
.AmpEntity(pDst
);
674 pDst
= QuoteEntity( pDst
);
683 // do not normalize new lines in attributes - just escape them
684 pDst
= CarriageReturnEntity( pDst
);
687 // do not normalize new lines in attributes - just escape them
688 pDst
= LineFeedEntity( pDst
);
691 const string hexDigits
= "0123456789ABCDEF";
692 fixed ( byte * pUriEscapingBuffer
= uriEscapingBuffer
) {
693 byte * pByte
= pUriEscapingBuffer
;
696 XmlUtf8RawTextWriter
.CharToUTF8( ref pSrc
, pSrcEnd
, ref pEnd
);
698 while ( pByte
< pEnd
) {
699 *pDst
++ = (byte) '%';
700 *pDst
++ = (byte) hexDigits
[*pByte
>> 4];
701 *pDst
++ = (byte) hexDigits
[*pByte
& 0xF];
709 bufPos
= (int)(pDst
- pDstBegin
);
713 // For handling &{ in Html text field. If & is not followed by {, it still needs to be escaped.
714 private void OutputRestAmps() {
715 base.bufBytes
[bufPos
++] = (byte)'a';
716 base.bufBytes
[bufPos
++] = (byte)'m';
717 base.bufBytes
[bufPos
++] = (byte)'p';
718 base.bufBytes
[bufPos
++] = (byte)';';
724 // Indentation HtmlWriter only indent <BLOCK><BLOCK> situations
726 // Here are all the cases:
727 // ELEMENT1 actions ELEMENT2 actions SC EE
728 // 1). SE SC store SE blockPro SE a). check ELEMENT1 blockPro <A> </A>
729 // EE if SE, EE are blocks b). true: check ELEMENT2 blockPro <B> <B>
730 // c). detect ELEMENT is SE, SC
731 // d). increase the indexlevel
733 // 2). SE SC, Store EE blockPro EE a). check stored blockPro <A></A> </A>
734 // EE if SE, EE are blocks b). true: indexLevel same </B>
739 // This is an alternative way to make the output looks better
741 // Indentation HtmlWriter only indent <BLOCK><BLOCK> situations
743 // Here are all the cases:
744 // ELEMENT1 actions ELEMENT2 actions Samples
745 // 1). SE SC store SE blockPro SE a). check ELEMENT1 blockPro <A>(blockPos)
746 // b). true: check ELEMENT2 blockPro <B>
747 // c). detect ELEMENT is SE, SC
748 // d). increase the indentLevel
750 // 2). EE Store EE blockPro SE a). check stored blockPro </A>
751 // b). true: indentLevel same <B>
754 // 3). EE same as above EE a). check stored blockPro </A>
755 // b). true: --indentLevel </B>
758 // 4). SE SC same as above EE a). check stored blockPro <A></A>
759 // b). true: indentLevel no change
760 internal class HtmlUtf8RawTextWriterIndent
: HtmlUtf8RawTextWriter
{
766 // for detecting SE SC sitution
771 bool newLineOnAttributes
;
783 public HtmlUtf8RawTextWriterIndent( Stream stream
, XmlWriterSettings settings
) : base( stream
, settings
) {
788 // XmlRawWriter overrides
791 /// Serialize the document type declaration.
793 public override void WriteDocType( string name
, string pubid
, string sysid
, string subset
) {
794 base.WriteDocType( name
, pubid
, sysid
, subset
);
796 // Allow indentation after DocTypeDecl
797 endBlockPos
= base.bufPos
;
800 public override void WriteStartElement(string prefix
, string localName
, string ns
) {
801 Debug
.Assert( localName
!= null && localName
.Length
!= 0 && prefix
!= null && ns
!= null );
805 base.elementScope
.Push( (byte)base.currentElementProperties
);
807 if ( ns
.Length
== 0 ) {
808 Debug
.Assert( prefix
.Length
== 0 );
810 base.currentElementProperties
= (ElementProperties
)elementPropertySearch
.FindCaseInsensitiveString( localName
);
812 if ( endBlockPos
== base.bufPos
&& ( base.currentElementProperties
& ElementProperties
.BLOCK_WS
) != 0 ) {
817 base.bufBytes
[bufPos
++] = (byte) '<';
820 base.currentElementProperties
= ElementProperties
.HAS_NS
| ElementProperties
.BLOCK_WS
;
822 if ( endBlockPos
== base.bufPos
) {
827 base.bufBytes
[base.bufPos
++] = (byte) '<';
828 if ( prefix
.Length
!= 0 ) {
829 base.RawText( prefix
);
830 base.bufBytes
[base.bufPos
++] = (byte) ':';
833 base.RawText( localName
);
834 base.attrEndPos
= bufPos
;
837 internal override void StartElementContent() {
838 base.bufBytes
[base.bufPos
++] = (byte) '>';
840 // Detect whether content is output
841 base.contentPos
= base.bufPos
;
843 if ( ( currentElementProperties
& ElementProperties
.HEAD
) != 0) {
846 endBlockPos
= base.bufPos
;
848 else if ( ( base.currentElementProperties
& ElementProperties
.BLOCK_WS
) != 0 ) {
849 // store the element block position
850 endBlockPos
= base.bufPos
;
854 internal override void WriteEndElement( string prefix
, string localName
, string ns
) {
856 Debug
.Assert( localName
!= null && localName
.Length
!= 0 && prefix
!= null && ns
!= null );
860 // If this element has block whitespace properties,
861 isBlockWs
= ( base.currentElementProperties
& ElementProperties
.BLOCK_WS
) != 0;
863 // And if the last node to be output had block whitespace properties,
864 // And if content was output within this element,
865 if ( endBlockPos
== base.bufPos
&& base.contentPos
!= base.bufPos
) {
871 base.WriteEndElement(prefix
, localName
, ns
);
873 // Reset contentPos in case of empty elements
876 // Mark end of element in buffer for element's with block whitespace properties
878 endBlockPos
= base.bufPos
;
882 public override void WriteStartAttribute( string prefix
, string localName
, string ns
) {
883 if ( newLineOnAttributes
) {
884 RawText( base.newLineChars
);
889 base.WriteStartAttribute( prefix
, localName
, ns
);
892 protected override void FlushBuffer() {
893 // Make sure the buffer will reset the block position
894 endBlockPos
= ( endBlockPos
== base.bufPos
) ? 1 : 0;
901 private void Init( XmlWriterSettings settings
) {
903 indentChars
= settings
.IndentChars
;
904 newLineOnAttributes
= settings
.NewLineOnAttributes
;
907 private void WriteIndent() {
908 // <block><inline> -- suppress ws betw <block> and <inline>
909 // <block><block> -- don't suppress ws betw <block> and <block>
910 // <block>text -- suppress ws betw <block> and text (handled by wcharText method)
911 // <block><?PI?> -- suppress ws betw <block> and PI
912 // <block><!-- --> -- suppress ws betw <block> and comment
914 // <inline><block> -- suppress ws betw <inline> and <block>
915 // <inline><inline> -- suppress ws betw <inline> and <inline>
916 // <inline>text -- suppress ws betw <inline> and text (handled by wcharText method)
917 // <inline><?PI?> -- suppress ws betw <inline> and PI
918 // <inline><!-- --> -- suppress ws betw <inline> and comment
920 RawText( base.newLineChars
);
921 for ( int i
= indentLevel
; i
> 0; i
-- ) {
922 RawText( indentChars
);