2009-02-26 Marek Habersack <mhabersack@novell.com>
[mono.git] / mcs / class / System.Web / System.Web.UI / HtmlTextWriter.cs
index 833a19d1264752a1af5d7b105de3bca9edcbdd5f..ab2e7b7dc7a774c8410a9077d2d6ead78916a762 100644 (file)
 using System.IO;
 using System.Globalization;
 using System.Collections;
+using System.Security.Permissions;
 using System.Text;
+using System.Web.UI.WebControls;
 
 namespace System.Web.UI {
-       
+
+       // CAS
+       [AspNetHostingPermission (SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
+       [AspNetHostingPermission (SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
        public class HtmlTextWriter : TextWriter {
 
-               ArrayList styles = new ArrayList ();
-               ArrayList attrs = new ArrayList ();
 
-               class AddedStyle {
-                       public string name;
-                       public HtmlTextWriterStyle key;
-                       public string value;
-               }
-               
-               class AddedAttr {
-                       public string name;
-                       public HtmlTextWriterAttribute key;
-                       public string value;
+               readonly static Hashtable _tagTable;
+               readonly static Hashtable _attributeTable;
+               readonly static Hashtable _styleTable;
+
+               static HtmlTextWriter ()
+               {
+#if NET_2_0
+                       _tagTable = new Hashtable (tags.Length, StringComparer.OrdinalIgnoreCase);
+                       _attributeTable = new Hashtable (htmlattrs.Length, StringComparer.OrdinalIgnoreCase);
+                       _styleTable = new Hashtable (htmlstyles.Length, StringComparer.OrdinalIgnoreCase);
+#else
+                       _tagTable = new Hashtable (tags.Length, 
+                               CaseInsensitiveHashCodeProvider.Default, CaseInsensitiveComparer.Default);
+                       
+                       _attributeTable = new Hashtable (htmlattrs.Length, 
+                               CaseInsensitiveHashCodeProvider.Default, CaseInsensitiveComparer.Default);
+                       
+                       _styleTable = new Hashtable (htmlstyles.Length, 
+                               CaseInsensitiveHashCodeProvider.Default, CaseInsensitiveComparer.Default);
+#endif
+                       foreach (HtmlTag tag in tags)
+                               _tagTable.Add (tag.name, tag);
+
+                       foreach (HtmlAttribute attr in htmlattrs)
+                               _attributeTable.Add (attr.name, attr);
+
+                       foreach (HtmlStyle style in htmlstyles)
+                               _styleTable.Add (style.name, style);
                }
 
                public HtmlTextWriter (TextWriter writer) : this (writer, DefaultTabString)
                {
                }
-       
+
                public HtmlTextWriter (TextWriter writer, string tabString)
                {
-                       if (writer == null)
-                               throw new ArgumentNullException ();
-
                        b = writer;
                        tab_string = tabString;
                }
 
-               [MonoTODO]
-               internal static string StaticGetStyleName (System.Web.UI.HtmlTextWriterStyle styleKey) 
+               internal static string StaticGetStyleName (System.Web.UI.HtmlTextWriterStyle styleKey)
                {
-                       return "";
+                       if ((int) styleKey < htmlstyles.Length)
+                               return htmlstyles [(int) styleKey].name;
+
+                       return null;
                }
-               
-               [MonoTODO]
+
+               [MonoTODO ("Does nothing")]
                protected static void RegisterAttribute (string name, HtmlTextWriterAttribute key)
                {
                }
-               
-               [MonoTODO]
+
+               [MonoTODO ("Does nothing")]
                protected static void RegisterStyle (string name, HtmlTextWriterStyle key)
                {
                }
-               
-               [MonoTODO]
+
+               [MonoTODO ("Does nothing")]
                protected static void RegisterTag (string name, HtmlTextWriterTag key)
                {
                }
-               
-       
+
+
                public virtual void AddAttribute (HtmlTextWriterAttribute key, string value, bool fEncode)
                {
                        if (fEncode)
-                               value = EncodeAttributeValue (key, value);
+                               value = HttpUtility.HtmlAttributeEncode (value);
+
                        AddAttribute (GetAttributeName (key), value, key);
                }
-               
-               
+
+
                public virtual void AddAttribute (HtmlTextWriterAttribute key, string value)
                {
-                       AddAttribute (key, value, true);
+                       if ((key != HtmlTextWriterAttribute.Name) && (key != HtmlTextWriterAttribute.Id))
+                               value = HttpUtility.HtmlAttributeEncode (value);
+
+                       AddAttribute (GetAttributeName (key), value, key);
                }
-       
-       
+
+
                public virtual void AddAttribute (string name, string value, bool fEncode)
                {
                        if (fEncode)
-                               ; // FIXME
+                               value = HttpUtility.HtmlAttributeEncode (value);
 
                        AddAttribute (name, value, GetAttributeKey (name));
                }
-               
+
                public virtual void AddAttribute (string name, string value)
                {
-                       AddAttribute (name, value, true);
+                       HtmlTextWriterAttribute key = GetAttributeKey (name);
+
+                       if ((key != HtmlTextWriterAttribute.Name) && (key != HtmlTextWriterAttribute.Id))
+                               value = HttpUtility.HtmlAttributeEncode (value);
+
+                       AddAttribute (name, value, key);
                }
-       
+
                protected virtual void AddAttribute (string name, string value, HtmlTextWriterAttribute key)
                {
-                       AddedAttr a = new AddedAttr ();
-                       a.name = name;
-                       a.value = value;
-                       a.key = key;
-                       attrs.Add (a);
+                       NextAttrStack ();
+#if TARGET_JVM
+                       if (attrs [attrs_pos] == null)
+                               attrs [attrs_pos] = new AddedAttr ();
+#endif
+                       attrs [attrs_pos].name = name;
+                       attrs [attrs_pos].value = value;
+                       attrs [attrs_pos].key = key;
                }
-               
-               
+
+
                protected virtual void AddStyleAttribute (string name, string value, HtmlTextWriterStyle key)
                {
-                       AddedStyle a = new AddedStyle ();
-                       a.name = name;
-                       a.value = value;
-                       a.key = key;
-                       styles.Add (a);
+                       NextStyleStack ();
+#if TARGET_JVM
+                       if (styles [styles_pos] == null)
+                               styles [styles_pos] = new AddedStyle ();
+#endif
+                       styles [styles_pos].name = name;
+#if NET_2_0
+                       value = HttpUtility.HtmlAttributeEncode (value);
+#endif
+                       styles [styles_pos].value = value;
+                       styles [styles_pos].key = key;
                }
-               
+
 
                public virtual void AddStyleAttribute (string name, string value)
                {
                        AddStyleAttribute (name, value, GetStyleKey (name));
                }
-               
+
                public virtual void AddStyleAttribute (HtmlTextWriterStyle key, string value)
                {
                        AddStyleAttribute (GetStyleName (key), value, key);
                }
-       
+
                public override void Close ()
                {
-                       b.Close ();     
+                       b.Close ();
                }
 
-               [MonoTODO]
                protected virtual string EncodeAttributeValue (HtmlTextWriterAttribute attrKey, string value)
                {
-                       return value;
+                       return HttpUtility.HtmlAttributeEncode (value);
                }
-               
-               [MonoTODO]
+
                protected string EncodeAttributeValue (string value, bool fEncode)
                {
+                       if (fEncode)
+                               return HttpUtility.HtmlAttributeEncode (value);
                        return value;
                }
-               
-               [MonoTODO]
+
                protected string EncodeUrl (string url)
                {
-                       return url;
+                       return HttpUtility.UrlPathEncode (url);
                }
-               
+
 
                protected virtual void FilterAttributes ()
                {
-                       AddedAttr style_attr = null;
-                       
-                       foreach (AddedAttr a in attrs) {
+                       AddedAttr style_attr = new AddedAttr ();
+
+                       for (int i = 0; i <= attrs_pos; i++) {
+                               AddedAttr a = attrs [i];
                                if (OnAttributeRender (a.name, a.value, a.key)) {
                                        if (a.key == HtmlTextWriterAttribute.Style) {
                                                style_attr = a;
                                                continue;
                                        }
-                                       
+
                                        WriteAttribute (a.name, a.value, false);
                                }
                        }
-                       
-                       attrs.Clear ();
 
-                       if (styles.Count != 0 || style_attr != null) {
+                       if (styles_pos != -1 || style_attr.value != null) {
                                Write (SpaceChar);
                                Write ("style");
                                Write (EqualsDoubleQuoteString);
 
-                               foreach (AddedStyle a in styles)
-                                       if (OnStyleAttributeRender (a.name, a.value, a.key))
+
+                               for (int i = 0; i <= styles_pos; i++) {
+                                       AddedStyle a = styles [i];
+                                       if (OnStyleAttributeRender (a.name, a.value, a.key)) {
+#if NET_2_0
+                                               if (a.key == HtmlTextWriterStyle.BackgroundImage) {
+                                                       a.value = String.Concat ("url(", HttpUtility.UrlPathEncode (a.value), ")");
+                                               }
+#endif
                                                WriteStyleAttribute (a.name, a.value, false);
+                                       }
+                               }
 
-                               if (style_attr != null)
-                                       Write (style_attr.value);
-                                                               
+                               Write (style_attr.value);
                                Write (DoubleQuoteChar);
                        }
-                       
-                       styles.Clear ();
+
+                       styles_pos = attrs_pos = -1;
                }
-       
+
                public override void Flush ()
                {
                        b.Flush ();
                }
 
-               [MonoTODO]
                protected HtmlTextWriterAttribute GetAttributeKey (string attrName)
                {
-                       // I don't think we want to binary search
-                       // because there might be something added to
-                       // the enum later. Do we really need anything
-                       // faster than a linear search?
-                       
-                       foreach (HtmlAttribute t in htmlattrs) {
-                               if (t.name == attrName)
-                                       return t.key;
-                       }
+                       object attribute = _attributeTable [attrName];
+                       if (attribute == null)
+                               return (HtmlTextWriterAttribute) (-1);
 
-                       return 0;               
+                       return (HtmlTextWriterAttribute) ((HtmlAttribute) attribute).key;
                }
 
-               [MonoTODO]
                protected string GetAttributeName (HtmlTextWriterAttribute attrKey)
                {
                        if ((int) attrKey < htmlattrs.Length)
@@ -230,46 +265,28 @@ namespace System.Web.UI {
 
                        return null;
                }
-               
-               [MonoTODO]
+
                protected HtmlTextWriterStyle GetStyleKey (string styleName)
                {
-                       // I don't think we want to binary search
-                       // because there might be something added to
-                       // the enum later. Do we really need anything
-                       // faster than a linear search?
-                       
-                       foreach (HtmlStyle t in htmlstyles) {
-                               if (t.name == styleName)
-                                       return t.key;
-                       }
+                       object style = _styleTable [styleName];
+                       if (style == null)
+                               return (HtmlTextWriterStyle) (-1);
 
-                       return 0;                       
+                       return (HtmlTextWriterStyle) ((HtmlStyle) style).key;
                }
-               
-               [MonoTODO]
+
                protected string GetStyleName (HtmlTextWriterStyle styleKey)
                {
-                       if ((int) styleKey < htmlstyles.Length)
-                               return htmlstyles [(int) styleKey].name;
-
-                       return null;
+                       return StaticGetStyleName (styleKey);
                }
-               
-               [MonoTODO]
-               protected virtual HtmlTextWriterTag GetTagKey (string tagName) 
+
+               protected virtual HtmlTextWriterTag GetTagKey (string tagName)
                {
-                       // I don't think we want to binary search
-                       // because there might be something added to
-                       // the enum later. Do we really need anything
-                       // faster than a linear search?
-                       
-                       foreach (HtmlTag t in tags) {
-                               if (t.name == tagName)
-                                       return t.key;
-                       }
+                       object tag = _tagTable [tagName];
+                       if (tag == null)
+                               return HtmlTextWriterTag.Unknown;
 
-                       return HtmlTextWriterTag.Unknown;
+                       return (HtmlTextWriterTag) ((HtmlTag) tag).key;
                }
 
                internal static string StaticGetTagName (HtmlTextWriterTag tagKey)
@@ -277,11 +294,10 @@ namespace System.Web.UI {
                        if ((int) tagKey < tags.Length)
                                return tags [(int) tagKey].name;
 
-                       return null;    
+                       return null;
                }
-               
-               
-               [MonoTODO]
+
+
                protected virtual string GetTagName (HtmlTextWriterTag tagKey)
                {
                        if ((int) tagKey < tags.Length)
@@ -289,122 +305,109 @@ namespace System.Web.UI {
 
                        return null;
                }
-               
+
                protected bool IsAttributeDefined (HtmlTextWriterAttribute key)
                {
                        string value;
                        return IsAttributeDefined (key, out value);
                }
-       
+
                protected bool IsAttributeDefined (HtmlTextWriterAttribute key, out string value)
                {
-                       foreach (AddedAttr a in attrs)
-                               if (a.key == key) {
-                                       value = a.value;
+                       for (int i = 0; i <= attrs_pos; i++)
+                               if (attrs [i].key == key) {
+                                       value = attrs [i].value;
                                        return true;
                                }
 
                        value = null;
                        return false;
                }
-               
+
                protected bool IsStyleAttributeDefined (HtmlTextWriterStyle key)
                {
                        string value;
                        return IsStyleAttributeDefined (key, out value);
                }
-       
+
                protected bool IsStyleAttributeDefined (HtmlTextWriterStyle key, out string value)
                {
-
-                       foreach (AddedStyle a in styles)
-                               if (a.key == key){
-                                       value = a.value;
+                       for (int i = 0; i <= styles_pos; i++)
+                               if (styles [i].key == key) {
+                                       value = styles [i].value;
                                        return true;
                                }
 
                        value = null;
                        return false;
                }
-               
+
                protected virtual bool OnAttributeRender (string name, string value, HtmlTextWriterAttribute key)
                {
                        return true;
                }
-               
+
                protected virtual bool OnStyleAttributeRender (string name, string value, HtmlTextWriterStyle key)
                {
                        return true;
                }
-               
+
                protected virtual bool OnTagRender (string name, HtmlTextWriterTag key)
                {
                        return true;
                }
-               
-       
+
+
                protected virtual void OutputTabs ()
                {
-                       if (! newline)
+                       if (!newline)
                                return;
                        newline = false;
-                       
-                       for (int i = 0; i < Indent; i ++)
+
+                       for (int i = 0; i < Indent; i++)
                                b.Write (tab_string);
                }
-       
-               class TagStack {
-                       public string name;
-                       public HtmlTextWriterTag key;
-                       public TagStack next;
-               }
 
-               TagStack cur_tag;
-                       
+
+
                protected string PopEndTag ()
                {
-                       if (cur_tag == null)
+                       if (tagstack_pos == -1)
                                throw new InvalidOperationException ();
-                       
+
                        string s = TagName;
-                       cur_tag = cur_tag.next;
+                       tagstack_pos--;
                        return s;
                }
-               
+
                protected void PushEndTag (string endTag)
                {
-                       // TODO optimize -- too much memory!
-                       TagStack ts = new TagStack ();
-                       ts.next = cur_tag;
-                       cur_tag = ts;
+                       NextTagStack ();
                        TagName = endTag;
                }
 
                void PushEndTag (HtmlTextWriterTag t)
                {
-                       // TODO optimize!
-                       TagStack ts = new TagStack ();
-                       ts.next = cur_tag;
-                       cur_tag = ts;
+                       NextTagStack ();
                        TagKey = t;
                }
-               
+
 
                protected virtual string RenderAfterContent ()
                {
                        return null;
                }
-               
+
                protected virtual string RenderAfterTag ()
                {
                        return null;
                }
-               
+
                protected virtual string RenderBeforeContent ()
                {
                        return null;
                }
-                       
+
                protected virtual string RenderBeforeTag ()
                {
                        return null;
@@ -412,22 +415,20 @@ namespace System.Web.UI {
 
                public virtual void RenderBeginTag (string tagName)
                {
-                       if (! OnTagRender (tagName, GetTagKey (tagName)))
-                               return;
+                       bool ignore = !OnTagRender (tagName, GetTagKey (tagName));
 
                        PushEndTag (tagName);
-                       
+                       TagIgnore = ignore;
                        DoBeginTag ();
                }
-               
+
                public virtual void RenderBeginTag (HtmlTextWriterTag tagKey)
                {
-                       if (! OnTagRender (GetTagName (tagKey), tagKey))
-                               return;
+                       bool ignore = !OnTagRender (GetTagName (tagKey), tagKey);
 
                        PushEndTag (tagKey);
-
                        DoBeginTag ();
+                       TagIgnore = ignore;
                }
 
                void WriteIfNotNull (string s)
@@ -435,61 +436,67 @@ namespace System.Web.UI {
                        if (s != null)
                                Write (s);
                }
-               
+
 
                void DoBeginTag ()
                {
                        WriteIfNotNull (RenderBeforeTag ());
-                       WriteBeginTag (TagName);
-                       FilterAttributes ();
-
-                       HtmlTextWriterTag key = (int) TagKey < tags.Length ? TagKey : HtmlTextWriterTag.Unknown;
-
-                       switch (tags [(int) key].tag_type) {
-                       case TagType.Inline:
-                               Write (TagRightChar);
-                               break;
-                       case TagType.Block:
-                               Write (TagRightChar);
-                               WriteLine ();
-                               Indent ++;
-                               break;
-                       case TagType.SelfClosing:
-                               Write (SelfClosingTagEnd);
-                               break;
+                       if (!TagIgnore) {
+                               WriteBeginTag (TagName);
+                               FilterAttributes ();
+
+                               HtmlTextWriterTag key = (int) TagKey < tags.Length ? TagKey : HtmlTextWriterTag.Unknown;
+
+                               switch (tags [(int) key].tag_type) {
+                                       case TagType.Inline:
+                                               Write (TagRightChar);
+                                               break;
+                                       case TagType.Block:
+                                               Write (TagRightChar);
+                                               WriteLine ();
+                                               Indent++;
+                                               break;
+                                       case TagType.SelfClosing:
+                                               Write (SelfClosingTagEnd);
+                                               break;
+                               }
                        }
                        
                        // FIXME what do i do for self close here?
                        WriteIfNotNull (RenderBeforeContent ());
                }
-               
+
 
                public virtual void RenderEndTag ()
                {
+                       
                        // FIXME what do i do for self close here?
                        WriteIfNotNull (RenderAfterContent ());
-                       
-                       HtmlTextWriterTag key = (int) TagKey < tags.Length ? TagKey : HtmlTextWriterTag.Unknown;
-
-                       switch (tags [(int) key].tag_type) {
-                       case TagType.Inline:
-                               WriteEndTag (TagName);
-                               break;
-                       case TagType.Block:
-                               Indent --;
-                               WriteLineNoTabs ("");
-                               WriteEndTag (TagName);
-                               
-                               break;
-                       case TagType.SelfClosing:
-                               // NADA
-                               break;
+
+                       if (!TagIgnore) {
+                               HtmlTextWriterTag key = (int) TagKey < tags.Length ? TagKey : HtmlTextWriterTag.Unknown;
+
+                               switch (tags [(int) key].tag_type) {
+                                       case TagType.Inline:
+                                               WriteEndTag (TagName);
+                                               break;
+                                       case TagType.Block:
+                                               Indent--;
+                                               WriteLineNoTabs ("");
+                                               WriteEndTag (TagName);
+
+                                               break;
+                                       case TagType.SelfClosing:
+                                               // NADA
+                                               break;
+                               }
                        }
+                       
                        WriteIfNotNull (RenderAfterTag ());
 
                        PopEndTag ();
                }
-               
+
 
                public virtual void WriteAttribute (string name, string value, bool fEncode)
                {
@@ -502,31 +509,31 @@ namespace System.Web.UI {
                                Write (DoubleQuoteChar);
                        }
                }
-               
-       
+
+
                public virtual void WriteBeginTag (string tagName)
                {
                        Write (TagLeftChar);
                        Write (tagName);
                }
-               
+
                public virtual void WriteEndTag (string tagName)
                {
                        Write (EndTagLeftChars);
                        Write (tagName);
-                       Write (TagRightChar);   
+                       Write (TagRightChar);
                }
-               
+
                public virtual void WriteFullBeginTag (string tagName)
                {
                        Write (TagLeftChar);
                        Write (tagName);
                        Write (TagRightChar);
                }
-                       
+
                public virtual void WriteStyleAttribute (string name, string value)
                {
-                       WriteStyleAttribute (name, value, true);
+                       WriteStyleAttribute (name, value, false);
                }
 
                public virtual void WriteStyleAttribute (string name, string value, bool fEncode)
@@ -536,49 +543,49 @@ namespace System.Web.UI {
                        Write (EncodeAttributeValue (value, fEncode));
                        Write (SemicolonChar);
                }
-               
+
                public override void Write (char [] buffer, int index, int count)
                {
                        OutputTabs ();
                        b.Write (buffer, index, count);
                }
-       
+
                public override void Write (double value)
                {
                        OutputTabs ();
                        b.Write (value);
                }
-       
+
                public override void Write (char value)
                {
                        OutputTabs ();
                        b.Write (value);
                }
-       
+
                public override void Write (char [] buffer)
                {
                        OutputTabs ();
                        b.Write (buffer);
                }
-       
+
                public override void Write (int value)
                {
                        OutputTabs ();
                        b.Write (value);
                }
-       
+
                public override void Write (string format, object arg0)
                {
                        OutputTabs ();
                        b.Write (format, arg0);
                }
-       
+
                public override void Write (string format, object arg0, object arg1)
                {
                        OutputTabs ();
                        b.Write (format, arg0, arg1);
                }
-       
+
                public override void Write (string format, params object [] args)
                {
                        OutputTabs ();
@@ -590,34 +597,34 @@ namespace System.Web.UI {
                        OutputTabs ();
                        b.Write (s);
                }
-               
+
                public override void Write (long value)
                {
                        OutputTabs ();
                        b.Write (value);
                }
-       
+
                public override void Write (object value)
                {
                        OutputTabs ();
                        b.Write (value);
                }
-               
+
                public override void Write (float value)
                {
                        OutputTabs ();
                        b.Write (value);
                }
-       
+
                public override void Write (bool value)
                {
                        OutputTabs ();
                        b.Write (value);
                }
-       
+
                public virtual void WriteAttribute (string name, string value)
                {
-                       WriteAttribute (name, value, true);
+                       WriteAttribute (name, value, false);
                }
 
                public override void WriteLine (char value)
@@ -626,84 +633,84 @@ namespace System.Web.UI {
                        b.WriteLine (value);
                        newline = true;
                }
-       
+
                public override void WriteLine (long value)
                {
                        OutputTabs ();
                        b.WriteLine (value);
                        newline = true;
                }
-       
+
                public override void WriteLine (object value)
                {
                        OutputTabs ();
                        b.WriteLine (value);
-                       newline = true; 
+                       newline = true;
                }
-       
+
                public override void WriteLine (double value)
                {
                        OutputTabs ();
                        b.WriteLine (value);
                        newline = true;
                }
-       
+
                public override void WriteLine (char [] buffer, int index, int count)
                {
                        OutputTabs ();
                        b.WriteLine (buffer, index, count);
                        newline = true;
                }
-       
+
                public override void WriteLine (char [] buffer)
                {
                        OutputTabs ();
                        b.WriteLine (buffer);
                        newline = true;
                }
-               
+
                public override void WriteLine (bool value)
                {
                        OutputTabs ();
                        b.WriteLine (value);
                        newline = true;
                }
-       
+
                public override void WriteLine ()
                {
                        OutputTabs ();
                        b.WriteLine ();
                        newline = true;
                }
-       
+
                public override void WriteLine (int value)
                {
                        OutputTabs ();
                        b.WriteLine (value);
                        newline = true;
                }
-       
+
                public override void WriteLine (string format, object arg0, object arg1)
                {
                        OutputTabs ();
                        b.WriteLine (format, arg0, arg1);
                        newline = true;
                }
-       
+
                public override void WriteLine (string format, object arg0)
                {
                        OutputTabs ();
                        b.WriteLine (format, arg0);
                        newline = true;
                }
-       
+
                public override void WriteLine (string format, params object [] args)
                {
                        OutputTabs ();
                        b.WriteLine (format, args);
                        newline = true;
                }
-               
+
                [CLSCompliant (false)]
                public override void WriteLine (uint value)
                {
@@ -711,21 +718,21 @@ namespace System.Web.UI {
                        b.WriteLine (value);
                        newline = true;
                }
-       
+
                public override void WriteLine (string s)
                {
                        OutputTabs ();
                        b.WriteLine (s);
                        newline = true;
                }
-       
+
                public override void WriteLine (float value)
                {
                        OutputTabs ();
                        b.WriteLine (value);
                        newline = true;
                }
-       
+
                public void WriteLineNoTabs (string s)
                {
                        b.WriteLine (s);
@@ -734,7 +741,7 @@ namespace System.Web.UI {
 
                public override Encoding Encoding {
                        get {
-                               return b.Encoding;      
+                               return b.Encoding;
                        }
                }
 
@@ -747,16 +754,16 @@ namespace System.Web.UI {
                                indent = value;
                        }
                }
-       
+
                public System.IO.TextWriter InnerWriter {
                        get {
                                return b;
                        }
                        set {
                                b = value;
-                       }       
+                       }
                }
-       
+
                public override string NewLine {
                        get {
                                return b.NewLine;
@@ -765,40 +772,156 @@ namespace System.Web.UI {
                                b.NewLine = value;
                        }
                }
-       
+
                protected HtmlTextWriterTag TagKey {
                        get {
-                               if (cur_tag == null)
+                               if (tagstack_pos == -1)
                                        throw new InvalidOperationException ();
 
-                               return cur_tag.key;
+                               return tagstack [tagstack_pos].key;
                        }
                        set {
-                               cur_tag.key = value;
-                               cur_tag.name = GetTagName (value);
+#if TARGET_JVM
+                               if (tagstack [tagstack_pos] == null)
+                                       tagstack [tagstack_pos] = new AddedTag ();
+#endif
+                               tagstack [tagstack_pos].key = value;
+                               tagstack [tagstack_pos].name = GetTagName (value);
                        }
                }
-       
+
                protected string TagName {
                        get {
-                               if (cur_tag == null)
+                               if (tagstack_pos == -1)
                                        throw new InvalidOperationException ();
-                               
-                               return cur_tag.name;
+
+                               return tagstack [tagstack_pos].name;
                        }
                        set {
-                               cur_tag.name = value;
-                               cur_tag.key = GetTagKey (value);
-                               if (cur_tag.key != HtmlTextWriterTag.Unknown)
-                                       cur_tag.name = GetTagName (cur_tag.key);
+#if TARGET_JVM
+                               if (tagstack [tagstack_pos] == null)
+                                       tagstack [tagstack_pos] = new AddedTag ();
+#endif
+                               tagstack [tagstack_pos].name = value;
+                               tagstack [tagstack_pos].key = GetTagKey (value);
+                               if (tagstack [tagstack_pos].key != HtmlTextWriterTag.Unknown)
+                                       tagstack [tagstack_pos].name = GetTagName (tagstack [tagstack_pos].key);
+                       }
+               }
+
+               bool TagIgnore {
+                       get {
+                               if (tagstack_pos == -1)
+                                       throw new InvalidOperationException ();
+
+                               return tagstack [tagstack_pos].ignore;
+                       }
+
+                       set {
+                               if (tagstack_pos == -1)
+                                       throw new InvalidOperationException ();
+                               
+                               tagstack [tagstack_pos].ignore = value;
                        }
                }
                
+               internal HttpWriter GetHttpWriter ()
+               {
+                       return b as HttpWriter;
+               }
 
                TextWriter b;
                string tab_string;
                bool newline;
-       
+
+               //
+               // These emulate generic Stack <T>, since we can't use that ;-(. _pos is the current
+               // element.IE, you edit blah [blah_pos]. I *really* want generics, sigh.
+               //
+               AddedStyle [] styles;
+               AddedAttr [] attrs;
+               AddedTag [] tagstack;
+
+               int styles_pos = -1, attrs_pos = -1, tagstack_pos = -1;
+
+#if TARGET_JVM
+               class
+#else
+               struct 
+#endif
+               AddedTag {
+                       public string name;
+                       public HtmlTextWriterTag key;
+                       public bool ignore;
+               }
+
+#if TARGET_JVM
+               class
+#else
+               struct 
+#endif
+               AddedStyle {
+                       public string name;
+                       public HtmlTextWriterStyle key;
+                       public string value;
+               }
+
+#if TARGET_JVM
+               class
+#else
+               struct 
+#endif
+               AddedAttr {
+                       public string name;
+                       public HtmlTextWriterAttribute key;
+                       public string value;
+               }
+
+               void NextStyleStack ()
+               {
+                       if (styles == null)
+                               styles = new AddedStyle [16];
+
+                       if (++styles_pos < styles.Length)
+                               return;
+
+                       int nsize = styles.Length * 2;
+                       AddedStyle [] ncontents = new AddedStyle [nsize];
+
+                       Array.Copy (styles, ncontents, styles.Length);
+                       styles = ncontents;
+               }
+
+               void NextAttrStack ()
+               {
+                       if (attrs == null)
+                               attrs = new AddedAttr [16];
+
+                       if (++attrs_pos < attrs.Length)
+                               return;
+
+                       int nsize = attrs.Length * 2;
+                       AddedAttr [] ncontents = new AddedAttr [nsize];
+
+                       Array.Copy (attrs, ncontents, attrs.Length);
+                       attrs = ncontents;
+               }
+
+               void NextTagStack ()
+               {
+                       if (tagstack == null)
+                               tagstack = new AddedTag [16];
+
+                       if (++tagstack_pos < tagstack.Length)
+                               return;
+
+                       int nsize = tagstack.Length * 2;
+                       AddedTag [] ncontents = new AddedTag [nsize];
+
+                       Array.Copy (tagstack, ncontents, tagstack.Length);
+                       tagstack = ncontents;
+               }
+
                public const string DefaultTabString = "\t";
                public const char DoubleQuoteChar = '"';
                public const string EndTagLeftChars = "</";
@@ -809,7 +932,7 @@ namespace System.Web.UI {
                public const char SemicolonChar = ';';
                public const char SingleQuoteChar = '\'';
                public const char SlashChar = '/';
-               public const char SpaceChar = ' ' ;
+               public const char SpaceChar = ' ';
                public const char StyleEqualsChar = ':';
                public const char TagLeftChar = '<';
                public const char TagRightChar = '>';
@@ -819,12 +942,12 @@ namespace System.Web.UI {
                        Inline,
                        SelfClosing,
                }
-               
-               
-               struct HtmlTag {
-                       public HtmlTextWriterTag key;
-                       public string name;
-                       public TagType tag_type;
+
+
+               sealed class HtmlTag {
+                       readonly public HtmlTextWriterTag key;
+                       readonly public string name;
+                       readonly public TagType tag_type;
 
                        public HtmlTag (HtmlTextWriterTag k, string n, TagType tt)
                        {
@@ -834,10 +957,10 @@ namespace System.Web.UI {
                        }
                }
 
-               struct HtmlStyle {
-                       public HtmlTextWriterStyle key;
-                       public string name;
-                       
+               sealed class HtmlStyle {
+                       readonly public HtmlTextWriterStyle key;
+                       readonly public string name;
+
                        public HtmlStyle (HtmlTextWriterStyle k, string n)
                        {
                                key = k;
@@ -845,10 +968,10 @@ namespace System.Web.UI {
                        }
                }
 
-               
-               struct HtmlAttribute {
-                       public HtmlTextWriterAttribute key;
-                       public string name;
+
+               sealed class HtmlAttribute {
+                       readonly public HtmlTextWriterAttribute key;
+                       readonly public string name;
 
                        public HtmlAttribute (HtmlTextWriterAttribute k, string n)
                        {
@@ -856,7 +979,7 @@ namespace System.Web.UI {
                                name = n;
                        }
                }
-               
+
                static HtmlTag [] tags = {
                        new HtmlTag (HtmlTextWriterTag.Unknown,    "",                  TagType.Block),
                        new HtmlTag (HtmlTextWriterTag.A,          "a",                 TagType.Inline),
@@ -957,64 +1080,183 @@ namespace System.Web.UI {
                        new HtmlTag (HtmlTextWriterTag.Xml,        "xml",               TagType.Block),
                };
 
-               HtmlAttribute [] htmlattrs = {
-                       new HtmlAttribute (HtmlTextWriterAttribute.Accesskey,   "accesskey"),
-                       new HtmlAttribute (HtmlTextWriterAttribute.Align,       "align"),
-                       new HtmlAttribute (HtmlTextWriterAttribute.Alt,         "alt"),
-                       new HtmlAttribute (HtmlTextWriterAttribute.Background,  "background"),
-                       new HtmlAttribute (HtmlTextWriterAttribute.Bgcolor,     "bgcolor"),
-                       new HtmlAttribute (HtmlTextWriterAttribute.Border,      "border"),
-                       new HtmlAttribute (HtmlTextWriterAttribute.Bordercolor, "bordercolor"),
-                       new HtmlAttribute (HtmlTextWriterAttribute.Cellpadding, "cellpadding"),
-                       new HtmlAttribute (HtmlTextWriterAttribute.Cellspacing, "cellspacing"),
-                       new HtmlAttribute (HtmlTextWriterAttribute.Checked,     "checked"),
-                       new HtmlAttribute (HtmlTextWriterAttribute.Class,       "class"),
-                       new HtmlAttribute (HtmlTextWriterAttribute.Cols,        "cols"),
-                       new HtmlAttribute (HtmlTextWriterAttribute.Colspan,     "colspan"),
-                       new HtmlAttribute (HtmlTextWriterAttribute.Disabled,    "disabled"),
-                       new HtmlAttribute (HtmlTextWriterAttribute.For,         "for"),
-                       new HtmlAttribute (HtmlTextWriterAttribute.Height,      "height"),
-                       new HtmlAttribute (HtmlTextWriterAttribute.Href,        "href"),
-                       new HtmlAttribute (HtmlTextWriterAttribute.Id,          "id"),
-                       new HtmlAttribute (HtmlTextWriterAttribute.Maxlength,   "maxlength"),
-                       new HtmlAttribute (HtmlTextWriterAttribute.Multiple,    "multiple"),
-                       new HtmlAttribute (HtmlTextWriterAttribute.Name,        "name"),
-                       new HtmlAttribute (HtmlTextWriterAttribute.Nowrap,      "nowrap"),
-                       new HtmlAttribute (HtmlTextWriterAttribute.Onchange,    "onchange"),
-                       new HtmlAttribute (HtmlTextWriterAttribute.Onclick,     "onclick"),
-                       new HtmlAttribute (HtmlTextWriterAttribute.ReadOnly,    "readonly"),
-                       new HtmlAttribute (HtmlTextWriterAttribute.Rows,        "rows"),
-                       new HtmlAttribute (HtmlTextWriterAttribute.Rowspan,     "rowspan"),
-                       new HtmlAttribute (HtmlTextWriterAttribute.Rules,       "rules"),
-                       new HtmlAttribute (HtmlTextWriterAttribute.Selected,    "selected"),
-                       new HtmlAttribute (HtmlTextWriterAttribute.Size,        "size"),
-                       new HtmlAttribute (HtmlTextWriterAttribute.Src,         "src"),
-                       new HtmlAttribute (HtmlTextWriterAttribute.Style,       "style"),
-                       new HtmlAttribute (HtmlTextWriterAttribute.Tabindex,    "tabindex"),
-                       new HtmlAttribute (HtmlTextWriterAttribute.Target,      "target"),
-                       new HtmlAttribute (HtmlTextWriterAttribute.Title,       "title"),
-                       new HtmlAttribute (HtmlTextWriterAttribute.Type,        "type"),
-                       new HtmlAttribute (HtmlTextWriterAttribute.Valign,      "valign"),
-                       new HtmlAttribute (HtmlTextWriterAttribute.Value,       "value"),
-                       new HtmlAttribute (HtmlTextWriterAttribute.Width,       "width"),
-                       new HtmlAttribute (HtmlTextWriterAttribute.Wrap,        "wrap"),
+               static HtmlAttribute [] htmlattrs = {
+                       new HtmlAttribute (HtmlTextWriterAttribute.Accesskey,         "accesskey"),
+                       new HtmlAttribute (HtmlTextWriterAttribute.Align,             "align"),
+                       new HtmlAttribute (HtmlTextWriterAttribute.Alt,               "alt"),
+                       new HtmlAttribute (HtmlTextWriterAttribute.Background,        "background"),
+                       new HtmlAttribute (HtmlTextWriterAttribute.Bgcolor,           "bgcolor"),
+                       new HtmlAttribute (HtmlTextWriterAttribute.Border,            "border"),
+                       new HtmlAttribute (HtmlTextWriterAttribute.Bordercolor,       "bordercolor"),
+                       new HtmlAttribute (HtmlTextWriterAttribute.Cellpadding,       "cellpadding"),
+                       new HtmlAttribute (HtmlTextWriterAttribute.Cellspacing,       "cellspacing"),
+                       new HtmlAttribute (HtmlTextWriterAttribute.Checked,           "checked"),
+                       new HtmlAttribute (HtmlTextWriterAttribute.Class,             "class"),
+                       new HtmlAttribute (HtmlTextWriterAttribute.Cols,              "cols"),
+                       new HtmlAttribute (HtmlTextWriterAttribute.Colspan,           "colspan"),
+                       new HtmlAttribute (HtmlTextWriterAttribute.Disabled,          "disabled"),
+                       new HtmlAttribute (HtmlTextWriterAttribute.For,               "for"),
+                       new HtmlAttribute (HtmlTextWriterAttribute.Height,            "height"),
+                       new HtmlAttribute (HtmlTextWriterAttribute.Href,              "href"),
+                       new HtmlAttribute (HtmlTextWriterAttribute.Id,                "id"),
+                       new HtmlAttribute (HtmlTextWriterAttribute.Maxlength,         "maxlength"),
+                       new HtmlAttribute (HtmlTextWriterAttribute.Multiple,          "multiple"),
+                       new HtmlAttribute (HtmlTextWriterAttribute.Name,              "name"),
+                       new HtmlAttribute (HtmlTextWriterAttribute.Nowrap,            "nowrap"),
+                       new HtmlAttribute (HtmlTextWriterAttribute.Onchange,          "onchange"),
+                       new HtmlAttribute (HtmlTextWriterAttribute.Onclick,           "onclick"),
+                       new HtmlAttribute (HtmlTextWriterAttribute.ReadOnly,          "readonly"),
+                       new HtmlAttribute (HtmlTextWriterAttribute.Rows,              "rows"),
+                       new HtmlAttribute (HtmlTextWriterAttribute.Rowspan,           "rowspan"),
+                       new HtmlAttribute (HtmlTextWriterAttribute.Rules,             "rules"),
+                       new HtmlAttribute (HtmlTextWriterAttribute.Selected,          "selected"),
+                       new HtmlAttribute (HtmlTextWriterAttribute.Size,              "size"),
+                       new HtmlAttribute (HtmlTextWriterAttribute.Src,               "src"),
+                       new HtmlAttribute (HtmlTextWriterAttribute.Style,             "style"),
+                       new HtmlAttribute (HtmlTextWriterAttribute.Tabindex,          "tabindex"),
+                       new HtmlAttribute (HtmlTextWriterAttribute.Target,            "target"),
+                       new HtmlAttribute (HtmlTextWriterAttribute.Title,             "title"),
+                       new HtmlAttribute (HtmlTextWriterAttribute.Type,              "type"),
+                       new HtmlAttribute (HtmlTextWriterAttribute.Valign,            "valign"),
+                       new HtmlAttribute (HtmlTextWriterAttribute.Value,             "value"),
+                       new HtmlAttribute (HtmlTextWriterAttribute.Width,             "width"),
+                       new HtmlAttribute (HtmlTextWriterAttribute.Wrap,              "wrap"),
+#if NET_2_0
+                       new HtmlAttribute (HtmlTextWriterAttribute.Abbr,              "abbr"),
+                       new HtmlAttribute (HtmlTextWriterAttribute.AutoComplete,      "autocomplete"),
+                       new HtmlAttribute (HtmlTextWriterAttribute.Axis,              "axis"),
+                       new HtmlAttribute (HtmlTextWriterAttribute.Content,           "content"),
+                       new HtmlAttribute (HtmlTextWriterAttribute.Coords,            "coords"),
+                       new HtmlAttribute (HtmlTextWriterAttribute.DesignerRegion,    "_designerregion"),
+                       new HtmlAttribute (HtmlTextWriterAttribute.Dir,               "dir"),
+                       new HtmlAttribute (HtmlTextWriterAttribute.Headers,           "headers"),
+                       new HtmlAttribute (HtmlTextWriterAttribute.Longdesc,          "longdesc"),
+                       new HtmlAttribute (HtmlTextWriterAttribute.Rel,               "rel"),
+                       new HtmlAttribute (HtmlTextWriterAttribute.Scope,             "scope"),
+                       new HtmlAttribute (HtmlTextWriterAttribute.Shape,             "shape"),
+                       new HtmlAttribute (HtmlTextWriterAttribute.Usemap,            "usemap"),
+                       new HtmlAttribute (HtmlTextWriterAttribute.VCardName,         "vcard_name"),
+#endif
                };
 
-               HtmlStyle [] htmlstyles = {
-                       new HtmlStyle (HtmlTextWriterStyle.BackgroundColor, "background-color"),
-                       new HtmlStyle (HtmlTextWriterStyle.BackgroundImage, "background-image"),
-                       new HtmlStyle (HtmlTextWriterStyle.BorderCollapse,  "border-collapse"),
-                       new HtmlStyle (HtmlTextWriterStyle.BorderColor,     "border-color"),
-                       new HtmlStyle (HtmlTextWriterStyle.BorderStyle,     "border-style"),
-                       new HtmlStyle (HtmlTextWriterStyle.BorderWidth,     "border-width"),
-                       new HtmlStyle (HtmlTextWriterStyle.Color,           "color"),
-                       new HtmlStyle (HtmlTextWriterStyle.FontFamily,      "font-family"),
-                       new HtmlStyle (HtmlTextWriterStyle.FontSize,        "font-size"),
-                       new HtmlStyle (HtmlTextWriterStyle.FontStyle,       "font-style"),
-                       new HtmlStyle (HtmlTextWriterStyle.FontWeight,      "font-weight"),
-                       new HtmlStyle (HtmlTextWriterStyle.Height,          "height"),
-                       new HtmlStyle (HtmlTextWriterStyle.TextDecoration,  "text-decoration"),
-                       new HtmlStyle (HtmlTextWriterStyle.Width,           "width"),
+               static HtmlStyle [] htmlstyles = {
+                       new HtmlStyle (HtmlTextWriterStyle.BackgroundColor,    "background-color"),
+                       new HtmlStyle (HtmlTextWriterStyle.BackgroundImage,    "background-image"),
+                       new HtmlStyle (HtmlTextWriterStyle.BorderCollapse,     "border-collapse"),
+                       new HtmlStyle (HtmlTextWriterStyle.BorderColor,        "border-color"),
+                       new HtmlStyle (HtmlTextWriterStyle.BorderStyle,        "border-style"),
+                       new HtmlStyle (HtmlTextWriterStyle.BorderWidth,        "border-width"),
+                       new HtmlStyle (HtmlTextWriterStyle.Color,              "color"),
+                       new HtmlStyle (HtmlTextWriterStyle.FontFamily,         "font-family"),
+                       new HtmlStyle (HtmlTextWriterStyle.FontSize,           "font-size"),
+                       new HtmlStyle (HtmlTextWriterStyle.FontStyle,          "font-style"),
+                       new HtmlStyle (HtmlTextWriterStyle.FontWeight,         "font-weight"),
+                       new HtmlStyle (HtmlTextWriterStyle.Height,             "height"),
+                       new HtmlStyle (HtmlTextWriterStyle.TextDecoration,     "text-decoration"),
+                       new HtmlStyle (HtmlTextWriterStyle.Width,              "width"),
+#if NET_2_0
+                       new HtmlStyle (HtmlTextWriterStyle.ListStyleImage,     "list-style-image"),
+                       new HtmlStyle (HtmlTextWriterStyle.ListStyleType,      "list-style-type"),
+                       new HtmlStyle (HtmlTextWriterStyle.Cursor,             "cursor"),
+                       new HtmlStyle (HtmlTextWriterStyle.Direction,          "direction"),
+                       new HtmlStyle (HtmlTextWriterStyle.Display,            "display"),
+                       new HtmlStyle (HtmlTextWriterStyle.Filter,             "filter"),
+                       new HtmlStyle (HtmlTextWriterStyle.FontVariant,        "font-variant"),
+                       new HtmlStyle (HtmlTextWriterStyle.Left,               "left"),
+                       new HtmlStyle (HtmlTextWriterStyle.Margin,             "margin"),
+                       new HtmlStyle (HtmlTextWriterStyle.MarginBottom,       "margin-bottom"),
+                       new HtmlStyle (HtmlTextWriterStyle.MarginLeft,         "margin-left"),
+                       new HtmlStyle (HtmlTextWriterStyle.MarginRight,        "margin-right"),
+                       new HtmlStyle (HtmlTextWriterStyle.MarginTop,          "margin-top"),
+                       new HtmlStyle (HtmlTextWriterStyle.Overflow,           "overflow"),
+                       new HtmlStyle (HtmlTextWriterStyle.OverflowX,          "overflow-x"),
+                       new HtmlStyle (HtmlTextWriterStyle.OverflowY,          "overflow-y"),
+                       new HtmlStyle (HtmlTextWriterStyle.Padding,            "padding"),
+                       new HtmlStyle (HtmlTextWriterStyle.PaddingBottom,      "padding-bottom"),
+                       new HtmlStyle (HtmlTextWriterStyle.PaddingLeft,        "padding-left"),
+                       new HtmlStyle (HtmlTextWriterStyle.PaddingRight,       "padding-right"),
+                       new HtmlStyle (HtmlTextWriterStyle.PaddingTop,         "padding-top"),
+                       new HtmlStyle (HtmlTextWriterStyle.Position,           "position"),
+                       new HtmlStyle (HtmlTextWriterStyle.TextAlign,          "text-align"),
+                       new HtmlStyle (HtmlTextWriterStyle.VerticalAlign,      "vertical-align"),
+                       new HtmlStyle (HtmlTextWriterStyle.TextOverflow,       "text-overflow"),
+                       new HtmlStyle (HtmlTextWriterStyle.Top,                "top"),
+                       new HtmlStyle (HtmlTextWriterStyle.Visibility,         "visibility"),
+                       new HtmlStyle (HtmlTextWriterStyle.WhiteSpace,         "white-space"),
+                       new HtmlStyle (HtmlTextWriterStyle.ZIndex,             "z-index"),
+#endif
                };
+
+#if NET_2_0
+               public virtual bool IsValidFormAttribute (string attribute)
+               {
+                       return true;
+               }
+
+               // writes <br />
+               public virtual void WriteBreak ()
+               {
+                       string br = GetTagName (HtmlTextWriterTag.Br);
+                       WriteBeginTag (br);
+                       Write (SelfClosingTagEnd);
+               }
+
+               public virtual void WriteEncodedText (string text)
+               {
+                       Write (HttpUtility.HtmlEncode (text));
+               }
+
+               [MonoNotSupported ("")]
+               public virtual void WriteEncodedUrl (string url)
+               {
+                       // WriteUrlEncodedString (url, false);
+                       throw new NotImplementedException ();
+               }
+
+               [MonoNotSupported ("")]
+               public virtual void WriteEncodedUrlParameter (string urlText)
+               {
+                       // WriteUrlEncodedString (urlText, true);
+                       throw new NotImplementedException ();
+               }
+
+               [MonoNotSupported ("")]
+               protected void WriteUrlEncodedString (string text, bool argument)
+               {
+                       throw new NotImplementedException ();
+               }
+
+               [MonoNotSupported ("")]
+               public virtual void EnterStyle (Style style)
+               {
+                       throw new NotImplementedException ();
+               }
+
+               [MonoNotSupported ("")]
+               public virtual void EnterStyle (Style style, HtmlTextWriterTag tag)
+               {
+                       throw new NotImplementedException ();
+               }
+
+               [MonoNotSupported ("")]
+               public virtual void ExitStyle (Style style)
+               {
+                       throw new NotImplementedException ();
+               }
+
+               [MonoNotSupported ("")]
+               public virtual void ExitStyle (Style style, HtmlTextWriterTag tag)
+               {
+                       throw new NotImplementedException ();
+               }
+               
+               public virtual void BeginRender ()
+               {
+               }
+
+               public virtual void EndRender ()
+               {
+               }
+#endif
        }
 }