HtmlDescriptionTextBlock.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314
  1. using FastReport.Utils;
  2. using System.Drawing;
  3. using System.Globalization;
  4. using System.Text;
  5. using System.Windows.Forms;
  6. namespace FastReport.Controls
  7. {
  8. internal class HtmlDescriptionTextBlock : System.Windows.Controls.TextBlock
  9. {
  10. public System.Windows.Media.ImageSource Image { get; set; }
  11. public string Description { get; set; }
  12. public void ParseDescription()
  13. {
  14. Inlines.Clear();
  15. if (Image != null)
  16. {
  17. Inlines.Add(
  18. new System.Windows.Documents.InlineUIContainer(
  19. new System.Windows.Controls.Image() { Source = Image, Width = 16, Height = 16, Margin = new System.Windows.Thickness(0, 0, 4, 0) })
  20. { BaselineAlignment = System.Windows.BaselineAlignment.Center });
  21. }
  22. ConvertHtml(Description, new StyleDescriptor(DrawUtils.DefaultFont));
  23. }
  24. private enum BaseLine
  25. {
  26. Normal,
  27. Subscript,
  28. Superscript
  29. }
  30. private class StyleDescriptor
  31. {
  32. public string FontName;
  33. public float FontSize;
  34. public FontStyle FontStyle;
  35. public Color Color;
  36. public BaseLine BaseLine;
  37. public StyleDescriptor(string fontName, float fontSize, FontStyle fontStyle, Color color, BaseLine baseLine)
  38. {
  39. FontName = fontName;
  40. FontStyle = fontStyle;
  41. FontSize = fontSize;
  42. Color = color;
  43. BaseLine = baseLine;
  44. }
  45. public StyleDescriptor(Font font) : this(font.Name, font.Size, FontStyle.Regular, Color.Black, BaseLine.Normal) { }
  46. public StyleDescriptor(StyleDescriptor other) : this(other.FontName, other.FontSize, other.FontStyle, other.Color, other.BaseLine) { }
  47. }
  48. private void AddRun(string text, StyleDescriptor s)
  49. {
  50. var run = new System.Windows.Documents.Run();
  51. run.Text = text;
  52. Helper.SetFont(s.FontName, s.FontSize, s.FontStyle, Helper.GetDpiScale(this), out var family, out var size, out var style, out var weight, out var deco);
  53. run.FontFamily = family;
  54. run.FontSize = size;
  55. run.FontStyle = style;
  56. run.FontWeight = weight;
  57. run.TextDecorations = deco;
  58. run.Foreground = Helper.GetBrush(s.Color);
  59. Inlines.Add(run);
  60. }
  61. private void AddLineBreak()
  62. {
  63. Inlines.Add(new System.Windows.Documents.LineBreak());
  64. }
  65. private void ConvertHtml(string text, StyleDescriptor defaultStyle)
  66. {
  67. StringBuilder currentWord = new StringBuilder(100);
  68. StyleDescriptor style = new StyleDescriptor(defaultStyle);
  69. for (int i = 0; i < text.Length; i++)
  70. {
  71. char lastChar = text[i];
  72. if (lastChar == '<')
  73. {
  74. // probably html tag
  75. StyleDescriptor newStyle = new StyleDescriptor(style);
  76. string tag = "";
  77. bool match = false;
  78. // <b>, <i>, <u>
  79. if (i + 3 <= text.Length)
  80. {
  81. match = true;
  82. tag = text.Substring(i, 3).ToLower();
  83. if (tag == "<b>")
  84. newStyle.FontStyle |= System.Drawing.FontStyle.Bold;
  85. else if (tag == "<i>")
  86. newStyle.FontStyle |= System.Drawing.FontStyle.Italic;
  87. else if (tag == "<u>")
  88. newStyle.FontStyle |= System.Drawing.FontStyle.Underline;
  89. else
  90. match = false;
  91. if (match)
  92. i += 3;
  93. }
  94. // </b>, </i>, </u>
  95. if (!match && i + 4 <= text.Length && text[i + 1] == '/')
  96. {
  97. match = true;
  98. tag = text.Substring(i, 4).ToLower();
  99. if (tag == "</b>")
  100. newStyle.FontStyle &= ~System.Drawing.FontStyle.Bold;
  101. else if (tag == "</i>")
  102. newStyle.FontStyle &= ~System.Drawing.FontStyle.Italic;
  103. else if (tag == "</u>")
  104. newStyle.FontStyle &= ~System.Drawing.FontStyle.Underline;
  105. else
  106. match = false;
  107. if (match)
  108. i += 4;
  109. }
  110. // <sub>, <sup>, <font
  111. if (!match && i + 5 <= text.Length)
  112. {
  113. match = true;
  114. tag = text.Substring(i, 5).ToLower();
  115. if (tag == "<sub>")
  116. newStyle.BaseLine = BaseLine.Subscript;
  117. else if (tag == "<sup>")
  118. newStyle.BaseLine = BaseLine.Superscript;
  119. else if (tag == "<font")
  120. {
  121. //try to found end of open tag
  122. int right = text.IndexOf('>', i + 5);
  123. if (right <= 0) match = false;
  124. else
  125. {
  126. //found font and parse them
  127. string color = null;
  128. string face = null;
  129. string size = null;
  130. int color_ind = text.IndexOf("color=\"", i + 5);
  131. if (color_ind < right && color_ind >= 0)
  132. {
  133. color_ind += 7;
  134. int color_end = text.IndexOf("\"", color_ind);
  135. if (color_end < right && color_end >= 0)
  136. {
  137. color = text.Substring(color_ind, color_end - color_ind);
  138. }
  139. }
  140. int face_ind = text.IndexOf("face=\"", i + 5);
  141. if (face_ind < right && face_ind >= 0)
  142. {
  143. face_ind += 6;
  144. int face_end = text.IndexOf("\"", face_ind);
  145. if (face_end < right && face_end >= 0)
  146. {
  147. face = text.Substring(face_ind, face_end - face_ind);
  148. }
  149. }
  150. int size_ind = text.IndexOf("size=\"", i + 5);
  151. if (size_ind < right && size_ind >= 0)
  152. {
  153. size_ind += 6;
  154. int size_end = text.IndexOf("\"", size_ind);
  155. if (size_end < right && size_end >= 0)
  156. {
  157. size = text.Substring(size_ind, size_end - size_ind);
  158. }
  159. }
  160. if (color != null)
  161. {
  162. if (color.StartsWith("\"") && color.EndsWith("\""))
  163. color = color.Substring(1, color.Length - 2);
  164. if (color.StartsWith("#"))
  165. {
  166. newStyle.Color = Color.FromArgb((int)(0xFF000000 + uint.Parse(color.Substring(1), NumberStyles.HexNumber)));
  167. }
  168. else
  169. {
  170. newStyle.Color = Color.FromName(color);
  171. }
  172. }
  173. if (face != null)
  174. newStyle.FontName = face;
  175. if (size != null)
  176. {
  177. try
  178. {
  179. size = size.Trim(' ');
  180. newStyle.FontSize = (float)Converter.FromString(typeof(float), size);
  181. }
  182. catch { }
  183. }
  184. i = right - 4;
  185. }
  186. }
  187. else
  188. match = false;
  189. if (match)
  190. i += 5;
  191. }
  192. // </sub>, </sup>
  193. if (!match && i + 6 <= text.Length && text[i + 1] == '/')
  194. {
  195. match = true;
  196. tag = text.Substring(i, 6).ToLower();
  197. if (tag == "</sub>")
  198. newStyle.BaseLine = BaseLine.Normal;
  199. else if (tag == "</sup>")
  200. newStyle.BaseLine = BaseLine.Normal;
  201. else
  202. match = false;
  203. if (match)
  204. i += 6;
  205. }
  206. // <strike>
  207. if (!match && i + 8 <= text.Length && text.Substring(i, 8).ToLower() == "<strike>")
  208. {
  209. newStyle.FontStyle |= System.Drawing.FontStyle.Strikeout;
  210. match = true;
  211. i += 8;
  212. }
  213. // </strike>
  214. if (!match && i + 9 <= text.Length && text.Substring(i, 9).ToLower() == "</strike>")
  215. {
  216. newStyle.FontStyle &= ~System.Drawing.FontStyle.Strikeout;
  217. match = true;
  218. i += 9;
  219. }
  220. // </font>
  221. if (!match && i + 7 <= text.Length && text.Substring(i, 7).ToLower() == "</font>")
  222. {
  223. newStyle = new StyleDescriptor(defaultStyle);
  224. match = true;
  225. i += 7;
  226. }
  227. // <br/>
  228. if (!match && i + 5 <= text.Length && text.Substring(i, 5).ToLower() == "<br/>")
  229. {
  230. i += 5 - 1;
  231. lastChar = '\n';
  232. }
  233. if (match)
  234. {
  235. if (currentWord.Length != 0)
  236. {
  237. // finish the word
  238. AddRun(currentWord.ToString(), style);
  239. }
  240. currentWord.Clear();
  241. style = newStyle;
  242. i--;
  243. continue;
  244. }
  245. }
  246. if (lastChar == '&')
  247. {
  248. if (Converter.FromHtmlEntities(text, ref i, currentWord))
  249. {
  250. if (i >= text.Length - 1)
  251. {
  252. AddRun(currentWord.ToString(), style);
  253. break;
  254. }
  255. else
  256. {
  257. continue;
  258. }
  259. }
  260. }
  261. // skip r, handle n
  262. if (lastChar == '\r')
  263. continue;
  264. if (lastChar == '\n')
  265. {
  266. if (currentWord.Length != 0)
  267. AddRun(currentWord.ToString(), style);
  268. currentWord.Clear();
  269. AddLineBreak();
  270. continue;
  271. }
  272. currentWord.Append(lastChar);
  273. if (i == text.Length - 1)
  274. {
  275. // finish the last word
  276. if (currentWord.Length != 0)
  277. AddRun(currentWord.ToString(), style);
  278. }
  279. }
  280. }
  281. }
  282. }