New tests.
[mono.git] / mcs / class / Managed.Windows.Forms / System.Windows.Forms / RichTextBox.cs
index 12f036570237a40c3e543c8f0568576ec2cf3653..1db7f29a519e0819d7696faeb9cff1a41f001da9 100644 (file)
@@ -48,6 +48,7 @@ namespace System.Windows.Forms {
                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 StringBuilder   rtf_line;
@@ -57,7 +58,6 @@ namespace System.Windows.Forms {
                private Stack           rtf_section_stack;
 
                private RTF.TextMap rtf_text_map;
-               private int rtf_skip_width;
                private int rtf_skip_count;
                private int             rtf_cursor_x;
                private int             rtf_cursor_y;
@@ -74,16 +74,17 @@ namespace System.Windows.Forms {
                #region Public Constructors
                public RichTextBox() {
                        accepts_return = true;
+                       auto_size = false;
                        auto_word_select = false;
                        bullet_indent = 0;
-                       max_length = Int32.MaxValue;
+                       base.MaxLength = Int32.MaxValue;
                        margin_right = 0;
                        zoom = 1;
                        base.Multiline = true;
                        document.CRLFSize = 1;
                        shortcuts_enabled = true;
-                       disabled_foreground_grey = false;
                        base.EnableLinks = true;
+                       richtext = true;
                        
                        rtf_style = new RtfSectionStyle ();
                        rtf_section_stack = null;
@@ -132,6 +133,11 @@ namespace System.Windows.Forms {
                        return backColor;
                }
 
+               internal override void RaiseSelectionChanged()
+               {
+                       OnSelectionChanged (EventArgs.Empty);
+               }
+               
                private void RichTextBox_LostFocus(object sender, EventArgs e) {
                        Invalidate();
                }
@@ -174,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)]
@@ -228,7 +230,7 @@ namespace System.Windows.Forms {
                }
 
 #if NET_2_0
-               [MonoTODO ("Stub")]
+               [MonoTODO ("Stub, does nothing")]
                [DefaultValue (false)]
                public bool EnableAutoDragDrop {
                        get { return enable_auto_drag_drop; }
@@ -273,7 +275,7 @@ namespace System.Windows.Forms {
                }
 
 #if NET_2_0
-               [MonoTODO ("Stub")]
+               [MonoTODO ("Stub, does nothing")]
                [Browsable (false)]
                [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
                public RichTextBoxLanguageOptions LanguageOption {
@@ -284,13 +286,8 @@ namespace System.Windows.Forms {
 
                [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)]
@@ -306,7 +303,6 @@ namespace System.Windows.Forms {
 
                [Browsable(false)]
                [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
-               [MonoTODO]
                public string RedoActionName {
                        get {
                                return document.undo.RedoActionName;
@@ -314,7 +310,7 @@ namespace System.Windows.Forms {
                }
 
 #if NET_2_0
-               [MonoTODO ("Stub")]
+               [MonoTODO ("Stub, does nothing")]
                [Browsable (false)]
                [DefaultValue (true)]
                [EditorBrowsable (EditorBrowsableState.Never)]
@@ -326,7 +322,8 @@ namespace System.Windows.Forms {
 
                [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;
@@ -411,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();
@@ -432,6 +443,8 @@ namespace System.Windows.Forms {
                        }
 
                        set {
+                               // TextBox/TextBoxBase don't set Modified in this same property
+                               Modified = true;
                                base.SelectedText = value;
                        }
                }
@@ -491,7 +504,7 @@ namespace System.Windows.Forms {
                }
 
 #if NET_2_0
-               [MonoTODO ("Stub")]
+               [MonoTODO ("Stub, does nothing")]
                [Browsable (false)]
                [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
                public Color SelectionBackColor {
@@ -503,7 +516,7 @@ namespace System.Windows.Forms {
                [Browsable(false)]
                [DefaultValue(false)]
                [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
-               [MonoTODO]
+               [MonoTODO ("Stub, does nothing")]
                public bool SelectionBullet {
                        get {
                                return false;
@@ -516,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;
@@ -535,16 +548,25 @@ namespace System.Windows.Forms {
                                LineTag end;
                                LineTag tag;
 
-                               start = document.selection_start.line.FindTag (document.selection_start.pos);
-                               end = document.selection_start.line.FindTag (document.selection_end.pos);
+                               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 (tag != null && tag != end) {
+                               while (tag != null) {
 
                                        if (!color.Equals (tag.Color))
                                                return Color.Empty;
 
+                                       if (tag == end)
+                                               break;
+
                                        tag = document.NextTag (tag);
                                }
 
@@ -569,7 +591,10 @@ namespace System.Windows.Forms {
                                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);
                        }
                }
 
@@ -582,17 +607,26 @@ namespace System.Windows.Forms {
                                LineTag end;
                                LineTag tag;
 
-                               start = document.selection_start.line.FindTag (document.selection_start.pos);
-                               end = document.selection_start.line.FindTag (document.selection_end.pos);
+                               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;
+                               }
+
                                font = start.Font;
 
                                if (selection_length > 1) {
                                        tag = start;
-                                       while (tag != null && tag != end) {
+                                       while (tag != null) {
 
                                                if (!font.Equals(tag.Font))
                                                        return null;
 
+                                               if (tag == end)
+                                                       break;
+
                                                tag = document.NextTag (tag);
                                        }
                                }
@@ -615,7 +649,8 @@ namespace System.Windows.Forms {
                                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);
 
                        }
                }
@@ -623,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;
@@ -636,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;
@@ -661,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;
@@ -674,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;
@@ -686,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];
@@ -714,7 +749,7 @@ namespace System.Windows.Forms {
                }
 
                [DefaultValue(false)]
-               [MonoTODO]
+               [MonoTODO ("Stub, does nothing")]
                public bool ShowSelectionMargin {
                        get {
                                return false;
@@ -962,8 +997,8 @@ namespace System.Windows.Forms {
                        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) {
@@ -988,6 +1023,11 @@ namespace System.Windows.Forms {
                                        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;
                        }
@@ -999,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) {
@@ -1037,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) {
@@ -1063,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());
@@ -1128,18 +1166,11 @@ namespace System.Windows.Forms {
 
 #if NET_2_0
                [EditorBrowsable (EditorBrowsableState.Never)]
-               public new void DrawToBitmap (Bitmap bitmap, Rectangle clip)
+               public new void DrawToBitmap (Bitmap bitmap, Rectangle targetBounds)
                {
                        Graphics dc = Graphics.FromImage (bitmap);
 
-                       if (backcolor_set || (Enabled && !read_only)) {
-                               dc.FillRectangle (ThemeEngine.Current.ResPool.GetSolidBrush (BackColor), clip);
-                       } else {
-                               dc.FillRectangle (ThemeEngine.Current.ResPool.GetSolidBrush (ThemeEngine.Current.ColorControl), clip);
-                       }
-                       
-                       // Draw the viewable document
-                       document.Draw (dc, clip);
+                       Draw (dc, targetBounds);
                }
 #endif
 
@@ -1178,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)
@@ -1228,9 +1259,9 @@ namespace System.Windows.Forms {
                }
 
 #if NET_2_0
-               protected override bool ProcessCmdKey (ref Message msg, Keys keyData)
+               protected override bool ProcessCmdKey (ref Message m, Keys keyData)
                {
-                       return base.ProcessCmdKey (ref msg, keyData);
+                       return base.ProcessCmdKey (ref m, keyData);
                }
 #endif
                #endregion      // Protected Instance Methods
@@ -1342,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); }
@@ -1367,6 +1399,8 @@ namespace System.Windows.Forms {
                        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 ()
                        {
@@ -1378,6 +1412,8 @@ namespace System.Windows.Forms {
                                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;
                        }
@@ -1395,6 +1431,9 @@ namespace System.Windows.Forms {
 
                        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);
@@ -1404,18 +1443,19 @@ namespace System.Windows.Forms {
                        }
                }
 
-               [MonoTODO("Add QuadJust support for justified alignment")]
+               [MonoInternalNote ("Add QuadJust support for justified alignment")]
                private void HandleControl(RTF.RTF rtf) {
                        switch(rtf.Major) {
                                case RTF.Major.Unicode: {
                                        switch(rtf.Minor) {
                                                case RTF.Minor.UnicodeCharBytes: {
-                                                       rtf_skip_width = rtf.Param;
+                                                       rtf_style.rtf_skip_width = rtf.Param;
                                                        break;
                                                }
 
                                                case RTF.Minor.UnicodeChar: {
-                                                       rtf_skip_count += rtf_skip_width;
+                                                       FlushText (rtf, false);
+                                                       rtf_skip_count += rtf_style.rtf_skip_width;
                                                        rtf_line.Append((char)rtf.Param);
                                                        break;
                                                }
@@ -1522,6 +1562,12 @@ namespace System.Windows.Forms {
                                                        break;
                                                }
 
+                                               case RTF.Minor.Invisible: {
+                                                       FlushText (rtf, false);
+                                                       rtf_style.rtf_visible = false;
+                                                       break;
+                                               }
+
                                                case RTF.Minor.NoUnderline: {
                                                        FlushText(rtf, false);
                                                        rtf_style.rtf_rtfstyle &= ~FontStyle.Underline;
@@ -1656,9 +1702,14 @@ 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;
                        }
 
                        /*
@@ -1673,7 +1724,9 @@ namespace System.Windows.Forms {
                                }
                        }
                        */
-                       rtf_line.Append (rtf.EncodedText);
+
+                       if  (rtf_style.rtf_visible)
+                               rtf_line.Append (str);
                }
 
                private void FlushText(RTF.RTF rtf, bool newline) {
@@ -1708,9 +1761,12 @@ namespace System.Windows.Forms {
 
                        rtf_chars += rtf_line.Length;
 
+                       // 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);
 
-
-                       if (rtf_cursor_x == 0) {
                                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) {
@@ -1729,10 +1785,14 @@ namespace System.Windows.Forms {
                                                        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) {
@@ -1762,7 +1822,6 @@ namespace System.Windows.Forms {
                        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_style.rtf_color = Color.Empty;
@@ -1770,6 +1829,8 @@ namespace System.Windows.Forms {
                        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;
@@ -1887,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
@@ -1966,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");
@@ -1977,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))) {
@@ -1988,7 +2096,8 @@ 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;}");
@@ -2047,14 +2156,16 @@ namespace System.Windows.Forms {
                                }
                                if (pos >= line.text.Length) {
                                        if (line.ending != LineEnding.Wrap) {
-                                               sb.Append("\\par\n");
+                                               sb.Append("\\par");
+                                               sb.Append(Environment.NewLine);
                                        }
                                }
                                pos = 0;
                                line_no++;
                        }
 
-                       sb.Append("}\n");
+                       sb.Append("}");
+                       sb.Append(Environment.NewLine);
 
                        return sb;
                }