/// <summary> /// See 8.2.5.4.6 The "after head" insertion mode. /// </summary> /// <param name="token">The passed token.</param> void AfterHead(HtmlToken token) { switch (token.Type) { case HtmlTokenType.Character: { var str = token.TrimStart(); AddCharacters(str); if (token.IsEmpty) return; break; } case HtmlTokenType.Comment: { CurrentNode.AddComment(token); return; } case HtmlTokenType.Doctype: { RaiseErrorOccurred(HtmlParseError.DoctypeTagInappropriate, token); return; } case HtmlTokenType.StartTag: { var tagName = token.Name; if (tagName.Is(TagNames.Html)) { InBody(token); return; } else if (tagName.Is(TagNames.Body)) { AfterHeadStartTagBody(token.AsTag()); return; } else if (tagName.Is(TagNames.Frameset)) { AddElement(new HtmlFrameSetElement(_document), token.AsTag()); _currentMode = HtmlTreeMode.InFrameset; return; } else if (TagNames.AllHeadNoTemplate.Contains(tagName)) { RaiseErrorOccurred(HtmlParseError.TagMustBeInHead, token); var index = _openElements.Count; var head = _document.Head as Element; _openElements.Add(head); InHead(token); _openElements.Remove(head); return; } else if (tagName.Is(TagNames.Head)) { RaiseErrorOccurred(HtmlParseError.HeadTagMisplaced, token); return; } break; } case HtmlTokenType.EndTag: { if (token.Name.IsOneOf(TagNames.Html, TagNames.Body, TagNames.Br)) break; RaiseErrorOccurred(HtmlParseError.TagCannotEndHere, token); return; } } AfterHeadStartTagBody(HtmlTagToken.Open(TagNames.Body)); _frameset = true; Home(token); }
/// <summary> /// See 8.2.5.4.4 The "in head" insertion mode. /// </summary> /// <param name="token">The passed token.</param> void InHead(HtmlToken token) { switch (token.Type) { case HtmlTokenType.Character: { var str = token.TrimStart(); AddCharacters(str); if (token.IsEmpty) return; break; } case HtmlTokenType.Comment: { CurrentNode.AddComment(token); return; } case HtmlTokenType.Doctype: { RaiseErrorOccurred(HtmlParseError.DoctypeTagInappropriate, token); return; } case HtmlTokenType.StartTag: { var tagName = token.Name; if (tagName.Is(TagNames.Html)) { InBody(token); return; } else if (tagName.Is(TagNames.Meta)) { var element = new HtmlMetaElement(_document); AddElement(element, token.AsTag(), true); var encoding = element.GetEncoding(); CloseCurrentNode(); if (encoding != null) { try { _document.Source.CurrentEncoding = encoding; } catch (NotSupportedException) { Restart(); } } return; } else if (TagNames.AllHeadBase.Contains(tagName)) { AddElement(token.AsTag(), true); CloseCurrentNode(); return; } else if (tagName.Is(TagNames.Title)) { RCDataAlgorithm(token.AsTag()); return; } else if (tagName.IsOneOf(TagNames.Style, TagNames.NoFrames) || (_options.IsScripting && tagName.Is(TagNames.NoScript))) { RawtextAlgorithm(token.AsTag()); return; } else if (tagName.Is(TagNames.NoScript)) { AddElement(token.AsTag()); _currentMode = HtmlTreeMode.InHeadNoScript; return; } else if (tagName.Is(TagNames.Script)) { var script = new HtmlScriptElement(_document, parserInserted: true, started: IsFragmentCase); AddElement(script, token.AsTag()); _tokenizer.State = HtmlParseMode.Script; _previousMode = _currentMode; _currentMode = HtmlTreeMode.Text; return; } else if (tagName.Is(TagNames.Head)) { RaiseErrorOccurred(HtmlParseError.HeadTagMisplaced, token); return; } else if (tagName.Is(TagNames.Template)) { AddElement(new HtmlTemplateElement(_document), token.AsTag()); _formattingElements.AddScopeMarker(); _frameset = false; _currentMode = HtmlTreeMode.InTemplate; _templateModes.Push(HtmlTreeMode.InTemplate); return; } break; } case HtmlTokenType.EndTag: { var tagName = token.Name; if (tagName.Is(TagNames.Head)) { CloseCurrentNode(); _currentMode = HtmlTreeMode.AfterHead; _waiting = _document.WaitForReady(); return; } else if (tagName.Is(TagNames.Template)) { if (TagCurrentlyOpen(TagNames.Template)) { GenerateImpliedEndTags(); if (!CurrentNode.LocalName.Is(TagNames.Template)) RaiseErrorOccurred(HtmlParseError.TagClosingMismatch, token); CloseTemplate(); } else RaiseErrorOccurred(HtmlParseError.TagInappropriate, token); return; } else if (!tagName.IsOneOf(TagNames.Html, TagNames.Body, TagNames.Br)) { RaiseErrorOccurred(HtmlParseError.TagCannotEndHere, token); return; } break; } } CloseCurrentNode(); _currentMode = HtmlTreeMode.AfterHead; AfterHead(token); }
/// <summary> /// See 8.2.5.4.5 The "in head noscript" insertion mode. /// </summary> /// <param name="token">The passed token.</param> void InHeadNoScript(HtmlToken token) { switch (token.Type) { case HtmlTokenType.Character: { var str = token.TrimStart(); AddCharacters(str); if (token.IsEmpty) return; break; } case HtmlTokenType.Comment: { InHead(token); return; } case HtmlTokenType.StartTag: { var tagName = token.Name; if (TagNames.AllNoScript.Contains(tagName)) InHead(token); else if (tagName.Is(TagNames.Html)) InBody(token); else if (tagName.IsOneOf(TagNames.Head, TagNames.NoScript)) RaiseErrorOccurred(HtmlParseError.TagInappropriate, token); else break; return; } case HtmlTokenType.EndTag: { var tagName = token.Name; if (tagName.Is(TagNames.NoScript)) { CloseCurrentNode(); _currentMode = HtmlTreeMode.InHead; return; } else if (!tagName.Is(TagNames.Br)) { RaiseErrorOccurred(HtmlParseError.TagCannotEndHere, token); return; } break; } case HtmlTokenType.Doctype: { RaiseErrorOccurred(HtmlParseError.DoctypeTagInappropriate, token); return; } } RaiseErrorOccurred(HtmlParseError.TokenNotPossible, token); CloseCurrentNode(); _currentMode = HtmlTreeMode.InHead; InHead(token); }
/// <summary> /// See 8.2.5.4.2 The "before html" insertion mode. /// </summary> /// <param name="token">The passed token.</param> void BeforeHtml(HtmlToken token) { switch (token.Type) { case HtmlTokenType.Character: { token.TrimStart(); if (token.IsEmpty) return; break; } case HtmlTokenType.Comment: { _document.AddComment(token); return; } case HtmlTokenType.StartTag: { if (!token.Name.Is(TagNames.Html)) break; AddRoot(token.AsTag()); _currentMode = HtmlTreeMode.BeforeHead; return; } case HtmlTokenType.EndTag: { if (TagNames.AllBeforeHead.Contains(token.Name)) break; RaiseErrorOccurred(HtmlParseError.TagCannotEndHere, token); return; } case HtmlTokenType.Doctype: { RaiseErrorOccurred(HtmlParseError.DoctypeTagInappropriate, token); return; } } BeforeHtml(HtmlTagToken.Open(TagNames.Html)); BeforeHead(token); }
/// <summary> /// See 8.2.5.4.3 The "before head" insertion mode. /// </summary> /// <param name="token">The passed token.</param> void BeforeHead(HtmlToken token) { switch (token.Type) { case HtmlTokenType.Character: { token.TrimStart(); if (token.IsEmpty) return; break; } case HtmlTokenType.StartTag: { var tagName = token.Name; if (tagName.Is(TagNames.Html)) { InBody(token); return; } else if (tagName.Is(TagNames.Head)) { AddElement(new HtmlHeadElement(_document), token.AsTag()); _currentMode = HtmlTreeMode.InHead; return; } break; } case HtmlTokenType.EndTag: { if (TagNames.AllBeforeHead.Contains(token.Name)) break; RaiseErrorOccurred(HtmlParseError.TagCannotEndHere, token); return; } case HtmlTokenType.Comment: { CurrentNode.AddComment(token); return; } case HtmlTokenType.Doctype: { RaiseErrorOccurred(HtmlParseError.DoctypeTagInappropriate, token); return; } } BeforeHead(HtmlTagToken.Open(TagNames.Head)); InHead(token); }
/// <summary> /// See 8.2.5.4.23 The "after after frameset" insertion mode. /// </summary> /// <param name="token">The passed token.</param> void AfterAfterFrameset(HtmlToken token) { switch (token.Type) { case HtmlTokenType.Comment: { _document.AddComment(token); return; } case HtmlTokenType.Character: { var str = token.TrimStart(); ReconstructFormatting(); AddCharacters(str); if (token.IsEmpty) return; break; } case HtmlTokenType.Doctype: { InBody(token); return; } case HtmlTokenType.StartTag: { var tagName = token.Name; if (tagName.Is(TagNames.Html)) InBody(token); else if (tagName.Is(TagNames.NoFrames)) InHead(token); else break; return; } case HtmlTokenType.EndOfFile: { End(); return; } } RaiseErrorOccurred(HtmlParseError.TokenNotPossible, token); }
/// <summary> /// See 8.2.5.4.1 The "initial" insertion mode. /// </summary> /// <param name="token">The passed token.</param> void Initial(HtmlToken token) { switch (token.Type) { case HtmlTokenType.Doctype: { var doctype = (HtmlDoctypeToken)token; if (!doctype.IsValid) RaiseErrorOccurred(HtmlParseError.DoctypeInvalid, token); _document.AddNode(new DocumentType(_document, doctype.Name ?? String.Empty) { SystemIdentifier = doctype.SystemIdentifier, PublicIdentifier = doctype.PublicIdentifier }); if (doctype.IsFullQuirks) _document.QuirksMode = QuirksMode.On; else if (doctype.IsLimitedQuirks) _document.QuirksMode = QuirksMode.Limited; _currentMode = HtmlTreeMode.BeforeHtml; return; } case HtmlTokenType.Character: { token.TrimStart(); if (token.IsEmpty) return; break; } case HtmlTokenType.Comment: { _document.AddComment(token); return; } } if (_options.IsEmbedded == false) { RaiseErrorOccurred(HtmlParseError.DoctypeMissing, token); _document.QuirksMode = QuirksMode.On; } _currentMode = HtmlTreeMode.BeforeHtml; BeforeHtml(token); }
/// <summary> /// See 8.2.5.4.22 The "after after body" insertion mode. /// </summary> /// <param name="token">The passed token.</param> void AfterAfterBody(HtmlToken token) { switch (token.Type) { case HtmlTokenType.Character: { var str = token.TrimStart(); ReconstructFormatting(); AddCharacters(str); if (token.IsEmpty) return; break; } case HtmlTokenType.EndOfFile: { End(); return; } case HtmlTokenType.Comment: { _document.AddComment(token); return; } case HtmlTokenType.Doctype: { InBody(token); return; } case HtmlTokenType.StartTag: { if (!token.Name.Is(TagNames.Html)) break; InBody(token); return; } } RaiseErrorOccurred(HtmlParseError.TokenNotPossible, token); _currentMode = HtmlTreeMode.InBody; InBody(token); }
/// <summary> /// See 8.2.5.4.21 The "after frameset" insertion mode. /// </summary> /// <param name="token">The passed token.</param> void AfterFrameset(HtmlToken token) { switch (token.Type) { case HtmlTokenType.Character: { var str = token.TrimStart(); AddCharacters(str); if (token.IsEmpty) return; break; } case HtmlTokenType.Comment: { CurrentNode.AddComment(token); return; } case HtmlTokenType.Doctype: { RaiseErrorOccurred(HtmlParseError.DoctypeTagInappropriate, token); return; } case HtmlTokenType.StartTag: { var tagName = token.Name; if (tagName.Is(TagNames.Html)) InBody(token); else if (tagName.Is(TagNames.NoFrames)) InHead(token); else break; return; } case HtmlTokenType.EndTag: { if (!token.Name.Is(TagNames.Html)) break; _currentMode = HtmlTreeMode.AfterAfterFrameset; return; } case HtmlTokenType.EndOfFile: { End(); return; } } RaiseErrorOccurred(HtmlParseError.TokenNotPossible, token); }
/// <summary> /// See 8.2.5.4.20 The "in frameset" insertion mode. /// </summary> /// <param name="token">The passed token.</param> void InFrameset(HtmlToken token) { switch (token.Type) { case HtmlTokenType.Character: { var str = token.TrimStart(); AddCharacters(str); if (token.IsEmpty) return; break; } case HtmlTokenType.Comment: { CurrentNode.AddComment(token); return; } case HtmlTokenType.Doctype: { RaiseErrorOccurred(HtmlParseError.DoctypeTagInappropriate, token); return; } case HtmlTokenType.StartTag: { var tagName = token.Name; if (tagName.Is(TagNames.Html)) InBody(token); else if (tagName.Is(TagNames.Frameset)) AddElement(new HtmlFrameSetElement(_document), token.AsTag()); else if (tagName.Is(TagNames.Frame)) { AddElement(new HtmlFrameElement(_document), token.AsTag(), true); CloseCurrentNode(); } else if (tagName.Is(TagNames.NoFrames)) InHead(token); else break; return; } case HtmlTokenType.EndTag: { if (!token.Name.Is(TagNames.Frameset)) break; if (CurrentNode != _openElements[0]) { CloseCurrentNode(); if (!IsFragmentCase && !CurrentNode.LocalName.Is(TagNames.Frameset)) _currentMode = HtmlTreeMode.AfterFrameset; } else RaiseErrorOccurred(HtmlParseError.CurrentNodeIsRoot, token); return; } case HtmlTokenType.EndOfFile: { if (CurrentNode != _document.DocumentElement) RaiseErrorOccurred(HtmlParseError.CurrentNodeIsNotRoot, token); End(); return; } } RaiseErrorOccurred(HtmlParseError.TokenNotPossible, token); }
/// <summary> /// See 8.2.5.4.19 The "after body" insertion mode. /// </summary> /// <param name="token">The passed token.</param> void AfterBody(HtmlToken token) { switch (token.Type) { case HtmlTokenType.Character: { var str = token.TrimStart(); ReconstructFormatting(); AddCharacters(str); if (token.IsEmpty) return; break; } case HtmlTokenType.Comment: { _openElements[0].AddComment(token); return; } case HtmlTokenType.Doctype: { RaiseErrorOccurred(HtmlParseError.DoctypeTagInappropriate, token); return; } case HtmlTokenType.StartTag: { if (token.Name.Is(TagNames.Html)) { InBody(token); return; } break; } case HtmlTokenType.EndTag: { if (token.Name.Is(TagNames.Html)) { if (IsFragmentCase) RaiseErrorOccurred(HtmlParseError.TagInvalidInFragmentMode, token); else _currentMode = HtmlTreeMode.AfterAfterBody; return; } break; } case HtmlTokenType.EndOfFile: { End(); return; } } RaiseErrorOccurred(HtmlParseError.TokenNotPossible, token); _currentMode = HtmlTreeMode.InBody; InBody(token); }
/// <summary> /// See 8.2.5.4.12 The "in column group" insertion mode. /// </summary> /// <param name="token">The passed token.</param> void InColumnGroup(HtmlToken token) { switch (token.Type) { case HtmlTokenType.Character: { var str = token.TrimStart(); AddCharacters(str); if (token.IsEmpty) return; break; } case HtmlTokenType.Comment: { CurrentNode.AddComment(token); return; } case HtmlTokenType.Doctype: { RaiseErrorOccurred(HtmlParseError.DoctypeTagInappropriate, token); return; } case HtmlTokenType.StartTag: { var tagName = token.Name; if (tagName.Is(TagNames.Html)) { InBody(token); } else if (tagName.Is(TagNames.Col)) { AddElement(new HtmlTableColElement(_document), token.AsTag(), true); CloseCurrentNode(); } else if (tagName.Is(TagNames.Template)) { InHead(token); } else { break; } return; } case HtmlTokenType.EndTag: { var tagName = token.Name; if (tagName.Is(TagNames.Colgroup)) InColumnGroupEndTagColgroup(token); else if (tagName.Is(TagNames.Col)) RaiseErrorOccurred(HtmlParseError.TagClosedWrong, token); else if (tagName.Is(TagNames.Template)) InHead(token); else break; return; } case HtmlTokenType.EndOfFile: { InBody(token); return; } } if (InColumnGroupEndTagColgroup(token)) InTable(token); }