diff --git a/html/parse.go b/html/parse.go index 6ab1e487df..c801a6a04e 100644 --- a/html/parse.go +++ b/html/parse.go @@ -2136,28 +2136,31 @@ func parseForeignContent(p *parser) bool { Data: p.tok.Data, }) case StartTagToken: - b := breakout[p.tok.Data] - if p.tok.DataAtom == a.Font { - loop: - for _, attr := range p.tok.Attr { - switch attr.Key { - case "color", "face", "size": - b = true - break loop + if !p.fragment { + b := breakout[p.tok.Data] + if p.tok.DataAtom == a.Font { + loop: + for _, attr := range p.tok.Attr { + switch attr.Key { + case "color", "face", "size": + b = true + break loop + } } } - } - if b { - for i := len(p.oe) - 1; i >= 0; i-- { - n := p.oe[i] - if n.Namespace == "" || htmlIntegrationPoint(n) || mathMLTextIntegrationPoint(n) { - p.oe = p.oe[:i+1] - break + if b { + for i := len(p.oe) - 1; i >= 0; i-- { + n := p.oe[i] + if n.Namespace == "" || htmlIntegrationPoint(n) || mathMLTextIntegrationPoint(n) { + p.oe = p.oe[:i+1] + break + } } + return false } - return false } - switch p.top().Namespace { + current := p.adjustedCurrentNode() + switch current.Namespace { case "math": adjustAttributeNames(p.tok.Attr, mathMLAttributeAdjustments) case "svg": @@ -2172,7 +2175,7 @@ func parseForeignContent(p *parser) bool { panic("html: bad parser state: unexpected namespace") } adjustForeignAttributes(p.tok.Attr) - namespace := p.top().Namespace + namespace := current.Namespace p.addElement() p.top().Namespace = namespace if namespace != "" { @@ -2201,12 +2204,20 @@ func parseForeignContent(p *parser) bool { return true } +// Section 12.2.4.2. +func (p *parser) adjustedCurrentNode() *Node { + if len(p.oe) == 1 && p.fragment && p.context != nil { + return p.context + } + return p.oe.top() +} + // Section 12.2.6. func (p *parser) inForeignContent() bool { if len(p.oe) == 0 { return false } - n := p.oe[len(p.oe)-1] + n := p.adjustedCurrentNode() if n.Namespace == "" { return false } @@ -2364,7 +2375,6 @@ func ParseFragmentWithOptions(r io.Reader, context *Node, opts ...ParseOption) ( contextTag = context.DataAtom.String() } p := &parser{ - tokenizer: NewTokenizerFragment(r, contextTag), doc: &Node{ Type: DocumentNode, }, @@ -2372,6 +2382,11 @@ func ParseFragmentWithOptions(r io.Reader, context *Node, opts ...ParseOption) ( fragment: true, context: context, } + if context != nil && context.Namespace != "" { + p.tokenizer = NewTokenizer(r) + } else { + p.tokenizer = NewTokenizerFragment(r, contextTag) + } for _, f := range opts { f(p) diff --git a/html/parse_test.go b/html/parse_test.go index 0d70c9c465..ee82de1528 100644 --- a/html/parse_test.go +++ b/html/parse_test.go @@ -307,10 +307,15 @@ func testParseCase(text, want, context string, opts ...ParseOption) (err error) return err } } else { + namespace := "" + if i := strings.IndexByte(context, ' '); i >= 0 { + namespace, context = context[:i], context[i+1:] + } contextNode := &Node{ - Type: ElementNode, - DataAtom: atom.Lookup([]byte(context)), - Data: context, + Data: context, + DataAtom: atom.Lookup([]byte(context)), + Namespace: namespace, + Type: ElementNode, } nodes, err := ParseFragmentWithOptions(strings.NewReader(text), contextNode, opts...) if err != nil { diff --git a/html/testdata/webkit/foreign-fragment.dat b/html/testdata/webkit/foreign-fragment.dat new file mode 100644 index 0000000000..2e3cb6c6f6 --- /dev/null +++ b/html/testdata/webkit/foreign-fragment.dat @@ -0,0 +1,550 @@ +#data +X +#errors +6: HTML start tag “nobr” in a foreign namespace context. +7: End of file seen and there were open elements. +6: Unclosed element “nobr”. +#document-fragment +svg path +#document +| +| "X" + +#data +X +#errors +12: HTML start tag “font” in a foreign namespace context. +#document-fragment +svg path +#document +| +| color="" +| "X" + +#data +X +#errors +#document-fragment +svg path +#document +| +| "X" + +#data +X +#errors +10: End tag “path” did not match the name of the current open element (“g”). +11: End of file seen and there were open elements. +3: Unclosed element “g”. +#document-fragment +svg path +#document +| +| "X" + +#data +X +#errors +5: Stray end tag “path”. +#document-fragment +svg path +#document +| "X" + +#data +X +#errors +5: Stray end tag “foreignobject”. +#document-fragment +svg foreignObject +#document +| "X" + +#data +X +#errors +5: Stray end tag “desc”. +#document-fragment +svg desc +#document +| "X" + +#data +X +#errors +5: Stray end tag “title”. +#document-fragment +svg title +#document +| "X" + +#data +X +#errors +5: Stray end tag “svg”. +#document-fragment +svg svg +#document +| "X" + +#data +X +#errors +5: Stray end tag “mfenced”. +#document-fragment +math mfenced +#document +| "X" + +#data +X +#errors +5: Stray end tag “malignmark”. +#document-fragment +math malignmark +#document +| "X" + +#data +X +#errors +5: Stray end tag “math”. +#document-fragment +math math +#document +| "X" + +#data +X +#errors +5: Stray end tag “annotation-xml”. +#document-fragment +math annotation-xml +#document +| "X" + +#data +X +#errors +5: Stray end tag “mtext”. +#document-fragment +math mtext +#document +| "X" + +#data +X +#errors +5: Stray end tag “mi”. +#document-fragment +math mi +#document +| "X" + +#data +X +#errors +5: Stray end tag “mo”. +#document-fragment +math mo +#document +| "X" + +#data +X +#errors +5: Stray end tag “mn”. +#document-fragment +math mn +#document +| "X" + +#data +X +#errors +5: Stray end tag “ms”. +#document-fragment +math ms +#document +| "X" + +#data +X +#errors +51: Self-closing syntax (“/>”) used on a non-void HTML element. Ignoring the slash and treating as a start tag. +52: End of file seen and there were open elements. +51: Unclosed element “ms”. +#document-fragment +math ms +#document +| +| +| +| +| +| +| "X" + +#data + +#errors +#document-fragment +math ms +#document +| + +#data +
+#errors +#document-fragment +math ms +#document +|
+ +#data +
+#errors +#document-fragment +math ms +#document +|
+ +#data +X +#errors +51: Self-closing syntax (“/>”) used on a non-void HTML element. Ignoring the slash and treating as a start tag. +52: End of file seen and there were open elements. +51: Unclosed element “mn”. +#document-fragment +math mn +#document +| +| +| +| +| +| +| "X" + +#data + +#errors +#document-fragment +math mn +#document +| + +#data +
+#errors +#document-fragment +math mn +#document +|
+ +#data +
+#errors +#document-fragment +math mn +#document +|
+ +#data +X +#errors +51: Self-closing syntax (“/>”) used on a non-void HTML element. Ignoring the slash and treating as a start tag. +52: End of file seen and there were open elements. +51: Unclosed element “mo”. +#document-fragment +math mo +#document +| +| +| +| +| +| +| "X" + +#data + +#errors +#document-fragment +math mo +#document +| + +#data +
+#errors +#document-fragment +math mo +#document +|
+ +#data +
+#errors +#document-fragment +math mo +#document +|
+ +#data +X +#errors +51: Self-closing syntax (“/>”) used on a non-void HTML element. Ignoring the slash and treating as a start tag. +52: End of file seen and there were open elements. +51: Unclosed element “mi”. +#document-fragment +math mi +#document +| +| +| +| +| +| +| "X" + +#data + +#errors +#document-fragment +math mi +#document +| + +#data +
+#errors +#document-fragment +math mi +#document +|
+ +#data +
+#errors +#document-fragment +math mi +#document +|
+ +#data +X +#errors +51: Self-closing syntax (“/>”) used on a non-void HTML element. Ignoring the slash and treating as a start tag. +52: End of file seen and there were open elements. +51: Unclosed element “mtext”. +#document-fragment +math mtext +#document +| +| +| +| +| +| +| "X" + +#data + +#errors +#document-fragment +math mtext +#document +| + +#data +
+#errors +#document-fragment +math mtext +#document +|
+ +#data +
+#errors +#document-fragment +math mtext +#document +|
+ +#data +
+#errors +5: HTML start tag “div” in a foreign namespace context. +#document-fragment +math annotation-xml +#document +| + +#data +
+#errors +#document-fragment +math annotation-xml +#document +| + +#data +
+#errors +5: HTML start tag “div” in a foreign namespace context. +#document-fragment +math math +#document +| + +#data +
+#errors +#document-fragment +math math +#document +| + +#data +
+#errors +#document-fragment +svg foreignObject +#document +|
+ +#data +
+#errors +#document-fragment +svg foreignObject +#document +|
+ +#data +
+#errors +#document-fragment +svg title +#document +|
+ +#data +
+#errors +#document-fragment +svg title +#document +|
+ +#data +
+#errors +#document-fragment +svg desc +#document +|
+ +#data +

X

+#errors +5: HTML start tag “div” in a foreign namespace context. +9: HTML start tag “h1” in a foreign namespace context. +#document-fragment +svg svg +#document +| +| +| "X" + +#data +
+#errors +5: HTML start tag “div” in a foreign namespace context. +#document-fragment +svg svg +#document +| + +#data +
+#errors +#document-fragment +svg desc +#document +|
+ +#data +
+#errors +#document-fragment +svg desc +#document +|
+ +#data +<foo> +#errors +16: End of file seen and there were open elements. +11: Unclosed element “plaintext”. +#document-fragment +svg desc +#document +| <plaintext> +| "<foo>" + +#data +<frameset>X +#errors +6: Stray start tag “frameset”. +#document-fragment +svg desc +#document +| "X" + +#data +<head>X +#errors +6: Stray start tag “head”. +#document-fragment +svg desc +#document +| "X" + +#data +<body>X +#errors +6: Stray start tag “body”. +#document-fragment +svg desc +#document +| "X" + +#data +<html>X +#errors +6: Stray start tag “html”. +#document-fragment +svg desc +#document +| "X" + +#data +<html class="foo">X +#errors +6: Stray start tag “html”. +#document-fragment +svg desc +#document +| "X" + +#data +<body class="foo">X +#errors +6: Stray start tag “body”. +#document-fragment +svg desc +#document +| "X"