Free cookie consent management tool by TermsFeed Policy Generator

source: branches/2389-EpsLexicase/HeuristicLab.ExtLibs/HeuristicLab.AvalonEdit/5.0.1/AvalonEdit-5.0.1/Highlighting/HtmlRichTextWriter.cs @ 15945

Last change on this file since 15945 was 11700, checked in by jkarder, 10 years ago

#2077: created branch and added first version

File size: 6.9 KB
Line 
1// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
2//
3// Permission is hereby granted, free of charge, to any person obtaining a copy of this
4// software and associated documentation files (the "Software"), to deal in the Software
5// without restriction, including without limitation the rights to use, copy, modify, merge,
6// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
7// to whom the Software is furnished to do so, subject to the following conditions:
8//
9// The above copyright notice and this permission notice shall be included in all copies or
10// substantial portions of the Software.
11//
12// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
13// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
14// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
15// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
16// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
17// DEALINGS IN THE SOFTWARE.
18
19using System;
20using System.Collections.Generic;
21using System.IO;
22#if DOTNET4
23using System.Net;
24#else
25using System.Web;
26#endif
27using System.Text;
28using System.Windows;
29using System.Windows.Media;
30using ICSharpCode.AvalonEdit.Utils;
31
32namespace ICSharpCode.AvalonEdit.Highlighting
33{
34  /// <summary>
35  /// RichTextWriter implementation that produces HTML.
36  /// </summary>
37  class HtmlRichTextWriter : RichTextWriter
38  {
39    readonly TextWriter htmlWriter;
40    readonly HtmlOptions options;
41    Stack<string> endTagStack = new Stack<string>();
42    bool spaceNeedsEscaping = true;
43    bool hasSpace;
44    bool needIndentation = true;
45    int indentationLevel;
46   
47    /// <summary>
48    /// Creates a new HtmlRichTextWriter instance.
49    /// </summary>
50    /// <param name="htmlWriter">
51    /// The text writer where the raw HTML is written to.
52    /// The HtmlRichTextWriter does not take ownership of the htmlWriter;
53    /// disposing the HtmlRichTextWriter will not dispose the underlying htmlWriter!
54    /// </param>
55    /// <param name="options">Options that control the HTML output.</param>
56    public HtmlRichTextWriter(TextWriter htmlWriter, HtmlOptions options = null)
57    {
58      if (htmlWriter == null)
59        throw new ArgumentNullException("htmlWriter");
60      this.htmlWriter = htmlWriter;
61      this.options = options ?? new HtmlOptions();
62    }
63   
64    /// <inheritdoc/>
65    public override Encoding Encoding {
66      get { return htmlWriter.Encoding; }
67    }
68   
69    /// <inheritdoc/>
70    public override void Flush()
71    {
72      FlushSpace(true); // next char potentially might be whitespace
73      htmlWriter.Flush();
74    }
75   
76    /// <inheritdoc/>
77    protected override void Dispose(bool disposing)
78    {
79      if (disposing) {
80        FlushSpace(true);
81      }
82      base.Dispose(disposing);
83    }
84   
85    void FlushSpace(bool nextIsWhitespace)
86    {
87      if (hasSpace) {
88        if (spaceNeedsEscaping || nextIsWhitespace)
89          htmlWriter.Write("&nbsp;");
90        else
91          htmlWriter.Write(' ');
92        hasSpace = false;
93        spaceNeedsEscaping = true;
94      }
95    }
96   
97    void WriteIndentation()
98    {
99      if (needIndentation) {
100        for (int i = 0; i < indentationLevel; i++) {
101          WriteChar('\t');
102        }
103        needIndentation = false;
104      }
105    }
106   
107    /// <inheritdoc/>
108    public override void Write(char value)
109    {
110      WriteIndentation();
111      WriteChar(value);
112    }
113   
114    static readonly char[] specialChars = { ' ', '\t', '\r', '\n' };
115   
116    void WriteChar(char c)
117    {
118      bool isWhitespace = char.IsWhiteSpace(c);
119      FlushSpace(isWhitespace);
120      switch (c) {
121        case ' ':
122          if (spaceNeedsEscaping)
123            htmlWriter.Write("&nbsp;");
124          else
125            hasSpace = true;
126          break;
127        case '\t':
128          for (int i = 0; i < options.TabSize; i++) {
129            htmlWriter.Write("&nbsp;");
130          }
131          break;
132        case '\r':
133          break; // ignore; we'll write the <br/> with the following \n
134        case '\n':
135          htmlWriter.Write("<br/>");
136          needIndentation = true;
137          break;
138        default:
139          #if DOTNET4
140          WebUtility.HtmlEncode(c.ToString(), htmlWriter);
141          #else
142          HttpUtility.HtmlEncode(c.ToString(), htmlWriter);
143          #endif
144          break;
145      }
146      // If we just handled a space by setting hasSpace = true,
147      // we mustn't set spaceNeedsEscaping as doing so would affect our own space,
148      // not just the following spaces.
149      if (c != ' ') {
150        // Following spaces must be escaped if c was a newline/tab;
151        // and they don't need escaping if c was a normal character.
152        spaceNeedsEscaping = isWhitespace;
153      }
154    }
155   
156    /// <inheritdoc/>
157    public override void Write(string value)
158    {
159      int pos = 0;
160      do {
161        int endPos = value.IndexOfAny(specialChars, pos);
162        if (endPos < 0) {
163          WriteSimpleString(value.Substring(pos));
164          return; // reached end of string
165        }
166        if (endPos > pos)
167          WriteSimpleString(value.Substring(pos, endPos - pos));
168        WriteChar(value[pos]);
169        pos = endPos + 1;
170      } while (pos < value.Length);
171    }
172   
173    void WriteIndentationAndSpace()
174    {
175      WriteIndentation();
176      FlushSpace(false);
177    }
178   
179    void WriteSimpleString(string value)
180    {
181      if (value.Length == 0)
182        return;
183      WriteIndentationAndSpace();
184      #if DOTNET4
185      WebUtility.HtmlEncode(value, htmlWriter);
186      #else
187      HttpUtility.HtmlEncode(value, htmlWriter);
188      #endif
189    }
190   
191    /// <inheritdoc/>
192    public override void Indent()
193    {
194      indentationLevel++;
195    }
196   
197    /// <inheritdoc/>
198    public override void Unindent()
199    {
200      if (indentationLevel == 0)
201        throw new NotSupportedException();
202      indentationLevel--;
203    }
204   
205    /// <inheritdoc/>
206    protected override void BeginUnhandledSpan()
207    {
208      endTagStack.Push(null);
209    }
210   
211    /// <inheritdoc/>
212    public override void EndSpan()
213    {
214      htmlWriter.Write(endTagStack.Pop());
215    }
216   
217    /// <inheritdoc/>
218    public override void BeginSpan(Color foregroundColor)
219    {
220      BeginSpan(new HighlightingColor { Foreground = new SimpleHighlightingBrush(foregroundColor) });
221    }
222   
223    /// <inheritdoc/>
224    public override void BeginSpan(FontFamily fontFamily)
225    {
226      BeginUnhandledSpan(); // TODO
227    }
228   
229    /// <inheritdoc/>
230    public override void BeginSpan(FontStyle fontStyle)
231    {
232      BeginSpan(new HighlightingColor { FontStyle = fontStyle });
233    }
234   
235    /// <inheritdoc/>
236    public override void BeginSpan(FontWeight fontWeight)
237    {
238      BeginSpan(new HighlightingColor { FontWeight = fontWeight });
239    }
240   
241    /// <inheritdoc/>
242    public override void BeginSpan(HighlightingColor highlightingColor)
243    {
244      WriteIndentationAndSpace();
245      if (options.ColorNeedsSpanForStyling(highlightingColor)) {
246        htmlWriter.Write("<span");
247        options.WriteStyleAttributeForColor(htmlWriter, highlightingColor);
248        htmlWriter.Write('>');
249        endTagStack.Push("</span>");
250      } else {
251        endTagStack.Push(null);
252      }
253    }
254   
255    /// <inheritdoc/>
256    public override void BeginHyperlinkSpan(Uri uri)
257    {
258      WriteIndentationAndSpace();
259      #if DOTNET4
260      string link = WebUtility.HtmlEncode(uri.ToString());
261      #else
262      string link = HttpUtility.HtmlEncode(uri.ToString());
263      #endif
264      htmlWriter.Write("<a href=\"" + link + "\">");
265      endTagStack.Push("</a>");
266    }
267  }
268}
Note: See TracBrowser for help on using the repository browser.