/// <summary> /// See 8.2.5.4.7 The "in body" insertion mode. /// </summary> /// <param name="token">The passed token.</param> void InBody(HtmlToken token) { if (token.Type == HtmlTokenType.Character) { var chrs = (HtmlCharacterToken)token; ReconstructFormatting(); InsertCharacters(chrs.Data); if(chrs.HasContent) frameset = false; } else if (token.Type == HtmlTokenType.Comment) AddComment(CurrentNode, token); else if (token.Type == HtmlTokenType.DOCTYPE) RaiseErrorOccurred(ErrorCode.DoctypeTagInappropriate); else if (token.Type == HtmlTokenType.StartTag) { var tag = (HtmlTagToken)token; switch (tag.Name) { case HTMLHtmlElement.Tag: { RaiseErrorOccurred(ErrorCode.HtmlTagMisplaced); AppendAttributes(tag, open[0]); break; } case HTMLBaseElement.Tag: case HTMLBaseFontElement.Tag: case HTMLBgsoundElement.Tag: case HTMLLinkElement.Tag: case HTMLMenuItemElement.Tag: case HTMLMetaElement.Tag: case HTMLNoElement.NoFramesTag: case HTMLScriptElement.Tag: case HTMLStyleElement.Tag: case HTMLTitleElement.Tag: { InHead(token); break; } case HTMLBodyElement.Tag: { RaiseErrorOccurred(ErrorCode.BodyTagMisplaced); if (open.Count > 1 && open[1] is HTMLBodyElement) { frameset = false; AppendAttributes(tag, open[1]); } break; } case HTMLFrameSetElement.Tag: { RaiseErrorOccurred(ErrorCode.FramesetMisplaced); if (open.Count != 1 && open[1] is HTMLBodyElement && frameset) { open[1].ParentNode.RemoveChild(open[1]); while (open.Count > 1) CloseCurrentNode(); var element = new HTMLFrameSetElement(); AddElementToCurrentNode(element, token); insert = HtmlTreeMode.InFrameset; } break; } case HTMLSemanticElement.AddressTag: case HTMLSemanticElement.ArticleTag: case HTMLSemanticElement.AsideTag: case HTMLQuoteElement.BlockTag: case HTMLSemanticElement.CenterTag: case HTMLDetailsElement.Tag: case HTMLDialogElement.Tag: case HTMLDirectoryElement.Tag: case HTMLDivElement.Tag: case HTMLDListElement.Tag: case HTMLFieldSetElement.Tag: case HTMLSemanticElement.FigcaptionTag: case HTMLSemanticElement.FigureTag: case HTMLSemanticElement.FooterTag: case HTMLSemanticElement.HeaderTag: case HTMLSemanticElement.HgroupTag: case HTMLMenuElement.Tag: case HTMLSemanticElement.NavTag: case HTMLOListElement.Tag: case HTMLParagraphElement.Tag: case HTMLSemanticElement.SectionTag: case HTMLSemanticElement.SummaryTag: case HTMLUListElement.Tag: { if (IsInButtonScope(HTMLParagraphElement.Tag)) InBodyEndTagParagraph(); var element = HTMLElement.Factory(tag.Name); AddElementToCurrentNode(element, token); break; } case HTMLHeadingElement.ChapterTag: case HTMLHeadingElement.SubSubSubSubSectionTag: case HTMLHeadingElement.SubSubSubSectionTag: case HTMLHeadingElement.SubSubSectionTag: case HTMLHeadingElement.SubSectionTag: case HTMLHeadingElement.SectionTag: { if (IsInButtonScope(HTMLParagraphElement.Tag)) InBodyEndTagParagraph(); if (CurrentNode is HTMLHeadingElement) { RaiseErrorOccurred(ErrorCode.HeadingNested); CloseCurrentNode(); } var element = new HTMLHeadingElement(); AddElementToCurrentNode(element, token); break; } case HTMLPreElement.Tag: case HTMLSemanticElement.ListingTag: { if (IsInButtonScope(HTMLParagraphElement.Tag)) InBodyEndTagParagraph(); var element = new HTMLPreElement(); AddElementToCurrentNode(element, token); frameset = false; PreventNewLine(); break; } case HTMLFormElement.Tag: { if (form == null) { if (IsInButtonScope(HTMLParagraphElement.Tag)) InBodyEndTagParagraph(); var element = new HTMLFormElement(); AddElementToCurrentNode(element, token); form = element; } else RaiseErrorOccurred(ErrorCode.FormAlreadyOpen); break; } case HTMLLIElement.ItemTag: { InBodyStartTagListItem(tag); break; } case HTMLLIElement.DefinitionTag: case HTMLLIElement.DescriptionTag: { InBodyStartTagDefinitionItem(tag); break; } case HTMLSemanticElement.PlaintextTag: { if (IsInButtonScope(HTMLParagraphElement.Tag)) InBodyEndTagParagraph(); var plaintext = new HTMLElement(); AddElementToCurrentNode(plaintext, token); tokenizer.Switch(HtmlParseMode.Plaintext); break; } case HTMLButtonElement.Tag: { if (IsInScope(tag.Name)) { RaiseErrorOccurred(ErrorCode.ButtonInScope); InBodyEndTagBlock(tag.Name); InBody(token); } else { ReconstructFormatting(); var element = new HTMLButtonElement(); AddElementToCurrentNode(element, token); frameset = false; } break; } case HTMLAnchorElement.Tag: { for (var i = formatting.Count - 1; i >= 0; i--) { if (formatting[i] is ScopeMarkerNode) break; else if (formatting[i].NodeName == HTMLAnchorElement.Tag) { var format = formatting[i]; RaiseErrorOccurred(ErrorCode.AnchorNested); HeisenbergAlgorithm(HtmlToken.CloseTag(HTMLAnchorElement.Tag)); if(open.Contains(format)) open.Remove(format); if(formatting.Contains(format)) formatting.RemoveAt(i); break; } } ReconstructFormatting(); var element = new HTMLAnchorElement(); AddElementToCurrentNode(element, token); AddFormattingElement(element); break; } case HTMLFormattingElement.BTag: case HTMLFormattingElement.BigTag: case HTMLFormattingElement.CodeTag: case HTMLFormattingElement.EmTag: case HTMLFontElement.Tag: case HTMLFormattingElement.ITag: case HTMLFormattingElement.STag: case HTMLFormattingElement.SmallTag: case HTMLFormattingElement.StrikeTag: case HTMLFormattingElement.StrongTag: case HTMLFormattingElement.TtTag: case HTMLFormattingElement.UTag: { ReconstructFormatting(); var element = HTMLElement.Factory(tag.Name); AddElementToCurrentNode(element, token); AddFormattingElement(element); break; } case HTMLFormattingElement.NobrTag: { ReconstructFormatting(); if (IsInScope(HTMLFormattingElement.NobrTag)) { RaiseErrorOccurred(ErrorCode.NobrInScope); HeisenbergAlgorithm(tag); ReconstructFormatting(); } var element = new HTMLElement(); AddElementToCurrentNode(element, token); AddFormattingElement(element); break; } case HTMLAppletElement.Tag: case HTMLMarqueeElement.Tag: case HTMLObjectElement.Tag: { ReconstructFormatting(); var element = HTMLElement.Factory(tag.Name); AddElementToCurrentNode(element, token); InsertScopeMarker(); frameset = false; break; } case HTMLTableElement.Tag: { if (doc.QuirksMode == QuirksMode.Off && IsInButtonScope(HTMLParagraphElement.Tag)) InBodyEndTagParagraph(); var element = new HTMLTableElement(); AddElementToCurrentNode(element, token); frameset = false; insert = HtmlTreeMode.InTable; break; } case HTMLAreaElement.Tag: case HTMLBRElement.Tag: case HTMLEmbedElement.Tag: case HTMLImageElement.Tag: case HTMLKeygenElement.Tag: case HTMLWbrElement.Tag: { InBodyStartTagBreakrow(tag); break; } case HTMLInputElement.Tag: { ReconstructFormatting(); var element = new HTMLInputElement(); AddElementToCurrentNode(element, token, true); CloseCurrentNode(); if (!tag.GetAttribute("type").Equals("hidden", StringComparison.OrdinalIgnoreCase)) frameset = false; break; } case HTMLParamElement.Tag: case HTMLSourceElement.Tag: case HTMLTrackElement.Tag: { var element = HTMLElement.Factory(tag.Name); AddElementToCurrentNode(element, token, true); CloseCurrentNode(); break; } case HTMLHRElement.Tag: { if (IsInButtonScope(HTMLParagraphElement.Tag)) InBodyEndTagParagraph(); var element = new HTMLHRElement(); AddElementToCurrentNode(element, token, true); CloseCurrentNode(); frameset = false; break; } case HTMLImageElement.FalseTag: { RaiseErrorOccurred(ErrorCode.ImageTagNamedWrong); tag.Name = HTMLImageElement.Tag; goto case HTMLImageElement.Tag; } case HTMLIsIndexElement.Tag: { RaiseErrorOccurred(ErrorCode.TagInappropriate); if (form == null) { InBody(HtmlToken.OpenTag(HTMLFormElement.Tag)); if (tag.GetAttribute("action") != String.Empty) form.SetAttribute("action", tag.GetAttribute("action")); InBody(HtmlToken.OpenTag(HTMLHRElement.Tag)); InBody(HtmlToken.OpenTag(HTMLLabelElement.Tag)); if (tag.GetAttribute("prompt") != String.Empty) InsertCharacters(tag.GetAttribute("prompt")); else InsertCharacters("This is a searchable index. Enter search keywords:"); var input = HtmlToken.OpenTag(HTMLInputElement.Tag); input.AddAttribute("name", HTMLIsIndexElement.Tag); for (int i = 0; i < tag.Attributes.Count; i++) { if (tag.Attributes[i].Key == "name" || tag.Attributes[i].Key == "action" || tag.Attributes[i].Key == "prompt") continue; input.AddAttribute(tag.Attributes[i].Key, tag.Attributes[i].Value); } InBody(input); InBody(HtmlToken.CloseTag(HTMLLabelElement.Tag)); InBody(HtmlToken.OpenTag(HTMLHRElement.Tag)); InBody(HtmlToken.CloseTag(HTMLFormElement.Tag)); } break; } case HTMLTextAreaElement.Tag: { var element = new HTMLTextAreaElement(); AddElementToCurrentNode(element, token); tokenizer.Switch(HtmlParseMode.RCData); originalInsert = insert; frameset = false; insert = HtmlTreeMode.Text; PreventNewLine(); break; } case HTMLSemanticElement.XmpTag: { if (IsInButtonScope(HTMLParagraphElement.Tag)) InBodyEndTagParagraph(); ReconstructFormatting(); frameset = false; RawtextAlgorithm(tag); break; } case HTMLIFrameElement.Tag: { frameset = false; RawtextAlgorithm(tag); break; } case HTMLSelectElement.Tag: { ReconstructFormatting(); var element = new HTMLSelectElement(); AddElementToCurrentNode(element, token); 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; } break; } case HTMLOptGroupElement.Tag: case HTMLOptionElement.Tag: { if (CurrentNode.NodeName == HTMLOptionElement.Tag) InBodyEndTagAnythingElse(HtmlToken.CloseTag(HTMLOptionElement.Tag)); ReconstructFormatting(); var element = HTMLElement.Factory(tag.Name); AddElementToCurrentNode(element, token); break; } case "rp": case "rt": { if (IsInScope("ruby")) { GenerateImpliedEndTags(); if (CurrentNode.NodeName != "ruby") RaiseErrorOccurred(ErrorCode.TagDoesNotMatchCurrentNode); } var element = HTMLElement.Factory(tag.Name); AddElementToCurrentNode(element, token); break; } case HTMLNoElement.NoEmbedTag: { RawtextAlgorithm(tag); break; } case HTMLNoElement.NoScriptTag: { if (!doc.IsScripting) goto default; RawtextAlgorithm(tag); break; } case MathMLElement.RootTag: { var element = new MathMLElement(); element.NodeName = tag.Name; ReconstructFormatting(); for (int i = 0; i < tag.Attributes.Count; i++) { var name = tag.Attributes[i].Key; var value = tag.Attributes[i].Value; element.SetAttribute(ForeignHelpers.AdjustAttributeName(MathMLHelpers.AdjustAttributeName(name)), value); } CurrentNode.AppendChild(element); if (!tag.IsSelfClosing) open.Add(element); break; } case SVGElement.RootTag: { var element = new SVGElement(); element.NodeName = tag.Name; ReconstructFormatting(); for (int i = 0; i < tag.Attributes.Count; i++) { var name = tag.Attributes[i].Key; var value = tag.Attributes[i].Value; element.SetAttribute(ForeignHelpers.AdjustAttributeName(MathMLHelpers.AdjustAttributeName(name)), value); } CurrentNode.AppendChild(element); if (!tag.IsSelfClosing) { open.Add(element); tokenizer.AcceptsCharacterData = true; } break; } case HTMLTableCaptionElement.Tag: case HTMLTableColElement.ColTag: case HTMLTableColElement.ColgroupTag: case HTMLFrameElement.Tag: case HTMLHeadElement.Tag: case HTMLTableSectionElement.BodyTag: case HTMLTableCellElement.NormalTag: case HTMLTableSectionElement.FootTag: case HTMLTableCellElement.HeadTag: case HTMLTableSectionElement.HeadTag: case HTMLTableRowElement.Tag: { RaiseErrorOccurred(ErrorCode.TagCannotStartHere); break; } default: { ReconstructFormatting(); var element = new HTMLUnknownElement(); AddElementToCurrentNode(element, token); break; } } } else if (token.Type == HtmlTokenType.EndTag) { var tag = (HtmlTagToken)token; switch (tag.Name) { case HTMLBodyElement.Tag: { InBodyEndTagBody(); break; } case HTMLHtmlElement.Tag: { if (InBodyEndTagBody()) AfterBody(token); break; } case HTMLSemanticElement.AddressTag: case HTMLSemanticElement.ArticleTag: case HTMLSemanticElement.AsideTag: case HTMLQuoteElement.BlockTag: case HTMLButtonElement.Tag: case HTMLSemanticElement.CenterTag: case HTMLDetailsElement.Tag: case HTMLDialogElement.Tag: case HTMLDirectoryElement.Tag: case HTMLDivElement.Tag: case HTMLDListElement.Tag: case HTMLFieldSetElement.Tag: case HTMLSemanticElement.FigcaptionTag: case HTMLSemanticElement.FigureTag: case HTMLSemanticElement.FooterTag: case HTMLSemanticElement.HeaderTag: case HTMLSemanticElement.HgroupTag: case HTMLSemanticElement.ListingTag: case HTMLSemanticElement.MainTag: case HTMLMenuElement.Tag: case HTMLSemanticElement.NavTag: case HTMLOListElement.Tag: case HTMLPreElement.Tag: case HTMLSemanticElement.SectionTag: case HTMLSemanticElement.SummaryTag: case HTMLUListElement.Tag: { InBodyEndTagBlock(tag.Name); break; } case HTMLFormElement.Tag: { var node = form; form = null; if (node != null && IsInScope(node.NodeName)) { GenerateImpliedEndTags(); if (CurrentNode != node) RaiseErrorOccurred(ErrorCode.FormClosedWrong); open.Remove(node); } else RaiseErrorOccurred(ErrorCode.FormNotInScope); break; } case HTMLParagraphElement.Tag: { InBodyEndTagParagraph(); break; } case HTMLLIElement.ItemTag: { if (IsInListItemScope(tag.Name)) { GenerateImpliedEndTagsExceptFor(tag.Name); if (CurrentNode.NodeName != tag.Name) RaiseErrorOccurred(ErrorCode.TagDoesNotMatchCurrentNode); ClearStackBackTo(tag.Name); CloseCurrentNode(); } else RaiseErrorOccurred(ErrorCode.ListItemNotInScope); break; } case HTMLLIElement.DefinitionTag: case HTMLLIElement.DescriptionTag: { if (IsInScope(tag.Name)) { GenerateImpliedEndTagsExceptFor(tag.Name); if (CurrentNode.NodeName != tag.Name) RaiseErrorOccurred(ErrorCode.TagDoesNotMatchCurrentNode); ClearStackBackTo(tag.Name); CloseCurrentNode(); } else RaiseErrorOccurred(ErrorCode.ListItemNotInScope); break; } case HTMLHeadingElement.ChapterTag: case HTMLHeadingElement.SubSubSubSubSectionTag: case HTMLHeadingElement.SubSubSubSectionTag: case HTMLHeadingElement.SubSubSectionTag: case HTMLHeadingElement.SubSectionTag: case HTMLHeadingElement.SectionTag: { if (IsHeadingInScope()) { GenerateImpliedEndTags(); if (CurrentNode.NodeName != tag.Name) RaiseErrorOccurred(ErrorCode.TagDoesNotMatchCurrentNode); ClearStackBackToHeading(); CloseCurrentNode(); } else RaiseErrorOccurred(ErrorCode.HeadingNotInScope); break; } case HTMLAnchorElement.Tag: case HTMLFormattingElement.BTag: case HTMLFormattingElement.BigTag: case HTMLFormattingElement.CodeTag: case HTMLFormattingElement.EmTag: case HTMLFontElement.Tag: case HTMLFormattingElement.ITag: case HTMLFormattingElement.NobrTag: case HTMLFormattingElement.STag: case HTMLFormattingElement.SmallTag: case HTMLFormattingElement.StrikeTag: case HTMLFormattingElement.StrongTag: case HTMLFormattingElement.TtTag: case HTMLFormattingElement.UTag: { HeisenbergAlgorithm(tag); break; } case HTMLAppletElement.Tag: case HTMLMarqueeElement.Tag: case HTMLObjectElement.Tag: { if (IsInScope(tag.Name)) { GenerateImpliedEndTags(); if (CurrentNode.NodeName != tag.Name) RaiseErrorOccurred(ErrorCode.TagDoesNotMatchCurrentNode); ClearStackBackTo(tag.Name); CloseCurrentNode(); ClearFormattingElements(); } else RaiseErrorOccurred(ErrorCode.ObjectNotInScope); break; } case HTMLBRElement.Tag: { RaiseErrorOccurred(ErrorCode.TagCannotEndHere); InBodyStartTagBreakrow(HtmlToken.OpenTag(HTMLBRElement.Tag)); break; } default: { InBodyEndTagAnythingElse(tag); break; } } } else if (token.Type == HtmlTokenType.EOF) { for (var i = 0; i < open.Count; i++) { switch (open[i].NodeName) { case HTMLLIElement.DescriptionTag: case HTMLLIElement.DefinitionTag: case HTMLLIElement.ItemTag: case HTMLParagraphElement.Tag: case HTMLTableSectionElement.BodyTag: case HTMLTableCellElement.HeadTag: case HTMLTableSectionElement.FootTag: case HTMLTableCellElement.NormalTag: case HTMLTableSectionElement.HeadTag: case HTMLTableRowElement.Tag: case HTMLBodyElement.Tag: case HTMLHtmlElement.Tag: break; default: RaiseErrorOccurred(ErrorCode.BodyClosedWrong); i = open.Count; break; } } End(); } }
/// <summary> /// 8.2.5.5 The rules for parsing tokens in foreign content /// </summary> /// <param name="token">The token to examine.</param> void Foreign(HtmlToken token) { if (token.Type == HtmlTokenType.Character) { var chrs = (HtmlCharacterToken)token; InsertCharacters(chrs.Data.Replace(Specification.NULL, Specification.REPLACEMENT)); if(chrs.HasContent) frameset = false; } else if (token.Type == HtmlTokenType.Comment) { AddComment(CurrentNode, token); } else if (token.Type == HtmlTokenType.DOCTYPE) { RaiseErrorOccurred(ErrorCode.DoctypeTagInappropriate); } else if (token.Type == HtmlTokenType.StartTag) { var tag = (HtmlTagToken)token; switch (tag.Name) { case HTMLFormattingElement.BTag: case HTMLFormattingElement.BigTag: case HTMLQuoteElement.BlockTag: case HTMLBodyElement.Tag: case HTMLBRElement.Tag: case HTMLSemanticElement.CenterTag: case HTMLFormattingElement.CodeTag: case HTMLLIElement.DefinitionTag: case HTMLDivElement.Tag: case HTMLDListElement.Tag: case HTMLLIElement.DescriptionTag: case HTMLFormattingElement.EmTag: case HTMLEmbedElement.Tag: case HTMLHeadingElement.ChapterTag: case HTMLHeadingElement.SubSubSubSubSectionTag: case HTMLHeadingElement.SubSubSubSectionTag: case HTMLHeadingElement.SubSubSectionTag: case HTMLHeadingElement.SubSectionTag: case HTMLHeadingElement.SectionTag: case HTMLHeadElement.Tag: case HTMLHRElement.Tag: case HTMLFormattingElement.ITag: case HTMLImageElement.Tag: case HTMLLIElement.ItemTag: case HTMLSemanticElement.ListingTag: case HTMLSemanticElement.MainTag: case HTMLMenuElement.Tag: case HTMLMetaElement.Tag: case HTMLFormattingElement.NobrTag: case HTMLOListElement.Tag: case HTMLParagraphElement.Tag: case HTMLPreElement.Tag: case "ruby": case HTMLFormattingElement.STag: case HTMLFormattingElement.SmallTag: case HTMLSpanElement.Tag: case HTMLFormattingElement.StrongTag: case HTMLFormattingElement.StrikeTag: case "sub": case "sup": case HTMLTableElement.Tag: case HTMLFormattingElement.TtTag: case HTMLFormattingElement.UTag: case HTMLUListElement.Tag: case "var": { RaiseErrorOccurred(ErrorCode.TagCannotStartHere); CloseCurrentNode(); while (!CurrentNode.IsHtmlTIP && !CurrentNode.IsMathMLTIP && !CurrentNode.IsInHtml) CloseCurrentNode(); Consume(token); break; } case HTMLFontElement.Tag: { for (var i = 0; i != tag.Attributes.Count; i++) { if (tag.Attributes[i].Key == "color" || tag.Attributes[i].Key == "face" || tag.Attributes[i].Key == "size") goto case "var"; } goto default; } default: { Element node; if (AdjustedCurrentNode.IsInMathML) { node = new MathMLElement(); node.NodeName = tag.Name; for (int i = 0; i < tag.Attributes.Count; i++) { var name = tag.Attributes[i].Key; var value = tag.Attributes[i].Value; node.SetAttribute(ForeignHelpers.AdjustAttributeName(MathMLHelpers.AdjustAttributeName(name)), value); } } else if (AdjustedCurrentNode.IsInSvg) { node = new SVGElement(); node.NodeName = SVGHelpers.AdjustTagName(tag.Name); for (int i = 0; i < tag.Attributes.Count; i++) { var name = tag.Attributes[i].Key; var value = tag.Attributes[i].Value; node.SetAttribute(ForeignHelpers.AdjustAttributeName(SVGHelpers.AdjustAttributeName(name)), value); } } else break; node.NamespaceURI = AdjustedCurrentNode.NamespaceURI; CurrentNode.AppendChild(node); open.Add(node); if (!tag.IsSelfClosing) tokenizer.AcceptsCharacterData = true; else if (tag.Name == HTMLScriptElement.Tag) Foreign(HtmlToken.CloseTag(HTMLScriptElement.Tag)); break; } } } else if (token.Type == HtmlTokenType.EndTag) { var tag = (HtmlTagToken)token; if (CurrentNode != null && CurrentNode is HTMLScriptElement && tag.Name == HTMLScriptElement.Tag) { CloseCurrentNode(); var oldInsert = tokenizer.Stream.InsertionPoint; nesting++; pause = true; InSvg(tag); nesting--; if (nesting == 0) pause = false; tokenizer.Stream.InsertionPoint = oldInsert; } else { var node = CurrentNode; if (node.NodeName != tag.Name) RaiseErrorOccurred(ErrorCode.TagClosingMismatch); while (open.Count > 0) { open.RemoveAt(open.Count - 1); if (node.NodeName.ToLower() == tag.Name) break; node = CurrentNode; if (node == null || node.IsInHtml) break; } Reset(); Consume(token); } } }