HtmlParser
Represents the Tree construction as specified in
8.2.5 Tree construction, on the following page:
http://www.w3.org/html/wg/drafts/html/master/syntax.html
using AngleSharp.DOM;
using AngleSharp.DOM.Html;
using AngleSharp.DOM.Mathml;
using AngleSharp.DOM.Svg;
using AngleSharp.Extensions;
using AngleSharp.Html;
using AngleSharp.Network;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace AngleSharp.Parser.Html
{
[DebuggerStepThrough]
public sealed class HtmlParser
{
private readonly HtmlTokenizer tokenizer;
private readonly Document doc;
private readonly List<Element> open;
private readonly List<Element> formatting;
private readonly Stack<HtmlTreeMode> templateMode;
private readonly object sync;
private HtmlTreeMode insert;
private HtmlTreeMode originalInsert;
private HTMLFormElement form;
private bool frameset;
private Element fragmentContext;
private bool foster;
private int nesting;
private bool started;
private HTMLScriptElement pendingParsingBlock;
private Task<IDocument> task;
public IDocument Result {
get {
Parse();
return doc;
}
}
public bool IsAsync => task != null;
public bool IsFragmentCase => fragmentContext != null;
internal Element AdjustedCurrentNode {
get {
if (fragmentContext == null || open.Count != 1)
return CurrentNode;
return fragmentContext;
}
}
internal Element CurrentNode {
get {
if (open.Count <= 0)
return null;
return open[open.Count - 1];
}
}
internal HTMLScriptElement PendingParsingBlock {
get {
return pendingParsingBlock;
}
set {
pendingParsingBlock = value;
}
}
public event EventHandler<ParseErrorEventArgs> ParseError {
add {
tokenizer.ErrorOccurred += value;
}
remove {
tokenizer.ErrorOccurred -= value;
}
}
public HtmlParser(string source, IConfiguration configuration = null)
: this(new Document(new TextSource(source)) {
Options = configuration
})
{
}
public HtmlParser(Stream stream, IConfiguration configuration = null)
: this(new Document(new TextSource(stream, configuration.DefaultEncoding())) {
Options = configuration
})
{
}
internal HtmlParser(Document document)
{
tokenizer = new HtmlTokenizer(document.Source);
sync = new object();
started = false;
doc = document;
open = new List<Element>();
templateMode = new Stack<HtmlTreeMode>();
formatting = new List<Element>();
frameset = true;
insert = HtmlTreeMode.Initial;
}
public Task<IDocument> ParseAsync()
{
return ParseAsync(CancellationToken.None);
}
public Task<IDocument> ParseAsync(CancellationToken cancelToken)
{
lock (sync) {
if (!started) {
started = true;
task = KernelAsync(cancelToken);
}
}
return task;
}
public IDocument Parse()
{
if (!started) {
started = true;
Kernel();
}
return doc;
}
internal HtmlParser SwitchToFragment(Element context)
{
if (started)
throw new InvalidOperationException("Fragment mode has to be activated before running the parser!");
string nodeName = context.NodeName;
if (nodeName.IsOneOf(Tags.Title, Tags.Textarea))
tokenizer.State = HtmlParseMode.RCData;
else if (nodeName.IsOneOf(Tags.Style, Tags.Xmp, Tags.Iframe, Tags.NoEmbed, Tags.NoFrames)) {
tokenizer.State = HtmlParseMode.Rawtext;
} else if (nodeName == Tags.Script) {
tokenizer.State = HtmlParseMode.Script;
} else if (nodeName == Tags.Plaintext) {
tokenizer.State = HtmlParseMode.Plaintext;
} else if (nodeName == Tags.NoScript && doc.Options.IsScripting) {
tokenizer.State = HtmlParseMode.Rawtext;
}
HTMLHtmlElement hTMLHtmlElement = new HTMLHtmlElement();
hTMLHtmlElement.Owner = doc;
HTMLHtmlElement hTMLHtmlElement2 = hTMLHtmlElement;
doc.AddNode(hTMLHtmlElement2);
open.Add(hTMLHtmlElement2);
if (context is HTMLTemplateElement)
templateMode.Push(HtmlTreeMode.InTemplate);
Reset(context);
fragmentContext = context;
tokenizer.IsAcceptingCharacterData = !AdjustedCurrentNode.Flags.HasFlag(NodeFlags.HtmlMember);
do {
if (context is HTMLFormElement) {
form = (HTMLFormElement)context;
break;
}
context = (context.ParentElement as Element);
} while (context != null);
return this;
}
private void Reset(Node context = null)
{
bool flag = false;
int num = open.Count - 1;
while (true) {
if (num < 0)
return;
Node node = open[num];
if (num == 0) {
flag = true;
node = (context ?? node);
}
string nodeName = node.NodeName;
if (nodeName == Tags.Select) {
insert = HtmlTreeMode.InSelect;
return;
}
if (nodeName.IsOneOf(Tags.Th, Tags.Td)) {
insert = (flag ? HtmlTreeMode.InBody : HtmlTreeMode.InCell);
return;
}
if (nodeName == Tags.Tr) {
insert = HtmlTreeMode.InRow;
return;
}
if (nodeName.IsOneOf(Tags.Thead, Tags.Tfoot, Tags.Tbody)) {
insert = HtmlTreeMode.InTableBody;
return;
}
if (nodeName == Tags.Body) {
insert = HtmlTreeMode.InBody;
return;
}
if (nodeName == Tags.Table) {
insert = HtmlTreeMode.InTable;
return;
}
if (nodeName == Tags.Caption) {
insert = HtmlTreeMode.InCaption;
return;
}
if (nodeName == Tags.Colgroup) {
insert = HtmlTreeMode.InColumnGroup;
return;
}
if (nodeName == Tags.Template) {
insert = templateMode.Peek();
return;
}
if (nodeName == Tags.Html) {
insert = HtmlTreeMode.BeforeHead;
return;
}
if (nodeName == Tags.Head) {
insert = (flag ? HtmlTreeMode.InBody : HtmlTreeMode.InHead);
return;
}
if (nodeName == Tags.Frameset) {
insert = HtmlTreeMode.InFrameset;
return;
}
if (flag)
break;
num--;
}
insert = HtmlTreeMode.InBody;
}
private void Consume(HtmlToken token)
{
Element adjustedCurrentNode = AdjustedCurrentNode;
if (adjustedCurrentNode == null || token.IsEof || adjustedCurrentNode.Flags.HasFlag(NodeFlags.HtmlMember) || (adjustedCurrentNode.Flags.HasFlag(NodeFlags.HtmlTip) && token.IsHtmlCompatible) || (adjustedCurrentNode.Flags.HasFlag(NodeFlags.MathTip) && token.IsMathCompatible) || (adjustedCurrentNode.Flags.HasFlag(NodeFlags.MathMember) && token.IsSvg && adjustedCurrentNode.NodeName == Tags.AnnotationXml))
Home(token);
else
Foreign(token);
}
private void Home(HtmlToken token)
{
switch (insert) {
case HtmlTreeMode.Initial:
Initial(token);
break;
case HtmlTreeMode.BeforeHtml:
BeforeHtml(token);
break;
case HtmlTreeMode.BeforeHead:
BeforeHead(token);
break;
case HtmlTreeMode.InHead:
InHead(token);
break;
case HtmlTreeMode.InHeadNoScript:
InHeadNoScript(token);
break;
case HtmlTreeMode.AfterHead:
AfterHead(token);
break;
case HtmlTreeMode.InBody:
InBody(token);
break;
case HtmlTreeMode.Text:
Text(token);
break;
case HtmlTreeMode.InTable:
InTable(token);
break;
case HtmlTreeMode.InCaption:
InCaption(token);
break;
case HtmlTreeMode.InColumnGroup:
InColumnGroup(token);
break;
case HtmlTreeMode.InTableBody:
InTableBody(token);
break;
case HtmlTreeMode.InRow:
InRow(token);
break;
case HtmlTreeMode.InCell:
InCell(token);
break;
case HtmlTreeMode.InSelect:
InSelect(token);
break;
case HtmlTreeMode.InSelectInTable:
InSelectInTable(token);
break;
case HtmlTreeMode.InTemplate:
InTemplate(token);
break;
case HtmlTreeMode.AfterBody:
AfterBody(token);
break;
case HtmlTreeMode.InFrameset:
InFrameset(token);
break;
case HtmlTreeMode.AfterFrameset:
AfterFrameset(token);
break;
case HtmlTreeMode.AfterAfterBody:
AfterAfterBody(token);
break;
case HtmlTreeMode.AfterAfterFrameset:
AfterAfterFrameset(token);
break;
}
}
private void Initial(HtmlToken token)
{
switch (token.Type) {
case HtmlTokenType.DOCTYPE: {
HtmlDoctypeToken htmlDoctypeToken = (HtmlDoctypeToken)token;
if (!htmlDoctypeToken.IsValid)
RaiseErrorOccurred(ErrorCode.DoctypeInvalid);
AddDoctype(htmlDoctypeToken);
if (htmlDoctypeToken.IsFullQuirks)
doc.QuirksMode = QuirksMode.On;
else if (htmlDoctypeToken.IsLimitedQuirks) {
doc.QuirksMode = QuirksMode.Limited;
}
insert = HtmlTreeMode.BeforeHtml;
return;
}
case HtmlTokenType.Character:
token.TrimStart();
if (token.IsEmpty)
return;
break;
case HtmlTokenType.Comment:
doc.AddComment(token.Data);
return;
}
if (!doc.Options.IsEmbedded) {
RaiseErrorOccurred(ErrorCode.DoctypeMissing);
doc.QuirksMode = QuirksMode.On;
}
insert = HtmlTreeMode.BeforeHtml;
BeforeHtml(token);
}
private void BeforeHtml(HtmlToken token)
{
switch (token.Type) {
case HtmlTokenType.Character:
token.TrimStart();
if (token.IsEmpty)
return;
break;
case HtmlTokenType.Comment:
doc.AddComment(token.Data);
return;
case HtmlTokenType.StartTag:
if (!(token.Name != Tags.Html)) {
AddRoot(token.AsTag());
insert = HtmlTreeMode.BeforeHead;
return;
}
break;
case HtmlTokenType.EndTag:
if (!token.Name.IsOneOf(Tags.Html, Tags.Body, Tags.Br, Tags.Head)) {
RaiseErrorOccurred(ErrorCode.TagCannotEndHere);
return;
}
break;
case HtmlTokenType.DOCTYPE:
RaiseErrorOccurred(ErrorCode.DoctypeTagInappropriate);
return;
}
BeforeHtml(HtmlToken.OpenTag(Tags.Html));
BeforeHead(token);
}
private void BeforeHead(HtmlToken token)
{
switch (token.Type) {
case HtmlTokenType.Character:
token.TrimStart();
if (token.IsEmpty)
return;
break;
case HtmlTokenType.StartTag: {
string name = token.Name;
if (name == Tags.Html) {
InBody(token);
return;
}
if (name == Tags.Head) {
AddElement<HTMLHeadElement>(token.AsTag(), false);
insert = HtmlTreeMode.InHead;
return;
}
break;
}
case HtmlTokenType.EndTag:
if (!token.Name.IsOneOf(Tags.Html, Tags.Body, Tags.Br, Tags.Head)) {
RaiseErrorOccurred(ErrorCode.TagCannotEndHere);
return;
}
break;
case HtmlTokenType.Comment:
CurrentNode.AddComment(token.Data);
return;
case HtmlTokenType.DOCTYPE:
RaiseErrorOccurred(ErrorCode.DoctypeTagInappropriate);
return;
}
BeforeHead(HtmlToken.OpenTag(Tags.Head));
InHead(token);
}
private void InHead(HtmlToken token)
{
switch (token.Type) {
case HtmlTokenType.Character: {
string text = token.TrimStart();
AddCharacters(text);
if (token.IsEmpty)
return;
break;
}
case HtmlTokenType.Comment:
CurrentNode.AddComment(token.Data);
return;
case HtmlTokenType.DOCTYPE:
RaiseErrorOccurred(ErrorCode.DoctypeTagInappropriate);
return;
case HtmlTokenType.StartTag: {
string name2 = token.Name;
if (name2 == Tags.Html) {
InBody(token);
return;
}
if (name2 == Tags.Meta) {
HTMLMetaElement hTMLMetaElement = AddElement<HTMLMetaElement>(token.AsTag(), true);
CloseCurrentNode();
string attribute = hTMLMetaElement.GetAttribute(AttributeNames.Charset);
if (attribute == null || !DocumentEncoding.IsSupported(attribute)) {
attribute = hTMLMetaElement.GetAttribute(AttributeNames.HttpEquiv);
if (attribute != null && attribute.Equals(HeaderNames.ContentType, StringComparison.OrdinalIgnoreCase)) {
attribute = (hTMLMetaElement.GetAttribute(AttributeNames.Content) ?? string.Empty);
attribute = DocumentEncoding.Extract(attribute);
if (DocumentEncoding.IsSupported(attribute))
SetCharset(attribute);
}
} else
SetCharset(attribute);
return;
}
if (name2.IsOneOf(Tags.Link, Tags.Base, Tags.BaseFont, Tags.Bgsound)) {
AddElement(token.AsTag(), true);
CloseCurrentNode();
return;
}
if (name2 == Tags.Title) {
RCDataAlgorithm(token.AsTag());
return;
}
if (name2.IsOneOf(Tags.Style, Tags.NoFrames) || (doc.Options.IsScripting && name2 == Tags.NoScript)) {
RawtextAlgorithm(token.AsTag());
return;
}
if (name2 == Tags.NoScript) {
AddElement(token.AsTag(), false);
insert = HtmlTreeMode.InHeadNoScript;
return;
}
if (name2 == Tags.Script) {
HTMLScriptElement hTMLScriptElement = AddElement<HTMLScriptElement>(token.AsTag(), false);
hTMLScriptElement.IsParserInserted = true;
hTMLScriptElement.IsAlreadyStarted = IsFragmentCase;
tokenizer.State = HtmlParseMode.Script;
originalInsert = insert;
insert = HtmlTreeMode.Text;
return;
}
if (name2 == Tags.Head) {
RaiseErrorOccurred(ErrorCode.HeadTagMisplaced);
return;
}
if (name2 == Tags.Template) {
AddElement<HTMLTemplateElement>(token.AsTag(), false);
formatting.AddScopeMarker();
frameset = false;
insert = HtmlTreeMode.InTemplate;
templateMode.Push(HtmlTreeMode.InTemplate);
return;
}
break;
}
case HtmlTokenType.EndTag: {
string name = token.Name;
if (name == Tags.Head) {
CloseCurrentNode();
insert = HtmlTreeMode.AfterHead;
return;
}
if (name == Tags.Template) {
if (TagCurrentlyOpen(Tags.Template)) {
GenerateImpliedEndTags();
if (!(CurrentNode is HTMLTemplateElement))
RaiseErrorOccurred(ErrorCode.TagClosingMismatch);
CloseTemplate();
} else
RaiseErrorOccurred(ErrorCode.TagInappropriate);
return;
}
if (!name.IsOneOf(Tags.Html, Tags.Body, Tags.Br)) {
RaiseErrorOccurred(ErrorCode.TagCannotEndHere);
return;
}
break;
}
}
CloseCurrentNode();
insert = HtmlTreeMode.AfterHead;
AfterHead(token);
}
private void InHeadNoScript(HtmlToken token)
{
switch (token.Type) {
case HtmlTokenType.Character: {
string text = token.TrimStart();
AddCharacters(text);
if (token.IsEmpty)
return;
break;
}
case HtmlTokenType.Comment:
InHead(token);
return;
case HtmlTokenType.StartTag: {
string name2 = token.Name;
if (name2.IsOneOf(Tags.Style, Tags.Link, Tags.BaseFont, Tags.Meta, Tags.NoFrames, Tags.Bgsound)) {
InHead(token);
return;
}
if (name2 == Tags.Html) {
InBody(token);
return;
}
if (name2.IsOneOf(Tags.Head, Tags.NoScript)) {
RaiseErrorOccurred(ErrorCode.TagInappropriate);
return;
}
break;
}
case HtmlTokenType.EndTag: {
string name = token.Name;
if (name == Tags.NoScript) {
CloseCurrentNode();
insert = HtmlTreeMode.InHead;
return;
}
if (name != Tags.Br) {
RaiseErrorOccurred(ErrorCode.TagCannotEndHere);
return;
}
break;
}
case HtmlTokenType.DOCTYPE:
RaiseErrorOccurred(ErrorCode.DoctypeTagInappropriate);
return;
}
RaiseErrorOccurred(ErrorCode.TokenNotPossible);
CloseCurrentNode();
insert = HtmlTreeMode.InHead;
InHead(token);
}
private void AfterHead(HtmlToken token)
{
switch (token.Type) {
case HtmlTokenType.Character: {
string text = token.TrimStart();
AddCharacters(text);
if (token.IsEmpty)
return;
break;
}
case HtmlTokenType.Comment:
CurrentNode.AddComment(token.Data);
return;
case HtmlTokenType.DOCTYPE:
RaiseErrorOccurred(ErrorCode.DoctypeTagInappropriate);
return;
case HtmlTokenType.StartTag: {
string name = token.Name;
if (name == Tags.Html) {
InBody(token);
return;
}
if (name == Tags.Body) {
AfterHeadStartTagBody(token.AsTag());
return;
}
if (name == Tags.Frameset) {
AddElement<HTMLFrameSetElement>(token.AsTag(), false);
insert = HtmlTreeMode.InFrameset;
return;
}
if (name.IsOneOf(Tags.Link, Tags.Meta, Tags.Script, Tags.Style, Tags.Title) || name.IsOneOf(Tags.Base, Tags.BaseFont, Tags.Bgsound, Tags.NoFrames)) {
RaiseErrorOccurred(ErrorCode.TagMustBeInHead);
int count = open.Count;
open.Add(doc.Head as Element);
InHead(token);
open.RemoveAt(count);
return;
}
if (name == Tags.Head) {
RaiseErrorOccurred(ErrorCode.HeadTagMisplaced);
return;
}
break;
}
case HtmlTokenType.EndTag:
if (!token.Name.IsOneOf(Tags.Html, Tags.Body, Tags.Br)) {
RaiseErrorOccurred(ErrorCode.TagCannotEndHere);
return;
}
break;
}
AfterHeadStartTagBody(HtmlToken.OpenTag(Tags.Body));
frameset = true;
Home(token);
}
private void InBodyStartTag(HtmlTagToken tag)
{
string name = tag.Name;
if (name == Tags.Div) {
if (IsInButtonScope())
InBodyEndTagParagraph();
AddElement(tag, false);
} else if (name == Tags.A) {
for (int num = formatting.Count - 1; num >= 0; num--) {
if (formatting[num] == null)
break;
if (formatting[num] is HTMLAnchorElement) {
Element item = formatting[num];
RaiseErrorOccurred(ErrorCode.AnchorNested);
HeisenbergAlgorithm(HtmlToken.CloseTag(Tags.A));
if (open.Contains(item))
open.Remove(item);
if (formatting.Contains(item))
formatting.RemoveAt(num);
break;
}
}
ReconstructFormatting();
HTMLAnchorElement element = AddElement<HTMLAnchorElement>(tag, false);
formatting.AddFormatting(element);
} else if (name == Tags.Span) {
ReconstructFormatting();
AddElement(tag, false);
} else if (name == Tags.Li) {
InBodyStartTagListItem(tag);
} else if (name == Tags.Img) {
InBodyStartTagBreakrow(tag);
} else if (name.IsOneOf(Tags.Ul, Tags.P)) {
if (IsInButtonScope())
InBodyEndTagParagraph();
AddElement(tag, false);
} else if (name == Tags.Script) {
InHead(tag);
} else if (name.IsOneOf(Tags.H3, Tags.H2, Tags.H4, Tags.H1, Tags.H6, Tags.H5)) {
if (IsInButtonScope())
InBodyEndTagParagraph();
if (CurrentNode is HTMLHeadingElement) {
RaiseErrorOccurred(ErrorCode.HeadingNested);
CloseCurrentNode();
}
AddElement(new HTMLHeadingElement(name) {
Owner = doc
}, tag, false);
} else if (name == Tags.Input) {
ReconstructFormatting();
AddElement<HTMLInputElement>(tag, true);
CloseCurrentNode();
if (!tag.GetAttribute(AttributeNames.Type).Equals(AttributeNames.Hidden, StringComparison.OrdinalIgnoreCase))
frameset = false;
} else if (name == Tags.Form) {
if (form == null) {
if (IsInButtonScope())
InBodyEndTagParagraph();
form = AddElement<HTMLFormElement>(tag, false);
} else
RaiseErrorOccurred(ErrorCode.FormAlreadyOpen);
} else if (name.IsOneOf(Tags.Ol, Tags.Dl, Tags.Fieldset) || name.IsOneOf(Tags.Figcaption, Tags.Figure, Tags.Article, Tags.Aside, Tags.BlockQuote, Tags.Center) || name.IsOneOf(Tags.Address, Tags.Dialog, Tags.Dir, Tags.Summary, Tags.Details) || name.IsOneOf(Tags.Footer, Tags.Header, Tags.Nav, Tags.Section, Tags.Menu, Tags.Hgroup)) {
if (IsInButtonScope())
InBodyEndTagParagraph();
AddElement(tag, false);
} else if (name.IsOneOf(Tags.B, Tags.Strong, Tags.Code, Tags.Em, Tags.U, Tags.I) || name.IsOneOf(Tags.Font, Tags.S, Tags.Small, Tags.Strike, Tags.Big, Tags.Tt)) {
ReconstructFormatting();
HTMLElement element2 = HtmlElementFactory.Create(name, doc);
AddElement(element2, tag, false);
formatting.AddFormatting(element2);
} else if (name.IsOneOf(Tags.Caption, Tags.Col, Tags.Colgroup) || name.IsOneOf(Tags.Frame, Tags.Head) || name.IsOneOf(Tags.Tbody, Tags.Td, Tags.Tfoot, Tags.Th, Tags.Thead, Tags.Tr)) {
RaiseErrorOccurred(ErrorCode.TagCannotStartHere);
} else if (name.IsOneOf(Tags.Style, Tags.Link) || name.IsOneOf(Tags.Meta, Tags.MenuItem, Tags.Title, Tags.NoFrames, Tags.Template) || name.IsOneOf(Tags.Base, Tags.BaseFont, Tags.Bgsound)) {
InHead(tag);
} else if (name.IsOneOf(Tags.Pre, Tags.Listing)) {
if (IsInButtonScope())
InBodyEndTagParagraph();
AddElement(new HTMLPreElement(name) {
Owner = doc
}, tag, false);
frameset = false;
PreventNewLine();
} else if (name == Tags.Button) {
if (IsInScope<HTMLButtonElement>()) {
RaiseErrorOccurred(ErrorCode.ButtonInScope);
InBodyEndTagBlock(Tags.Button);
InBody(tag);
} else {
ReconstructFormatting();
AddElement<HTMLButtonElement>(tag, false);
frameset = false;
}
} else if (name == Tags.Table) {
if (doc.QuirksMode == QuirksMode.Off && IsInButtonScope())
InBodyEndTagParagraph();
AddElement<HTMLTableElement>(tag, false);
frameset = false;
insert = HtmlTreeMode.InTable;
} else if (name.IsOneOf(Tags.Br, Tags.Area, Tags.Embed, Tags.Keygen, Tags.Wbr)) {
InBodyStartTagBreakrow(tag);
} else if (name.IsOneOf(Tags.Param, Tags.Source, Tags.Track)) {
AddElement(tag, true);
CloseCurrentNode();
} else if (name == Tags.Hr) {
if (IsInButtonScope())
InBodyEndTagParagraph();
AddElement<HTMLHRElement>(tag, true);
CloseCurrentNode();
frameset = false;
} else if (name == Tags.Textarea) {
AddElement<HTMLTextAreaElement>(tag, false);
tokenizer.State = HtmlParseMode.RCData;
originalInsert = insert;
frameset = false;
insert = HtmlTreeMode.Text;
PreventNewLine();
} else if (name == Tags.Select) {
ReconstructFormatting();
AddElement<HTMLSelectElement>(tag, false);
frameset = false;
switch (insert) {
case HtmlTreeMode.InTable:
case HtmlTreeMode.InCaption:
case HtmlTreeMode.InRow:
case HtmlTreeMode.InCell:
insert = HtmlTreeMode.InSelectInTable;
break;
default:
insert = HtmlTreeMode.InSelect;
break;
}
} else if (name.IsOneOf(Tags.Optgroup, Tags.Option)) {
if (CurrentNode is HTMLOptionElement)
InBodyEndTagAnythingElse(HtmlToken.CloseTag(Tags.Option));
ReconstructFormatting();
AddElement(tag, false);
} else if (name.IsOneOf(Tags.Dd, Tags.Dt)) {
InBodyStartTagDefinitionItem(tag);
} else if (name == Tags.Iframe) {
frameset = false;
RawtextAlgorithm(tag);
} else if (name.IsOneOf(Tags.Applet, Tags.Marquee, Tags.Object)) {
ReconstructFormatting();
AddElement(tag, false);
formatting.AddScopeMarker();
frameset = false;
} else if (name == Tags.Image) {
RaiseErrorOccurred(ErrorCode.ImageTagNamedWrong);
tag.Name = Tags.Img;
InBodyStartTagBreakrow(tag);
} else if (name == Tags.NoBr) {
ReconstructFormatting();
if (IsInScope<HTMLNoNewlineElement>()) {
RaiseErrorOccurred(ErrorCode.NobrInScope);
HeisenbergAlgorithm(tag);
ReconstructFormatting();
}
HTMLElement element3 = HtmlElementFactory.Create(name, doc);
AddElement(element3, tag, false);
formatting.AddFormatting(element3);
} else if (name == Tags.Xmp) {
if (IsInButtonScope())
InBodyEndTagParagraph();
ReconstructFormatting();
frameset = false;
RawtextAlgorithm(tag);
} else if (name.IsOneOf(Tags.Rp, Tags.Rt)) {
if (IsInScope<HTMLRubyElement>()) {
GenerateImpliedEndTags();
if (!(CurrentNode is HTMLRubyElement))
RaiseErrorOccurred(ErrorCode.TagDoesNotMatchCurrentNode);
}
AddElement(tag, false);
} else if (name == Tags.NoEmbed) {
RawtextAlgorithm(tag);
} else if (name == Tags.NoScript) {
if (doc.Options.IsScripting)
RawtextAlgorithm(tag);
else {
ReconstructFormatting();
AddElement(tag, false);
}
} else if (name == Tags.Math) {
MathElement mathElement = new MathElement(name, NodeFlags.None);
mathElement.Owner = doc;
MathElement mathElement2 = mathElement;
ReconstructFormatting();
for (int i = 0; i < tag.Attributes.Count; i++) {
string key = tag.Attributes[i].Key;
string value = tag.Attributes[i].Value;
mathElement2.SetAdjustedAttribute(key.AdjustMathMLAttributeName(), value);
}
AddElement(mathElement2);
if (tag.IsSelfClosing)
open.Remove(mathElement2);
} else if (name == Tags.Svg) {
SVGElement sVGElement = new SVGElement(name, NodeFlags.None);
sVGElement.Owner = doc;
SVGElement sVGElement2 = sVGElement;
ReconstructFormatting();
for (int j = 0; j < tag.Attributes.Count; j++) {
string key2 = tag.Attributes[j].Key;
string value2 = tag.Attributes[j].Value;
sVGElement2.SetAdjustedAttribute(key2.AdjustSvgAttributeName(), value2);
}
AddElement(sVGElement2);
if (tag.IsSelfClosing)
open.Remove(sVGElement2);
} else if (name == Tags.Plaintext) {
if (IsInButtonScope())
InBodyEndTagParagraph();
AddElement(tag, false);
tokenizer.State = HtmlParseMode.Plaintext;
} else if (name == Tags.Frameset) {
RaiseErrorOccurred(ErrorCode.FramesetMisplaced);
if (open.Count != 1 && open[1] is HTMLBodyElement && frameset) {
open[1].Parent.RemoveChild(open[1]);
while (open.Count > 1) {
CloseCurrentNode();
}
AddElement<HTMLFrameSetElement>(tag, false);
insert = HtmlTreeMode.InFrameset;
}
} else if (name == Tags.Html) {
RaiseErrorOccurred(ErrorCode.HtmlTagMisplaced);
if (templateMode.Count == 0)
open[0].SetAttributes(tag.Attributes);
} else if (name == Tags.Body) {
RaiseErrorOccurred(ErrorCode.BodyTagMisplaced);
if (templateMode.Count == 0 && open.Count > 1 && open[1] is HTMLBodyElement) {
frameset = false;
open[1].SetAttributes(tag.Attributes);
}
} else if (name == Tags.IsIndex) {
RaiseErrorOccurred(ErrorCode.TagInappropriate);
if (form == null) {
InBody(HtmlToken.OpenTag(Tags.Form));
if (tag.GetAttribute(AttributeNames.Action) != string.Empty)
form.SetAttribute(AttributeNames.Action, tag.GetAttribute(AttributeNames.Action));
InBody(HtmlToken.OpenTag(Tags.Hr));
InBody(HtmlToken.OpenTag(Tags.Label));
if (tag.GetAttribute(AttributeNames.Prompt) != string.Empty)
AddCharacters(tag.GetAttribute(AttributeNames.Prompt));
else
AddCharacters("This is a searchable index. Enter search keywords: ");
HtmlTagToken htmlTagToken = HtmlToken.OpenTag(Tags.Input);
htmlTagToken.AddAttribute(AttributeNames.Name, Tags.IsIndex);
for (int k = 0; k < tag.Attributes.Count; k++) {
if (!tag.Attributes[k].Key.IsOneOf(AttributeNames.Name, AttributeNames.Action, AttributeNames.Prompt))
htmlTagToken.AddAttribute(tag.Attributes[k].Key, tag.Attributes[k].Value);
}
InBody(htmlTagToken);
InBody(HtmlToken.CloseTag(Tags.Label));
InBody(HtmlToken.OpenTag(Tags.Hr));
InBody(HtmlToken.CloseTag(Tags.Form));
}
} else {
ReconstructFormatting();
AddElement(tag, false);
}
}
private void InBodyEndTag(HtmlTagToken tag)
{
string name = tag.Name;
if (name == Tags.Div)
InBodyEndTagBlock(name);
else if (name == Tags.A) {
HeisenbergAlgorithm(tag);
} else if (name == Tags.Li) {
if (IsInListItemScope()) {
GenerateImpliedEndTagsExceptFor(name);
if (!(CurrentNode is HTMLLIElement))
RaiseErrorOccurred(ErrorCode.TagDoesNotMatchCurrentNode);
ClearStackBackTo<HTMLLIElement>();
CloseCurrentNode();
} else
RaiseErrorOccurred(ErrorCode.ListItemNotInScope);
} else if (name == Tags.P) {
InBodyEndTagParagraph();
} else if (name.IsOneOf(Tags.Ol, Tags.Ul, Tags.Dl, Tags.Fieldset, Tags.Button) || name.IsOneOf(Tags.Figcaption, Tags.Figure, Tags.Article, Tags.Aside, Tags.BlockQuote, Tags.Center) || name.IsOneOf(Tags.Address, Tags.Dialog, Tags.Dir, Tags.Summary, Tags.Details, Tags.Listing) || name.IsOneOf(Tags.Footer, Tags.Header, Tags.Nav, Tags.Section, Tags.Menu, Tags.Hgroup) || name.IsOneOf(Tags.Main, Tags.Pre)) {
InBodyEndTagBlock(name);
} else if (name.IsOneOf(Tags.B, Tags.Strong, Tags.Code) || name.IsOneOf(Tags.NoBr, Tags.Em, Tags.U, Tags.I) || name.IsOneOf(Tags.Font, Tags.S, Tags.Small, Tags.Strike, Tags.Big, Tags.Tt)) {
HeisenbergAlgorithm(tag);
} else if (name == Tags.Form) {
HTMLFormElement hTMLFormElement = form;
form = null;
if (hTMLFormElement != null && IsInScope(hTMLFormElement.NodeName)) {
GenerateImpliedEndTags();
if (CurrentNode != hTMLFormElement)
RaiseErrorOccurred(ErrorCode.FormClosedWrong);
open.Remove(hTMLFormElement);
} else
RaiseErrorOccurred(ErrorCode.FormNotInScope);
} else if (name == Tags.Br) {
RaiseErrorOccurred(ErrorCode.TagCannotEndHere);
InBodyStartTagBreakrow(HtmlToken.OpenTag(Tags.Br));
} else if (name.IsOneOf(Tags.H3, Tags.H2, Tags.H4, Tags.H1, Tags.H6, Tags.H5)) {
if (IsInScope<HTMLHeadingElement>()) {
GenerateImpliedEndTags();
if (CurrentNode.NodeName != name)
RaiseErrorOccurred(ErrorCode.TagDoesNotMatchCurrentNode);
ClearStackBackTo<HTMLHeadingElement>();
CloseCurrentNode();
} else
RaiseErrorOccurred(ErrorCode.HeadingNotInScope);
} else if (name.IsOneOf(Tags.Dd, Tags.Dt)) {
if (IsInScope(name)) {
GenerateImpliedEndTagsExceptFor(name);
if (CurrentNode.NodeName != name)
RaiseErrorOccurred(ErrorCode.TagDoesNotMatchCurrentNode);
ClearStackBackTo(name);
CloseCurrentNode();
} else
RaiseErrorOccurred(ErrorCode.ListItemNotInScope);
} else if (name.IsOneOf(Tags.Applet, Tags.Marquee, Tags.Object)) {
if (IsInScope(name)) {
GenerateImpliedEndTags();
if (CurrentNode.NodeName != name)
RaiseErrorOccurred(ErrorCode.TagDoesNotMatchCurrentNode);
ClearStackBackTo(name);
CloseCurrentNode();
formatting.ClearFormatting();
} else
RaiseErrorOccurred(ErrorCode.ObjectNotInScope);
} else if (name == Tags.Body) {
InBodyEndTagBody();
} else if (name == Tags.Html) {
if (InBodyEndTagBody())
AfterBody(tag);
} else if (name == Tags.Template) {
InHead(tag);
} else {
InBodyEndTagAnythingElse(tag);
}
}
private void InBody(HtmlToken token)
{
switch (token.Type) {
case HtmlTokenType.Character:
ReconstructFormatting();
AddCharacters(token.Data);
if (token.HasContent)
frameset = false;
break;
case HtmlTokenType.StartTag:
InBodyStartTag(token.AsTag());
break;
case HtmlTokenType.EndTag:
InBodyEndTag(token.AsTag());
break;
case HtmlTokenType.Comment:
CurrentNode.AddComment(token.Data);
break;
case HtmlTokenType.DOCTYPE:
RaiseErrorOccurred(ErrorCode.DoctypeTagInappropriate);
break;
case HtmlTokenType.EOF:
CheckBodyOnClosing();
if (templateMode.Count != 0)
InTemplate(token);
else
End();
break;
}
}
private void Text(HtmlToken token)
{
switch (token.Type) {
case HtmlTokenType.Comment:
break;
case HtmlTokenType.Character:
AddCharacters(token.Data);
break;
case HtmlTokenType.EndTag:
if (token.Name != Tags.Script) {
CloseCurrentNode();
insert = originalInsert;
} else
RunScript(CurrentNode as HTMLScriptElement);
break;
case HtmlTokenType.EOF:
RaiseErrorOccurred(ErrorCode.EOF);
CloseCurrentNode();
insert = originalInsert;
Consume(token);
break;
}
}
private void InTable(HtmlToken token)
{
switch (token.Type) {
case HtmlTokenType.Comment:
CurrentNode.AddComment(token.Data);
return;
case HtmlTokenType.DOCTYPE:
RaiseErrorOccurred(ErrorCode.DoctypeTagInappropriate);
return;
case HtmlTokenType.StartTag: {
string name2 = token.Name;
if (name2 == Tags.Caption) {
ClearStackBackTo<HTMLTableElement>();
formatting.AddScopeMarker();
AddElement<HTMLTableCaptionElement>(token.AsTag(), false);
insert = HtmlTreeMode.InCaption;
} else if (name2 == Tags.Colgroup) {
ClearStackBackTo<HTMLTableElement>();
AddElement<HTMLTableColgroupElement>(token.AsTag(), false);
insert = HtmlTreeMode.InColumnGroup;
} else if (name2 == Tags.Col) {
InTable(HtmlToken.OpenTag(Tags.Colgroup));
InColumnGroup(token);
} else if (name2.IsOneOf(Tags.Tbody, Tags.Thead, Tags.Tfoot)) {
ClearStackBackTo<HTMLTableElement>();
HTMLTableSectionElement hTMLTableSectionElement = new HTMLTableSectionElement(name2);
hTMLTableSectionElement.Owner = doc;
HTMLTableSectionElement element = hTMLTableSectionElement;
AddElement(element, token.AsTag(), false);
insert = HtmlTreeMode.InTableBody;
} else if (name2.IsOneOf(Tags.Td, Tags.Th, Tags.Tr)) {
InTable(HtmlToken.OpenTag(Tags.Tbody));
InTableBody(token);
} else if (name2 == Tags.Table) {
RaiseErrorOccurred(ErrorCode.TableNesting);
if (InTableEndTagTable())
Home(token);
} else if (name2.IsOneOf(Tags.Script, Tags.Style, Tags.Template)) {
InHead(token);
} else if (name2 == Tags.Input) {
HtmlTagToken htmlTagToken = token.AsTag();
if (htmlTagToken.GetAttribute(AttributeNames.Type).Equals(AttributeNames.Hidden, StringComparison.OrdinalIgnoreCase)) {
RaiseErrorOccurred(ErrorCode.InputUnexpected);
AddElement<HTMLInputElement>(htmlTagToken, true);
CloseCurrentNode();
} else {
RaiseErrorOccurred(ErrorCode.TokenNotPossible);
InBodyWithFoster(token);
}
} else if (name2 == Tags.Form) {
RaiseErrorOccurred(ErrorCode.FormInappropriate);
if (form == null) {
form = AddElement<HTMLFormElement>(token.AsTag(), false);
CloseCurrentNode();
}
} else {
RaiseErrorOccurred(ErrorCode.IllegalElementInTableDetected);
InBodyWithFoster(token);
}
return;
}
case HtmlTokenType.EndTag: {
string name = token.Name;
if (name == Tags.Table)
InTableEndTagTable();
else if (name == Tags.Template) {
InHead(token);
} else if (name.IsOneOf(Tags.Body, Tags.Colgroup, Tags.Col, Tags.Caption, Tags.Html) || name.IsOneOf(Tags.Tbody, Tags.Tr, Tags.Thead, Tags.Th, Tags.Tfoot, Tags.Td)) {
RaiseErrorOccurred(ErrorCode.TagCannotEndHere);
} else {
RaiseErrorOccurred(ErrorCode.IllegalElementInTableDetected);
InBodyWithFoster(token);
}
return;
}
case HtmlTokenType.EOF:
InBody(token);
return;
case HtmlTokenType.Character:
if (CurrentNode.IsTableElement()) {
InTableText(token);
return;
}
break;
}
RaiseErrorOccurred(ErrorCode.TokenNotPossible);
InBodyWithFoster(token);
}
private void InTableText(HtmlToken token)
{
if (token.HasContent) {
RaiseErrorOccurred(ErrorCode.TokenNotPossible);
InBodyWithFoster(token);
} else
AddCharacters(token.Data);
}
private void InCaption(HtmlToken token)
{
switch (token.Type) {
case HtmlTokenType.EndTag: {
string name2 = token.Name;
if (name2 == Tags.Caption) {
InCaptionEndTagCaption();
return;
}
if (name2.IsOneOf(Tags.Body, Tags.Th, Tags.Colgroup, Tags.Html) || name2.IsOneOf(Tags.Tbody, Tags.Col, Tags.Tfoot, Tags.Td, Tags.Thead, Tags.Tr)) {
RaiseErrorOccurred(ErrorCode.TagCannotEndHere);
return;
}
if (name2 == Tags.Table) {
RaiseErrorOccurred(ErrorCode.TableNesting);
if (InCaptionEndTagCaption())
InTable(token);
return;
}
break;
}
case HtmlTokenType.StartTag: {
string name = token.Name;
if (name.IsOneOf(Tags.Caption, Tags.Th, Tags.Colgroup) || name.IsOneOf(Tags.Tbody, Tags.Col, Tags.Tfoot, Tags.Td, Tags.Thead, Tags.Tr)) {
RaiseErrorOccurred(ErrorCode.TagCannotStartHere);
if (InCaptionEndTagCaption())
InTable(token);
return;
}
break;
}
}
InBody(token);
}
private void InColumnGroup(HtmlToken token)
{
switch (token.Type) {
case HtmlTokenType.Character: {
string text = token.TrimStart();
AddCharacters(text);
return;
}
case HtmlTokenType.Comment:
CurrentNode.AddComment(token.Data);
return;
case HtmlTokenType.DOCTYPE:
RaiseErrorOccurred(ErrorCode.DoctypeTagInappropriate);
return;
case HtmlTokenType.StartTag: {
string name2 = token.Name;
if (name2 == Tags.Html) {
InBody(token);
return;
}
if (name2 == Tags.Col) {
AddElement<HTMLTableColElement>(token.AsTag(), true);
CloseCurrentNode();
return;
}
if (name2 == Tags.Template) {
InHead(token);
return;
}
break;
}
case HtmlTokenType.EndTag: {
string name = token.Name;
if (name == Tags.Colgroup) {
InColumnGroupEndTagColgroup();
return;
}
if (name == Tags.Col) {
RaiseErrorOccurred(ErrorCode.TagClosedWrong);
return;
}
if (name == Tags.Template) {
InHead(token);
return;
}
break;
}
case HtmlTokenType.EOF:
InBody(token);
return;
}
if (InColumnGroupEndTagColgroup())
InTable(token);
}
private void InTableBody(HtmlToken token)
{
switch (token.Type) {
case HtmlTokenType.StartTag: {
string name2 = token.Name;
if (name2 == Tags.Tr) {
ClearStackBackTo<HTMLTableSectionElement>();
AddElement<HTMLTableRowElement>(token.AsTag(), false);
insert = HtmlTreeMode.InRow;
return;
}
if (name2.IsTableCellElement()) {
InTableBody(HtmlToken.OpenTag(Tags.Tr));
InRow(token);
return;
}
if (name2.IsGeneralTableElement(false)) {
InTableBodyCloseTable(token.AsTag());
return;
}
break;
}
case HtmlTokenType.EndTag: {
string name = token.Name;
if (name.IsTableSectionElement()) {
if (IsInTableScope(name)) {
ClearStackBackTo<HTMLTableSectionElement>();
CloseCurrentNode();
insert = HtmlTreeMode.InTable;
} else
RaiseErrorOccurred(ErrorCode.TableSectionNotInScope);
return;
}
if (name.IsSpecialTableElement(true)) {
RaiseErrorOccurred(ErrorCode.TagCannotEndHere);
return;
}
if (name == Tags.Table) {
InTableBodyCloseTable(token.AsTag());
return;
}
break;
}
}
InTable(token);
}
private void InRow(HtmlToken token)
{
switch (token.Type) {
case HtmlTokenType.StartTag: {
string name2 = token.Name;
if (name2.IsTableCellElement()) {
ClearStackBackTo<HTMLTableRowElement>();
HTMLElement element = HtmlElementFactory.Create(name2, doc);
AddElement(element, token.AsTag(), false);
insert = HtmlTreeMode.InCell;
formatting.AddScopeMarker();
return;
}
if (name2.IsGeneralTableElement(true)) {
if (InRowEndTagTablerow())
InTableBody(token);
return;
}
break;
}
case HtmlTokenType.EndTag: {
string name = token.Name;
if (name == Tags.Tr) {
InRowEndTagTablerow();
return;
}
if (name == Tags.Table) {
if (InRowEndTagTablerow())
InTableBody(token);
return;
}
if (name.IsTableSectionElement()) {
if (IsInTableScope(name)) {
InRowEndTagTablerow();
InTableBody(token);
} else
RaiseErrorOccurred(ErrorCode.TableSectionNotInScope);
return;
}
if (name.IsSpecialTableElement(false)) {
RaiseErrorOccurred(ErrorCode.TagCannotEndHere);
return;
}
break;
}
}
InTable(token);
}
private void InCell(HtmlToken token)
{
switch (token.Type) {
case HtmlTokenType.StartTag: {
string name2 = token.Name;
if (name2.IsTableCellElement() || name2.IsGeneralTableElement(true)) {
if (IsInTableScope(Tags.Td) || IsInTableScope(Tags.Th)) {
InCellEndTagCell();
Home(token);
} else
RaiseErrorOccurred(ErrorCode.TableCellNotInScope);
return;
}
break;
}
case HtmlTokenType.EndTag: {
string name = token.Name;
if (name.IsTableCellElement())
InCellEndTagCell();
else if (name.IsSpecialTableElement(false)) {
RaiseErrorOccurred(ErrorCode.TagCannotEndHere);
} else if (name.IsTableElement()) {
if (IsInTableScope(name)) {
InCellEndTagCell();
Home(token);
} else
RaiseErrorOccurred(ErrorCode.TableNotInScope);
} else {
InBody(token);
}
return;
}
}
InBody(token);
}
private void InSelect(HtmlToken token)
{
switch (token.Type) {
case HtmlTokenType.Character:
AddCharacters(token.Data);
break;
case HtmlTokenType.Comment:
CurrentNode.AddComment(token.Data);
break;
case HtmlTokenType.DOCTYPE:
RaiseErrorOccurred(ErrorCode.DoctypeTagInappropriate);
break;
case HtmlTokenType.StartTag: {
string name2 = token.Name;
if (name2 == Tags.Html)
InBody(token);
else if (name2 == Tags.Option) {
if (CurrentNode is HTMLOptionElement)
InSelectEndTagOption();
AddElement<HTMLOptionElement>(token.AsTag(), false);
} else if (name2 == Tags.Optgroup) {
if (CurrentNode is HTMLOptionElement)
InSelectEndTagOption();
if (CurrentNode is HTMLOptGroupElement)
InSelectEndTagOptgroup();
AddElement<HTMLOptGroupElement>(token.AsTag(), false);
} else if (name2 == Tags.Select) {
RaiseErrorOccurred(ErrorCode.SelectNesting);
InSelectEndTagSelect();
} else if (name2.IsOneOf(Tags.Input, Tags.Keygen, Tags.Textarea)) {
RaiseErrorOccurred(ErrorCode.IllegalElementInSelectDetected);
if (IsInSelectScope(Tags.Select)) {
InSelectEndTagSelect();
Home(token);
}
} else if (name2.IsOneOf(Tags.Template, Tags.Script)) {
InHead(token);
} else {
RaiseErrorOccurred(ErrorCode.IllegalElementInSelectDetected);
}
break;
}
case HtmlTokenType.EndTag: {
string name = token.Name;
if (name == Tags.Template)
InHead(token);
else if (name == Tags.Optgroup) {
InSelectEndTagOptgroup();
} else if (name == Tags.Option) {
InSelectEndTagOption();
} else if (name == Tags.Select) {
if (IsInSelectScope(Tags.Select))
InSelectEndTagSelect();
else
RaiseErrorOccurred(ErrorCode.SelectNotInScope);
} else {
RaiseErrorOccurred(ErrorCode.TagCannotEndHere);
}
break;
}
case HtmlTokenType.EOF:
InBody(token);
break;
default:
RaiseErrorOccurred(ErrorCode.TokenNotPossible);
break;
}
}
private void InSelectInTable(HtmlToken token)
{
switch (token.Type) {
case HtmlTokenType.StartTag: {
string name2 = token.Name;
if (name2.IsTableCellElement() || name2.IsTableElement() || name2 == Tags.Caption) {
RaiseErrorOccurred(ErrorCode.IllegalElementInSelectDetected);
InSelectEndTagSelect();
Home(token);
return;
}
break;
}
case HtmlTokenType.EndTag: {
string name = token.Name;
if (name.IsTableCellElement() || name.IsTableElement() || name == Tags.Caption) {
RaiseErrorOccurred(ErrorCode.TagCannotEndHere);
if (IsInTableScope(name)) {
InSelectEndTagSelect();
Home(token);
}
return;
}
break;
}
}
InSelect(token);
}
private void InTemplate(HtmlToken token)
{
switch (token.Type) {
case HtmlTokenType.StartTag: {
string name = token.Name;
if (name.IsOneOf(Tags.Link, Tags.Meta, Tags.Script, Tags.Style) || name.IsOneOf(Tags.Base, Tags.BaseFont, Tags.Bgsound, Tags.NoFrames, Tags.Template, Tags.Title))
InHead(token);
else if (name.IsOneOf(Tags.Caption, Tags.Colgroup, Tags.Tbody, Tags.Tfoot, Tags.Thead)) {
TemplateStep(token, HtmlTreeMode.InTable);
} else if (name == Tags.Col) {
TemplateStep(token, HtmlTreeMode.InColumnGroup);
} else if (name == Tags.Tr) {
TemplateStep(token, HtmlTreeMode.InTableBody);
} else if (name.IsOneOf(Tags.Td, Tags.Th)) {
TemplateStep(token, HtmlTreeMode.InRow);
} else {
TemplateStep(token, HtmlTreeMode.InBody);
}
break;
}
case HtmlTokenType.EndTag:
if (token.Name == Tags.Template)
InHead(token);
else
RaiseErrorOccurred(ErrorCode.TagCannotEndHere);
break;
case HtmlTokenType.EOF:
if (TagCurrentlyOpen(Tags.Template)) {
RaiseErrorOccurred(ErrorCode.EOF);
CloseTemplate();
Home(token);
} else
End();
break;
default:
InBody(token);
break;
}
}
private void AfterBody(HtmlToken token)
{
switch (token.Type) {
case HtmlTokenType.Character: {
string text = token.TrimStart();
ReconstructFormatting();
AddCharacters(text);
if (token.IsEmpty)
return;
break;
}
case HtmlTokenType.Comment:
open[0].AddComment(token.Data);
return;
case HtmlTokenType.DOCTYPE:
RaiseErrorOccurred(ErrorCode.DoctypeTagInappropriate);
return;
case HtmlTokenType.StartTag:
if (token.Name == Tags.Html) {
InBody(token);
return;
}
break;
case HtmlTokenType.EndTag:
if (token.Name == Tags.Html) {
if (IsFragmentCase)
RaiseErrorOccurred(ErrorCode.TagInvalidInFragmentMode);
else
insert = HtmlTreeMode.AfterAfterBody;
return;
}
break;
case HtmlTokenType.EOF:
End();
return;
}
RaiseErrorOccurred(ErrorCode.TokenNotPossible);
insert = HtmlTreeMode.InBody;
InBody(token);
}
private void InFrameset(HtmlToken token)
{
switch (token.Type) {
case HtmlTokenType.Character: {
string text = token.TrimStart();
AddCharacters(text);
if (token.IsEmpty)
return;
break;
}
case HtmlTokenType.Comment:
CurrentNode.AddComment(token.Data);
return;
case HtmlTokenType.DOCTYPE:
RaiseErrorOccurred(ErrorCode.DoctypeTagInappropriate);
return;
case HtmlTokenType.StartTag: {
string name = token.Name;
if (name == Tags.Html) {
InBody(token);
return;
}
if (name == Tags.Frameset) {
AddElement<HTMLFrameSetElement>(token.AsTag(), false);
return;
}
if (name == Tags.Frame) {
AddElement<HTMLFrameElement>(token.AsTag(), true);
CloseCurrentNode();
return;
}
if (name == Tags.NoFrames) {
InHead(token);
return;
}
break;
}
case HtmlTokenType.EndTag:
if (!(token.Name != Tags.Frameset)) {
if (CurrentNode != open[0]) {
CloseCurrentNode();
if (!IsFragmentCase && !(CurrentNode is HTMLFrameSetElement))
insert = HtmlTreeMode.AfterFrameset;
} else
RaiseErrorOccurred(ErrorCode.CurrentNodeIsRoot);
return;
}
break;
case HtmlTokenType.EOF:
if (CurrentNode != doc.DocumentElement)
RaiseErrorOccurred(ErrorCode.CurrentNodeIsNotRoot);
End();
return;
}
RaiseErrorOccurred(ErrorCode.TokenNotPossible);
}
private void AfterFrameset(HtmlToken token)
{
switch (token.Type) {
case HtmlTokenType.Character: {
string text = token.TrimStart();
AddCharacters(text);
if (token.IsEmpty)
return;
break;
}
case HtmlTokenType.Comment:
CurrentNode.AddComment(token.Data);
return;
case HtmlTokenType.DOCTYPE:
RaiseErrorOccurred(ErrorCode.DoctypeTagInappropriate);
return;
case HtmlTokenType.StartTag: {
string name = token.Name;
if (name == Tags.Html) {
InBody(token);
return;
}
if (name == Tags.NoFrames) {
InHead(token);
return;
}
break;
}
case HtmlTokenType.EndTag:
if (!(token.Name != Tags.Html)) {
insert = HtmlTreeMode.AfterAfterFrameset;
return;
}
break;
case HtmlTokenType.EOF:
End();
return;
}
RaiseErrorOccurred(ErrorCode.TokenNotPossible);
}
private void AfterAfterBody(HtmlToken token)
{
switch (token.Type) {
case HtmlTokenType.Comment:
doc.AddComment(token.Data);
return;
case HtmlTokenType.Character: {
string text = token.TrimStart();
ReconstructFormatting();
AddCharacters(text);
if (token.IsEmpty)
return;
break;
}
case HtmlTokenType.DOCTYPE:
InBody(token);
return;
case HtmlTokenType.StartTag:
if (!(token.Name != Tags.Html)) {
InBody(token);
return;
}
break;
case HtmlTokenType.EOF:
End();
return;
}
RaiseErrorOccurred(ErrorCode.TokenNotPossible);
insert = HtmlTreeMode.InBody;
InBody(token);
}
private void AfterAfterFrameset(HtmlToken token)
{
switch (token.Type) {
case HtmlTokenType.Comment:
doc.AddComment(token.Data);
return;
case HtmlTokenType.Character: {
string text = token.TrimStart();
ReconstructFormatting();
AddCharacters(text);
if (token.IsEmpty)
return;
break;
}
case HtmlTokenType.DOCTYPE:
InBody(token);
return;
case HtmlTokenType.StartTag: {
string name = token.Name;
if (name == Tags.Html) {
InBody(token);
return;
}
if (name == Tags.NoFrames) {
InHead(token);
return;
}
break;
}
case HtmlTokenType.EOF:
End();
return;
}
RaiseErrorOccurred(ErrorCode.TokenNotPossible);
}
private void TemplateStep(HtmlToken token, HtmlTreeMode mode)
{
templateMode.Pop();
templateMode.Push(mode);
insert = mode;
Home(token);
}
private void CloseTemplate()
{
while (open.Count > 0) {
Element currentNode = CurrentNode;
CloseCurrentNode();
if (currentNode is HTMLTemplateElement)
break;
}
formatting.ClearFormatting();
templateMode.Pop();
Reset(null);
}
private void InTableBodyCloseTable(HtmlTagToken tag)
{
if (IsInTableScope<HTMLTableSectionElement>()) {
ClearStackBackTo<HTMLTableSectionElement>();
CloseCurrentNode();
insert = HtmlTreeMode.InTable;
InTable(tag);
} else
RaiseErrorOccurred(ErrorCode.TableSectionNotInScope);
}
private void InSelectEndTagOption()
{
if (CurrentNode is HTMLOptionElement)
CloseCurrentNode();
else
RaiseErrorOccurred(ErrorCode.TagDoesNotMatchCurrentNode);
}
private void InSelectEndTagOptgroup()
{
if (open.Count > 1 && open[open.Count - 1] is HTMLOptionElement && open[open.Count - 2] is HTMLOptGroupElement)
CloseCurrentNode();
if (CurrentNode is HTMLOptGroupElement)
CloseCurrentNode();
else
RaiseErrorOccurred(ErrorCode.TagDoesNotMatchCurrentNode);
}
private bool InColumnGroupEndTagColgroup()
{
if (CurrentNode.NodeName == Tags.Colgroup) {
CloseCurrentNode();
insert = HtmlTreeMode.InTable;
return true;
}
RaiseErrorOccurred(ErrorCode.TagDoesNotMatchCurrentNode);
return false;
}
private void AfterHeadStartTagBody(HtmlTagToken token)
{
AddElement<HTMLBodyElement>(token, false);
frameset = false;
insert = HtmlTreeMode.InBody;
}
private void RawtextAlgorithm(HtmlTagToken tag)
{
HTMLElement element = HtmlElementFactory.Create(tag.Name, doc);
AddElement(element, tag, false);
originalInsert = insert;
insert = HtmlTreeMode.Text;
tokenizer.State = HtmlParseMode.Rawtext;
}
private void RCDataAlgorithm(HtmlTagToken tag)
{
HTMLElement element = HtmlElementFactory.Create(tag.Name, doc);
AddElement(element, tag, false);
originalInsert = insert;
insert = HtmlTreeMode.Text;
tokenizer.State = HtmlParseMode.RCData;
}
private void InBodyStartTagListItem(HtmlTagToken tag)
{
int num = open.Count - 1;
Element element = open[num];
frameset = false;
while (true) {
if (element is HTMLLIElement && element.NodeName == Tags.Li) {
InBody(HtmlToken.CloseTag(element.NodeName));
break;
}
if (!(element is HTMLAddressElement) && !(element is HTMLDivElement) && !(element is HTMLParagraphElement) && element.Flags.HasFlag(NodeFlags.Special))
break;
element = open[--num];
}
if (IsInButtonScope())
InBodyEndTagParagraph();
HTMLElement element2 = HtmlElementFactory.Create(tag.Name, doc);
AddElement(element2, tag, false);
}
private void InBodyStartTagDefinitionItem(HtmlTagToken tag)
{
frameset = false;
int num = open.Count - 1;
Element element = open[num];
while (true) {
if (element is HTMLLIElement && (element.NodeName == Tags.Dd || element.NodeName == Tags.Dt)) {
InBody(HtmlToken.CloseTag(element.NodeName));
break;
}
if (element.Flags.HasFlag(NodeFlags.Special) && !(element is HTMLAddressElement) && !(element is HTMLDivElement) && !(element is HTMLParagraphElement))
break;
element = open[--num];
}
if (IsInButtonScope())
InBodyEndTagParagraph();
HTMLElement element2 = HtmlElementFactory.Create(tag.Name, doc);
AddElement(element2, tag, false);
}
private bool InBodyEndTagBlock(string tagName)
{
if (IsInScope(tagName)) {
GenerateImpliedEndTags();
if (CurrentNode.NodeName != tagName)
RaiseErrorOccurred(ErrorCode.TagDoesNotMatchCurrentNode);
ClearStackBackTo(tagName);
CloseCurrentNode();
return true;
}
RaiseErrorOccurred(ErrorCode.BlockNotInScope);
return false;
}
private void HeisenbergAlgorithm(HtmlTagToken tag)
{
int num = 0;
int num2 = 0;
int num3 = 0;
int num4 = 0;
Element element;
Element element2;
while (true) {
if (num >= 8)
return;
element = null;
element2 = null;
num++;
num4 = 0;
num2 = 0;
for (int num5 = formatting.Count - 1; num5 >= 0; num5--) {
if (formatting[num5] == null)
break;
if (formatting[num5].NodeName == tag.Name) {
num4 = num5;
element = formatting[num5];
break;
}
}
if (element == null) {
InBodyEndTagAnythingElse(tag);
return;
}
int num6 = open.IndexOf(element);
if (num6 == -1) {
RaiseErrorOccurred(ErrorCode.FormattingElementNotFound);
formatting.Remove(element);
return;
}
if (!IsInScope(element.NodeName)) {
RaiseErrorOccurred(ErrorCode.ElementNotInScope);
return;
}
if (num6 != open.Count - 1)
RaiseErrorOccurred(ErrorCode.TagClosedWrong);
num3 = num4;
for (int i = num6 + 1; i < open.Count; i++) {
if (open[i].Flags.HasFlag(NodeFlags.Special)) {
num4 = i;
element2 = open[i];
break;
}
}
if (element2 == null)
break;
Element element3 = open[num6 - 1];
Element element4 = element2;
Element element5 = element2;
while (true) {
num2++;
element4 = open[--num4];
if (element4 == element)
break;
if (num2 > 3 && formatting.Contains(element4))
formatting.Remove(element4);
if (!formatting.Contains(element4))
open.Remove(element4);
else {
Element element6 = CopyElement(element4);
element3.AddNode(element6);
open[num4] = element6;
for (int j = 0; j != formatting.Count; j++) {
if (formatting[j] == element4) {
formatting[j] = element6;
break;
}
}
element4 = element6;
if (element5 == element2)
num3++;
if (element5.Parent != null)
element5.Parent.RemoveChild(element5);
element4.AddNode(element5);
element5 = element4;
}
}
if (!element3.IsTableElement()) {
if (element5.Parent != null)
element5.Parent.RemoveChild(element5);
element3.AddNode(element5);
} else
AddElementWithFoster(element5);
Element element7 = CopyElement(element);
while (element2.ChildNodes.Length > 0) {
Node node = element2.ChildNodes[0];
element2.RemoveNode(0, node);
element7.AddNode(node);
}
element2.AddNode(element7);
formatting.Remove(element);
formatting.Insert(num3, element7);
open.Remove(element);
open.Insert(open.IndexOf(element2) + 1, element7);
}
do {
element2 = CurrentNode;
CloseCurrentNode();
} while (element2 != element);
formatting.Remove(element);
}
private Element CopyElement(Element element)
{
HTMLElement hTMLElement = HtmlElementFactory.Create(element.NodeName, doc);
foreach (IAttr attribute in element.Attributes) {
hTMLElement.AddAttribute(attribute.Name, attribute.Value);
}
return hTMLElement;
}
private void InBodyWithFoster(HtmlToken token)
{
foster = true;
InBody(token);
foster = false;
}
private void InBodyEndTagAnythingElse(HtmlTagToken tag)
{
int num = open.Count - 1;
Element element = CurrentNode;
while (true) {
if (element.NodeName == tag.Name) {
GenerateImpliedEndTagsExceptFor(tag.Name);
if (element.NodeName == tag.Name)
RaiseErrorOccurred(ErrorCode.TagClosedWrong);
int num2 = open.Count - 1;
while (num <= num2) {
CloseCurrentNode();
num2--;
}
return;
}
if (element.Flags.HasFlag(NodeFlags.Special))
break;
element = open[--num];
}
RaiseErrorOccurred(ErrorCode.TagClosedWrong);
}
private bool InBodyEndTagBody()
{
if (IsInScope<HTMLBodyElement>()) {
CheckBodyOnClosing();
insert = HtmlTreeMode.AfterBody;
return true;
}
RaiseErrorOccurred(ErrorCode.BodyNotInScope);
return false;
}
private void InBodyStartTagBreakrow(HtmlTagToken tag)
{
ReconstructFormatting();
HTMLElement element = HtmlElementFactory.Create(tag.Name, doc);
AddElement(element, tag, false);
CloseCurrentNode();
frameset = false;
}
private bool InBodyEndTagParagraph()
{
if (IsInButtonScope()) {
GenerateImpliedEndTagsExceptFor(Tags.P);
if (!(CurrentNode is HTMLParagraphElement))
RaiseErrorOccurred(ErrorCode.TagDoesNotMatchCurrentNode);
ClearStackBackTo<HTMLParagraphElement>();
CloseCurrentNode();
return true;
}
RaiseErrorOccurred(ErrorCode.ParagraphNotInScope);
InBody(HtmlToken.OpenTag(Tags.P));
InBodyEndTagParagraph();
return false;
}
private bool InTableEndTagTable()
{
if (IsInTableScope<HTMLTableElement>()) {
ClearStackBackTo<HTMLTableElement>();
CloseCurrentNode();
Reset(null);
return true;
}
RaiseErrorOccurred(ErrorCode.TableNotInScope);
return false;
}
private bool InRowEndTagTablerow()
{
if (IsInTableScope<HTMLTableRowElement>()) {
ClearStackBackTo<HTMLTableRowElement>();
CloseCurrentNode();
insert = HtmlTreeMode.InTableBody;
return true;
}
RaiseErrorOccurred(ErrorCode.TableRowNotInScope);
return false;
}
private void InSelectEndTagSelect()
{
ClearStackBackTo<HTMLSelectElement>();
CloseCurrentNode();
Reset(null);
}
private bool InCaptionEndTagCaption()
{
if (IsInTableScope<HTMLTableCaptionElement>()) {
GenerateImpliedEndTags();
if (!(CurrentNode is HTMLTableCaptionElement))
RaiseErrorOccurred(ErrorCode.TagDoesNotMatchCurrentNode);
ClearStackBackTo<HTMLTableCaptionElement>();
CloseCurrentNode();
formatting.ClearFormatting();
insert = HtmlTreeMode.InTable;
return true;
}
RaiseErrorOccurred(ErrorCode.CaptionNotInScope);
return false;
}
private bool InCellEndTagCell()
{
if (IsInTableScope<HTMLTableCellElement>()) {
GenerateImpliedEndTags();
if (!(CurrentNode is HTMLTableCellElement))
RaiseErrorOccurred(ErrorCode.TagDoesNotMatchCurrentNode);
ClearStackBackTo<HTMLTableCellElement>();
CloseCurrentNode();
formatting.ClearFormatting();
insert = HtmlTreeMode.InRow;
return true;
}
RaiseErrorOccurred(ErrorCode.TableCellNotInScope);
return false;
}
private void Foreign(HtmlToken token)
{
switch (token.Type) {
case HtmlTokenType.Character:
AddCharacters(token.Data.Replace(' ', '�'));
if (token.HasContent)
frameset = false;
break;
case HtmlTokenType.Comment:
CurrentNode.AddComment(token.Data);
break;
case HtmlTokenType.DOCTYPE:
RaiseErrorOccurred(ErrorCode.DoctypeTagInappropriate);
break;
case HtmlTokenType.StartTag: {
string name2 = token.Name;
if (name2 == Tags.Font) {
HtmlTagToken htmlTagToken = token.AsTag();
for (int i = 0; i != htmlTagToken.Attributes.Count; i++) {
if (htmlTagToken.Attributes[i].Key.IsOneOf(AttributeNames.Color, AttributeNames.Face, AttributeNames.Size)) {
ForeignNormalTag(token);
return;
}
}
ForeignSpecialTag(htmlTagToken);
} else if (name2.IsOneOf(Tags.B, Tags.Big, Tags.BlockQuote, Tags.Body, Tags.Br, Tags.Center) || name2.IsOneOf(Tags.Code, Tags.Dd, Tags.Div, Tags.Dl, Tags.Dt, Tags.Em) || name2.IsOneOf(Tags.Embed, Tags.Head, Tags.Hr, Tags.I, Tags.Img, Tags.Li, Tags.Ul) || name2.IsOneOf(Tags.H3, Tags.H2, Tags.H4, Tags.H1, Tags.H6, Tags.H5) || name2.IsOneOf(Tags.Listing, Tags.Main, Tags.Menu, Tags.Meta, Tags.NoBr, Tags.Ol) || name2.IsOneOf(Tags.P, Tags.Pre, Tags.Ruby, Tags.S, Tags.Small, Tags.Span, Tags.Strike) || name2.IsOneOf(Tags.Strong, Tags.Sub, Tags.Sup, Tags.Table, Tags.Tt, Tags.U, Tags.Var)) {
ForeignNormalTag(token);
} else {
ForeignSpecialTag(token.AsTag());
}
break;
}
case HtmlTokenType.EndTag: {
string name = token.Name;
Element element = CurrentNode;
HTMLScriptElement hTMLScriptElement = element as HTMLScriptElement;
if (hTMLScriptElement == null) {
if (element.NodeName != name)
RaiseErrorOccurred(ErrorCode.TagClosingMismatch);
int num = open.Count - 1;
while (true) {
if (num <= 0)
return;
if (element.NodeName.Equals(name, StringComparison.OrdinalIgnoreCase)) {
open.RemoveRange(num + 1, open.Count - num - 1);
CloseCurrentNode();
return;
}
element = open[num - 1];
if (element.Flags.HasFlag(NodeFlags.HtmlMember))
break;
num--;
}
Home(token);
} else
RunScript(hTMLScriptElement);
break;
}
}
}
private void ForeignSpecialTag(HtmlTagToken tag)
{
Element element = CreateForeignElementFrom(tag);
if (element != null) {
AddForeignElement(element);
if (!tag.IsSelfClosing) {
open.Add(element);
tokenizer.IsAcceptingCharacterData = true;
} else if (tag.Name == Tags.Script) {
Foreign(HtmlToken.CloseTag(Tags.Script));
}
}
}
private Element CreateForeignElementFrom(HtmlTagToken tag)
{
if (AdjustedCurrentNode.Flags.HasFlag(NodeFlags.MathMember)) {
MathElement mathElement = MathElementFactory.Create(tag.Name, doc);
for (int i = 0; i < tag.Attributes.Count; i++) {
string key = tag.Attributes[i].Key;
string value = tag.Attributes[i].Value;
mathElement.SetAdjustedAttribute(key.AdjustMathMLAttributeName(), value);
}
return mathElement;
}
if (AdjustedCurrentNode.Flags.HasFlag(NodeFlags.SvgMember)) {
SVGElement sVGElement = SvgElementFactory.Create(tag.Name.AdjustSvgTagName(), doc);
for (int j = 0; j < tag.Attributes.Count; j++) {
string key2 = tag.Attributes[j].Key;
string value2 = tag.Attributes[j].Value;
sVGElement.SetAdjustedAttribute(key2.AdjustSvgAttributeName(), value2);
}
return sVGElement;
}
return null;
}
private void ForeignNormalTag(HtmlToken token)
{
RaiseErrorOccurred(ErrorCode.TagCannotStartHere);
do {
CloseCurrentNode();
if (CurrentNode is MathAnnotationXmlElement) {
string attribute = CurrentNode.GetAttribute(AttributeNames.Encoding);
if (!string.IsNullOrEmpty(attribute) && (attribute.Equals(MimeTypes.Html, StringComparison.OrdinalIgnoreCase) || attribute.Equals(MimeTypes.ApplicationXHtml, StringComparison.OrdinalIgnoreCase)))
break;
}
} while ((CurrentNode.Flags & (NodeFlags.HtmlMember | NodeFlags.HtmlTip | NodeFlags.MathTip)) == NodeFlags.None);
Consume(token);
}
private bool IsInScope(string tagName)
{
for (int num = open.Count - 1; num >= 0; num--) {
Element element = open[num];
if (element.NodeName == tagName)
return true;
if (element.Flags.HasFlag(NodeFlags.Scoped))
return false;
}
return false;
}
private bool IsInScope<T>()
{
for (int num = open.Count - 1; num >= 0; num--) {
Element element = open[num];
if (element is T)
return true;
if (element.Flags.HasFlag(NodeFlags.Scoped))
return false;
}
return false;
}
private bool IsInListItemScope()
{
for (int num = open.Count - 1; num >= 0; num--) {
Element element = open[num];
if (element is HTMLLIElement)
return true;
if (element.Flags.HasFlag(NodeFlags.HtmlListScoped))
return false;
}
return false;
}
private bool IsInButtonScope()
{
for (int num = open.Count - 1; num >= 0; num--) {
Element element = open[num];
if (element is HTMLParagraphElement)
return true;
if (element.Flags.HasFlag(NodeFlags.Scoped) || element is HTMLButtonElement)
return false;
}
return false;
}
private bool IsInTableScope<T>()
{
for (int num = open.Count - 1; num >= 0; num--) {
Element element = open[num];
if (element is T)
return true;
if (element.Flags.HasFlag(NodeFlags.HtmlTableScoped))
return false;
}
return false;
}
private bool IsInTableScope(string tagName)
{
for (int num = open.Count - 1; num >= 0; num--) {
Element element = open[num];
if (element.NodeName == tagName)
return true;
if (element.Flags.HasFlag(NodeFlags.HtmlTableScoped))
return false;
}
return false;
}
private bool IsInSelectScope(string tagName)
{
for (int num = open.Count - 1; num >= 0; num--) {
Element element = open[num];
if (element.NodeName == tagName)
return true;
if (!element.Flags.HasFlag(NodeFlags.HtmlSelectScoped))
return false;
}
return false;
}
private void Kernel()
{
HtmlToken htmlToken;
do {
htmlToken = tokenizer.Get();
Consume(htmlToken);
} while (htmlToken.Type != HtmlTokenType.EOF);
}
private async Task<IDocument> KernelAsync(CancellationToken cancelToken)
{
ITextSource source = doc.Source;
HtmlToken token;
do {
if (source.Length - source.Index < 1024)
await source.Prefetch(8192, cancelToken).ConfigureAwait(false);
token = tokenizer.Get();
Consume(token);
} while (token.Type != HtmlTokenType.EOF);
return doc;
}
private void RunScript(HTMLScriptElement script)
{
if (script != null) {
doc.PerformMicrotaskCheckpoint();
doc.ProvideStableState();
CloseCurrentNode();
insert = originalInsert;
nesting++;
script.Prepare();
nesting--;
if (pendingParsingBlock != null && nesting == 0) {
do {
script = pendingParsingBlock;
pendingParsingBlock = null;
doc.WaitForReady();
nesting++;
script.Run();
nesting--;
tokenizer.ResetInsertionPoint();
} while (pendingParsingBlock != null);
}
}
}
private void CheckBodyOnClosing()
{
int num = 0;
while (true) {
if (num >= open.Count)
return;
if (!open[num].Flags.HasFlag(NodeFlags.ImplicitelyClosed))
break;
num++;
}
RaiseErrorOccurred(ErrorCode.BodyClosedWrong);
}
private bool TagCurrentlyOpen(string tagName)
{
for (int i = 0; i < open.Count; i++) {
if (open[i].NodeName == tagName)
return true;
}
return false;
}
private void PreventNewLine()
{
HtmlToken htmlToken = tokenizer.Get();
if (htmlToken.Type == HtmlTokenType.Character)
htmlToken.RemoveNewLine();
Home(htmlToken);
}
private void SetCharset(string charset)
{
Encoding encoding = DocumentEncoding.Resolve(charset);
if (encoding != null)
doc.Source.CurrentEncoding = encoding;
}
private void End()
{
while (open.Count != 0) {
CloseCurrentNode();
}
doc.CloseCurrent();
}
private void AddDoctype(HtmlDoctypeToken doctypeToken)
{
doc.AddNode(new DocumentType(doctypeToken.Name ?? string.Empty) {
Owner = doc,
SystemIdentifier = doctypeToken.SystemIdentifier,
PublicIdentifier = doctypeToken.PublicIdentifier
});
}
private void AddRoot(HtmlTagToken tag)
{
HTMLHtmlElement hTMLHtmlElement = new HTMLHtmlElement();
hTMLHtmlElement.Owner = doc;
HTMLHtmlElement hTMLHtmlElement2 = hTMLHtmlElement;
doc.AddNode(hTMLHtmlElement2);
SetupElement(hTMLHtmlElement2, tag, false);
open.Add(hTMLHtmlElement2);
tokenizer.IsAcceptingCharacterData = false;
hTMLHtmlElement2.ApplyManifest();
}
private void CloseCurrentNode()
{
if (open.Count > 0) {
open[open.Count - 1].Close();
open.RemoveAt(open.Count - 1);
Element adjustedCurrentNode = AdjustedCurrentNode;
tokenizer.IsAcceptingCharacterData = (adjustedCurrentNode != null && !adjustedCurrentNode.Flags.HasFlag(NodeFlags.HtmlMember));
}
}
private void SetupElement(Element element, HtmlTagToken tag, bool acknowledgeSelfClosing)
{
if (tag.IsSelfClosing && !acknowledgeSelfClosing)
RaiseErrorOccurred(ErrorCode.TagCannotBeSelfClosed);
element.SetAttributes(tag.Attributes);
}
private Element AddElement(HtmlTagToken tag, bool acknowledgeSelfClosing = false)
{
HTMLElement hTMLElement = HtmlElementFactory.Create(tag.Name, doc);
SetupElement(hTMLElement, tag, acknowledgeSelfClosing);
AddElement(hTMLElement);
return hTMLElement;
}
private TElement AddElement<TElement>(HtmlTagToken tag, bool acknowledgeSelfClosing = false) where TElement : Element, new
{
TElement val = new TElement();
val.Owner = doc;
TElement val2 = val;
SetupElement(val2, tag, acknowledgeSelfClosing);
AddElement(val2);
return val2;
}
private void AddElement(Element element, HtmlTagToken tag, bool acknowledgeSelfClosing = false)
{
SetupElement(element, tag, acknowledgeSelfClosing);
AddElement(element);
}
private void AddElement(Element element)
{
Element currentNode = CurrentNode;
if (foster && currentNode.IsTableElement())
AddElementWithFoster(element);
else
currentNode.AddNode(element);
open.Add(element);
tokenizer.IsAcceptingCharacterData = !element.Flags.HasFlag(NodeFlags.HtmlMember);
}
private void AddElementWithFoster(Element element)
{
bool flag = false;
int num = open.Count;
while (--num != 0) {
if (open[num] is HTMLTemplateElement) {
open[num].AddNode(element);
return;
}
if (open[num] is HTMLTableElement) {
flag = true;
break;
}
}
Node node = open[num].Parent ?? open[num + 1];
if (flag && open[num].Parent != null) {
int num2 = 0;
while (true) {
if (num2 >= node.ChildNodes.Length)
return;
if (node.ChildNodes[num2] == open[num])
break;
num2++;
}
node.InsertNode(num2, element);
} else
node.AddNode(element);
}
private void AddForeignElement(Element element)
{
element.NamespaceUri = AdjustedCurrentNode.NamespaceUri;
CurrentNode.AddNode(element);
}
private void AddCharacters(string text)
{
if (!string.IsNullOrEmpty(text)) {
Element currentNode = CurrentNode;
if (foster && currentNode.IsTableElement())
AddCharactersWithFoster(text);
else
currentNode.AppendText(text);
}
}
private void AddCharactersWithFoster(string text)
{
bool flag = false;
int num = open.Count;
while (--num != 0) {
if (open[num] is HTMLTemplateElement) {
open[num].AppendText(text);
return;
}
if (open[num] is HTMLTableElement) {
flag = true;
break;
}
}
Node node = open[num].Parent ?? open[num + 1];
if (flag && open[num].Parent != null) {
int num2 = 0;
while (true) {
if (num2 >= node.ChildNodes.Length)
return;
if (node.ChildNodes[num2] == open[num])
break;
num2++;
}
node.InsertText(num2, text);
} else
node.AppendText(text);
}
private void ClearStackBackTo(string tagName)
{
Element currentNode = CurrentNode;
while (currentNode.NodeName != tagName && !(currentNode is HTMLHtmlElement) && !(currentNode is HTMLTemplateElement)) {
CloseCurrentNode();
currentNode = CurrentNode;
}
}
private void ClearStackBackTo<T>()
{
Element currentNode = CurrentNode;
while (!(currentNode is T) && !(currentNode is HTMLHtmlElement) && !(currentNode is HTMLTemplateElement)) {
CloseCurrentNode();
currentNode = CurrentNode;
}
}
private void GenerateImpliedEndTagsExceptFor(string tagName)
{
Element currentNode = CurrentNode;
while (currentNode.Flags.HasFlag(NodeFlags.ImpliedEnd) && currentNode.NodeName != tagName) {
CloseCurrentNode();
currentNode = CurrentNode;
}
}
private void GenerateImpliedEndTags()
{
while (CurrentNode.Flags.HasFlag(NodeFlags.ImpliedEnd)) {
CloseCurrentNode();
}
}
private void ReconstructFormatting()
{
if (formatting.Count != 0) {
int i = formatting.Count - 1;
Element element = formatting[i];
if (element != null && !open.Contains(element)) {
while (i > 0) {
element = formatting[--i];
if (element == null || open.Contains(element)) {
i++;
break;
}
}
for (; i < formatting.Count; i++) {
Element element2 = CopyElement(formatting[i]);
AddElement(element2);
formatting[i] = element2;
}
}
}
}
private void RaiseErrorOccurred(ErrorCode code)
{
tokenizer.RaiseErrorOccurred(code);
}
}
}