using FastReport.Utils;
using System.Drawing;
using System.Globalization;
using System.Text;
using System.Windows.Forms;
namespace FastReport.Controls
{
internal class HtmlDescriptionTextBlock : System.Windows.Controls.TextBlock
{
public System.Windows.Media.ImageSource Image { get; set; }
public string Description { get; set; }
public void ParseDescription()
{
Inlines.Clear();
if (Image != null)
{
Inlines.Add(
new System.Windows.Documents.InlineUIContainer(
new System.Windows.Controls.Image() { Source = Image, Width = 16, Height = 16, Margin = new System.Windows.Thickness(0, 0, 4, 0) })
{ BaselineAlignment = System.Windows.BaselineAlignment.Center });
}
ConvertHtml(Description, new StyleDescriptor(DrawUtils.DefaultFont));
}
private enum BaseLine
{
Normal,
Subscript,
Superscript
}
private class StyleDescriptor
{
public string FontName;
public float FontSize;
public FontStyle FontStyle;
public Color Color;
public BaseLine BaseLine;
public StyleDescriptor(string fontName, float fontSize, FontStyle fontStyle, Color color, BaseLine baseLine)
{
FontName = fontName;
FontStyle = fontStyle;
FontSize = fontSize;
Color = color;
BaseLine = baseLine;
}
public StyleDescriptor(Font font) : this(font.Name, font.Size, FontStyle.Regular, Color.Black, BaseLine.Normal) { }
public StyleDescriptor(StyleDescriptor other) : this(other.FontName, other.FontSize, other.FontStyle, other.Color, other.BaseLine) { }
}
private void AddRun(string text, StyleDescriptor s)
{
var run = new System.Windows.Documents.Run();
run.Text = text;
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);
run.FontFamily = family;
run.FontSize = size;
run.FontStyle = style;
run.FontWeight = weight;
run.TextDecorations = deco;
run.Foreground = Helper.GetBrush(s.Color);
Inlines.Add(run);
}
private void AddLineBreak()
{
Inlines.Add(new System.Windows.Documents.LineBreak());
}
private void ConvertHtml(string text, StyleDescriptor defaultStyle)
{
StringBuilder currentWord = new StringBuilder(100);
StyleDescriptor style = new StyleDescriptor(defaultStyle);
for (int i = 0; i < text.Length; i++)
{
char lastChar = text[i];
if (lastChar == '<')
{
// probably html tag
StyleDescriptor newStyle = new StyleDescriptor(style);
string tag = "";
bool match = false;
// , ,
if (i + 3 <= text.Length)
{
match = true;
tag = text.Substring(i, 3).ToLower();
if (tag == "")
newStyle.FontStyle |= System.Drawing.FontStyle.Bold;
else if (tag == "")
newStyle.FontStyle |= System.Drawing.FontStyle.Italic;
else if (tag == "")
newStyle.FontStyle |= System.Drawing.FontStyle.Underline;
else
match = false;
if (match)
i += 3;
}
// , ,
if (!match && i + 4 <= text.Length && text[i + 1] == '/')
{
match = true;
tag = text.Substring(i, 4).ToLower();
if (tag == "")
newStyle.FontStyle &= ~System.Drawing.FontStyle.Bold;
else if (tag == "")
newStyle.FontStyle &= ~System.Drawing.FontStyle.Italic;
else if (tag == "")
newStyle.FontStyle &= ~System.Drawing.FontStyle.Underline;
else
match = false;
if (match)
i += 4;
}
// , , ")
newStyle.BaseLine = BaseLine.Subscript;
else if (tag == "")
newStyle.BaseLine = BaseLine.Superscript;
else if (tag == "', i + 5);
if (right <= 0) match = false;
else
{
//found font and parse them
string color = null;
string face = null;
string size = null;
int color_ind = text.IndexOf("color=\"", i + 5);
if (color_ind < right && color_ind >= 0)
{
color_ind += 7;
int color_end = text.IndexOf("\"", color_ind);
if (color_end < right && color_end >= 0)
{
color = text.Substring(color_ind, color_end - color_ind);
}
}
int face_ind = text.IndexOf("face=\"", i + 5);
if (face_ind < right && face_ind >= 0)
{
face_ind += 6;
int face_end = text.IndexOf("\"", face_ind);
if (face_end < right && face_end >= 0)
{
face = text.Substring(face_ind, face_end - face_ind);
}
}
int size_ind = text.IndexOf("size=\"", i + 5);
if (size_ind < right && size_ind >= 0)
{
size_ind += 6;
int size_end = text.IndexOf("\"", size_ind);
if (size_end < right && size_end >= 0)
{
size = text.Substring(size_ind, size_end - size_ind);
}
}
if (color != null)
{
if (color.StartsWith("\"") && color.EndsWith("\""))
color = color.Substring(1, color.Length - 2);
if (color.StartsWith("#"))
{
newStyle.Color = Color.FromArgb((int)(0xFF000000 + uint.Parse(color.Substring(1), NumberStyles.HexNumber)));
}
else
{
newStyle.Color = Color.FromName(color);
}
}
if (face != null)
newStyle.FontName = face;
if (size != null)
{
try
{
size = size.Trim(' ');
newStyle.FontSize = (float)Converter.FromString(typeof(float), size);
}
catch { }
}
i = right - 4;
}
}
else
match = false;
if (match)
i += 5;
}
// ,
if (!match && i + 6 <= text.Length && text[i + 1] == '/')
{
match = true;
tag = text.Substring(i, 6).ToLower();
if (tag == "")
newStyle.BaseLine = BaseLine.Normal;
else if (tag == "")
newStyle.BaseLine = BaseLine.Normal;
else
match = false;
if (match)
i += 6;
}
//
if (!match && i + 8 <= text.Length && text.Substring(i, 8).ToLower() == "")
{
newStyle.FontStyle |= System.Drawing.FontStyle.Strikeout;
match = true;
i += 8;
}
//
if (!match && i + 9 <= text.Length && text.Substring(i, 9).ToLower() == "")
{
newStyle.FontStyle &= ~System.Drawing.FontStyle.Strikeout;
match = true;
i += 9;
}
//
if (!match && i + 7 <= text.Length && text.Substring(i, 7).ToLower() == "")
{
newStyle = new StyleDescriptor(defaultStyle);
match = true;
i += 7;
}
//
if (!match && i + 5 <= text.Length && text.Substring(i, 5).ToLower() == "
")
{
i += 5 - 1;
lastChar = '\n';
}
if (match)
{
if (currentWord.Length != 0)
{
// finish the word
AddRun(currentWord.ToString(), style);
}
currentWord.Clear();
style = newStyle;
i--;
continue;
}
}
if (lastChar == '&')
{
if (Converter.FromHtmlEntities(text, ref i, currentWord))
{
if (i >= text.Length - 1)
{
AddRun(currentWord.ToString(), style);
break;
}
else
{
continue;
}
}
}
// skip r, handle n
if (lastChar == '\r')
continue;
if (lastChar == '\n')
{
if (currentWord.Length != 0)
AddRun(currentWord.ToString(), style);
currentWord.Clear();
AddLineBreak();
continue;
}
currentWord.Append(lastChar);
if (i == text.Length - 1)
{
// finish the last word
if (currentWord.Length != 0)
AddRun(currentWord.ToString(), style);
}
}
}
}
}