1 //------------------------------------------------------------------------------
2 // <copyright file="HtmlTextWriter.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
5 //------------------------------------------------------------------------------
9 namespace System
.Web
.UI
{
11 using System
.Collections
;
12 using System
.Collections
.Specialized
;
15 using System
.Globalization
;
16 using System
.Security
.Permissions
;
17 using System
.Web
.UI
.WebControls
;
18 using System
.Web
.Util
;
20 public class HtmlTextWriter
: TextWriter
{
21 private Layout _currentLayout
= new Layout(HorizontalAlign
.NotSet
, true /* wrap */);
22 private Layout _currentWrittenLayout
= null;
24 internal virtual bool RenderDivAroundHiddenInputs
{
30 public virtual void EnterStyle(Style style
, HtmlTextWriterTag tag
) {
31 if (!style
.IsEmpty
|| tag
!= HtmlTextWriterTag
.Span
) {
32 style
.AddAttributesToRender(this);
37 public virtual void ExitStyle(System
.Web
.UI
.WebControls
.Style style
, HtmlTextWriterTag tag
) {
38 // Review: This requires that the style doesn't change between beginstyle/endstyle.
39 if (!style
.IsEmpty
|| tag
!= HtmlTextWriterTag
.Span
) {
44 internal virtual void OpenDiv() {
45 OpenDiv(_currentLayout
,
46 (_currentLayout
!= null) && (_currentLayout
.Align
!= HorizontalAlign
.NotSet
),
47 (_currentLayout
!= null) && !_currentLayout
.Wrap
);
50 private void OpenDiv(Layout layout
, bool writeHorizontalAlign
, bool writeWrapping
) {
52 if (writeHorizontalAlign
) {
54 switch (layout
.Align
) {
55 case HorizontalAlign
.Right
:
56 alignment
= "text-align:right";
59 case HorizontalAlign
.Center
:
60 alignment
= "text-align:center";
64 alignment
= "text-align:left";
68 WriteAttribute("style", alignment
);
71 WriteAttribute("mode",
72 layout
.Wrap
== true ? "wrap" : "nowrap");
75 _currentWrittenLayout
= layout
;
78 public virtual bool IsValidFormAttribute(String attribute
) {
82 private TextWriter writer
;
83 private int indentLevel
;
84 private bool tabsPending
;
85 private string tabString
;
86 public const char TagLeftChar
= '<';
87 public const char TagRightChar
= '>';
88 public const string SelfClosingChars
= " /";
89 public const string SelfClosingTagEnd
= " />";
90 public const string EndTagLeftChars
= "</";
91 public const char DoubleQuoteChar
= '"';
92 public const char SingleQuoteChar
= '\'';
93 public const char SpaceChar
= ' ';
94 public const char EqualsChar
= '=';
95 public const char SlashChar
= '/';
96 public const string EqualsDoubleQuoteString
= "=\"";
97 public const char SemicolonChar
= ';';
98 public const char StyleEqualsChar
= ':';
99 public const string DefaultTabString
= "\t";
101 // The DesignerRegion attribute name must be kept in sync with
102 // System.Web.UI.Design.DesignerRegion.DesignerRegionNameAttribute
103 internal const string DesignerRegionAttributeName
= "_designerRegion";
105 private static Hashtable _tagKeyLookupTable
;
106 private static Hashtable _attrKeyLookupTable
;
107 private static TagInformation
[] _tagNameLookupArray
;
108 private static AttributeInformation
[] _attrNameLookupArray
;
110 private RenderAttribute
[] _attrList
;
111 private int _attrCount
;
112 private int _endTagCount
;
113 private TagStackEntry
[] _endTags
;
114 private HttpWriter _httpWriter
;
115 private int _inlineCount
;
116 private bool _isDescendant
;
117 private RenderStyle
[] _styleList
;
118 private int _styleCount
;
119 private int _tagIndex
;
120 private HtmlTextWriterTag _tagKey
;
121 private string _tagName
;
123 static HtmlTextWriter() {
125 // register known tags
126 _tagKeyLookupTable
= new Hashtable((int)HtmlTextWriterTag
.Xml
+ 1);
127 _tagNameLookupArray
= new TagInformation
[(int)HtmlTextWriterTag
.Xml
+ 1];
129 RegisterTag(String
.Empty
, HtmlTextWriterTag
.Unknown
, TagType
.Other
);
130 RegisterTag("a", HtmlTextWriterTag
.A
, TagType
.Inline
);
131 RegisterTag("acronym", HtmlTextWriterTag
.Acronym
, TagType
.Inline
);
132 RegisterTag("address", HtmlTextWriterTag
.Address
, TagType
.Other
);
133 RegisterTag("area", HtmlTextWriterTag
.Area
, TagType
.NonClosing
);
134 RegisterTag("b", HtmlTextWriterTag
.B
, TagType
.Inline
);
135 RegisterTag("base", HtmlTextWriterTag
.Base
, TagType
.NonClosing
);
136 RegisterTag("basefont", HtmlTextWriterTag
.Basefont
, TagType
.NonClosing
);
137 RegisterTag("bdo", HtmlTextWriterTag
.Bdo
, TagType
.Inline
);
138 RegisterTag("bgsound", HtmlTextWriterTag
.Bgsound
, TagType
.NonClosing
);
139 RegisterTag("big", HtmlTextWriterTag
.Big
, TagType
.Inline
);
140 RegisterTag("blockquote", HtmlTextWriterTag
.Blockquote
, TagType
.Other
);
141 RegisterTag("body", HtmlTextWriterTag
.Body
, TagType
.Other
);
142 // Devdiv 852940, BR is a self-closing tag
143 RegisterTag("br", HtmlTextWriterTag
.Br
,
144 BinaryCompatibility
.Current
.TargetsAtLeastFramework46
? TagType
.NonClosing
: TagType
.Other
);
145 RegisterTag("button", HtmlTextWriterTag
.Button
, TagType
.Inline
);
146 RegisterTag("caption", HtmlTextWriterTag
.Caption
, TagType
.Other
);
147 RegisterTag("center", HtmlTextWriterTag
.Center
, TagType
.Other
);
148 RegisterTag("cite", HtmlTextWriterTag
.Cite
, TagType
.Inline
);
149 RegisterTag("code", HtmlTextWriterTag
.Code
, TagType
.Inline
);
150 RegisterTag("col", HtmlTextWriterTag
.Col
, TagType
.NonClosing
);
151 RegisterTag("colgroup", HtmlTextWriterTag
.Colgroup
, TagType
.Other
);
152 RegisterTag("del", HtmlTextWriterTag
.Del
, TagType
.Inline
);
153 RegisterTag("dd", HtmlTextWriterTag
.Dd
, TagType
.Inline
);
154 RegisterTag("dfn", HtmlTextWriterTag
.Dfn
, TagType
.Inline
);
155 RegisterTag("dir", HtmlTextWriterTag
.Dir
, TagType
.Other
);
156 RegisterTag("div", HtmlTextWriterTag
.Div
, TagType
.Other
);
157 RegisterTag("dl", HtmlTextWriterTag
.Dl
, TagType
.Other
);
158 RegisterTag("dt", HtmlTextWriterTag
.Dt
, TagType
.Inline
);
159 RegisterTag("em", HtmlTextWriterTag
.Em
, TagType
.Inline
);
160 RegisterTag("embed", HtmlTextWriterTag
.Embed
, TagType
.NonClosing
);
161 RegisterTag("fieldset", HtmlTextWriterTag
.Fieldset
, TagType
.Other
);
162 RegisterTag("font", HtmlTextWriterTag
.Font
, TagType
.Inline
);
163 RegisterTag("form", HtmlTextWriterTag
.Form
, TagType
.Other
);
164 RegisterTag("frame", HtmlTextWriterTag
.Frame
, TagType
.NonClosing
);
165 RegisterTag("frameset", HtmlTextWriterTag
.Frameset
, TagType
.Other
);
166 RegisterTag("h1", HtmlTextWriterTag
.H1
, TagType
.Other
);
167 RegisterTag("h2", HtmlTextWriterTag
.H2
, TagType
.Other
);
168 RegisterTag("h3", HtmlTextWriterTag
.H3
, TagType
.Other
);
169 RegisterTag("h4", HtmlTextWriterTag
.H4
, TagType
.Other
);
170 RegisterTag("h5", HtmlTextWriterTag
.H5
, TagType
.Other
);
171 RegisterTag("h6", HtmlTextWriterTag
.H6
, TagType
.Other
);
172 RegisterTag("head", HtmlTextWriterTag
.Head
, TagType
.Other
);
173 RegisterTag("hr", HtmlTextWriterTag
.Hr
, TagType
.NonClosing
);
174 RegisterTag("html", HtmlTextWriterTag
.Html
, TagType
.Other
);
175 RegisterTag("i", HtmlTextWriterTag
.I
, TagType
.Inline
);
176 RegisterTag("iframe", HtmlTextWriterTag
.Iframe
, TagType
.Other
);
177 RegisterTag("img", HtmlTextWriterTag
.Img
, TagType
.NonClosing
);
178 RegisterTag("input", HtmlTextWriterTag
.Input
, TagType
.NonClosing
);
179 RegisterTag("ins", HtmlTextWriterTag
.Ins
, TagType
.Inline
);
180 RegisterTag("isindex", HtmlTextWriterTag
.Isindex
, TagType
.NonClosing
);
181 RegisterTag("kbd", HtmlTextWriterTag
.Kbd
, TagType
.Inline
);
182 RegisterTag("label", HtmlTextWriterTag
.Label
, TagType
.Inline
);
183 RegisterTag("legend", HtmlTextWriterTag
.Legend
, TagType
.Other
);
184 RegisterTag("li", HtmlTextWriterTag
.Li
, TagType
.Inline
);
185 RegisterTag("link", HtmlTextWriterTag
.Link
, TagType
.NonClosing
);
186 RegisterTag("map", HtmlTextWriterTag
.Map
, TagType
.Other
);
187 RegisterTag("marquee", HtmlTextWriterTag
.Marquee
, TagType
.Other
);
188 RegisterTag("menu", HtmlTextWriterTag
.Menu
, TagType
.Other
);
189 RegisterTag("meta", HtmlTextWriterTag
.Meta
, TagType
.NonClosing
);
190 RegisterTag("nobr", HtmlTextWriterTag
.Nobr
, TagType
.Inline
);
191 RegisterTag("noframes", HtmlTextWriterTag
.Noframes
, TagType
.Other
);
192 RegisterTag("noscript", HtmlTextWriterTag
.Noscript
, TagType
.Other
);
193 RegisterTag("object", HtmlTextWriterTag
.Object
, TagType
.Other
);
194 RegisterTag("ol", HtmlTextWriterTag
.Ol
, TagType
.Other
);
195 RegisterTag("option", HtmlTextWriterTag
.Option
, TagType
.Other
);
196 RegisterTag("p", HtmlTextWriterTag
.P
, TagType
.Inline
);
197 RegisterTag("param", HtmlTextWriterTag
.Param
, TagType
.Other
);
198 RegisterTag("pre", HtmlTextWriterTag
.Pre
, TagType
.Other
);
199 RegisterTag("ruby", HtmlTextWriterTag
.Ruby
, TagType
.Other
);
200 RegisterTag("rt", HtmlTextWriterTag
.Rt
, TagType
.Other
);
201 RegisterTag("q", HtmlTextWriterTag
.Q
, TagType
.Inline
);
202 RegisterTag("s", HtmlTextWriterTag
.S
, TagType
.Inline
);
203 RegisterTag("samp", HtmlTextWriterTag
.Samp
, TagType
.Inline
);
204 RegisterTag("script", HtmlTextWriterTag
.Script
, TagType
.Other
);
205 RegisterTag("select", HtmlTextWriterTag
.Select
, TagType
.Other
);
206 RegisterTag("small", HtmlTextWriterTag
.Small
, TagType
.Other
);
207 RegisterTag("span", HtmlTextWriterTag
.Span
, TagType
.Inline
);
208 RegisterTag("strike", HtmlTextWriterTag
.Strike
, TagType
.Inline
);
209 RegisterTag("strong", HtmlTextWriterTag
.Strong
, TagType
.Inline
);
210 RegisterTag("style", HtmlTextWriterTag
.Style
, TagType
.Other
);
211 RegisterTag("sub", HtmlTextWriterTag
.Sub
, TagType
.Inline
);
212 RegisterTag("sup", HtmlTextWriterTag
.Sup
, TagType
.Inline
);
213 RegisterTag("table", HtmlTextWriterTag
.Table
, TagType
.Other
);
214 RegisterTag("tbody", HtmlTextWriterTag
.Tbody
, TagType
.Other
);
215 RegisterTag("td", HtmlTextWriterTag
.Td
, TagType
.Inline
);
216 RegisterTag("textarea", HtmlTextWriterTag
.Textarea
, TagType
.Inline
);
217 RegisterTag("tfoot", HtmlTextWriterTag
.Tfoot
, TagType
.Other
);
218 RegisterTag("th", HtmlTextWriterTag
.Th
, TagType
.Inline
);
219 RegisterTag("thead", HtmlTextWriterTag
.Thead
, TagType
.Other
);
220 RegisterTag("title", HtmlTextWriterTag
.Title
, TagType
.Other
);
221 RegisterTag("tr", HtmlTextWriterTag
.Tr
, TagType
.Other
);
222 RegisterTag("tt", HtmlTextWriterTag
.Tt
, TagType
.Inline
);
223 RegisterTag("u", HtmlTextWriterTag
.U
, TagType
.Inline
);
224 RegisterTag("ul", HtmlTextWriterTag
.Ul
, TagType
.Other
);
225 RegisterTag("var", HtmlTextWriterTag
.Var
, TagType
.Inline
);
226 RegisterTag("wbr", HtmlTextWriterTag
.Wbr
, TagType
.NonClosing
);
227 RegisterTag("xml", HtmlTextWriterTag
.Xml
, TagType
.Other
);
229 // register known attributes
230 _attrKeyLookupTable
= new Hashtable((int)HtmlTextWriterAttribute
.VCardName
+ 1);
231 _attrNameLookupArray
= new AttributeInformation
[(int)HtmlTextWriterAttribute
.VCardName
+ 1];
233 RegisterAttribute("abbr", HtmlTextWriterAttribute
.Abbr
, true);
234 RegisterAttribute("accesskey", HtmlTextWriterAttribute
.Accesskey
, true);
235 RegisterAttribute("align", HtmlTextWriterAttribute
.Align
, false);
236 RegisterAttribute("alt", HtmlTextWriterAttribute
.Alt
, true);
237 RegisterAttribute("autocomplete", HtmlTextWriterAttribute
.AutoComplete
, false);
238 RegisterAttribute("axis", HtmlTextWriterAttribute
.Axis
, true);
239 RegisterAttribute("background", HtmlTextWriterAttribute
.Background
, true, true);
240 RegisterAttribute("bgcolor", HtmlTextWriterAttribute
.Bgcolor
, false);
241 RegisterAttribute("border", HtmlTextWriterAttribute
.Border
, false);
242 RegisterAttribute("bordercolor", HtmlTextWriterAttribute
.Bordercolor
, false);
243 RegisterAttribute("cellpadding", HtmlTextWriterAttribute
.Cellpadding
, false);
244 RegisterAttribute("cellspacing", HtmlTextWriterAttribute
.Cellspacing
, false);
245 RegisterAttribute("checked", HtmlTextWriterAttribute
.Checked
, false);
246 RegisterAttribute("class", HtmlTextWriterAttribute
.Class
, true);
247 RegisterAttribute("cols", HtmlTextWriterAttribute
.Cols
, false);
248 RegisterAttribute("colspan", HtmlTextWriterAttribute
.Colspan
, false);
249 RegisterAttribute("content", HtmlTextWriterAttribute
.Content
, true);
250 RegisterAttribute("coords", HtmlTextWriterAttribute
.Coords
, false);
251 RegisterAttribute("dir", HtmlTextWriterAttribute
.Dir
, false);
252 RegisterAttribute("disabled", HtmlTextWriterAttribute
.Disabled
, false);
253 RegisterAttribute("for", HtmlTextWriterAttribute
.For
, false);
254 RegisterAttribute("headers", HtmlTextWriterAttribute
.Headers
, true);
255 RegisterAttribute("height", HtmlTextWriterAttribute
.Height
, false);
256 RegisterAttribute("href", HtmlTextWriterAttribute
.Href
, true, true);
257 RegisterAttribute("id", HtmlTextWriterAttribute
.Id
, false);
258 RegisterAttribute("longdesc", HtmlTextWriterAttribute
.Longdesc
, true, true);
259 RegisterAttribute("maxlength", HtmlTextWriterAttribute
.Maxlength
, false);
260 RegisterAttribute("multiple", HtmlTextWriterAttribute
.Multiple
, false);
261 RegisterAttribute("name", HtmlTextWriterAttribute
.Name
, false);
262 RegisterAttribute("nowrap", HtmlTextWriterAttribute
.Nowrap
, false);
263 RegisterAttribute("onclick", HtmlTextWriterAttribute
.Onclick
, true);
264 RegisterAttribute("onchange", HtmlTextWriterAttribute
.Onchange
, true);
265 RegisterAttribute("readonly", HtmlTextWriterAttribute
.ReadOnly
, false);
266 RegisterAttribute("rel", HtmlTextWriterAttribute
.Rel
, false);
267 RegisterAttribute("rows", HtmlTextWriterAttribute
.Rows
, false);
268 RegisterAttribute("rowspan", HtmlTextWriterAttribute
.Rowspan
, false);
269 RegisterAttribute("rules", HtmlTextWriterAttribute
.Rules
, false);
270 RegisterAttribute("scope", HtmlTextWriterAttribute
.Scope
, false);
271 RegisterAttribute("selected", HtmlTextWriterAttribute
.Selected
, false);
272 RegisterAttribute("shape", HtmlTextWriterAttribute
.Shape
, false);
273 RegisterAttribute("size", HtmlTextWriterAttribute
.Size
, false);
274 RegisterAttribute("src", HtmlTextWriterAttribute
.Src
, true, true);
275 RegisterAttribute("style", HtmlTextWriterAttribute
.Style
, false);
276 RegisterAttribute("tabindex", HtmlTextWriterAttribute
.Tabindex
, false);
277 RegisterAttribute("target", HtmlTextWriterAttribute
.Target
, false);
278 RegisterAttribute("title", HtmlTextWriterAttribute
.Title
, true);
279 RegisterAttribute("type", HtmlTextWriterAttribute
.Type
, false);
280 RegisterAttribute("usemap", HtmlTextWriterAttribute
.Usemap
, false);
281 RegisterAttribute("valign", HtmlTextWriterAttribute
.Valign
, false);
282 RegisterAttribute("value", HtmlTextWriterAttribute
.Value
, true);
283 RegisterAttribute("vcard_name", HtmlTextWriterAttribute
.VCardName
, false);
284 RegisterAttribute("width", HtmlTextWriterAttribute
.Width
, false);
285 RegisterAttribute("wrap", HtmlTextWriterAttribute
.Wrap
, false);
286 RegisterAttribute(DesignerRegionAttributeName
, HtmlTextWriterAttribute
.DesignerRegion
, false);
289 public override Encoding Encoding
{
291 return writer
.Encoding
;
295 // Gets or sets the new line character to use.
296 public override string NewLine
{
298 return writer
.NewLine
;
302 writer
.NewLine
= value;
306 // Gets or sets the number of spaces to indent.
312 Debug
.Assert(value >= 0, "Bogus Indent... probably caused by mismatched Indent++ and Indent--");
320 //Gets or sets the TextWriter to use.
321 public TextWriter InnerWriter
{
327 _httpWriter
= value as HttpWriter
;
345 public virtual void BeginRender() {
348 //Closes the document being written to.
349 public override void Close() {
353 public virtual void EndRender() {
356 public virtual void EnterStyle(System
.Web
.UI
.WebControls
.Style style
) {
357 EnterStyle(style
, HtmlTextWriterTag
.Span
);
360 public virtual void ExitStyle(System
.Web
.UI
.WebControls
.Style style
) {
361 ExitStyle(style
, HtmlTextWriterTag
.Span
);
364 public override void Flush() {
368 protected virtual void OutputTabs() {
370 for (int i
=0; i
< indentLevel
; i
++) {
371 writer
.Write(tabString
);
377 //Writes a string to the text stream.
378 public override void Write(string s
) {
385 //Writes the text representation of a Boolean value to the text stream.
386 public override void Write(bool value) {
393 //Writes a character to the text stream.
394 public override void Write(char value) {
401 // Writes a character array to the text stream.
402 public override void Write(char[] buffer
) {
406 writer
.Write(buffer
);
409 // Writes a subarray of characters to the text stream.
410 public override void Write(char[] buffer
, int index
, int count
) {
414 writer
.Write(buffer
, index
, count
);
417 // Writes the text representation of a Double to the text stream.
418 public override void Write(double value) {
425 // Writes the text representation of a Single to the text stream.
426 public override void Write(float value) {
433 // Writes the text representation of an integer to the text stream.
434 public override void Write(int value) {
441 // Writes the text representation of an 8-byte integer to the text stream.
442 public override void Write(long value) {
449 // Writes the text representation of an object to the text stream.
450 public override void Write(object value) {
457 // Writes out a formatted string, using the same semantics as specified.
458 public override void Write(string format
, object arg0
) {
462 writer
.Write(format
, arg0
);
465 // Writes out a formatted string, using the same semantics as specified.
466 public override void Write(string format
, object arg0
, object arg1
) {
470 writer
.Write(format
, arg0
, arg1
);
473 // Writes out a formatted string, using the same semantics as specified.
474 public override void Write(string format
, params object[] arg
) {
478 writer
.Write(format
, arg
);
481 // Writes the specified string to a line without tabs.
482 public void WriteLineNoTabs(string s
) {
487 // Writes the specified string followed by a line terminator to the text stream.
488 public override void WriteLine(string s
) {
496 // Writes a line terminator.
497 public override void WriteLine() {
502 // Writes the text representation of a Boolean followed by a line terminator to the text stream.
503 public override void WriteLine(bool value) {
507 writer
.WriteLine(value);
511 public override void WriteLine(char value) {
515 writer
.WriteLine(value);
519 public override void WriteLine(char[] buffer
) {
523 writer
.WriteLine(buffer
);
527 public override void WriteLine(char[] buffer
, int index
, int count
) {
531 writer
.WriteLine(buffer
, index
, count
);
535 public override void WriteLine(double value) {
539 writer
.WriteLine(value);
543 public override void WriteLine(float value) {
547 writer
.WriteLine(value);
551 public override void WriteLine(int value) {
555 writer
.WriteLine(value);
559 public override void WriteLine(long value) {
563 writer
.WriteLine(value);
567 public override void WriteLine(object value) {
571 writer
.WriteLine(value);
575 public override void WriteLine(string format
, object arg0
) {
579 writer
.WriteLine(format
, arg0
);
583 public override void WriteLine(string format
, object arg0
, object arg1
) {
587 writer
.WriteLine(format
, arg0
, arg1
);
591 public override void WriteLine(string format
, params object[] arg
) {
595 writer
.WriteLine(format
, arg
);
599 [CLSCompliant(false)]
600 public override void WriteLine(UInt32
value) {
604 writer
.WriteLine(value);
608 protected static void RegisterTag(string name
, HtmlTextWriterTag key
) {
609 RegisterTag(name
, key
, TagType
.Other
);
612 private static void RegisterTag(string name
, HtmlTextWriterTag key
, TagType type
) {
613 string nameLCase
= name
.ToLower(CultureInfo
.InvariantCulture
);
615 _tagKeyLookupTable
.Add(nameLCase
, key
);
617 // Pre-resolve the end tag
618 string endTag
= null;
619 if (type
!= TagType
.NonClosing
&& key
!= HtmlTextWriterTag
.Unknown
) {
620 endTag
= EndTagLeftChars
+ nameLCase
+ TagRightChar
.ToString(CultureInfo
.InvariantCulture
);
623 if ((int)key
< _tagNameLookupArray
.Length
) {
624 _tagNameLookupArray
[(int)key
] = new TagInformation(name
, type
, endTag
);
628 protected static void RegisterAttribute(string name
, HtmlTextWriterAttribute key
) {
629 RegisterAttribute(name
, key
, false);
632 private static void RegisterAttribute(string name
, HtmlTextWriterAttribute key
, bool encode
) {
633 RegisterAttribute(name
, key
, encode
, false);
636 private static void RegisterAttribute(string name
, HtmlTextWriterAttribute key
, bool encode
, bool isUrl
) {
637 string nameLCase
= name
.ToLower(CultureInfo
.InvariantCulture
);
639 _attrKeyLookupTable
.Add(nameLCase
, key
);
641 if ((int)key
< _attrNameLookupArray
.Length
) {
642 _attrNameLookupArray
[(int)key
] = new AttributeInformation(name
, encode
, isUrl
);
646 protected static void RegisterStyle(string name
, HtmlTextWriterStyle key
) {
647 CssTextWriter
.RegisterAttribute(name
, key
);
650 public HtmlTextWriter(TextWriter writer
) : this(writer
, DefaultTabString
) {
653 public HtmlTextWriter(TextWriter writer
, string tabString
) : base(CultureInfo
.InvariantCulture
) {
654 this.writer
= writer
;
655 this.tabString
= tabString
;
659 // If it's an http writer, save it
660 _httpWriter
= writer
as HttpWriter
;
662 _isDescendant
= (GetType() != typeof(HtmlTextWriter
));
670 protected HtmlTextWriterTag TagKey
{
675 _tagIndex
= (int) value;
676 if (_tagIndex
< 0 || _tagIndex
>= _tagNameLookupArray
.Length
) {
677 throw new ArgumentOutOfRangeException("value");
680 // If explicitly setting to uknown, keep the old tag name. This allows a string tag
681 // to be set without clobbering it if setting TagKey to itself.
682 if (value != HtmlTextWriterTag
.Unknown
) {
683 _tagName
= _tagNameLookupArray
[_tagIndex
].name
;
688 protected string TagName
{
694 _tagKey
= GetTagKey(_tagName
);
695 _tagIndex
= (int) _tagKey
;
696 Debug
.Assert(_tagIndex
>= 0 && _tagIndex
< _tagNameLookupArray
.Length
);
700 public virtual void AddAttribute(string name
,string value) {
701 HtmlTextWriterAttribute attributeKey
= GetAttributeKey(name
);
702 value = EncodeAttributeValue(attributeKey
, value);
704 AddAttribute(name
, value, attributeKey
);
707 //do not fix this spelling error
708 //believe it or not, it is a backwards breaking change for languages that
709 //support late binding with named parameters VB.Net
710 public virtual void AddAttribute(string name
,string value, bool fEndode
) {
711 value = EncodeAttributeValue(value, fEndode
);
712 AddAttribute(name
, value, GetAttributeKey(name
));
715 public virtual void AddAttribute(HtmlTextWriterAttribute key
,string value) {
716 int attributeIndex
= (int) key
;
717 if (attributeIndex
>= 0 && attributeIndex
< _attrNameLookupArray
.Length
) {
718 AttributeInformation info
= _attrNameLookupArray
[attributeIndex
];
719 AddAttribute(info
.name
,value,key
, info
.encode
, info
.isUrl
);
723 public virtual void AddAttribute(HtmlTextWriterAttribute key
,string value, bool fEncode
) {
724 int attributeIndex
= (int) key
;
725 if (attributeIndex
>= 0 && attributeIndex
< _attrNameLookupArray
.Length
) {
726 AttributeInformation info
= _attrNameLookupArray
[attributeIndex
];
727 AddAttribute(info
.name
,value,key
, fEncode
, info
.isUrl
);
731 protected virtual void AddAttribute(string name
, string value, HtmlTextWriterAttribute key
) {
732 AddAttribute(name
, value, key
, false, false);
736 private void AddAttribute(string name
, string value, HtmlTextWriterAttribute key
, bool encode
, bool isUrl
) {
737 if(_attrList
== null) {
738 _attrList
= new RenderAttribute
[20];
740 else if (_attrCount
>= _attrList
.Length
) {
741 RenderAttribute
[] newArray
= new RenderAttribute
[_attrList
.Length
* 2];
742 Array
.Copy(_attrList
, newArray
, _attrList
.Length
);
743 _attrList
= newArray
;
745 RenderAttribute attr
;
749 attr
.encode
= encode
;
751 _attrList
[_attrCount
] = attr
;
755 public virtual void AddStyleAttribute(string name
, string value) {
756 AddStyleAttribute(name
, value, CssTextWriter
.GetStyleKey(name
));
759 public virtual void AddStyleAttribute(HtmlTextWriterStyle key
, string value) {
760 AddStyleAttribute(CssTextWriter
.GetStyleName(key
), value, key
);
763 protected virtual void AddStyleAttribute(string name
, string value, HtmlTextWriterStyle key
) {
764 if(_styleList
== null) {
765 _styleList
= new RenderStyle
[20];
767 else if (_styleCount
> _styleList
.Length
) {
768 RenderStyle
[] newArray
= new RenderStyle
[_styleList
.Length
* 2];
769 Array
.Copy(_styleList
, newArray
, _styleList
.Length
);
770 _styleList
= newArray
;
778 string attributeValue
= value;
779 if (CssTextWriter
.IsStyleEncoded(key
)) {
780 // note that only css attributes in an inline style value need to be attribute encoded
781 // since CssTextWriter is used to render both embedded stylesheets and style attributes
782 // the attribute encoding is done here.
783 attributeValue
= HttpUtility
.HtmlAttributeEncode(value);
785 style
.value = attributeValue
;
787 _styleList
[_styleCount
] = style
;
791 protected string EncodeAttributeValue(string value, bool fEncode
) {
799 return HttpUtility
.HtmlAttributeEncode(value);
802 protected virtual string EncodeAttributeValue(HtmlTextWriterAttribute attrKey
, string value) {
805 if (0 <= (int)attrKey
&& (int)attrKey
< _attrNameLookupArray
.Length
) {
806 encode
= _attrNameLookupArray
[(int)attrKey
].encode
;
809 return EncodeAttributeValue(value, encode
);
812 // This does minimal URL encoding by converting spaces in the url to "%20".
813 protected string EncodeUrl(string url
) {
814 // VSWhidbey 454348: escaped spaces in UNC share paths don't work in IE, so
815 // we're not going to encode if it's a share.
816 if (!UrlPath
.IsUncSharePath(url
)) {
817 return HttpUtility
.UrlPathEncode(url
);
822 protected HtmlTextWriterAttribute
GetAttributeKey(string attrName
) {
823 if (!String
.IsNullOrEmpty(attrName
)) {
824 object key
= _attrKeyLookupTable
[attrName
.ToLower(CultureInfo
.InvariantCulture
)];
826 return(HtmlTextWriterAttribute
)key
;
829 return(HtmlTextWriterAttribute
)(-1);
832 protected string GetAttributeName(HtmlTextWriterAttribute attrKey
) {
833 if ((int)attrKey
>= 0 && (int)attrKey
< _attrNameLookupArray
.Length
)
834 return _attrNameLookupArray
[(int)attrKey
].name
;
839 protected HtmlTextWriterStyle
GetStyleKey(string styleName
) {
840 return CssTextWriter
.GetStyleKey(styleName
);
843 protected string GetStyleName(HtmlTextWriterStyle styleKey
) {
844 return CssTextWriter
.GetStyleName(styleKey
);
847 protected virtual HtmlTextWriterTag
GetTagKey(string tagName
) {
848 if (!String
.IsNullOrEmpty(tagName
)) {
849 object key
= _tagKeyLookupTable
[tagName
.ToLower(CultureInfo
.InvariantCulture
)];
851 return(HtmlTextWriterTag
)key
;
854 return HtmlTextWriterTag
.Unknown
;
857 protected virtual string GetTagName(HtmlTextWriterTag tagKey
) {
858 int tagIndex
= (int) tagKey
;
859 if (tagIndex
>= 0 && tagIndex
< _tagNameLookupArray
.Length
)
860 return _tagNameLookupArray
[tagIndex
].name
;
865 protected bool IsAttributeDefined(HtmlTextWriterAttribute key
) {
866 for (int i
= 0; i
< _attrCount
; i
++) {
867 if (_attrList
[i
].key
== key
) {
874 protected bool IsAttributeDefined(HtmlTextWriterAttribute key
, out string value) {
876 for (int i
= 0; i
< _attrCount
; i
++) {
877 if (_attrList
[i
].key
== key
) {
878 value = _attrList
[i
].value;
885 protected bool IsStyleAttributeDefined(HtmlTextWriterStyle key
) {
886 for (int i
= 0; i
< _styleCount
; i
++) {
887 if (_styleList
[i
].key
== key
) {
894 protected bool IsStyleAttributeDefined(HtmlTextWriterStyle key
, out string value) {
896 for (int i
= 0; i
< _styleCount
; i
++) {
897 if (_styleList
[i
].key
== key
) {
898 value = _styleList
[i
].value;
905 protected virtual bool OnAttributeRender(string name
, string value, HtmlTextWriterAttribute key
) {
909 protected virtual bool OnStyleAttributeRender(string name
, string value, HtmlTextWriterStyle key
) {
913 protected virtual bool OnTagRender(string name
, HtmlTextWriterTag key
) {
917 protected string PopEndTag() {
918 if (_endTagCount
<= 0) {
919 throw new InvalidOperationException(SR
.GetString(SR
.HTMLTextWriterUnbalancedPop
));
922 TagKey
= _endTags
[_endTagCount
].tagKey
;
923 return _endTags
[_endTagCount
].endTagText
;
926 protected void PushEndTag(string endTag
) {
927 if(_endTags
== null) {
928 _endTags
= new TagStackEntry
[16];
930 else if (_endTagCount
>= _endTags
.Length
) {
931 TagStackEntry
[] newArray
= new TagStackEntry
[_endTags
.Length
* 2];
932 Array
.Copy(_endTags
, newArray
, _endTags
.Length
);
935 _endTags
[_endTagCount
].tagKey
= _tagKey
;
936 _endTags
[_endTagCount
].endTagText
= endTag
;
940 // This calls filers out all attributes and style attributes by calling OnAttributeRender
941 // and OnStyleAttributeRender on all properites and updates the lists</para>
942 protected virtual void FilterAttributes() {
944 // Create the filtered list of styles
945 int newStyleCount
= 0;
946 for (int i
= 0; i
< _styleCount
; i
++) {
947 RenderStyle style
= _styleList
[i
];
948 if (OnStyleAttributeRender(style
.name
, style
.value, style
.key
)) {
949 // Update the list. This can be done in place
950 _styleList
[newStyleCount
] = style
;
955 _styleCount
= newStyleCount
;
957 // Create the filtered list of attributes
958 int newAttrCount
= 0;
959 for (int i
= 0; i
< _attrCount
; i
++) {
960 RenderAttribute attr
= _attrList
[i
];
961 if (OnAttributeRender(attr
.name
, attr
.value, attr
.key
)) {
962 // Update the list. This can be done in place
963 _attrList
[newAttrCount
] = attr
;
968 _attrCount
= newAttrCount
;
971 public virtual void RenderBeginTag(string tagName
) {
972 this.TagName
= tagName
;
973 RenderBeginTag(_tagKey
);
976 public virtual void RenderBeginTag(HtmlTextWriterTag tagKey
) {
978 this.TagKey
= tagKey
;
979 bool renderTag
= true;
982 renderTag
= OnTagRender(_tagName
, _tagKey
);
984 // Inherited renderers will be expecting to be able to filter any of the attributes at this point
987 // write text before begin tag
988 string textBeforeTag
= RenderBeforeTag();
989 if (textBeforeTag
!= null) {
993 writer
.Write(textBeforeTag
);
997 // gather information about this tag.
998 TagInformation tagInfo
= _tagNameLookupArray
[_tagIndex
];
999 TagType tagType
= tagInfo
.tagType
;
1000 bool renderEndTag
= renderTag
&& (tagType
!= TagType
.NonClosing
);
1001 string endTag
= renderEndTag
? tagInfo
.closingTag
: null;
1003 // write the begin tag
1008 writer
.Write(TagLeftChar
);
1009 writer
.Write(_tagName
);
1011 string styleValue
= null;
1013 for (int i
= 0; i
< _attrCount
; i
++) {
1014 RenderAttribute attr
= _attrList
[i
];
1015 if (attr
.key
== HtmlTextWriterAttribute
.Style
) {
1016 // append style attribute in with other styles
1017 styleValue
= attr
.value;
1020 writer
.Write(SpaceChar
);
1021 writer
.Write(attr
.name
);
1022 if (attr
.value != null) {
1023 writer
.Write(EqualsDoubleQuoteString
);
1025 string attrValue
= attr
.value;
1027 if (attr
.key
!= HtmlTextWriterAttribute
.Href
|| !attrValue
.StartsWith("javascript:", StringComparison
.Ordinal
)) {
1028 attrValue
= EncodeUrl(attrValue
);
1032 WriteHtmlAttributeEncode(attrValue
);
1035 writer
.Write(attrValue
);
1037 writer
.Write(DoubleQuoteChar
);
1043 if (_styleCount
> 0 || styleValue
!= null) {
1044 writer
.Write(SpaceChar
);
1045 writer
.Write("style");
1046 writer
.Write(EqualsDoubleQuoteString
);
1048 CssTextWriter
.WriteAttributes(writer
, _styleList
, _styleCount
);
1049 if (styleValue
!= null) {
1050 writer
.Write(styleValue
);
1052 writer
.Write(DoubleQuoteChar
);
1055 if (tagType
== TagType
.NonClosing
) {
1056 writer
.Write(SelfClosingTagEnd
);
1059 writer
.Write(TagRightChar
);
1063 string textBeforeContent
= RenderBeforeContent();
1064 if (textBeforeContent
!= null) {
1068 writer
.Write(textBeforeContent
);
1071 // write text before the content
1074 if (tagType
== TagType
.Inline
) {
1078 // writeline and indent before rendering content
1082 // Manually build end tags for unknown tag types.
1083 if (endTag
== null) {
1084 endTag
= EndTagLeftChars
+ _tagName
+ TagRightChar
.ToString(CultureInfo
.InvariantCulture
);
1088 if (_isDescendant
) {
1089 // append text after the tag
1090 string textAfterTag
= RenderAfterTag();
1091 if (textAfterTag
!= null) {
1092 endTag
= (endTag
== null) ? textAfterTag
: textAfterTag
+ endTag
;
1095 // build end content and push it on stack to write in RenderEndTag
1096 // prepend text after the content
1097 string textAfterContent
= RenderAfterContent();
1098 if (textAfterContent
!= null) {
1099 endTag
= (endTag
== null) ? textAfterContent
: textAfterContent
+ endTag
;
1103 // push end tag onto stack
1106 // flush attribute and style lists for next tag
1112 public virtual void RenderEndTag() {
1113 string endTag
= PopEndTag();
1115 if (endTag
!= null) {
1116 if (_tagNameLookupArray
[_tagIndex
].tagType
== TagType
.Inline
) {
1118 // Never inject crlfs at end of inline tags.
1123 // unindent if not an inline tag
1131 protected virtual string RenderBeforeTag() {
1135 protected virtual string RenderBeforeContent() {
1139 protected virtual string RenderAfterContent() {
1143 protected virtual string RenderAfterTag() {
1147 public virtual void WriteAttribute(string name
, string value) {
1148 WriteAttribute(name
, value, false /*encode*/);
1151 public virtual void WriteAttribute(string name
, string value, bool fEncode
) {
1152 writer
.Write(SpaceChar
);
1154 if (value != null) {
1155 writer
.Write(EqualsDoubleQuoteString
);
1157 WriteHtmlAttributeEncode(value);
1160 writer
.Write(value);
1162 writer
.Write(DoubleQuoteChar
);
1166 public virtual void WriteBeginTag(string tagName
) {
1170 writer
.Write(TagLeftChar
);
1171 writer
.Write(tagName
);
1174 public virtual void WriteBreak() {
1175 // Space between br and / is for improved html compatibility. See XHTML 1.0 specification, section C.2.
1179 // DevDiv 33149: A backward compat. switch for Everett rendering
1180 internal void WriteObsoleteBreak() {
1184 public virtual void WriteFullBeginTag(string tagName
) {
1188 writer
.Write(TagLeftChar
);
1189 writer
.Write(tagName
);
1190 writer
.Write(TagRightChar
);
1193 public virtual void WriteEndTag(string tagName
) {
1197 writer
.Write(TagLeftChar
);
1198 writer
.Write(SlashChar
);
1199 writer
.Write(tagName
);
1200 writer
.Write(TagRightChar
);
1203 public virtual void WriteStyleAttribute(string name
, string value) {
1204 WriteStyleAttribute(name
, value, false /*encode*/);
1207 public virtual void WriteStyleAttribute(string name
, string value, bool fEncode
) {
1209 writer
.Write(StyleEqualsChar
);
1211 WriteHtmlAttributeEncode(value);
1214 writer
.Write(value);
1216 writer
.Write(SemicolonChar
);
1219 internal void WriteUTF8ResourceString(IntPtr pv
, int offset
, int size
, bool fAsciiOnly
) {
1221 // If we have an http writer, we can use the faster code path. Otherwise,
1222 // get a String out of the resource and write it.
1223 if (_httpWriter
!= null) {
1227 _httpWriter
.WriteUTF8ResourceString(pv
, offset
, size
, fAsciiOnly
);
1230 Write(StringResourceManager
.ResourceToString(pv
, offset
, size
));
1235 public virtual void WriteEncodedUrl(String url
) {
1236 int i
= url
.IndexOf('?');
1238 WriteUrlEncodedString(url
.Substring(0, i
), false);
1239 Write(url
.Substring(i
));
1242 WriteUrlEncodedString(url
, false);
1246 public virtual void WriteEncodedUrlParameter(String urlText
) {
1247 WriteUrlEncodedString(urlText
, true);
1250 public virtual void WriteEncodedText(String text
) {
1252 throw new ArgumentNullException("text");
1255 const char NBSP
= '\u00A0';
1257 // When inner text is retrieved for a text control, is
1258 // decoded to 0x00A0 (code point for nbsp in Unicode).
1259 // HtmlEncode doesn't encode 0x00A0 to , we need to do it
1261 int length
= text
.Length
;
1263 while (pos
< length
) {
1264 int nbsp
= text
.IndexOf(NBSP
, pos
);
1266 HttpUtility
.HtmlEncode(pos
== 0 ? text
: text
.Substring(pos
, length
- pos
), this);
1271 HttpUtility
.HtmlEncode(text
.Substring(pos
, nbsp
- pos
), this);
1279 protected void WriteUrlEncodedString(String text
, bool argument
) {
1280 int length
= text
.Length
;
1281 for (int i
= 0; i
< length
; i
++) {
1283 if (HttpEncoderUtility
.IsUrlSafeChar(ch
)) {
1286 else if ( !argument
&&
1295 else if (ch
== ' ' && argument
) {
1298 // for chars that their code number is less than 128 and have
1299 // not been handled above
1300 else if ((ch
& 0xff80) == 0) {
1302 Write(HttpEncoderUtility
.IntToHex((ch
>> 4) & 0xf));
1303 Write(HttpEncoderUtility
.IntToHex((ch
) & 0xf));
1306 // VSWhidbey 448625: For DBCS characters, use UTF8 encoding
1307 // which can be handled by IIS5 and above.
1308 Write(HttpUtility
.UrlEncodeNonAscii(Char
.ToString(ch
), Encoding
.UTF8
));
1313 internal void WriteHtmlAttributeEncode(string s
) {
1314 HttpUtility
.HtmlAttributeEncode(s
, _httpWriter
?? writer
);
1317 internal class Layout
{
1319 private HorizontalAlign _align
;
1322 public Layout(Layout currentLayout) {
1323 Align = currentLayout.Align;
1324 Wrap = currentLayout.Wrap;
1328 public Layout(HorizontalAlign alignment
, bool wrapping
) {
1345 public HorizontalAlign Align
1358 public bool Compare(Layout layout) {
1359 return Wrap == layout.Wrap && Align == layout.Align;
1363 public void MergeWith(Layout layout) {
1364 if (Align == HorizontalAlign.NotSet) {
1365 Align = layout.Align;
1374 private struct TagStackEntry
{
1375 public HtmlTextWriterTag tagKey
;
1376 public string endTagText
;
1379 private struct RenderAttribute
{
1381 public string value;
1382 public HtmlTextWriterAttribute key
;
1387 private struct AttributeInformation
{
1392 public AttributeInformation(string name
, bool encode
, bool isUrl
) {
1394 this.encode
= encode
;
1399 private enum TagType
{
1405 private struct TagInformation
{
1407 public TagType tagType
;
1408 public string closingTag
;
1410 public TagInformation(string name
, TagType tagType
, string closingTag
) {
1412 this.tagType
= tagType
;
1413 this.closingTag
= closingTag
;