You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
387 lines
15 KiB
387 lines
15 KiB
using System; |
|
using System.Collections.Generic; |
|
using System.Text; |
|
using UnityEngine; |
|
|
|
namespace FairyGUI.Utils |
|
{ |
|
/// <summary> |
|
/// |
|
/// </summary> |
|
public class HtmlParser |
|
{ |
|
public static HtmlParser inst = new HtmlParser(); |
|
|
|
protected class TextFormat2 : TextFormat |
|
{ |
|
public bool colorChanged; |
|
} |
|
|
|
protected List<TextFormat2> _textFormatStack; |
|
protected int _textFormatStackTop; |
|
protected TextFormat2 _format; |
|
protected List<HtmlElement> _elements; |
|
protected HtmlParseOptions _defaultOptions; |
|
|
|
static List<string> sHelperList1 = new List<string>(); |
|
static List<string> sHelperList2 = new List<string>(); |
|
|
|
public HtmlParser() |
|
{ |
|
_textFormatStack = new List<TextFormat2>(); |
|
_format = new TextFormat2(); |
|
_defaultOptions = new HtmlParseOptions(); |
|
} |
|
|
|
virtual public void Parse(string aSource, TextFormat defaultFormat, List<HtmlElement> elements, HtmlParseOptions parseOptions) |
|
{ |
|
if (parseOptions == null) |
|
parseOptions = _defaultOptions; |
|
|
|
_elements = elements; |
|
_textFormatStackTop = 0; |
|
_format.CopyFrom(defaultFormat); |
|
_format.colorChanged = false; |
|
int skipText = 0; |
|
bool ignoreWhiteSpace = parseOptions.ignoreWhiteSpace; |
|
bool skipNextCR = false; |
|
string text; |
|
|
|
XMLIterator.Begin(aSource, true); |
|
while (XMLIterator.NextTag()) |
|
{ |
|
if (skipText == 0) |
|
{ |
|
text = XMLIterator.GetText(ignoreWhiteSpace); |
|
if (text.Length > 0) |
|
{ |
|
if (skipNextCR && text[0] == '\n') |
|
text = text.Substring(1); |
|
AppendText(text); |
|
} |
|
} |
|
|
|
skipNextCR = false; |
|
switch (XMLIterator.tagName) |
|
{ |
|
case "b": |
|
if (XMLIterator.tagType == XMLTagType.Start) |
|
{ |
|
PushTextFormat(); |
|
_format.bold = true; |
|
} |
|
else |
|
PopTextFormat(); |
|
break; |
|
|
|
case "i": |
|
if (XMLIterator.tagType == XMLTagType.Start) |
|
{ |
|
PushTextFormat(); |
|
_format.italic = true; |
|
} |
|
else |
|
PopTextFormat(); |
|
break; |
|
|
|
case "u": |
|
if (XMLIterator.tagType == XMLTagType.Start) |
|
{ |
|
PushTextFormat(); |
|
_format.underline = true; |
|
} |
|
else |
|
PopTextFormat(); |
|
break; |
|
|
|
case "strike": |
|
if (XMLIterator.tagType == XMLTagType.Start) |
|
{ |
|
PushTextFormat(); |
|
_format.strikethrough = true; |
|
} |
|
else |
|
PopTextFormat(); |
|
break; |
|
|
|
case "sub": |
|
{ |
|
if (XMLIterator.tagType == XMLTagType.Start) |
|
{ |
|
PushTextFormat(); |
|
_format.specialStyle = TextFormat.SpecialStyle.Subscript; |
|
} |
|
else |
|
PopTextFormat(); |
|
} |
|
break; |
|
|
|
case "sup": |
|
{ |
|
if (XMLIterator.tagType == XMLTagType.Start) |
|
{ |
|
PushTextFormat(); |
|
_format.specialStyle = TextFormat.SpecialStyle.Superscript; |
|
} |
|
else |
|
PopTextFormat(); |
|
} |
|
break; |
|
|
|
case "font": |
|
if (XMLIterator.tagType == XMLTagType.Start) |
|
{ |
|
PushTextFormat(); |
|
|
|
_format.size = XMLIterator.GetAttributeInt("size", _format.size); |
|
string color = XMLIterator.GetAttribute("color"); |
|
if (color != null) |
|
{ |
|
string[] parts = color.Split(','); |
|
if (parts.Length == 1) |
|
{ |
|
_format.color = ToolSet.ConvertFromHtmlColor(color); |
|
_format.gradientColor = null; |
|
_format.colorChanged = true; |
|
} |
|
else |
|
{ |
|
if (_format.gradientColor == null) |
|
_format.gradientColor = new Color32[4]; |
|
_format.gradientColor[0] = ToolSet.ConvertFromHtmlColor(parts[0]); |
|
_format.gradientColor[1] = ToolSet.ConvertFromHtmlColor(parts[1]); |
|
if (parts.Length > 2) |
|
{ |
|
_format.gradientColor[2] = ToolSet.ConvertFromHtmlColor(parts[2]); |
|
if (parts.Length > 3) |
|
_format.gradientColor[3] = ToolSet.ConvertFromHtmlColor(parts[3]); |
|
else |
|
_format.gradientColor[3] = _format.gradientColor[2]; |
|
} |
|
else |
|
{ |
|
_format.gradientColor[2] = _format.gradientColor[0]; |
|
_format.gradientColor[3] = _format.gradientColor[1]; |
|
} |
|
} |
|
} |
|
} |
|
else if (XMLIterator.tagType == XMLTagType.End) |
|
PopTextFormat(); |
|
break; |
|
|
|
case "br": |
|
AppendText("\n"); |
|
break; |
|
|
|
case "img": |
|
if (XMLIterator.tagType == XMLTagType.Start || XMLIterator.tagType == XMLTagType.Void) |
|
{ |
|
HtmlElement element = HtmlElement.GetElement(HtmlElementType.Image); |
|
element.FetchAttributes(); |
|
element.name = element.GetString("name"); |
|
element.format.align = _format.align; |
|
_elements.Add(element); |
|
} |
|
break; |
|
|
|
case "a": |
|
if (XMLIterator.tagType == XMLTagType.Start) |
|
{ |
|
PushTextFormat(); |
|
|
|
_format.underline = _format.underline || parseOptions.linkUnderline; |
|
if (!_format.colorChanged && parseOptions.linkColor.a != 0) |
|
_format.color = parseOptions.linkColor; |
|
|
|
HtmlElement element = HtmlElement.GetElement(HtmlElementType.Link); |
|
element.FetchAttributes(); |
|
element.name = element.GetString("name"); |
|
element.format.align = _format.align; |
|
_elements.Add(element); |
|
} |
|
else if (XMLIterator.tagType == XMLTagType.End) |
|
{ |
|
PopTextFormat(); |
|
|
|
HtmlElement element = HtmlElement.GetElement(HtmlElementType.LinkEnd); |
|
_elements.Add(element); |
|
} |
|
break; |
|
|
|
case "input": |
|
{ |
|
HtmlElement element = HtmlElement.GetElement(HtmlElementType.Input); |
|
element.FetchAttributes(); |
|
element.name = element.GetString("name"); |
|
element.format.CopyFrom(_format); |
|
_elements.Add(element); |
|
} |
|
break; |
|
|
|
case "select": |
|
{ |
|
if (XMLIterator.tagType == XMLTagType.Start || XMLIterator.tagType == XMLTagType.Void) |
|
{ |
|
HtmlElement element = HtmlElement.GetElement(HtmlElementType.Select); |
|
element.FetchAttributes(); |
|
if (XMLIterator.tagType == XMLTagType.Start) |
|
{ |
|
sHelperList1.Clear(); |
|
sHelperList2.Clear(); |
|
while (XMLIterator.NextTag()) |
|
{ |
|
if (XMLIterator.tagName == "select") |
|
break; |
|
|
|
if (XMLIterator.tagName == "option") |
|
{ |
|
if (XMLIterator.tagType == XMLTagType.Start || XMLIterator.tagType == XMLTagType.Void) |
|
sHelperList2.Add(XMLIterator.GetAttribute("value", string.Empty)); |
|
else |
|
sHelperList1.Add(XMLIterator.GetText()); |
|
} |
|
} |
|
element.Set("items", sHelperList1.ToArray()); |
|
element.Set("values", sHelperList2.ToArray()); |
|
} |
|
element.name = element.GetString("name"); |
|
element.format.CopyFrom(_format); |
|
_elements.Add(element); |
|
} |
|
} |
|
break; |
|
|
|
case "p": |
|
if (XMLIterator.tagType == XMLTagType.Start) |
|
{ |
|
PushTextFormat(); |
|
string align = XMLIterator.GetAttribute("align"); |
|
switch (align) |
|
{ |
|
case "center": |
|
_format.align = AlignType.Center; |
|
break; |
|
case "right": |
|
_format.align = AlignType.Right; |
|
break; |
|
} |
|
if (!IsNewLine()) |
|
AppendText("\n"); |
|
} |
|
else if (XMLIterator.tagType == XMLTagType.End) |
|
{ |
|
AppendText("\n"); |
|
skipNextCR = true; |
|
|
|
PopTextFormat(); |
|
} |
|
break; |
|
|
|
case "ui": |
|
case "div": |
|
case "li": |
|
if (XMLIterator.tagType == XMLTagType.Start) |
|
{ |
|
if (!IsNewLine()) |
|
AppendText("\n"); |
|
} |
|
else |
|
{ |
|
AppendText("\n"); |
|
skipNextCR = true; |
|
} |
|
break; |
|
|
|
case "html": |
|
case "body": |
|
//full html |
|
ignoreWhiteSpace = true; |
|
break; |
|
|
|
case "head": |
|
case "style": |
|
case "script": |
|
case "form": |
|
if (XMLIterator.tagType == XMLTagType.Start) |
|
skipText++; |
|
else if (XMLIterator.tagType == XMLTagType.End) |
|
skipText--; |
|
break; |
|
} |
|
} |
|
|
|
if (skipText == 0) |
|
{ |
|
text = XMLIterator.GetText(ignoreWhiteSpace); |
|
if (text.Length > 0) |
|
{ |
|
if (skipNextCR && text[0] == '\n') |
|
text = text.Substring(1); |
|
AppendText(text); |
|
} |
|
} |
|
|
|
_elements = null; |
|
} |
|
|
|
protected void PushTextFormat() |
|
{ |
|
TextFormat2 tf; |
|
if (_textFormatStack.Count <= _textFormatStackTop) |
|
{ |
|
tf = new TextFormat2(); |
|
_textFormatStack.Add(tf); |
|
} |
|
else |
|
tf = _textFormatStack[_textFormatStackTop]; |
|
tf.CopyFrom(_format); |
|
tf.colorChanged = _format.colorChanged; |
|
_textFormatStackTop++; |
|
} |
|
|
|
protected void PopTextFormat() |
|
{ |
|
if (_textFormatStackTop > 0) |
|
{ |
|
TextFormat2 tf = _textFormatStack[_textFormatStackTop - 1]; |
|
_format.CopyFrom(tf); |
|
_format.colorChanged = tf.colorChanged; |
|
_textFormatStackTop--; |
|
} |
|
} |
|
|
|
protected bool IsNewLine() |
|
{ |
|
if (_elements.Count > 0) |
|
{ |
|
HtmlElement element = _elements[_elements.Count - 1]; |
|
if (element != null && element.type == HtmlElementType.Text) |
|
return element.text.EndsWith("\n"); |
|
else |
|
return false; |
|
} |
|
|
|
return true; |
|
} |
|
|
|
protected void AppendText(string text) |
|
{ |
|
HtmlElement element; |
|
if (_elements.Count > 0) |
|
{ |
|
element = _elements[_elements.Count - 1]; |
|
if (element.type == HtmlElementType.Text && element.format.EqualStyle(_format)) |
|
{ |
|
element.text += text; |
|
return; |
|
} |
|
} |
|
|
|
element = HtmlElement.GetElement(HtmlElementType.Text); |
|
element.text = text; |
|
element.format.CopyFrom(_format); |
|
_elements.Add(element); |
|
} |
|
} |
|
}
|
|
|