Updates referencesource to .NET 4.7
[mono-project.git] / mcs / class / referencesource / System.Web / UI / HTMLTextWriter.cs
blobb5c395a74f8e0c78bf1ff4688c0a6554b6024955
1 //------------------------------------------------------------------------------
2 // <copyright file="HtmlTextWriter.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
4 // </copyright>
5 //------------------------------------------------------------------------------
7 // HtmlTextWriter.cs
8 //
9 namespace System.Web.UI {
10 using System;
11 using System.Collections;
12 using System.Collections.Specialized;
13 using System.IO;
14 using System.Text;
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 {
25 get {
26 return true;
30 public virtual void EnterStyle(Style style, HtmlTextWriterTag tag) {
31 if (!style.IsEmpty || tag != HtmlTextWriterTag.Span) {
32 style.AddAttributesToRender(this);
33 RenderBeginTag(tag);
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) {
40 RenderEndTag();
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) {
51 WriteBeginTag("div");
52 if (writeHorizontalAlign) {
53 String alignment;
54 switch (layout.Align) {
55 case HorizontalAlign.Right:
56 alignment = "text-align:right";
57 break;
59 case HorizontalAlign.Center:
60 alignment = "text-align:center";
61 break;
63 default:
64 alignment = "text-align:left";
65 break;
68 WriteAttribute("style", alignment);
70 if (writeWrapping) {
71 WriteAttribute("mode",
72 layout.Wrap == true ? "wrap" : "nowrap");
74 Write('>');
75 _currentWrittenLayout = layout;
78 public virtual bool IsValidFormAttribute(String attribute) {
79 return true;
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 {
290 get {
291 return writer.Encoding;
295 // Gets or sets the new line character to use.
296 public override string NewLine {
297 get {
298 return writer.NewLine;
301 set {
302 writer.NewLine = value;
306 // Gets or sets the number of spaces to indent.
307 public int Indent {
308 get {
309 return indentLevel;
311 set {
312 Debug.Assert(value >= 0, "Bogus Indent... probably caused by mismatched Indent++ and Indent--");
313 if (value < 0) {
314 value = 0;
316 indentLevel = value;
320 //Gets or sets the TextWriter to use.
321 public TextWriter InnerWriter {
322 get {
323 return writer;
325 set {
326 writer = value;
327 _httpWriter = value as HttpWriter;
345 public virtual void BeginRender() {
348 //Closes the document being written to.
349 public override void Close() {
350 writer.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() {
365 writer.Flush();
368 protected virtual void OutputTabs() {
369 if (tabsPending) {
370 for (int i=0; i < indentLevel; i++) {
371 writer.Write(tabString);
373 tabsPending = false;
377 //Writes a string to the text stream.
378 public override void Write(string s) {
379 if (tabsPending) {
380 OutputTabs();
382 writer.Write(s);
385 //Writes the text representation of a Boolean value to the text stream.
386 public override void Write(bool value) {
387 if (tabsPending) {
388 OutputTabs();
390 writer.Write(value);
393 //Writes a character to the text stream.
394 public override void Write(char value) {
395 if (tabsPending) {
396 OutputTabs();
398 writer.Write(value);
401 // Writes a character array to the text stream.
402 public override void Write(char[] buffer) {
403 if (tabsPending) {
404 OutputTabs();
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) {
411 if (tabsPending) {
412 OutputTabs();
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) {
419 if (tabsPending) {
420 OutputTabs();
422 writer.Write(value);
425 // Writes the text representation of a Single to the text stream.
426 public override void Write(float value) {
427 if (tabsPending) {
428 OutputTabs();
430 writer.Write(value);
433 // Writes the text representation of an integer to the text stream.
434 public override void Write(int value) {
435 if (tabsPending) {
436 OutputTabs();
438 writer.Write(value);
441 // Writes the text representation of an 8-byte integer to the text stream.
442 public override void Write(long value) {
443 if (tabsPending) {
444 OutputTabs();
446 writer.Write(value);
449 // Writes the text representation of an object to the text stream.
450 public override void Write(object value) {
451 if (tabsPending) {
452 OutputTabs();
454 writer.Write(value);
457 // Writes out a formatted string, using the same semantics as specified.
458 public override void Write(string format, object arg0) {
459 if (tabsPending) {
460 OutputTabs();
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) {
467 if (tabsPending) {
468 OutputTabs();
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) {
475 if (tabsPending) {
476 OutputTabs();
478 writer.Write(format, arg);
481 // Writes the specified string to a line without tabs.
482 public void WriteLineNoTabs(string s) {
483 writer.WriteLine(s);
484 tabsPending = true;
487 // Writes the specified string followed by a line terminator to the text stream.
488 public override void WriteLine(string s) {
489 if (tabsPending) {
490 OutputTabs();
492 writer.WriteLine(s);
493 tabsPending = true;
496 // Writes a line terminator.
497 public override void WriteLine() {
498 writer.WriteLine();
499 tabsPending = true;
502 // Writes the text representation of a Boolean followed by a line terminator to the text stream.
503 public override void WriteLine(bool value) {
504 if (tabsPending) {
505 OutputTabs();
507 writer.WriteLine(value);
508 tabsPending = true;
511 public override void WriteLine(char value) {
512 if (tabsPending) {
513 OutputTabs();
515 writer.WriteLine(value);
516 tabsPending = true;
519 public override void WriteLine(char[] buffer) {
520 if (tabsPending) {
521 OutputTabs();
523 writer.WriteLine(buffer);
524 tabsPending = true;
527 public override void WriteLine(char[] buffer, int index, int count) {
528 if (tabsPending) {
529 OutputTabs();
531 writer.WriteLine(buffer, index, count);
532 tabsPending = true;
535 public override void WriteLine(double value) {
536 if (tabsPending) {
537 OutputTabs();
539 writer.WriteLine(value);
540 tabsPending = true;
543 public override void WriteLine(float value) {
544 if (tabsPending) {
545 OutputTabs();
547 writer.WriteLine(value);
548 tabsPending = true;
551 public override void WriteLine(int value) {
552 if (tabsPending) {
553 OutputTabs();
555 writer.WriteLine(value);
556 tabsPending = true;
559 public override void WriteLine(long value) {
560 if (tabsPending) {
561 OutputTabs();
563 writer.WriteLine(value);
564 tabsPending = true;
567 public override void WriteLine(object value) {
568 if (tabsPending) {
569 OutputTabs();
571 writer.WriteLine(value);
572 tabsPending = true;
575 public override void WriteLine(string format, object arg0) {
576 if (tabsPending) {
577 OutputTabs();
579 writer.WriteLine(format, arg0);
580 tabsPending = true;
583 public override void WriteLine(string format, object arg0, object arg1) {
584 if (tabsPending) {
585 OutputTabs();
587 writer.WriteLine(format, arg0, arg1);
588 tabsPending = true;
591 public override void WriteLine(string format, params object[] arg) {
592 if (tabsPending) {
593 OutputTabs();
595 writer.WriteLine(format, arg);
596 tabsPending = true;
599 [CLSCompliant(false)]
600 public override void WriteLine(UInt32 value) {
601 if (tabsPending) {
602 OutputTabs();
604 writer.WriteLine(value);
605 tabsPending = true;
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;
656 indentLevel = 0;
657 tabsPending = false;
659 // If it's an http writer, save it
660 _httpWriter = writer as HttpWriter;
662 _isDescendant = (GetType() != typeof(HtmlTextWriter));
664 _attrCount = 0;
665 _styleCount = 0;
666 _endTagCount = 0;
667 _inlineCount = 0;
670 protected HtmlTextWriterTag TagKey {
671 get {
672 return _tagKey;
674 set {
675 _tagIndex = (int) value;
676 if (_tagIndex < 0 || _tagIndex >= _tagNameLookupArray.Length) {
677 throw new ArgumentOutOfRangeException("value");
679 _tagKey = 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 {
689 get {
690 return _tagName;
692 set {
693 _tagName = value;
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;
746 attr.name = name;
747 attr.value = value;
748 attr.key = key;
749 attr.encode = encode;
750 attr.isUrl = isUrl;
751 _attrList[_attrCount] = attr;
752 _attrCount++;
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;
773 RenderStyle style;
775 style.name = name;
776 style.key = key;
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;
788 _styleCount++;
791 protected string EncodeAttributeValue(string value, bool fEncode) {
792 if (value == null) {
793 return null;
796 if (!fEncode)
797 return value;
799 return HttpUtility.HtmlAttributeEncode(value);
802 protected virtual string EncodeAttributeValue(HtmlTextWriterAttribute attrKey, string value) {
803 bool encode = true;
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);
819 return url;
822 protected HtmlTextWriterAttribute GetAttributeKey(string attrName) {
823 if (!String.IsNullOrEmpty(attrName)) {
824 object key = _attrKeyLookupTable[attrName.ToLower(CultureInfo.InvariantCulture)];
825 if (key != null)
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;
836 return string.Empty;
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)];
850 if (key != null)
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;
862 return string.Empty;
865 protected bool IsAttributeDefined(HtmlTextWriterAttribute key) {
866 for (int i = 0; i < _attrCount; i++) {
867 if (_attrList[i].key == key) {
868 return true;
871 return false;
874 protected bool IsAttributeDefined(HtmlTextWriterAttribute key, out string value) {
875 value = null;
876 for (int i = 0; i < _attrCount; i++) {
877 if (_attrList[i].key == key) {
878 value = _attrList[i].value;
879 return true;
882 return false;
885 protected bool IsStyleAttributeDefined(HtmlTextWriterStyle key) {
886 for (int i = 0; i < _styleCount; i++) {
887 if (_styleList[i].key == key) {
888 return true;
891 return false;
894 protected bool IsStyleAttributeDefined(HtmlTextWriterStyle key, out string value) {
895 value = null;
896 for (int i = 0; i < _styleCount; i++) {
897 if (_styleList[i].key == key) {
898 value = _styleList[i].value;
899 return true;
902 return false;
905 protected virtual bool OnAttributeRender(string name, string value, HtmlTextWriterAttribute key) {
906 return true;
909 protected virtual bool OnStyleAttributeRender(string name, string value, HtmlTextWriterStyle key) {
910 return true;
913 protected virtual bool OnTagRender(string name, HtmlTextWriterTag key) {
914 return true;
917 protected string PopEndTag() {
918 if (_endTagCount <= 0) {
919 throw new InvalidOperationException(SR.GetString(SR.HTMLTextWriterUnbalancedPop));
921 _endTagCount--;
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);
933 _endTags = newArray;
935 _endTags[_endTagCount].tagKey = _tagKey;
936 _endTags[_endTagCount].endTagText= endTag;
937 _endTagCount++;
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;
951 newStyleCount++;
954 // Update the count
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;
964 newAttrCount++;
967 // Update the count
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;
981 if (_isDescendant) {
982 renderTag = OnTagRender(_tagName, _tagKey);
984 // Inherited renderers will be expecting to be able to filter any of the attributes at this point
985 FilterAttributes();
987 // write text before begin tag
988 string textBeforeTag = RenderBeforeTag();
989 if (textBeforeTag != null) {
990 if (tabsPending) {
991 OutputTabs();
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
1004 if (renderTag) {
1005 if (tabsPending) {
1006 OutputTabs();
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;
1019 else {
1020 writer.Write(SpaceChar);
1021 writer.Write(attr.name);
1022 if (attr.value != null) {
1023 writer.Write(EqualsDoubleQuoteString);
1025 string attrValue = attr.value;
1026 if (attr.isUrl) {
1027 if (attr.key != HtmlTextWriterAttribute.Href || !attrValue.StartsWith("javascript:", StringComparison.Ordinal)) {
1028 attrValue = EncodeUrl(attrValue);
1031 if (attr.encode) {
1032 WriteHtmlAttributeEncode(attrValue);
1034 else {
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);
1058 else {
1059 writer.Write(TagRightChar);
1063 string textBeforeContent = RenderBeforeContent();
1064 if (textBeforeContent != null) {
1065 if (tabsPending) {
1066 OutputTabs();
1068 writer.Write(textBeforeContent);
1071 // write text before the content
1072 if (renderEndTag) {
1074 if (tagType == TagType.Inline) {
1075 _inlineCount += 1;
1077 else {
1078 // writeline and indent before rendering content
1079 WriteLine();
1080 Indent++;
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
1104 PushEndTag(endTag);
1106 // flush attribute and style lists for next tag
1107 _attrCount = 0;
1108 _styleCount = 0;
1112 public virtual void RenderEndTag() {
1113 string endTag = PopEndTag();
1115 if (endTag != null) {
1116 if (_tagNameLookupArray[_tagIndex].tagType == TagType.Inline) {
1117 _inlineCount -= 1;
1118 // Never inject crlfs at end of inline tags.
1120 Write(endTag);
1122 else {
1123 // unindent if not an inline tag
1124 WriteLine();
1125 this.Indent--;
1126 Write(endTag);
1131 protected virtual string RenderBeforeTag() {
1132 return null;
1135 protected virtual string RenderBeforeContent() {
1136 return null;
1139 protected virtual string RenderAfterContent() {
1140 return null;
1143 protected virtual string RenderAfterTag() {
1144 return null;
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);
1153 writer.Write(name);
1154 if (value != null) {
1155 writer.Write(EqualsDoubleQuoteString);
1156 if (fEncode) {
1157 WriteHtmlAttributeEncode(value);
1159 else {
1160 writer.Write(value);
1162 writer.Write(DoubleQuoteChar);
1166 public virtual void WriteBeginTag(string tagName) {
1167 if (tabsPending) {
1168 OutputTabs();
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.
1176 Write("<br />");
1179 // DevDiv 33149: A backward compat. switch for Everett rendering
1180 internal void WriteObsoleteBreak() {
1181 Write("<br>");
1184 public virtual void WriteFullBeginTag(string tagName) {
1185 if (tabsPending) {
1186 OutputTabs();
1188 writer.Write(TagLeftChar);
1189 writer.Write(tagName);
1190 writer.Write(TagRightChar);
1193 public virtual void WriteEndTag(string tagName) {
1194 if (tabsPending) {
1195 OutputTabs();
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) {
1208 writer.Write(name);
1209 writer.Write(StyleEqualsChar);
1210 if (fEncode) {
1211 WriteHtmlAttributeEncode(value);
1213 else {
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) {
1224 if (tabsPending) {
1225 OutputTabs();
1227 _httpWriter.WriteUTF8ResourceString(pv, offset, size, fAsciiOnly);
1229 else {
1230 Write(StringResourceManager.ResourceToString(pv, offset, size));
1235 public virtual void WriteEncodedUrl(String url) {
1236 int i = url.IndexOf('?');
1237 if (i != -1) {
1238 WriteUrlEncodedString(url.Substring(0, i), false);
1239 Write(url.Substring(i));
1241 else {
1242 WriteUrlEncodedString(url, false);
1246 public virtual void WriteEncodedUrlParameter(String urlText) {
1247 WriteUrlEncodedString(urlText, true);
1250 public virtual void WriteEncodedText(String text) {
1251 if (text == null) {
1252 throw new ArgumentNullException("text");
1255 const char NBSP = '\u00A0';
1257 // When inner text is retrieved for a text control, &nbsp; is
1258 // decoded to 0x00A0 (code point for nbsp in Unicode).
1259 // HtmlEncode doesn't encode 0x00A0 to &nbsp;, we need to do it
1260 // manually here.
1261 int length = text.Length;
1262 int pos = 0;
1263 while (pos < length) {
1264 int nbsp = text.IndexOf(NBSP, pos);
1265 if (nbsp < 0) {
1266 HttpUtility.HtmlEncode(pos == 0 ? text : text.Substring(pos, length - pos), this);
1267 pos = length;
1269 else {
1270 if (nbsp > pos) {
1271 HttpUtility.HtmlEncode(text.Substring(pos, nbsp - pos), this);
1273 Write("&nbsp;");
1274 pos = nbsp + 1;
1279 protected void WriteUrlEncodedString(String text, bool argument) {
1280 int length = text.Length;
1281 for (int i = 0; i < length; i++) {
1282 char ch = text[i];
1283 if (HttpEncoderUtility.IsUrlSafeChar(ch)) {
1284 Write(ch);
1286 else if ( !argument &&
1287 (ch == '/' ||
1288 ch == ':' ||
1289 ch == '#' ||
1290 ch == ','
1293 Write(ch);
1295 else if (ch == ' ' && argument) {
1296 Write('+');
1298 // for chars that their code number is less than 128 and have
1299 // not been handled above
1300 else if ((ch & 0xff80) == 0) {
1301 Write('%');
1302 Write(HttpEncoderUtility.IntToHex((ch >> 4) & 0xf));
1303 Write(HttpEncoderUtility.IntToHex((ch) & 0xf));
1305 else {
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 {
1318 private bool _wrap;
1319 private HorizontalAlign _align;
1322 public Layout(Layout currentLayout) {
1323 Align = currentLayout.Align;
1324 Wrap = currentLayout.Wrap;
1328 public Layout(HorizontalAlign alignment, bool wrapping) {
1329 Align = alignment;
1330 Wrap = wrapping;
1333 public bool Wrap
1337 return _wrap;
1341 _wrap = value;
1345 public HorizontalAlign Align
1349 return _align;
1353 _align = value;
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;
1367 if (Wrap) {
1368 Wrap = layout.Wrap;
1374 private struct TagStackEntry {
1375 public HtmlTextWriterTag tagKey;
1376 public string endTagText;
1379 private struct RenderAttribute {
1380 public string name;
1381 public string value;
1382 public HtmlTextWriterAttribute key;
1383 public bool encode;
1384 public bool isUrl;
1387 private struct AttributeInformation {
1388 public string name;
1389 public bool isUrl;
1390 public bool encode;
1392 public AttributeInformation(string name, bool encode, bool isUrl) {
1393 this.name = name;
1394 this.encode = encode;
1395 this.isUrl = isUrl;
1399 private enum TagType {
1400 Inline,
1401 NonClosing,
1402 Other,
1405 private struct TagInformation {
1406 public string name;
1407 public TagType tagType;
1408 public string closingTag;
1410 public TagInformation(string name, TagType tagType, string closingTag) {
1411 this.name = name;
1412 this.tagType = tagType;
1413 this.closingTag = closingTag;