New tests.
[mono.git] / mcs / class / Managed.Windows.Forms / System.Windows.Forms / RichTextBox.cs
index 0e4446a64e82ed54abf83b610f33c38674c9d519..1db7f29a519e0819d7696faeb9cff1a41f001da9 100644 (file)
@@ -30,6 +30,7 @@ using System;
 using System.Collections;
 using System.ComponentModel;
 using System.Drawing;
+using System.Drawing.Imaging;
 using System.IO;
 using System.Text;
 using System.Runtime.InteropServices;
@@ -40,47 +41,67 @@ namespace System.Windows.Forms {
        [ClassInterface (ClassInterfaceType.AutoDispatch)]
        [Docking (DockingBehavior.Ask)]
        [ComVisible (true)]
+       [Designer ("System.Windows.Forms.Design.RichTextBoxDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")]
 #endif
        public class RichTextBox : TextBoxBase {
                #region Local Variables
                internal bool           auto_word_select;
                internal int            bullet_indent;
                internal bool           detect_urls;
+               private bool            reuse_line;     // Sometimes we are loading text with already available lines
                internal int            margin_right;
                internal float          zoom;
-
-               private RTF.TextMap     rtf_text_map;
-               private int             rtf_skip_width;
-               private int             rtf_skip_count;
                private StringBuilder   rtf_line;
-               private SolidBrush      rtf_color;
-               private RTF.Font        rtf_rtffont;
-               private int             rtf_rtffont_size;
-               private FontStyle       rtf_rtfstyle;
-               private HorizontalAlignment rtf_rtfalign;
+
+               private RtfSectionStyle rtf_style;      // Replaces individual style
+                                                       // properties so we can revert
+               private Stack           rtf_section_stack;
+
+               private RTF.TextMap rtf_text_map;
+               private int rtf_skip_count;
                private int             rtf_cursor_x;
                private int             rtf_cursor_y;
                private int             rtf_chars;
+
+#if NET_2_0
+               private bool            enable_auto_drag_drop;
+               private RichTextBoxLanguageOptions language_option;
+               private bool            rich_text_shortcuts_enabled;
+               private Color           selection_back_color;
+#endif
                #endregion      // Local Variables
 
                #region Public Constructors
                public RichTextBox() {
                        accepts_return = true;
+                       auto_size = false;
                        auto_word_select = false;
                        bullet_indent = 0;
-                       detect_urls = true;
-                       max_length = Int32.MaxValue;
+                       base.MaxLength = Int32.MaxValue;
                        margin_right = 0;
                        zoom = 1;
                        base.Multiline = true;
                        document.CRLFSize = 1;
+                       shortcuts_enabled = true;
+                       base.EnableLinks = true;
+                       richtext = true;
+                       
+                       rtf_style = new RtfSectionStyle ();
+                       rtf_section_stack = null;
 
                        scrollbars = RichTextBoxScrollBars.Both;
                        alignment = HorizontalAlignment.Left;
                        LostFocus += new EventHandler(RichTextBox_LostFocus);
                        GotFocus += new EventHandler(RichTextBox_GotFocus);
                        BackColor = ThemeEngine.Current.ColorWindow;
+#if NET_2_0
+                       backcolor_set = false;
+                       language_option = RichTextBoxLanguageOptions.AutoFontSizeAdjust;
+                       rich_text_shortcuts_enabled = true;
+                       selection_back_color = DefaultBackColor;
+#endif
                        ForeColor = ThemeEngine.Current.ColorWindowText;
+
                        base.HScrolled += new EventHandler(RichTextBox_HScrolled);
                        base.VScrolled += new EventHandler(RichTextBox_VScrolled);
 
@@ -91,6 +112,32 @@ namespace System.Windows.Forms {
                #endregion      // Public Constructors
 
                #region Private & Internal Methods
+
+               internal override void HandleLinkClicked (LinkRectangle link)
+               {
+                       OnLinkClicked (new LinkClickedEventArgs (link.LinkTag.LinkText));
+               }
+
+               internal override Color ChangeBackColor (Color backColor)
+               {
+                       if (backColor == Color.Empty) {
+#if NET_2_0
+                               backcolor_set = false;
+                               if (!ReadOnly) {
+                                       backColor = SystemColors.Window;
+                               }
+#else
+                               backColor = SystemColors.Window;
+#endif
+                       }
+                       return backColor;
+               }
+
+               internal override void RaiseSelectionChanged()
+               {
+                       OnSelectionChanged (EventArgs.Empty);
+               }
+               
                private void RichTextBox_LostFocus(object sender, EventArgs e) {
                        Invalidate();
                }
@@ -133,15 +180,11 @@ namespace System.Windows.Forms {
                        }
                }
 
+               [MonoTODO ("Value not respected, always true")]
                [DefaultValue(false)]
                public bool AutoWordSelection {
-                       get {
-                               return auto_word_select;
-                       }
-
-                       set {
-                               auto_word_select = true;
-                       }
+                       get { return auto_word_select; }
+                       set { auto_word_select = value; }
                }
 
                [Browsable(false)]
@@ -151,6 +194,15 @@ namespace System.Windows.Forms {
                        set { base.BackgroundImage = value; }
                }
 
+#if NET_2_0
+               [Browsable (false)]
+               [EditorBrowsable (EditorBrowsableState.Never)]
+               public override ImageLayout BackgroundImageLayout {
+                       get { return base.BackgroundImageLayout; }
+                       set { base.BackgroundImageLayout = value; }
+               }
+#endif
+
                [DefaultValue(0)]
                [Localizable(true)]
                public int BulletIndent {
@@ -173,14 +225,18 @@ namespace System.Windows.Forms {
 
                [DefaultValue(true)]
                public bool DetectUrls {
-                       get {
-                               return detect_urls;
-                       }
+                       get { return base.EnableLinks; }
+                       set { base.EnableLinks = value; }
+               }
 
-                       set {
-                               detect_urls = true;
-                       }
+#if NET_2_0
+               [MonoTODO ("Stub, does nothing")]
+               [DefaultValue (false)]
+               public bool EnableAutoDragDrop {
+                       get { return enable_auto_drag_drop; }
+                       set { enable_auto_drag_drop = value; }
                }
+#endif
 
                public override Font Font {
                        get {
@@ -203,7 +259,7 @@ namespace System.Windows.Forms {
                                        // Font changes always set the whole doc to that font
                                        start = document.GetLine(1);
                                        end = document.GetLine(document.Lines);
-                                       document.FormatText(start, 1, end, end.text.Length + 1, base.Font, null, null, FormatSpecified.Font);
+                                       document.FormatText(start, 1, end, end.text.Length + 1, base.Font, Color.Empty, Color.Empty, FormatSpecified.Font);
                                }
                        }
                }
@@ -218,15 +274,20 @@ namespace System.Windows.Forms {
                        }
                }
 
+#if NET_2_0
+               [MonoTODO ("Stub, does nothing")]
+               [Browsable (false)]
+               [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
+               public RichTextBoxLanguageOptions LanguageOption {
+                       get { return language_option; }
+                       set { language_option = value; }
+               }
+#endif
+
                [DefaultValue(Int32.MaxValue)]
                public override int MaxLength {
-                       get {
-                               return base.max_length;
-                       }
-
-                       set {
-                               base.max_length = value;
-                       }
+                       get { return base.MaxLength; }
+                       set { base.MaxLength = value; }
                }
 
                [DefaultValue(true)]
@@ -242,16 +303,27 @@ namespace System.Windows.Forms {
 
                [Browsable(false)]
                [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
-               [MonoTODO]
                public string RedoActionName {
                        get {
                                return document.undo.RedoActionName;
                        }
                }
 
+#if NET_2_0
+               [MonoTODO ("Stub, does nothing")]
+               [Browsable (false)]
+               [DefaultValue (true)]
+               [EditorBrowsable (EditorBrowsableState.Never)]
+               public bool RichTextShortcutsEnabled {
+                       get { return rich_text_shortcuts_enabled; }
+                       set { rich_text_shortcuts_enabled = value; }
+               }
+#endif
+
                [DefaultValue(0)]
                [Localizable(true)]
-               [MonoTODO("Teach TextControl.RecalculateLine to consider the right margin as well")]
+               [MonoTODO ("Stub, does nothing")]
+               [MonoInternalNote ("Teach TextControl.RecalculateLine to consider the right margin as well")]
                public int RightMargin {
                        get {
                                return margin_right;
@@ -301,7 +373,14 @@ namespace System.Windows.Forms {
                        }
 
                        set {
-                               scrollbars = value;
+                               if (!Enum.IsDefined (typeof (RichTextBoxScrollBars), value))
+                                       throw new InvalidEnumArgumentException ("value", (int) value,
+                                               typeof (RichTextBoxScrollBars));
+
+                               if (value != scrollbars) {
+                                       scrollbars = value;
+                                       CalculateDocument ();
+                               }
                        }
                }
 
@@ -313,7 +392,7 @@ namespace System.Windows.Forms {
                                return GenerateRTF(document.selection_start.line, document.selection_start.pos, document.selection_end.line, document.selection_end.pos).ToString();
                        }
 
-                       set {
+                       set {                           
                                MemoryStream    data;
                                int             x;
                                int             y;
@@ -329,10 +408,24 @@ namespace System.Windows.Forms {
                                sel_start = document.LineTagToCharIndex(document.selection_start.line, document.selection_start.pos);
 
                                data = new MemoryStream(Encoding.ASCII.GetBytes(value), false);
-                               InsertRTFFromStream(data, document.selection_start.pos, document.selection_start.line.line_no, out x, out y, out chars);
+                               int cursor_x = document.selection_start.pos;
+                               int cursor_y = document.selection_start.line.line_no;
+
+                               // The RFT parser by default, when finds our x cursor in 0, it thinks if needs to
+                               // add a new line; but in *this* scenario the line is already created, so force it to reuse it.
+                               // Hackish, but works without touching the heart of the buggy parser.
+                               if (cursor_x == 0)
+                                       reuse_line = true;
+
+                               InsertRTFFromStream(data, cursor_x, cursor_y, out x, out y, out chars);
                                data.Close();
 
-                               document.CharIndexToLineTag(sel_start + chars + (y - document.selection_start.line.line_no) * 2, out line, out tag, out sel_start);
+                               int nl_length = document.LineEndingLength (XplatUI.RunningOnUnix ? LineEnding.Rich : LineEnding.Hard);
+                               document.CharIndexToLineTag(sel_start + chars + (y - document.selection_start.line.line_no) * nl_length, 
+                                               out line, out tag, out sel_start);
+                               if (sel_start >= line.text.Length)
+                                       sel_start = line.text.Length -1;
+
                                document.SetSelection(line, sel_start);
                                document.PositionCaret(line, sel_start);
                                document.DisplayCaret();
@@ -350,6 +443,8 @@ namespace System.Windows.Forms {
                        }
 
                        set {
+                               // TextBox/TextBoxBase don't set Modified in this same property
+                               Modified = true;
                                base.SelectedText = value;
                        }
                }
@@ -408,10 +503,20 @@ namespace System.Windows.Forms {
                        }
                }
 
+#if NET_2_0
+               [MonoTODO ("Stub, does nothing")]
+               [Browsable (false)]
+               [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
+               public Color SelectionBackColor {
+                       get { return selection_back_color; }
+                       set { selection_back_color = value; }
+               }
+#endif
+
                [Browsable(false)]
                [DefaultValue(false)]
                [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
-               [MonoTODO]
+               [MonoTODO ("Stub, does nothing")]
                public bool SelectionBullet {
                        get {
                                return false;
@@ -424,7 +529,7 @@ namespace System.Windows.Forms {
                [Browsable(false)]
                [DefaultValue(0)]
                [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
-               [MonoTODO]
+               [MonoTODO ("Stub, does nothing")]
                public int SelectionCharOffset {
                        get {
                                return 0;
@@ -443,48 +548,53 @@ namespace System.Windows.Forms {
                                LineTag end;
                                LineTag tag;
 
-                               start = document.selection_start.tag;
-                               end = document.selection_end.tag;
-                               color = ((SolidBrush)document.selection_start.tag.color).Color;
+                               if (selection_length > 0) {
+                                       start = document.selection_start.line.FindTag (document.selection_start.pos + 1);
+                                       end = document.selection_start.line.FindTag (document.selection_end.pos);
+                               } else {
+                                       start = document.selection_start.line.FindTag (document.selection_start.pos);
+                                       end = start;
+                               }
+
+                               color = start.Color;
 
                                tag = start;
-                               while (true) {
-                                       if (!color.Equals(((SolidBrush)tag.color).Color)) {
+                               while (tag != null) {
+
+                                       if (!color.Equals (tag.Color))
                                                return Color.Empty;
-                                       }
 
-                                       if (tag == end) {
+                                       if (tag == end)
                                                break;
-                                       }
-
-                                       tag = document.NextTag(tag);
 
-                                       if (tag == null) {
-                                               break;
-                                       }
+                                       tag = document.NextTag (tag);
                                }
 
                                return color;
                        }
 
                        set {
-                               FontDefinition  attributes;
-                               int             sel_start;
-                               int             sel_end;
-
-                               attributes = new FontDefinition();
-                               attributes.color = value;
+                               if (value == Color.Empty)
+                                       value = DefaultForeColor;
+                                       
+                               int sel_start;
+                               int sel_end;
 
                                sel_start = document.LineTagToCharIndex(document.selection_start.line, document.selection_start.pos);
                                sel_end = document.LineTagToCharIndex(document.selection_end.line, document.selection_end.pos);
 
-                               document.FormatText(document.selection_start.line, document.selection_start.pos + 1, document.selection_end.line, document.selection_end.pos + 1, attributes);
+                               document.FormatText (document.selection_start.line, document.selection_start.pos + 1,
+                                               document.selection_end.line, document.selection_end.pos + 1, null,
+                                               value, Color.Empty, FormatSpecified.Color);
 
                                document.CharIndexToLineTag(sel_start, out document.selection_start.line, out document.selection_start.tag, out document.selection_start.pos);
                                document.CharIndexToLineTag(sel_end, out document.selection_end.line, out document.selection_end.tag, out document.selection_end.pos);
 
                                document.UpdateView(document.selection_start.line, 0);
-                               document.AlignCaret();
+
+                               //Re-Align the caret in case its changed size or position
+                               //probably not necessary here
+                               document.AlignCaret(false);
                        }
                }
 
@@ -497,24 +607,27 @@ namespace System.Windows.Forms {
                                LineTag end;
                                LineTag tag;
 
-                               start = document.selection_start.tag;
-                               end = document.selection_end.tag;
-                               font = document.selection_start.tag.font;
+                               if (selection_length > 0) {
+                                       start = document.selection_start.line.FindTag (document.selection_start.pos + 1);
+                                       end = document.selection_start.line.FindTag (document.selection_end.pos);
+                               } else {
+                                       start = document.selection_start.line.FindTag (document.selection_start.pos);
+                                       end = start;
+                               }
 
-                               tag = start;
-                               while (true) {
-                                       if (!font.Equals(tag.font)) {
-                                               return null;
-                                       }
+                               font = start.Font;
 
-                                       if (tag == end) {
-                                               break;
-                                       }
+                               if (selection_length > 1) {
+                                       tag = start;
+                                       while (tag != null) {
 
-                                       tag = document.NextTag(tag);
+                                               if (!font.Equals(tag.Font))
+                                                       return null;
 
-                                       if (tag == null) {
-                                               break;
+                                               if (tag == end)
+                                                       break;
+
+                                               tag = document.NextTag (tag);
                                        }
                                }
 
@@ -522,23 +635,22 @@ namespace System.Windows.Forms {
                        }
 
                        set {
-                               FontDefinition  attributes;
                                int             sel_start;
                                int             sel_end;
 
-                               attributes = new FontDefinition();
-                               attributes.font_obj = value;
-
                                sel_start = document.LineTagToCharIndex(document.selection_start.line, document.selection_start.pos);
                                sel_end = document.LineTagToCharIndex(document.selection_end.line, document.selection_end.pos);
 
-                               document.FormatText(document.selection_start.line, document.selection_start.pos + 1, document.selection_end.line, document.selection_end.pos + 1, attributes);
+                               document.FormatText (document.selection_start.line, document.selection_start.pos + 1,
+                                               document.selection_end.line, document.selection_end.pos + 1, value,
+                                               Color.Empty, Color.Empty, FormatSpecified.Font);
 
                                document.CharIndexToLineTag(sel_start, out document.selection_start.line, out document.selection_start.tag, out document.selection_start.pos);
                                document.CharIndexToLineTag(sel_end, out document.selection_end.line, out document.selection_end.tag, out document.selection_end.pos);
 
                                document.UpdateView(document.selection_start.line, 0);
-                               document.AlignCaret();
+                               //Re-Align the caret in case its changed size or position
+                               Document.AlignCaret (false);
 
                        }
                }
@@ -546,7 +658,7 @@ namespace System.Windows.Forms {
                [Browsable(false)]
                [DefaultValue(0)]
                [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
-               [MonoTODO]
+               [MonoTODO ("Stub, does nothing")]
                public int SelectionHangingIndent {
                        get {
                                return 0;
@@ -559,7 +671,7 @@ namespace System.Windows.Forms {
                [Browsable(false)]
                [DefaultValue(0)]
                [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
-               [MonoTODO]
+               [MonoTODO ("Stub, does nothing")]
                public int SelectionIndent {
                        get {
                                return 0;
@@ -584,7 +696,7 @@ namespace System.Windows.Forms {
                [Browsable(false)]
                [DefaultValue(false)]
                [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
-               [MonoTODO]
+               [MonoTODO ("Stub, does nothing")]
                public bool SelectionProtected {
                        get {
                                return false;
@@ -597,7 +709,7 @@ namespace System.Windows.Forms {
                [Browsable(false)]
                [DefaultValue(0)]
                [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
-               [MonoTODO]
+               [MonoTODO ("Stub, does nothing")]
                public int SelectionRightIndent {
                        get {
                                return 0;
@@ -609,7 +721,7 @@ namespace System.Windows.Forms {
 
                [Browsable(false)]
                [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
-               [MonoTODO]
+               [MonoTODO ("Stub, does nothing")]
                public int[] SelectionTabs {
                        get {
                                return new int[0];
@@ -637,7 +749,7 @@ namespace System.Windows.Forms {
                }
 
                [DefaultValue(false)]
-               [MonoTODO]
+               [MonoTODO ("Stub, does nothing")]
                public bool ShowSelectionMargin {
                        get {
                                return false;
@@ -819,30 +931,53 @@ namespace System.Windows.Forms {
                        return Find(str, -1, -1, options);
                }
 
+               
+#if !NET_2_0
                public char GetCharFromPosition(Point pt) {
                        LineTag tag;
                        int     pos;
 
                        PointToTagPos(pt, out tag, out pos);
 
-                       if (pos >= tag.line.text.Length) {
+                       if (pos >= tag.Line.text.Length) {
                                return '\n';
                        }
 
-                       return tag.line.text[pos];
-                       
+                       return tag.Line.text[pos];
+               }
+#else
+               internal override char GetCharFromPositionInternal (Point p)
+               {
+                       LineTag tag;
+                       int pos;
+
+                       PointToTagPos (p, out tag, out pos);
+
+                       if (pos >= tag.Line.text.Length)
+                               return '\n';
+
+                       return tag.Line.text[pos];
                }
+#endif
 
-               public int GetCharIndexFromPosition(Point pt) {
+               public
+#if NET_2_0
+               override
+#endif 
+               int GetCharIndexFromPosition(Point pt) {
                        LineTag tag;
                        int     pos;
 
                        PointToTagPos(pt, out tag, out pos);
 
-                       return document.LineTagToCharIndex(tag.line, pos);
+                       return document.LineTagToCharIndex(tag.Line, pos);
                }
 
-               public int GetLineFromCharIndex(int index) {
+               public
+#if NET_2_0
+               override
+#endif
+               int GetLineFromCharIndex(int index) {
                        Line    line;
                        LineTag tag;
                        int     pos;
@@ -852,14 +987,18 @@ namespace System.Windows.Forms {
                        return line.LineNo - 1;
                }
 
-               public Point GetPositionFromCharIndex(int index) {
+               public
+#if NET_2_0
+               override
+#endif
+               Point GetPositionFromCharIndex(int index) {
                        Line    line;
                        LineTag tag;
                        int     pos;
 
                        document.CharIndexToLineTag(index, out line, out tag, out pos);
-
-                       return new Point((int)line.widths[pos] + 1, line.Y + 1);
+                       return new Point(line.X + (int)line.widths[pos] + document.OffsetX - document.ViewPortX, 
+                                        line.Y + document.OffsetY - document.ViewPortY);
                }
 
                public void LoadFile(System.IO.Stream data, RichTextBoxStreamType fileType) {
@@ -868,22 +1007,27 @@ namespace System.Windows.Forms {
                        
                        // FIXME - ignoring unicode
                        if (fileType == RichTextBoxStreamType.PlainText) {
-                               StringBuilder   sb;
-                               int             count;
-                               byte[]          buffer;
+                               StringBuilder sb;
+                               char[] buffer;
 
                                try {
-                                       sb = new StringBuilder((int)data.Length);
-                                       buffer = new byte[1024];
+                                       sb = new StringBuilder ((int) data.Length);
+                                       buffer = new char [1024];
                                } catch {
                                        throw new IOException("Not enough memory to load document");
                                }
 
-                               count = 0;
-                               while (count < data.Length) {
-                                       count += data.Read(buffer, count, 1024);
-                                       sb.Append(buffer);
+                               StreamReader sr = new StreamReader (data, Encoding.Default, true);
+                               int charsRead = sr.Read (buffer, 0, buffer.Length);
+                               while (charsRead > 0) {
+                                       sb.Append (buffer, 0, charsRead);
+                                       charsRead = sr.Read (buffer, 0, buffer.Length);
                                }
+
+                               // Remove the EOF converted to an extra EOL by the StreamReader
+                               if (sb.Length > 0 && sb [sb.Length - 1] == '\n')
+                                       sb.Remove (sb.Length - 1, 1);
+
                                base.Text = sb.ToString();
                                return;
                        }
@@ -895,13 +1039,8 @@ namespace System.Windows.Forms {
                        ScrollToCaret ();
                }
 
-               [MonoTODO("Make smarter RTF detection?")]
                public void LoadFile(string path) {
-                       if (path.EndsWith(".rtf")) {
-                               LoadFile(path, RichTextBoxStreamType.RichText);
-                       } else {
-                               LoadFile(path, RichTextBoxStreamType.PlainText);
-                       }
+                       LoadFile (path, RichTextBoxStreamType.RichText);
                }
 
                public void LoadFile(string path, RichTextBoxStreamType fileType) {
@@ -916,8 +1055,8 @@ namespace System.Windows.Forms {
                                LoadFile(data, fileType);
                        }
 #if !DEBUG
-                       catch {
-                               throw new IOException("Could not open file " + path);
+                       catch (Exception ex) {
+                               throw new IOException("Could not open file " + path, ex);
                        }
 #endif
                        finally {
@@ -933,7 +1072,8 @@ namespace System.Windows.Forms {
 
                public void Redo()
                {
-                       document.undo.Redo ();
+                       if (document.undo.Redo ())
+                               OnTextChanged (EventArgs.Empty);
                }
 
                public void SaveFile(Stream data, RichTextBoxStreamType fileType) {
@@ -959,7 +1099,9 @@ namespace System.Windows.Forms {
                                        }
 
                                        for (i = 1; i < document.Lines; i++) {
-                                               bytes = encoding.GetBytes(document.GetLine(i).text.ToString() + Environment.NewLine);
+                                               // Normalize the new lines to the system ones
+                                               string line_text = document.GetLine (i).TextWithoutEnding () + Environment.NewLine;
+                                               bytes = encoding.GetBytes(line_text);
                                                data.Write(bytes, 0, bytes.Length);
                                        }
                                        bytes = encoding.GetBytes(document.GetLine(document.Lines).text.ToString());
@@ -1022,6 +1164,16 @@ namespace System.Windows.Forms {
 //                     }
                }
 
+#if NET_2_0
+               [EditorBrowsable (EditorBrowsableState.Never)]
+               public new void DrawToBitmap (Bitmap bitmap, Rectangle targetBounds)
+               {
+                       Graphics dc = Graphics.FromImage (bitmap);
+
+                       Draw (dc, targetBounds);
+               }
+#endif
+
                #endregion      // Public Instance Methods
 
                #region Protected Instance Methods
@@ -1057,7 +1209,7 @@ namespace System.Windows.Forms {
                                eh (this, e);
                }
 
-               [MonoTODO("Determine when to call this")]
+               [MonoTODO ("Stub, never called")]
                protected virtual void OnImeChange(EventArgs e) {
                        EventHandler eh = (EventHandler)(Events [ImeChangeEvent]);
                        if (eh != null)
@@ -1086,6 +1238,7 @@ namespace System.Windows.Forms {
                                eh (this, e);
                }
 
+#if !NET_2_0
                protected override void OnSystemColorsChanged(EventArgs e) {
                        base.OnSystemColorsChanged (e);
                }
@@ -1093,6 +1246,7 @@ namespace System.Windows.Forms {
                protected override void OnTextChanged(EventArgs e) {
                        base.OnTextChanged (e);
                }
+#endif
 
                protected virtual void OnVScroll(EventArgs e) {
                        EventHandler eh = (EventHandler)(Events [VScrollEvent]);
@@ -1103,6 +1257,13 @@ namespace System.Windows.Forms {
                protected override void WndProc(ref Message m) {
                        base.WndProc (ref m);
                }
+
+#if NET_2_0
+               protected override bool ProcessCmdKey (ref Message m, Keys keyData)
+               {
+                       return base.ProcessCmdKey (ref m, keyData);
+               }
+#endif
                #endregion      // Protected Instance Methods
 
                #region Events
@@ -1121,17 +1282,28 @@ namespace System.Windows.Forms {
                        remove { base.BackgroundImageChanged -= value; }
                }
 
+#if NET_2_0
+               [Browsable (false)]
+               [EditorBrowsable (EditorBrowsableState.Never)]
+               public new event EventHandler BackgroundImageLayoutChanged {
+                       add { base.BackgroundImageLayoutChanged += value; }
+                       remove { base.BackgroundImageLayoutChanged -= value; }
+               }
+#endif
+
                public event ContentsResizedEventHandler ContentsResized {
                        add { Events.AddHandler (ContentsResizedEvent, value); }
                        remove { Events.RemoveHandler (ContentsResizedEvent, value); }
                }
 
+#if !NET_2_0
                [Browsable(false)]
                [EditorBrowsable(EditorBrowsableState.Never)]
                public new event EventHandler DoubleClick {
                        add { base.DoubleClick += value; }
                        remove { base.DoubleClick -= value; }
                }
+#endif
 
                [Browsable(false)]
 #if !NET_2_0
@@ -1201,6 +1373,7 @@ namespace System.Windows.Forms {
                        remove { base.QueryContinueDrag -= value; }
                }
 
+               [MonoTODO ("Event never raised")]
                public event EventHandler SelectionChanged {
                        add { Events.AddHandler (SelectionChangedEvent, value); }
                        remove { Events.RemoveHandler (SelectionChangedEvent, value); }
@@ -1219,17 +1392,70 @@ namespace System.Windows.Forms {
                        document.ExpandSelection(CaretSelection.Word, false);
                }
 
+               private class RtfSectionStyle : ICloneable {
+                       internal Color rtf_color;
+                       internal RTF.Font rtf_rtffont;
+                       internal int rtf_rtffont_size;
+                       internal FontStyle rtf_rtfstyle;
+                       internal HorizontalAlignment rtf_rtfalign;
+                       internal int rtf_par_line_left_indent;
+                       internal bool rtf_visible;
+                       internal int rtf_skip_width;
+
+                       public object Clone ()
+                       {
+                               RtfSectionStyle new_style = new RtfSectionStyle ();
+
+                               new_style.rtf_color = rtf_color;
+                               new_style.rtf_par_line_left_indent = rtf_par_line_left_indent;
+                               new_style.rtf_rtfalign = rtf_rtfalign;
+                               new_style.rtf_rtffont = rtf_rtffont;
+                               new_style.rtf_rtffont_size = rtf_rtffont_size;
+                               new_style.rtf_rtfstyle = rtf_rtfstyle;
+                               new_style.rtf_visible = rtf_visible;
+                               new_style.rtf_skip_width = rtf_skip_width;
+
+                               return new_style;
+                       }
+               }
+
+               // To allow us to keep track of the sections and revert formatting
+               // as we go in and out of sections of the document.
+               private void HandleGroup (RTF.RTF rtf)
+               {
+                       //start group - save the current formatting on to a stack
+                       //end group - go back to the formatting at the current group
+                       if (rtf_section_stack == null) {
+                               rtf_section_stack = new Stack ();
+                       }
+
+                       if (rtf.Major == RTF.Major.BeginGroup) {
+                               rtf_section_stack.Push (rtf_style.Clone ());
+                               //spec specifies resetting unicode ignore at begin group as an attempt at error
+                               //recovery.
+                               rtf_skip_count = 0;
+                       } else if (rtf.Major == RTF.Major.EndGroup) {
+                               if (rtf_section_stack.Count > 0) {
+                                       FlushText (rtf, false);
+
+                                       rtf_style = (RtfSectionStyle) rtf_section_stack.Pop ();
+                               }
+                       }
+               }
+
+               [MonoInternalNote ("Add QuadJust support for justified alignment")]
                private void HandleControl(RTF.RTF rtf) {
                        switch(rtf.Major) {
                                case RTF.Major.Unicode: {
                                        switch(rtf.Minor) {
-                                               case Minor.UnicodeCharBytes: {
-                                                       rtf_skip_width = rtf.Param;
+                                               case RTF.Minor.UnicodeCharBytes: {
+                                                       rtf_style.rtf_skip_width = rtf.Param;
                                                        break;
                                                }
 
-                                               case Minor.UnicodeChar: {
-                                                       rtf_skip_count += rtf_skip_width;
+                                               case RTF.Minor.UnicodeChar: {
+                                                       FlushText (rtf, false);
+                                                       rtf_skip_count += rtf_style.rtf_skip_width;
                                                        rtf_line.Append((char)rtf.Param);
                                                        break;
                                                }
@@ -1244,28 +1470,19 @@ namespace System.Windows.Forms {
                                }
 
                                case RTF.Major.PictAttr:
-                                       switch (rtf.Minor) {
-                                       case Minor.PngBlip:
-                                               FlushText (rtf, false);
-                                               try {
-                                                       Image img = new Bitmap (new MemoryStream (rtf.Image));
-
-                                                       Line line = document.GetLine (rtf_cursor_y);
-                                                       document.InsertImage (line, 0, img);
-                                                       rtf_cursor_x++;
-
-                                                       FlushText (rtf, true);
-                                                       rtf.Image = null;
-                                               } catch (Exception e) {
-                                                       Console.Error.WriteLine ("EXCEPTION while loading image:   {0}", e);
-                                               }
-                                               break;
+                                       if (rtf.Picture != null && rtf.Picture.IsValid ()) {
+                                               Line line = document.GetLine (rtf_cursor_y);
+                                               document.InsertPicture (line, 0, rtf.Picture);
+                                               rtf_cursor_x++;
+
+                                               FlushText (rtf, true);
+                                               rtf.Picture = null;
                                        }
                                        break;
 
                                case RTF.Major.CharAttr: {
                                        switch(rtf.Minor) {
-                                               case Minor.ForeColor: {
+                                               case RTF.Minor.ForeColor: {
                                                        System.Windows.Forms.RTF.Color  color;
 
                                                        color = System.Windows.Forms.RTF.Color.GetColor(rtf, rtf.Param);
@@ -1273,90 +1490,132 @@ namespace System.Windows.Forms {
                                                        if (color != null) {
                                                                FlushText(rtf, false);
                                                                if (color.Red == -1 && color.Green == -1 && color.Blue == -1) {
-                                                                       this.rtf_color = new SolidBrush(ForeColor);
+                                                                       this.rtf_style.rtf_color = ForeColor;
                                                                } else {
-                                                                       this.rtf_color = new SolidBrush(Color.FromArgb(color.Red, color.Green, color.Blue));
+                                                                       this.rtf_style.rtf_color = Color.FromArgb(color.Red, color.Green, color.Blue);
                                                                }
                                                                FlushText (rtf, false);
                                                        }
                                                        break;
                                                }
 
-                                               case Minor.FontSize: {
+                                               case RTF.Minor.FontSize: {
                                                        FlushText(rtf, false);
-                                                       this.rtf_rtffont_size = rtf.Param / 2;
+                                                       this.rtf_style.rtf_rtffont_size = rtf.Param / 2;
                                                        break;
                                                }
 
-                                               case Minor.FontNum: {
+                                               case RTF.Minor.FontNum: {
                                                        System.Windows.Forms.RTF.Font   font;
 
                                                        font = System.Windows.Forms.RTF.Font.GetFont(rtf, rtf.Param);
                                                        if (font != null) {
                                                                FlushText(rtf, false);
-                                                               this.rtf_rtffont = font;
+                                                               this.rtf_style.rtf_rtffont = font;
                                                        }
                                                        break;
                                                }
 
-                                               case Minor.Plain: {
+                                               case RTF.Minor.Plain: {
                                                        FlushText(rtf, false);
-                                                       rtf_rtfstyle = FontStyle.Regular;
+                                                       rtf_style.rtf_rtfstyle = FontStyle.Regular;
                                                        break;
                                                }
 
-                                               case Minor.Bold: {
+                                               case RTF.Minor.Bold: {
                                                        FlushText(rtf, false);
                                                        if (rtf.Param == RTF.RTF.NoParam) {
-                                                               rtf_rtfstyle |= FontStyle.Bold;
+                                                               rtf_style.rtf_rtfstyle |= FontStyle.Bold;
                                                        } else {
-                                                               rtf_rtfstyle &= ~FontStyle.Bold;
+                                                               rtf_style.rtf_rtfstyle &= ~FontStyle.Bold;
                                                        }
                                                        break;
                                                }
 
-                                               case Minor.Italic: {
+                                               case RTF.Minor.Italic: {
                                                        FlushText(rtf, false);
                                                        if (rtf.Param == RTF.RTF.NoParam) {
-                                                               rtf_rtfstyle |= FontStyle.Italic;
+                                                               rtf_style.rtf_rtfstyle |= FontStyle.Italic;
                                                        } else {
-                                                               rtf_rtfstyle &= ~FontStyle.Italic;
+                                                               rtf_style.rtf_rtfstyle &= ~FontStyle.Italic;
                                                        }
                                                        break;
                                                }
 
-                                               case Minor.StrikeThru: {
+                                               case RTF.Minor.StrikeThru: {
                                                        FlushText(rtf, false);
                                                        if (rtf.Param == RTF.RTF.NoParam) {
-                                                               rtf_rtfstyle |= FontStyle.Strikeout;
+                                                               rtf_style.rtf_rtfstyle |= FontStyle.Strikeout;
                                                        } else {
-                                                               rtf_rtfstyle &= ~FontStyle.Strikeout;
+                                                               rtf_style.rtf_rtfstyle &= ~FontStyle.Strikeout;
                                                        }
                                                        break;
                                                }
 
-                                               case Minor.Underline: {
+                                               case RTF.Minor.Underline: {
                                                        FlushText(rtf, false);
                                                        if (rtf.Param == RTF.RTF.NoParam) {
-                                                               rtf_rtfstyle |= FontStyle.Underline;
+                                                               rtf_style.rtf_rtfstyle |= FontStyle.Underline;
                                                        } else {
-                                                               rtf_rtfstyle = rtf_rtfstyle & ~FontStyle.Underline;
+                                                               rtf_style.rtf_rtfstyle = rtf_style.rtf_rtfstyle & ~FontStyle.Underline;
                                                        }
                                                        break;
                                                }
 
-                                               case Minor.NoUnderline: {
+                                               case RTF.Minor.Invisible: {
+                                                       FlushText (rtf, false);
+                                                       rtf_style.rtf_visible = false;
+                                                       break;
+                                               }
+
+                                               case RTF.Minor.NoUnderline: {
                                                        FlushText(rtf, false);
-                                                       rtf_rtfstyle &= ~FontStyle.Underline;
+                                                       rtf_style.rtf_rtfstyle &= ~FontStyle.Underline;
                                                        break;
                                                }
                                        }
                                        break;
                                }
 
-                               case RTF.Major.SpecialChar: {
+                       case RTF.Major.ParAttr: {
+                               switch (rtf.Minor) {
+
+                               case RTF.Minor.ParDef:
+                                       FlushText (rtf, false);
+                                       rtf_style.rtf_par_line_left_indent = 0;
+                                       rtf_style.rtf_rtfalign = HorizontalAlignment.Left;
+                                       break;
+
+                               case RTF.Minor.LeftIndent:
+                                       rtf_style.rtf_par_line_left_indent = (int) (((float) rtf.Param / 1440.0F) * CreateGraphics ().DpiX + 0.5F);
+                                       break;
+
+                               case RTF.Minor.QuadCenter:
+                                       FlushText (rtf, false);
+                                       rtf_style.rtf_rtfalign = HorizontalAlignment.Center;
+                                       break;
+
+                               case RTF.Minor.QuadJust:
+                                       FlushText (rtf, false);
+                                       rtf_style.rtf_rtfalign = HorizontalAlignment.Center;
+                                       break;
+
+                               case RTF.Minor.QuadLeft:
+                                       FlushText (rtf, false);
+                                       rtf_style.rtf_rtfalign = HorizontalAlignment.Left;
+                                       break;
+
+                               case RTF.Minor.QuadRight:
+                                       FlushText (rtf, false);
+                                       rtf_style.rtf_rtfalign = HorizontalAlignment.Right;
+                                       break;
+                               }
+                               break;
+                       }
+
+                       case RTF.Major.SpecialChar: {
                                        //Console.Write("[Got SpecialChar control {0}]", rtf.Minor);
-                                       SpecialChar(rtf);
+                                       SpecialChar (rtf);
                                        break;
                                }
                        }
@@ -1364,72 +1623,72 @@ namespace System.Windows.Forms {
 
                private void SpecialChar(RTF.RTF rtf) {
                        switch(rtf.Minor) {
-                               case Minor.Page:
-                               case Minor.Sect:
-                               case Minor.Row:
-                               case Minor.Line:
-                               case Minor.Par: {
+                               case RTF.Minor.Page:
+                               case RTF.Minor.Sect:
+                               case RTF.Minor.Row:
+                               case RTF.Minor.Line:
+                               case RTF.Minor.Par: {
                                        FlushText(rtf, true);
                                        break;
                                }
 
-                               case Minor.Cell: {
+                               case RTF.Minor.Cell: {
                                        Console.Write(" ");
                                        break;
                                }
 
-                               case Minor.NoBrkSpace: {
+                               case RTF.Minor.NoBrkSpace: {
                                        Console.Write(" ");
                                        break;
                                }
 
-                               case Minor.Tab: {
+                               case RTF.Minor.Tab: {
                                        rtf_line.Append ("\t");
 //                                     FlushText (rtf, false);
                                        break;
                                }
 
-                               case Minor.NoReqHyphen:
-                               case Minor.NoBrkHyphen: {
+                               case RTF.Minor.NoReqHyphen:
+                               case RTF.Minor.NoBrkHyphen: {
                                        rtf_line.Append ("-");
 //                                     FlushText (rtf, false);
                                        break;
                                }
 
-                               case Minor.Bullet: {
+                               case RTF.Minor.Bullet: {
                                        Console.WriteLine("*");
                                        break;
                                }
 
-                       case Minor.WidowCtrl:
+                       case RTF.Minor.WidowCtrl:
                                break;
 
-                               case Minor.EmDash: {
+                               case RTF.Minor.EmDash: {
                                rtf_line.Append ("\u2014");
                                        break;
                                }
 
-                               case Minor.EnDash: {
+                               case RTF.Minor.EnDash: {
                                        rtf_line.Append ("\u2013");
                                        break;
                                }
 /*
-                               case Minor.LQuote: {
+                               case RTF.Minor.LQuote: {
                                        Console.Write("\u2018");
                                        break;
                                }
 
-                               case Minor.RQuote: {
+                               case RTF.Minor.RQuote: {
                                        Console.Write("\u2019");
                                        break;
                                }
 
-                               case Minor.LDblQuote: {
+                               case RTF.Minor.LDblQuote: {
                                        Console.Write("\u201C");
                                        break;
                                }
 
-                               case Minor.RDblQuote: {
+                               case RTF.Minor.RDblQuote: {
                                        Console.Write("\u201D");
                                        break;
                                }
@@ -1443,11 +1702,17 @@ namespace System.Windows.Forms {
                }
 
                private void HandleText(RTF.RTF rtf) {
-                       if (rtf_skip_count > 0) {
-                               rtf_skip_count--;
-                               return;
+                       string str = rtf.EncodedText;
+
+                       //todo - simplistically skips characters, should skip bytes?
+                       if (rtf_skip_count > 0 && str.Length > 0) {
+                               int iToRemove = Math.Min (rtf_skip_count, str.Length);
+
+                               str = str.Substring (iToRemove);
+                               rtf_skip_count-=iToRemove;
                        }
 
+                       /*
                        if ((RTF.StandardCharCode)rtf.Minor != RTF.StandardCharCode.nothing) {
                                rtf_line.Append(rtf_text_map[(RTF.StandardCharCode)rtf.Minor]);
                        } else {
@@ -1458,6 +1723,10 @@ namespace System.Windows.Forms {
                                        Console.Write("[Literal:0x{0:X2}]", (int)rtf.Major);
                                }
                        }
+                       */
+
+                       if  (rtf_style.rtf_visible)
+                               rtf_line.Append (str);
                }
 
                private void FlushText(RTF.RTF rtf, bool newline) {
@@ -1469,42 +1738,61 @@ namespace System.Windows.Forms {
                                return;
                        }
 
-                       if (rtf_rtffont == null) {
+                       if (rtf_style.rtf_rtffont == null) {
                                // First font in table is default
-                               rtf_rtffont = System.Windows.Forms.RTF.Font.GetFont(rtf, 0);
+                               rtf_style.rtf_rtffont = System.Windows.Forms.RTF.Font.GetFont (rtf, 0);
                        }
 
-                       font = new Font(rtf_rtffont.Name, rtf_rtffont_size, rtf_rtfstyle);
+                       font = new Font (rtf_style.rtf_rtffont.Name, rtf_style.rtf_rtffont_size, rtf_style.rtf_rtfstyle);
 
-                       if (rtf_color == null) {
+                       if (rtf_style.rtf_color == Color.Empty) {
                                System.Windows.Forms.RTF.Color color;
 
                                // First color in table is default
-                               color = System.Windows.Forms.RTF.Color.GetColor(rtf, 0);
+                               color = System.Windows.Forms.RTF.Color.GetColor (rtf, 0);
 
                                if ((color == null) || (color.Red == -1 && color.Green == -1 && color.Blue == -1)) {
-                                       rtf_color = new SolidBrush(ForeColor);
+                                       rtf_style.rtf_color = ForeColor;
                                } else {
-                                       rtf_color = new SolidBrush(Color.FromArgb(color.Red, color.Green, color.Blue));
+                                       rtf_style.rtf_color = Color.FromArgb (color.Red, color.Green, color.Blue);
                                }
-                               
+
                        }
 
                        rtf_chars += rtf_line.Length;
 
-                       if (rtf_cursor_x == 0) {
-                               document.Add(rtf_cursor_y, rtf_line.ToString(), rtf_rtfalign, font, rtf_color);
+                       // Try to re-use if we are told so - this usually happens when we are inserting a flow of rtf text
+                       // with an already alive line.
+                       if (rtf_cursor_x == 0 && !reuse_line) {
+                               if (newline && rtf_line.ToString ().EndsWith (Environment.NewLine) == false)
+                                       rtf_line.Append (Environment.NewLine);
+
+                               document.Add (rtf_cursor_y, rtf_line.ToString (), rtf_style.rtf_rtfalign, font, rtf_style.rtf_color,
+                                                               newline ? LineEnding.Rich : LineEnding.Wrap);
+                               if (rtf_style.rtf_par_line_left_indent != 0) {
+                                       Line line = document.GetLine (rtf_cursor_y);
+                                       line.indent = rtf_style.rtf_par_line_left_indent;
+                               }
                        } else {
-                               Line    line;
+                               Line line;
 
-                               line = document.GetLine(rtf_cursor_y);
+                               line = document.GetLine (rtf_cursor_y);
+                               line.indent = rtf_style.rtf_par_line_left_indent;
                                if (rtf_line.Length > 0) {
-                                       document.InsertString(line, rtf_cursor_x, rtf_line.ToString());
-                                       document.FormatText(line, rtf_cursor_x + 1, line, rtf_cursor_x + 1 + length, font, rtf_color, null, FormatSpecified.Font | FormatSpecified.Color); // FormatText is 1-based
+                                       document.InsertString (line, rtf_cursor_x, rtf_line.ToString ());
+                                       document.FormatText (line, rtf_cursor_x + 1, line, rtf_cursor_x + 1 + length,
+                           font, rtf_style.rtf_color, Color.Empty,
+                                                       FormatSpecified.Font | FormatSpecified.Color);
                                }
                                if (newline) {
-                                       document.Split(line, rtf_cursor_x + length);
+                                       line = document.GetLine (rtf_cursor_y);
+                                       line.ending = LineEnding.Rich;
+
+                                       if (line.Text.EndsWith (Environment.NewLine) == false)
+                                               line.Text += Environment.NewLine;
                                }
+
+                               reuse_line = false; // sanity assignment - in this case we have already re-used one line.
                        }
 
                        if (newline) {
@@ -1532,15 +1820,17 @@ namespace System.Windows.Forms {
                        // Prepare
                        rtf.ClassCallback[RTF.TokenClass.Text] = new RTF.ClassDelegate(HandleText);
                        rtf.ClassCallback[RTF.TokenClass.Control] = new RTF.ClassDelegate(HandleControl);
+                       rtf.ClassCallback[RTF.TokenClass.Group] = new RTF.ClassDelegate(HandleGroup);
 
-                       rtf_skip_width = 0;
                        rtf_skip_count = 0;
                        rtf_line = new StringBuilder();
-                       rtf_color = null;
-                       rtf_rtffont_size = (int)this.Font.Size;
-                       rtf_rtfalign = HorizontalAlignment.Left;
-                       rtf_rtfstyle = FontStyle.Regular;
-                       rtf_rtffont = null;
+                       rtf_style.rtf_color = Color.Empty;
+                       rtf_style.rtf_rtffont_size = (int)this.Font.Size;
+                       rtf_style.rtf_rtfalign = HorizontalAlignment.Left;
+                       rtf_style.rtf_rtfstyle = FontStyle.Regular;
+                       rtf_style.rtf_rtffont = null;
+                       rtf_style.rtf_visible = true;
+                       rtf_style.rtf_skip_width = 1;
                        rtf_cursor_x = cursor_x;
                        rtf_cursor_y = cursor_y;
                        rtf_chars = 0;
@@ -1570,6 +1860,10 @@ namespace System.Windows.Forms {
                        to_y = rtf_cursor_y;
                        chars = rtf_chars;
 
+                       // clear the section stack if it was used
+                       if (rtf_section_stack != null)
+                               rtf_section_stack.Clear();
+
                        document.RecalculateDocument(CreateGraphicsInternal(), cursor_y, document.Lines, false);
                        document.ResumeRecalc (true);
 
@@ -1654,9 +1948,55 @@ namespace System.Windows.Forms {
                        }
                }
 
-               [MonoTODO("Emit unicode and other special characters properly")]
+               static readonly char [] ReservedRTFChars = new char [] { '\\', '{', '}' };
+
                private void EmitRTFText(StringBuilder rtf, string text) {
-                       rtf.Append(text);
+                       int start = rtf.Length;
+                       int count = text.Length;
+
+                       // First emit simple unicode chars as escaped
+                       EmitEscapedUnicode (rtf, text);
+
+                       // This method emits user text *only*, so it's safe to escape any reserved rtf chars
+                       // Escape '\' first, since it is used later to escape the other chars
+                       if (text.IndexOfAny (ReservedRTFChars) > -1) {
+                               rtf.Replace ("\\", "\\\\", start, count);
+                               rtf.Replace ("{", "\\{", start, count);
+                               rtf.Replace ("}", "\\}", start, count);
+                       }
+               }
+
+               // The chars to be escaped use "\'" + its hexadecimal value.
+               private void EmitEscapedUnicode (StringBuilder sb, string text)
+               {
+                       int pos;
+                       int start = 0;
+
+                       while ((pos = IndexOfNonAscii (text, start)) > -1) {
+                               sb.Append (text, start, pos - start);
+
+                               int n = (int)text [pos];
+                               sb.Append ("\\'");
+                               sb.Append (n.ToString ("X"));
+
+                               start = pos + 1;
+                       }
+
+                       // Append remaining (maybe all) the text value.
+                       if (start < text.Length)
+                               sb.Append (text, start, text.Length - start);
+               }
+
+               // MS seems to be escaping values larger than 0x80
+               private int IndexOfNonAscii (string text, int startIndex)
+               {
+                       for (int i = startIndex; i < text.Length; i++) {
+                               int n = (int)text [i];
+                               if (n < 0 || n >= 0x80)
+                                       return i;
+                       }
+
+                       return -1;
                }
 
                // start_pos and end_pos are 0-based
@@ -1688,8 +2028,8 @@ namespace System.Windows.Forms {
                        // Add default font and color; to optimize document content we don't
                        // use this.Font and this.ForeColor but the font/color from the first tag
                        tag = LineTag.FindTag(start_line, pos);
-                       font = tag.font;
-                       color = ((SolidBrush)tag.color).Color;
+                       font = tag.Font;
+                       color = tag.Color;
                        fonts.Add(font.Name);
                        colors.Add(color);
 
@@ -1704,22 +2044,22 @@ namespace System.Windows.Forms {
                                }
 
                                while (pos < line_len) {
-                                       if (tag.font.Name != font.Name) {
-                                               font = tag.font;
+                                       if (tag.Font.Name != font.Name) {
+                                               font = tag.Font;
                                                if (!fonts.Contains(font.Name)) {
                                                        fonts.Add(font.Name);
                                                }
                                        }
 
-                                       if (((SolidBrush)tag.color).Color != color) {
-                                               color = ((SolidBrush)tag.color).Color;
+                                       if (tag.Color != color) {
+                                               color = tag.Color;
                                                if (!colors.Contains(color)) {
                                                        colors.Add(color);
                                                }
                                        }
 
-                                       pos = tag.start + tag.length - 1;
-                                       tag = tag.next;
+                                       pos = tag.Start + tag.Length - 1;
+                                       tag = tag.Next;
                                }
                                pos = 0;
                                line_no++;
@@ -1733,7 +2073,7 @@ namespace System.Windows.Forms {
                        sb.Append(String.Format("\\deff{0}", fonts.IndexOf(this.Font.Name)));
 
                        // Default Language 
-                       sb.Append("\\deflang1033\n");   // FIXME - always 1033?
+                       sb.Append("\\deflang1033" + Environment.NewLine);       // FIXME - always 1033?
 
                        // Emit the font table
                        sb.Append("{\\fonttbl");
@@ -1744,7 +2084,8 @@ namespace System.Windows.Forms {
                                sb.Append((string)fonts[i]);            // Font name
                                sb.Append(";}");                        // }
                        }
-                       sb.Append("}\n");
+                       sb.Append("}");
+                       sb.Append(Environment.NewLine);
 
                        // Emit the color table (if needed)
                        if ((colors.Count > 1) || ((((Color)colors[0]).R != this.ForeColor.R) || (((Color)colors[0]).G != this.ForeColor.G) || (((Color)colors[0]).B != this.ForeColor.B))) {
@@ -1755,17 +2096,18 @@ namespace System.Windows.Forms {
                                        sb.Append(String.Format("\\blue{0}", ((Color)colors[i]).B));
                                        sb.Append(";");
                                }
-                               sb.Append("}\n");
+                               sb.Append("}");
+                               sb.Append(Environment.NewLine);
                        }
 
                        sb.Append("{\\*\\generator Mono RichTextBox;}");
                        // Emit initial paragraph settings
                        tag = LineTag.FindTag(start_line, start_pos);
                        sb.Append("\\pard");    // Reset to default paragraph properties
-                       EmitRTFFontProperties(sb, -1, fonts.IndexOf(tag.font.Name), null, tag.font);    // Font properties
+                       EmitRTFFontProperties(sb, -1, fonts.IndexOf(tag.Font.Name), null, tag.Font);    // Font properties
                        sb.Append(" ");         // Space separator
 
-                       font = tag.font;
+                       font = tag.Font;
                        color = (Color)colors[0];
                        line = start_line;
                        line_no = start_line.line_no;
@@ -1784,13 +2126,13 @@ namespace System.Windows.Forms {
                                while (pos < line_len) {
                                        length = sb.Length;
 
-                                       if (tag.font != font) {
-                                               EmitRTFFontProperties(sb, fonts.IndexOf(font.Name), fonts.IndexOf(tag.font.Name), font, tag.font);
-                                               font = tag.font;
+                                       if (tag.Font != font) {
+                                               EmitRTFFontProperties(sb, fonts.IndexOf(font.Name), fonts.IndexOf(tag.Font.Name), font, tag.Font);
+                                               font = tag.Font;
                                        }
 
-                                       if (((SolidBrush)tag.color).Color != color) {
-                                               color = ((SolidBrush)tag.color).Color;
+                                       if (tag.Color != color) {
+                                               color = tag.Color;
                                                sb.Append(String.Format("\\cf{0}", colors.IndexOf(color)));
                                        }
                                        if (length != sb.Length) {
@@ -1799,29 +2141,31 @@ namespace System.Windows.Forms {
 
                                        // Emit the string itself
                                        if (line_no != end_line.line_no) {
-                                               EmitRTFText(sb, tag.line.text.ToString(pos, tag.start + tag.length - pos - 1));
+                                               EmitRTFText(sb, tag.Line.text.ToString(pos, tag.Start + tag.Length - pos - 1));
                                        } else {
-                                               if (end_pos < (tag.start + tag.length - 1)) {
+                                               if (end_pos < (tag.Start + tag.Length - 1)) {
                                                        // Emit partial tag only, end_pos is inside this tag
-                                                       EmitRTFText(sb, tag.line.text.ToString(pos, end_pos - pos));
+                                                       EmitRTFText(sb, tag.Line.text.ToString(pos, end_pos - pos));
                                                } else {
-                                                       EmitRTFText(sb, tag.line.text.ToString(pos, tag.start + tag.length - pos - 1));
+                                                       EmitRTFText(sb, tag.Line.text.ToString(pos, tag.Start + tag.Length - pos - 1));
                                                }
                                        }
 
-                                       pos = tag.start + tag.length - 1;
-                                       tag = tag.next;
+                                       pos = tag.Start + tag.Length - 1;
+                                       tag = tag.Next;
                                }
                                if (pos >= line.text.Length) {
-                                       if (!line.soft_break) {
-                                               sb.Append("\\par\n");
+                                       if (line.ending != LineEnding.Wrap) {
+                                               sb.Append("\\par");
+                                               sb.Append(Environment.NewLine);
                                        }
                                }
                                pos = 0;
                                line_no++;
                        }
 
-                       sb.Append("}\n");
+                       sb.Append("}");
+                       sb.Append(Environment.NewLine);
 
                        return sb;
                }