parse.go 54 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303
  1. // Copyright 2010 The Go Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. package html
  5. import (
  6. "errors"
  7. "fmt"
  8. "io"
  9. "strings"
  10. a "golang.org/x/net/html/atom"
  11. )
  12. // A parser implements the HTML5 parsing algorithm:
  13. // https://html.spec.whatwg.org/multipage/syntax.html#tree-construction
  14. type parser struct {
  15. // tokenizer provides the tokens for the parser.
  16. tokenizer *Tokenizer
  17. // tok is the most recently read token.
  18. tok Token
  19. // Self-closing tags like <hr/> are treated as start tags, except that
  20. // hasSelfClosingToken is set while they are being processed.
  21. hasSelfClosingToken bool
  22. // doc is the document root element.
  23. doc *Node
  24. // The stack of open elements (section 12.2.4.2) and active formatting
  25. // elements (section 12.2.4.3).
  26. oe, afe nodeStack
  27. // Element pointers (section 12.2.4.4).
  28. head, form *Node
  29. // Other parsing state flags (section 12.2.4.5).
  30. scripting, framesetOK bool
  31. // The stack of template insertion modes
  32. templateStack insertionModeStack
  33. // im is the current insertion mode.
  34. im insertionMode
  35. // originalIM is the insertion mode to go back to after completing a text
  36. // or inTableText insertion mode.
  37. originalIM insertionMode
  38. // fosterParenting is whether new elements should be inserted according to
  39. // the foster parenting rules (section 12.2.6.1).
  40. fosterParenting bool
  41. // quirks is whether the parser is operating in "quirks mode."
  42. quirks bool
  43. // fragment is whether the parser is parsing an HTML fragment.
  44. fragment bool
  45. // context is the context element when parsing an HTML fragment
  46. // (section 12.4).
  47. context *Node
  48. }
  49. func (p *parser) top() *Node {
  50. if n := p.oe.top(); n != nil {
  51. return n
  52. }
  53. return p.doc
  54. }
  55. // Stop tags for use in popUntil. These come from section 12.2.4.2.
  56. var (
  57. defaultScopeStopTags = map[string][]a.Atom{
  58. "": {a.Applet, a.Caption, a.Html, a.Table, a.Td, a.Th, a.Marquee, a.Object, a.Template},
  59. "math": {a.AnnotationXml, a.Mi, a.Mn, a.Mo, a.Ms, a.Mtext},
  60. "svg": {a.Desc, a.ForeignObject, a.Title},
  61. }
  62. )
  63. type scope int
  64. const (
  65. defaultScope scope = iota
  66. listItemScope
  67. buttonScope
  68. tableScope
  69. tableRowScope
  70. tableBodyScope
  71. selectScope
  72. )
  73. // popUntil pops the stack of open elements at the highest element whose tag
  74. // is in matchTags, provided there is no higher element in the scope's stop
  75. // tags (as defined in section 12.2.4.2). It returns whether or not there was
  76. // such an element. If there was not, popUntil leaves the stack unchanged.
  77. //
  78. // For example, the set of stop tags for table scope is: "html", "table". If
  79. // the stack was:
  80. // ["html", "body", "font", "table", "b", "i", "u"]
  81. // then popUntil(tableScope, "font") would return false, but
  82. // popUntil(tableScope, "i") would return true and the stack would become:
  83. // ["html", "body", "font", "table", "b"]
  84. //
  85. // If an element's tag is in both the stop tags and matchTags, then the stack
  86. // will be popped and the function returns true (provided, of course, there was
  87. // no higher element in the stack that was also in the stop tags). For example,
  88. // popUntil(tableScope, "table") returns true and leaves:
  89. // ["html", "body", "font"]
  90. func (p *parser) popUntil(s scope, matchTags ...a.Atom) bool {
  91. if i := p.indexOfElementInScope(s, matchTags...); i != -1 {
  92. p.oe = p.oe[:i]
  93. return true
  94. }
  95. return false
  96. }
  97. // indexOfElementInScope returns the index in p.oe of the highest element whose
  98. // tag is in matchTags that is in scope. If no matching element is in scope, it
  99. // returns -1.
  100. func (p *parser) indexOfElementInScope(s scope, matchTags ...a.Atom) int {
  101. for i := len(p.oe) - 1; i >= 0; i-- {
  102. tagAtom := p.oe[i].DataAtom
  103. if p.oe[i].Namespace == "" {
  104. for _, t := range matchTags {
  105. if t == tagAtom {
  106. return i
  107. }
  108. }
  109. switch s {
  110. case defaultScope:
  111. // No-op.
  112. case listItemScope:
  113. if tagAtom == a.Ol || tagAtom == a.Ul {
  114. return -1
  115. }
  116. case buttonScope:
  117. if tagAtom == a.Button {
  118. return -1
  119. }
  120. case tableScope:
  121. if tagAtom == a.Html || tagAtom == a.Table || tagAtom == a.Template {
  122. return -1
  123. }
  124. case selectScope:
  125. if tagAtom != a.Optgroup && tagAtom != a.Option {
  126. return -1
  127. }
  128. default:
  129. panic("unreachable")
  130. }
  131. }
  132. switch s {
  133. case defaultScope, listItemScope, buttonScope:
  134. for _, t := range defaultScopeStopTags[p.oe[i].Namespace] {
  135. if t == tagAtom {
  136. return -1
  137. }
  138. }
  139. }
  140. }
  141. return -1
  142. }
  143. // elementInScope is like popUntil, except that it doesn't modify the stack of
  144. // open elements.
  145. func (p *parser) elementInScope(s scope, matchTags ...a.Atom) bool {
  146. return p.indexOfElementInScope(s, matchTags...) != -1
  147. }
  148. // clearStackToContext pops elements off the stack of open elements until a
  149. // scope-defined element is found.
  150. func (p *parser) clearStackToContext(s scope) {
  151. for i := len(p.oe) - 1; i >= 0; i-- {
  152. tagAtom := p.oe[i].DataAtom
  153. switch s {
  154. case tableScope:
  155. if tagAtom == a.Html || tagAtom == a.Table || tagAtom == a.Template {
  156. p.oe = p.oe[:i+1]
  157. return
  158. }
  159. case tableRowScope:
  160. if tagAtom == a.Html || tagAtom == a.Tr || tagAtom == a.Template {
  161. p.oe = p.oe[:i+1]
  162. return
  163. }
  164. case tableBodyScope:
  165. if tagAtom == a.Html || tagAtom == a.Tbody || tagAtom == a.Tfoot || tagAtom == a.Thead || tagAtom == a.Template {
  166. p.oe = p.oe[:i+1]
  167. return
  168. }
  169. default:
  170. panic("unreachable")
  171. }
  172. }
  173. }
  174. // generateImpliedEndTags pops nodes off the stack of open elements as long as
  175. // the top node has a tag name of dd, dt, li, optgroup, option, p, rp, or rt.
  176. // If exceptions are specified, nodes with that name will not be popped off.
  177. func (p *parser) generateImpliedEndTags(exceptions ...string) {
  178. var i int
  179. loop:
  180. for i = len(p.oe) - 1; i >= 0; i-- {
  181. n := p.oe[i]
  182. if n.Type == ElementNode {
  183. switch n.DataAtom {
  184. // TODO: add a.Rb and a.Rtc, to match the spec. This needs additions to the
  185. // atom package. Ditto for generateAllImpliedEndTags.
  186. case a.Dd, a.Dt, a.Li, a.Optgroup, a.Option, a.P, a.Rp, a.Rt:
  187. for _, except := range exceptions {
  188. if n.Data == except {
  189. break loop
  190. }
  191. }
  192. continue
  193. }
  194. }
  195. break
  196. }
  197. p.oe = p.oe[:i+1]
  198. }
  199. // generateAllImpliedEndTags pops nodes off the stack of open elements as long as
  200. // the top node has a tag name of caption, colgroup, dd, div, dt, li, optgroup, option, p, rp, rt,
  201. // span, tbody, td, tfoot, th, thead or tr.
  202. func (p *parser) generateAllImpliedEndTags() {
  203. var i int
  204. for i = len(p.oe) - 1; i >= 0; i-- {
  205. n := p.oe[i]
  206. if n.Type == ElementNode {
  207. switch n.DataAtom {
  208. // TODO: remove this divergence from the HTML5 spec
  209. case a.Caption, a.Colgroup, a.Dd, a.Div, a.Dt, a.Li, a.Optgroup, a.Option, a.P, a.Rp, a.Rt,
  210. a.Span, a.Tbody, a.Td, a.Tfoot, a.Th, a.Thead, a.Tr:
  211. continue
  212. }
  213. }
  214. break
  215. }
  216. p.oe = p.oe[:i+1]
  217. }
  218. // addChild adds a child node n to the top element, and pushes n onto the stack
  219. // of open elements if it is an element node.
  220. func (p *parser) addChild(n *Node) {
  221. if p.shouldFosterParent() {
  222. p.fosterParent(n)
  223. } else {
  224. p.top().AppendChild(n)
  225. }
  226. if n.Type == ElementNode {
  227. p.oe = append(p.oe, n)
  228. }
  229. }
  230. // shouldFosterParent returns whether the next node to be added should be
  231. // foster parented.
  232. func (p *parser) shouldFosterParent() bool {
  233. if p.fosterParenting {
  234. switch p.top().DataAtom {
  235. case a.Table, a.Tbody, a.Tfoot, a.Thead, a.Tr:
  236. return true
  237. }
  238. }
  239. return false
  240. }
  241. // fosterParent adds a child node according to the foster parenting rules.
  242. // Section 12.2.6.1, "foster parenting".
  243. func (p *parser) fosterParent(n *Node) {
  244. var table, parent, prev, template *Node
  245. var i int
  246. for i = len(p.oe) - 1; i >= 0; i-- {
  247. if p.oe[i].DataAtom == a.Table {
  248. table = p.oe[i]
  249. break
  250. }
  251. }
  252. var j int
  253. for j = len(p.oe) - 1; j >= 0; j-- {
  254. if p.oe[j].DataAtom == a.Template {
  255. template = p.oe[j]
  256. break
  257. }
  258. }
  259. if template != nil && (table == nil || j < i) {
  260. template.AppendChild(n)
  261. return
  262. }
  263. if table == nil {
  264. // The foster parent is the html element.
  265. parent = p.oe[0]
  266. } else {
  267. parent = table.Parent
  268. }
  269. if parent == nil {
  270. parent = p.oe[i-1]
  271. }
  272. if table != nil {
  273. prev = table.PrevSibling
  274. } else {
  275. prev = parent.LastChild
  276. }
  277. if prev != nil && prev.Type == TextNode && n.Type == TextNode {
  278. prev.Data += n.Data
  279. return
  280. }
  281. parent.InsertBefore(n, table)
  282. }
  283. // addText adds text to the preceding node if it is a text node, or else it
  284. // calls addChild with a new text node.
  285. func (p *parser) addText(text string) {
  286. if text == "" {
  287. return
  288. }
  289. if p.shouldFosterParent() {
  290. p.fosterParent(&Node{
  291. Type: TextNode,
  292. Data: text,
  293. })
  294. return
  295. }
  296. t := p.top()
  297. if n := t.LastChild; n != nil && n.Type == TextNode {
  298. n.Data += text
  299. return
  300. }
  301. p.addChild(&Node{
  302. Type: TextNode,
  303. Data: text,
  304. })
  305. }
  306. // addElement adds a child element based on the current token.
  307. func (p *parser) addElement() {
  308. p.addChild(&Node{
  309. Type: ElementNode,
  310. DataAtom: p.tok.DataAtom,
  311. Data: p.tok.Data,
  312. Attr: p.tok.Attr,
  313. })
  314. }
  315. // Section 12.2.4.3.
  316. func (p *parser) addFormattingElement() {
  317. tagAtom, attr := p.tok.DataAtom, p.tok.Attr
  318. p.addElement()
  319. // Implement the Noah's Ark clause, but with three per family instead of two.
  320. identicalElements := 0
  321. findIdenticalElements:
  322. for i := len(p.afe) - 1; i >= 0; i-- {
  323. n := p.afe[i]
  324. if n.Type == scopeMarkerNode {
  325. break
  326. }
  327. if n.Type != ElementNode {
  328. continue
  329. }
  330. if n.Namespace != "" {
  331. continue
  332. }
  333. if n.DataAtom != tagAtom {
  334. continue
  335. }
  336. if len(n.Attr) != len(attr) {
  337. continue
  338. }
  339. compareAttributes:
  340. for _, t0 := range n.Attr {
  341. for _, t1 := range attr {
  342. if t0.Key == t1.Key && t0.Namespace == t1.Namespace && t0.Val == t1.Val {
  343. // Found a match for this attribute, continue with the next attribute.
  344. continue compareAttributes
  345. }
  346. }
  347. // If we get here, there is no attribute that matches a.
  348. // Therefore the element is not identical to the new one.
  349. continue findIdenticalElements
  350. }
  351. identicalElements++
  352. if identicalElements >= 3 {
  353. p.afe.remove(n)
  354. }
  355. }
  356. p.afe = append(p.afe, p.top())
  357. }
  358. // Section 12.2.4.3.
  359. func (p *parser) clearActiveFormattingElements() {
  360. for {
  361. n := p.afe.pop()
  362. if len(p.afe) == 0 || n.Type == scopeMarkerNode {
  363. return
  364. }
  365. }
  366. }
  367. // Section 12.2.4.3.
  368. func (p *parser) reconstructActiveFormattingElements() {
  369. n := p.afe.top()
  370. if n == nil {
  371. return
  372. }
  373. if n.Type == scopeMarkerNode || p.oe.index(n) != -1 {
  374. return
  375. }
  376. i := len(p.afe) - 1
  377. for n.Type != scopeMarkerNode && p.oe.index(n) == -1 {
  378. if i == 0 {
  379. i = -1
  380. break
  381. }
  382. i--
  383. n = p.afe[i]
  384. }
  385. for {
  386. i++
  387. clone := p.afe[i].clone()
  388. p.addChild(clone)
  389. p.afe[i] = clone
  390. if i == len(p.afe)-1 {
  391. break
  392. }
  393. }
  394. }
  395. // Section 12.2.5.
  396. func (p *parser) acknowledgeSelfClosingTag() {
  397. p.hasSelfClosingToken = false
  398. }
  399. // An insertion mode (section 12.2.4.1) is the state transition function from
  400. // a particular state in the HTML5 parser's state machine. It updates the
  401. // parser's fields depending on parser.tok (where ErrorToken means EOF).
  402. // It returns whether the token was consumed.
  403. type insertionMode func(*parser) bool
  404. // setOriginalIM sets the insertion mode to return to after completing a text or
  405. // inTableText insertion mode.
  406. // Section 12.2.4.1, "using the rules for".
  407. func (p *parser) setOriginalIM() {
  408. if p.originalIM != nil {
  409. panic("html: bad parser state: originalIM was set twice")
  410. }
  411. p.originalIM = p.im
  412. }
  413. // Section 12.2.4.1, "reset the insertion mode".
  414. func (p *parser) resetInsertionMode() {
  415. for i := len(p.oe) - 1; i >= 0; i-- {
  416. n := p.oe[i]
  417. last := i == 0
  418. if last && p.context != nil {
  419. n = p.context
  420. }
  421. switch n.DataAtom {
  422. case a.Select:
  423. if !last {
  424. for ancestor, first := n, p.oe[0]; ancestor != first; {
  425. if ancestor == first {
  426. break
  427. }
  428. ancestor = p.oe[p.oe.index(ancestor)-1]
  429. switch ancestor.DataAtom {
  430. case a.Template:
  431. p.im = inSelectIM
  432. return
  433. case a.Table:
  434. p.im = inSelectInTableIM
  435. return
  436. }
  437. }
  438. }
  439. p.im = inSelectIM
  440. case a.Td, a.Th:
  441. // TODO: remove this divergence from the HTML5 spec.
  442. //
  443. // See https://bugs.chromium.org/p/chromium/issues/detail?id=829668
  444. p.im = inCellIM
  445. case a.Tr:
  446. p.im = inRowIM
  447. case a.Tbody, a.Thead, a.Tfoot:
  448. p.im = inTableBodyIM
  449. case a.Caption:
  450. p.im = inCaptionIM
  451. case a.Colgroup:
  452. p.im = inColumnGroupIM
  453. case a.Table:
  454. p.im = inTableIM
  455. case a.Template:
  456. p.im = p.templateStack.top()
  457. case a.Head:
  458. // TODO: remove this divergence from the HTML5 spec.
  459. //
  460. // See https://bugs.chromium.org/p/chromium/issues/detail?id=829668
  461. p.im = inHeadIM
  462. case a.Body:
  463. p.im = inBodyIM
  464. case a.Frameset:
  465. p.im = inFramesetIM
  466. case a.Html:
  467. if p.head == nil {
  468. p.im = beforeHeadIM
  469. } else {
  470. p.im = afterHeadIM
  471. }
  472. default:
  473. if last {
  474. p.im = inBodyIM
  475. return
  476. }
  477. continue
  478. }
  479. return
  480. }
  481. }
  482. const whitespace = " \t\r\n\f"
  483. // Section 12.2.6.4.1.
  484. func initialIM(p *parser) bool {
  485. switch p.tok.Type {
  486. case TextToken:
  487. p.tok.Data = strings.TrimLeft(p.tok.Data, whitespace)
  488. if len(p.tok.Data) == 0 {
  489. // It was all whitespace, so ignore it.
  490. return true
  491. }
  492. case CommentToken:
  493. p.doc.AppendChild(&Node{
  494. Type: CommentNode,
  495. Data: p.tok.Data,
  496. })
  497. return true
  498. case DoctypeToken:
  499. n, quirks := parseDoctype(p.tok.Data)
  500. p.doc.AppendChild(n)
  501. p.quirks = quirks
  502. p.im = beforeHTMLIM
  503. return true
  504. }
  505. p.quirks = true
  506. p.im = beforeHTMLIM
  507. return false
  508. }
  509. // Section 12.2.6.4.2.
  510. func beforeHTMLIM(p *parser) bool {
  511. switch p.tok.Type {
  512. case DoctypeToken:
  513. // Ignore the token.
  514. return true
  515. case TextToken:
  516. p.tok.Data = strings.TrimLeft(p.tok.Data, whitespace)
  517. if len(p.tok.Data) == 0 {
  518. // It was all whitespace, so ignore it.
  519. return true
  520. }
  521. case StartTagToken:
  522. if p.tok.DataAtom == a.Html {
  523. p.addElement()
  524. p.im = beforeHeadIM
  525. return true
  526. }
  527. case EndTagToken:
  528. switch p.tok.DataAtom {
  529. case a.Head, a.Body, a.Html, a.Br:
  530. p.parseImpliedToken(StartTagToken, a.Html, a.Html.String())
  531. return false
  532. default:
  533. // Ignore the token.
  534. return true
  535. }
  536. case CommentToken:
  537. p.doc.AppendChild(&Node{
  538. Type: CommentNode,
  539. Data: p.tok.Data,
  540. })
  541. return true
  542. }
  543. p.parseImpliedToken(StartTagToken, a.Html, a.Html.String())
  544. return false
  545. }
  546. // Section 12.2.6.4.3.
  547. func beforeHeadIM(p *parser) bool {
  548. switch p.tok.Type {
  549. case TextToken:
  550. p.tok.Data = strings.TrimLeft(p.tok.Data, whitespace)
  551. if len(p.tok.Data) == 0 {
  552. // It was all whitespace, so ignore it.
  553. return true
  554. }
  555. case StartTagToken:
  556. switch p.tok.DataAtom {
  557. case a.Head:
  558. p.addElement()
  559. p.head = p.top()
  560. p.im = inHeadIM
  561. return true
  562. case a.Html:
  563. return inBodyIM(p)
  564. }
  565. case EndTagToken:
  566. switch p.tok.DataAtom {
  567. case a.Head, a.Body, a.Html, a.Br:
  568. p.parseImpliedToken(StartTagToken, a.Head, a.Head.String())
  569. return false
  570. default:
  571. // Ignore the token.
  572. return true
  573. }
  574. case CommentToken:
  575. p.addChild(&Node{
  576. Type: CommentNode,
  577. Data: p.tok.Data,
  578. })
  579. return true
  580. case DoctypeToken:
  581. // Ignore the token.
  582. return true
  583. }
  584. p.parseImpliedToken(StartTagToken, a.Head, a.Head.String())
  585. return false
  586. }
  587. // Section 12.2.6.4.4.
  588. func inHeadIM(p *parser) bool {
  589. switch p.tok.Type {
  590. case TextToken:
  591. s := strings.TrimLeft(p.tok.Data, whitespace)
  592. if len(s) < len(p.tok.Data) {
  593. // Add the initial whitespace to the current node.
  594. p.addText(p.tok.Data[:len(p.tok.Data)-len(s)])
  595. if s == "" {
  596. return true
  597. }
  598. p.tok.Data = s
  599. }
  600. case StartTagToken:
  601. switch p.tok.DataAtom {
  602. case a.Html:
  603. return inBodyIM(p)
  604. case a.Base, a.Basefont, a.Bgsound, a.Command, a.Link, a.Meta:
  605. p.addElement()
  606. p.oe.pop()
  607. p.acknowledgeSelfClosingTag()
  608. return true
  609. case a.Script, a.Title, a.Noscript, a.Noframes, a.Style:
  610. p.addElement()
  611. p.setOriginalIM()
  612. p.im = textIM
  613. return true
  614. case a.Head:
  615. // Ignore the token.
  616. return true
  617. case a.Template:
  618. p.addElement()
  619. p.afe = append(p.afe, &scopeMarker)
  620. p.framesetOK = false
  621. p.im = inTemplateIM
  622. p.templateStack = append(p.templateStack, inTemplateIM)
  623. return true
  624. }
  625. case EndTagToken:
  626. switch p.tok.DataAtom {
  627. case a.Head:
  628. p.oe.pop()
  629. p.im = afterHeadIM
  630. return true
  631. case a.Body, a.Html, a.Br:
  632. p.parseImpliedToken(EndTagToken, a.Head, a.Head.String())
  633. return false
  634. case a.Template:
  635. if !p.oe.contains(a.Template) {
  636. return true
  637. }
  638. p.generateAllImpliedEndTags()
  639. if n := p.oe.top(); n.DataAtom != a.Template {
  640. return true
  641. }
  642. p.popUntil(defaultScope, a.Template)
  643. p.clearActiveFormattingElements()
  644. p.templateStack.pop()
  645. p.resetInsertionMode()
  646. return true
  647. default:
  648. // Ignore the token.
  649. return true
  650. }
  651. case CommentToken:
  652. p.addChild(&Node{
  653. Type: CommentNode,
  654. Data: p.tok.Data,
  655. })
  656. return true
  657. case DoctypeToken:
  658. // Ignore the token.
  659. return true
  660. }
  661. p.parseImpliedToken(EndTagToken, a.Head, a.Head.String())
  662. return false
  663. }
  664. // Section 12.2.6.4.6.
  665. func afterHeadIM(p *parser) bool {
  666. switch p.tok.Type {
  667. case TextToken:
  668. s := strings.TrimLeft(p.tok.Data, whitespace)
  669. if len(s) < len(p.tok.Data) {
  670. // Add the initial whitespace to the current node.
  671. p.addText(p.tok.Data[:len(p.tok.Data)-len(s)])
  672. if s == "" {
  673. return true
  674. }
  675. p.tok.Data = s
  676. }
  677. case StartTagToken:
  678. switch p.tok.DataAtom {
  679. case a.Html:
  680. return inBodyIM(p)
  681. case a.Body:
  682. p.addElement()
  683. p.framesetOK = false
  684. p.im = inBodyIM
  685. return true
  686. case a.Frameset:
  687. p.addElement()
  688. p.im = inFramesetIM
  689. return true
  690. case a.Base, a.Basefont, a.Bgsound, a.Link, a.Meta, a.Noframes, a.Script, a.Style, a.Template, a.Title:
  691. p.oe = append(p.oe, p.head)
  692. defer p.oe.remove(p.head)
  693. return inHeadIM(p)
  694. case a.Head:
  695. // Ignore the token.
  696. return true
  697. }
  698. case EndTagToken:
  699. switch p.tok.DataAtom {
  700. case a.Body, a.Html, a.Br:
  701. // Drop down to creating an implied <body> tag.
  702. case a.Template:
  703. return inHeadIM(p)
  704. default:
  705. // Ignore the token.
  706. return true
  707. }
  708. case CommentToken:
  709. p.addChild(&Node{
  710. Type: CommentNode,
  711. Data: p.tok.Data,
  712. })
  713. return true
  714. case DoctypeToken:
  715. // Ignore the token.
  716. return true
  717. }
  718. p.parseImpliedToken(StartTagToken, a.Body, a.Body.String())
  719. p.framesetOK = true
  720. return false
  721. }
  722. // copyAttributes copies attributes of src not found on dst to dst.
  723. func copyAttributes(dst *Node, src Token) {
  724. if len(src.Attr) == 0 {
  725. return
  726. }
  727. attr := map[string]string{}
  728. for _, t := range dst.Attr {
  729. attr[t.Key] = t.Val
  730. }
  731. for _, t := range src.Attr {
  732. if _, ok := attr[t.Key]; !ok {
  733. dst.Attr = append(dst.Attr, t)
  734. attr[t.Key] = t.Val
  735. }
  736. }
  737. }
  738. // Section 12.2.6.4.7.
  739. func inBodyIM(p *parser) bool {
  740. switch p.tok.Type {
  741. case TextToken:
  742. d := p.tok.Data
  743. switch n := p.oe.top(); n.DataAtom {
  744. case a.Pre, a.Listing:
  745. if n.FirstChild == nil {
  746. // Ignore a newline at the start of a <pre> block.
  747. if d != "" && d[0] == '\r' {
  748. d = d[1:]
  749. }
  750. if d != "" && d[0] == '\n' {
  751. d = d[1:]
  752. }
  753. }
  754. }
  755. d = strings.Replace(d, "\x00", "", -1)
  756. if d == "" {
  757. return true
  758. }
  759. p.reconstructActiveFormattingElements()
  760. p.addText(d)
  761. if p.framesetOK && strings.TrimLeft(d, whitespace) != "" {
  762. // There were non-whitespace characters inserted.
  763. p.framesetOK = false
  764. }
  765. case StartTagToken:
  766. switch p.tok.DataAtom {
  767. case a.Html:
  768. if p.oe.contains(a.Template) {
  769. return true
  770. }
  771. copyAttributes(p.oe[0], p.tok)
  772. case a.Base, a.Basefont, a.Bgsound, a.Command, a.Link, a.Meta, a.Noframes, a.Script, a.Style, a.Template, a.Title:
  773. return inHeadIM(p)
  774. case a.Body:
  775. if p.oe.contains(a.Template) {
  776. return true
  777. }
  778. if len(p.oe) >= 2 {
  779. body := p.oe[1]
  780. if body.Type == ElementNode && body.DataAtom == a.Body {
  781. p.framesetOK = false
  782. copyAttributes(body, p.tok)
  783. }
  784. }
  785. case a.Frameset:
  786. if !p.framesetOK || len(p.oe) < 2 || p.oe[1].DataAtom != a.Body {
  787. // Ignore the token.
  788. return true
  789. }
  790. body := p.oe[1]
  791. if body.Parent != nil {
  792. body.Parent.RemoveChild(body)
  793. }
  794. p.oe = p.oe[:1]
  795. p.addElement()
  796. p.im = inFramesetIM
  797. return true
  798. case a.Address, a.Article, a.Aside, a.Blockquote, a.Center, a.Details, a.Dir, a.Div, a.Dl, a.Fieldset, a.Figcaption, a.Figure, a.Footer, a.Header, a.Hgroup, a.Menu, a.Nav, a.Ol, a.P, a.Section, a.Summary, a.Ul:
  799. p.popUntil(buttonScope, a.P)
  800. p.addElement()
  801. case a.H1, a.H2, a.H3, a.H4, a.H5, a.H6:
  802. p.popUntil(buttonScope, a.P)
  803. switch n := p.top(); n.DataAtom {
  804. case a.H1, a.H2, a.H3, a.H4, a.H5, a.H6:
  805. p.oe.pop()
  806. }
  807. p.addElement()
  808. case a.Pre, a.Listing:
  809. p.popUntil(buttonScope, a.P)
  810. p.addElement()
  811. // The newline, if any, will be dealt with by the TextToken case.
  812. p.framesetOK = false
  813. case a.Form:
  814. if p.oe.contains(a.Template) || p.form == nil {
  815. p.popUntil(buttonScope, a.P)
  816. p.addElement()
  817. p.form = p.top()
  818. }
  819. case a.Li:
  820. p.framesetOK = false
  821. for i := len(p.oe) - 1; i >= 0; i-- {
  822. node := p.oe[i]
  823. switch node.DataAtom {
  824. case a.Li:
  825. p.oe = p.oe[:i]
  826. case a.Address, a.Div, a.P:
  827. continue
  828. default:
  829. if !isSpecialElement(node) {
  830. continue
  831. }
  832. }
  833. break
  834. }
  835. p.popUntil(buttonScope, a.P)
  836. p.addElement()
  837. case a.Dd, a.Dt:
  838. p.framesetOK = false
  839. for i := len(p.oe) - 1; i >= 0; i-- {
  840. node := p.oe[i]
  841. switch node.DataAtom {
  842. case a.Dd, a.Dt:
  843. p.oe = p.oe[:i]
  844. case a.Address, a.Div, a.P:
  845. continue
  846. default:
  847. if !isSpecialElement(node) {
  848. continue
  849. }
  850. }
  851. break
  852. }
  853. p.popUntil(buttonScope, a.P)
  854. p.addElement()
  855. case a.Plaintext:
  856. p.popUntil(buttonScope, a.P)
  857. p.addElement()
  858. case a.Button:
  859. p.popUntil(defaultScope, a.Button)
  860. p.reconstructActiveFormattingElements()
  861. p.addElement()
  862. p.framesetOK = false
  863. case a.A:
  864. for i := len(p.afe) - 1; i >= 0 && p.afe[i].Type != scopeMarkerNode; i-- {
  865. if n := p.afe[i]; n.Type == ElementNode && n.DataAtom == a.A {
  866. p.inBodyEndTagFormatting(a.A)
  867. p.oe.remove(n)
  868. p.afe.remove(n)
  869. break
  870. }
  871. }
  872. p.reconstructActiveFormattingElements()
  873. p.addFormattingElement()
  874. case a.B, a.Big, a.Code, a.Em, a.Font, a.I, a.S, a.Small, a.Strike, a.Strong, a.Tt, a.U:
  875. p.reconstructActiveFormattingElements()
  876. p.addFormattingElement()
  877. case a.Nobr:
  878. p.reconstructActiveFormattingElements()
  879. if p.elementInScope(defaultScope, a.Nobr) {
  880. p.inBodyEndTagFormatting(a.Nobr)
  881. p.reconstructActiveFormattingElements()
  882. }
  883. p.addFormattingElement()
  884. case a.Applet, a.Marquee, a.Object:
  885. p.reconstructActiveFormattingElements()
  886. p.addElement()
  887. p.afe = append(p.afe, &scopeMarker)
  888. p.framesetOK = false
  889. case a.Table:
  890. if !p.quirks {
  891. p.popUntil(buttonScope, a.P)
  892. }
  893. p.addElement()
  894. p.framesetOK = false
  895. p.im = inTableIM
  896. return true
  897. case a.Area, a.Br, a.Embed, a.Img, a.Input, a.Keygen, a.Wbr:
  898. p.reconstructActiveFormattingElements()
  899. p.addElement()
  900. p.oe.pop()
  901. p.acknowledgeSelfClosingTag()
  902. if p.tok.DataAtom == a.Input {
  903. for _, t := range p.tok.Attr {
  904. if t.Key == "type" {
  905. if strings.ToLower(t.Val) == "hidden" {
  906. // Skip setting framesetOK = false
  907. return true
  908. }
  909. }
  910. }
  911. }
  912. p.framesetOK = false
  913. case a.Param, a.Source, a.Track:
  914. p.addElement()
  915. p.oe.pop()
  916. p.acknowledgeSelfClosingTag()
  917. case a.Hr:
  918. p.popUntil(buttonScope, a.P)
  919. p.addElement()
  920. p.oe.pop()
  921. p.acknowledgeSelfClosingTag()
  922. p.framesetOK = false
  923. case a.Image:
  924. p.tok.DataAtom = a.Img
  925. p.tok.Data = a.Img.String()
  926. return false
  927. case a.Isindex:
  928. if p.form != nil {
  929. // Ignore the token.
  930. return true
  931. }
  932. action := ""
  933. prompt := "This is a searchable index. Enter search keywords: "
  934. attr := []Attribute{{Key: "name", Val: "isindex"}}
  935. for _, t := range p.tok.Attr {
  936. switch t.Key {
  937. case "action":
  938. action = t.Val
  939. case "name":
  940. // Ignore the attribute.
  941. case "prompt":
  942. prompt = t.Val
  943. default:
  944. attr = append(attr, t)
  945. }
  946. }
  947. p.acknowledgeSelfClosingTag()
  948. p.popUntil(buttonScope, a.P)
  949. p.parseImpliedToken(StartTagToken, a.Form, a.Form.String())
  950. if action != "" {
  951. p.form.Attr = []Attribute{{Key: "action", Val: action}}
  952. }
  953. p.parseImpliedToken(StartTagToken, a.Hr, a.Hr.String())
  954. p.parseImpliedToken(StartTagToken, a.Label, a.Label.String())
  955. p.addText(prompt)
  956. p.addChild(&Node{
  957. Type: ElementNode,
  958. DataAtom: a.Input,
  959. Data: a.Input.String(),
  960. Attr: attr,
  961. })
  962. p.oe.pop()
  963. p.parseImpliedToken(EndTagToken, a.Label, a.Label.String())
  964. p.parseImpliedToken(StartTagToken, a.Hr, a.Hr.String())
  965. p.parseImpliedToken(EndTagToken, a.Form, a.Form.String())
  966. case a.Textarea:
  967. p.addElement()
  968. p.setOriginalIM()
  969. p.framesetOK = false
  970. p.im = textIM
  971. case a.Xmp:
  972. p.popUntil(buttonScope, a.P)
  973. p.reconstructActiveFormattingElements()
  974. p.framesetOK = false
  975. p.addElement()
  976. p.setOriginalIM()
  977. p.im = textIM
  978. case a.Iframe:
  979. p.framesetOK = false
  980. p.addElement()
  981. p.setOriginalIM()
  982. p.im = textIM
  983. case a.Noembed, a.Noscript:
  984. p.addElement()
  985. p.setOriginalIM()
  986. p.im = textIM
  987. case a.Select:
  988. p.reconstructActiveFormattingElements()
  989. p.addElement()
  990. p.framesetOK = false
  991. p.im = inSelectIM
  992. return true
  993. case a.Optgroup, a.Option:
  994. if p.top().DataAtom == a.Option {
  995. p.oe.pop()
  996. }
  997. p.reconstructActiveFormattingElements()
  998. p.addElement()
  999. case a.Rp, a.Rt:
  1000. if p.elementInScope(defaultScope, a.Ruby) {
  1001. p.generateImpliedEndTags()
  1002. }
  1003. p.addElement()
  1004. case a.Math, a.Svg:
  1005. p.reconstructActiveFormattingElements()
  1006. if p.tok.DataAtom == a.Math {
  1007. adjustAttributeNames(p.tok.Attr, mathMLAttributeAdjustments)
  1008. } else {
  1009. adjustAttributeNames(p.tok.Attr, svgAttributeAdjustments)
  1010. }
  1011. adjustForeignAttributes(p.tok.Attr)
  1012. p.addElement()
  1013. p.top().Namespace = p.tok.Data
  1014. if p.hasSelfClosingToken {
  1015. p.oe.pop()
  1016. p.acknowledgeSelfClosingTag()
  1017. }
  1018. return true
  1019. case a.Frame:
  1020. // TODO: remove this divergence from the HTML5 spec.
  1021. if p.oe.contains(a.Template) {
  1022. p.addElement()
  1023. return true
  1024. }
  1025. case a.Caption, a.Col, a.Colgroup, a.Head, a.Tbody, a.Td, a.Tfoot, a.Th, a.Thead, a.Tr:
  1026. // Ignore the token.
  1027. default:
  1028. p.reconstructActiveFormattingElements()
  1029. p.addElement()
  1030. }
  1031. case EndTagToken:
  1032. switch p.tok.DataAtom {
  1033. case a.Body:
  1034. if p.elementInScope(defaultScope, a.Body) {
  1035. p.im = afterBodyIM
  1036. }
  1037. case a.Html:
  1038. if p.elementInScope(defaultScope, a.Body) {
  1039. p.parseImpliedToken(EndTagToken, a.Body, a.Body.String())
  1040. return false
  1041. }
  1042. return true
  1043. case a.Address, a.Article, a.Aside, a.Blockquote, a.Button, a.Center, a.Details, a.Dir, a.Div, a.Dl, a.Fieldset, a.Figcaption, a.Figure, a.Footer, a.Header, a.Hgroup, a.Listing, a.Menu, a.Nav, a.Ol, a.Pre, a.Section, a.Summary, a.Ul:
  1044. p.popUntil(defaultScope, p.tok.DataAtom)
  1045. case a.Form:
  1046. if p.oe.contains(a.Template) {
  1047. if !p.oe.contains(a.Form) {
  1048. // Ignore the token.
  1049. return true
  1050. }
  1051. p.generateImpliedEndTags()
  1052. if p.tok.DataAtom == a.Form {
  1053. // Ignore the token.
  1054. return true
  1055. }
  1056. p.popUntil(defaultScope, a.Form)
  1057. } else {
  1058. node := p.form
  1059. p.form = nil
  1060. i := p.indexOfElementInScope(defaultScope, a.Form)
  1061. if node == nil || i == -1 || p.oe[i] != node {
  1062. // Ignore the token.
  1063. return true
  1064. }
  1065. p.generateImpliedEndTags()
  1066. p.oe.remove(node)
  1067. }
  1068. case a.P:
  1069. if !p.elementInScope(buttonScope, a.P) {
  1070. p.parseImpliedToken(StartTagToken, a.P, a.P.String())
  1071. }
  1072. p.popUntil(buttonScope, a.P)
  1073. case a.Li:
  1074. p.popUntil(listItemScope, a.Li)
  1075. case a.Dd, a.Dt:
  1076. p.popUntil(defaultScope, p.tok.DataAtom)
  1077. case a.H1, a.H2, a.H3, a.H4, a.H5, a.H6:
  1078. p.popUntil(defaultScope, a.H1, a.H2, a.H3, a.H4, a.H5, a.H6)
  1079. case a.A, a.B, a.Big, a.Code, a.Em, a.Font, a.I, a.Nobr, a.S, a.Small, a.Strike, a.Strong, a.Tt, a.U:
  1080. p.inBodyEndTagFormatting(p.tok.DataAtom)
  1081. case a.Applet, a.Marquee, a.Object:
  1082. if p.popUntil(defaultScope, p.tok.DataAtom) {
  1083. p.clearActiveFormattingElements()
  1084. }
  1085. case a.Br:
  1086. p.tok.Type = StartTagToken
  1087. return false
  1088. case a.Template:
  1089. return inHeadIM(p)
  1090. default:
  1091. p.inBodyEndTagOther(p.tok.DataAtom)
  1092. }
  1093. case CommentToken:
  1094. p.addChild(&Node{
  1095. Type: CommentNode,
  1096. Data: p.tok.Data,
  1097. })
  1098. case ErrorToken:
  1099. // TODO: remove this divergence from the HTML5 spec.
  1100. if len(p.templateStack) > 0 {
  1101. p.im = inTemplateIM
  1102. return false
  1103. } else {
  1104. for _, e := range p.oe {
  1105. // TODO(namusyaka): rb and rtc elements should be added after updating atom.
  1106. switch e.DataAtom {
  1107. case a.Dd, a.Dt, a.Li, a.Optgroup, a.Option, a.P, a.Rp, a.Rt, a.Tbody, a.Td, a.Tfoot, a.Th,
  1108. a.Thead, a.Tr, a.Body, a.Html:
  1109. default:
  1110. return true
  1111. }
  1112. }
  1113. }
  1114. }
  1115. return true
  1116. }
  1117. func (p *parser) inBodyEndTagFormatting(tagAtom a.Atom) {
  1118. // This is the "adoption agency" algorithm, described at
  1119. // https://html.spec.whatwg.org/multipage/syntax.html#adoptionAgency
  1120. // TODO: this is a fairly literal line-by-line translation of that algorithm.
  1121. // Once the code successfully parses the comprehensive test suite, we should
  1122. // refactor this code to be more idiomatic.
  1123. // Steps 1-4. The outer loop.
  1124. for i := 0; i < 8; i++ {
  1125. // Step 5. Find the formatting element.
  1126. var formattingElement *Node
  1127. for j := len(p.afe) - 1; j >= 0; j-- {
  1128. if p.afe[j].Type == scopeMarkerNode {
  1129. break
  1130. }
  1131. if p.afe[j].DataAtom == tagAtom {
  1132. formattingElement = p.afe[j]
  1133. break
  1134. }
  1135. }
  1136. if formattingElement == nil {
  1137. p.inBodyEndTagOther(tagAtom)
  1138. return
  1139. }
  1140. feIndex := p.oe.index(formattingElement)
  1141. if feIndex == -1 {
  1142. p.afe.remove(formattingElement)
  1143. return
  1144. }
  1145. if !p.elementInScope(defaultScope, tagAtom) {
  1146. // Ignore the tag.
  1147. return
  1148. }
  1149. // Steps 9-10. Find the furthest block.
  1150. var furthestBlock *Node
  1151. for _, e := range p.oe[feIndex:] {
  1152. if isSpecialElement(e) {
  1153. furthestBlock = e
  1154. break
  1155. }
  1156. }
  1157. if furthestBlock == nil {
  1158. e := p.oe.pop()
  1159. for e != formattingElement {
  1160. e = p.oe.pop()
  1161. }
  1162. p.afe.remove(e)
  1163. return
  1164. }
  1165. // Steps 11-12. Find the common ancestor and bookmark node.
  1166. commonAncestor := p.oe[feIndex-1]
  1167. bookmark := p.afe.index(formattingElement)
  1168. // Step 13. The inner loop. Find the lastNode to reparent.
  1169. lastNode := furthestBlock
  1170. node := furthestBlock
  1171. x := p.oe.index(node)
  1172. // Steps 13.1-13.2
  1173. for j := 0; j < 3; j++ {
  1174. // Step 13.3.
  1175. x--
  1176. node = p.oe[x]
  1177. // Step 13.4 - 13.5.
  1178. if p.afe.index(node) == -1 {
  1179. p.oe.remove(node)
  1180. continue
  1181. }
  1182. // Step 13.6.
  1183. if node == formattingElement {
  1184. break
  1185. }
  1186. // Step 13.7.
  1187. clone := node.clone()
  1188. p.afe[p.afe.index(node)] = clone
  1189. p.oe[p.oe.index(node)] = clone
  1190. node = clone
  1191. // Step 13.8.
  1192. if lastNode == furthestBlock {
  1193. bookmark = p.afe.index(node) + 1
  1194. }
  1195. // Step 13.9.
  1196. if lastNode.Parent != nil {
  1197. lastNode.Parent.RemoveChild(lastNode)
  1198. }
  1199. node.AppendChild(lastNode)
  1200. // Step 13.10.
  1201. lastNode = node
  1202. }
  1203. // Step 14. Reparent lastNode to the common ancestor,
  1204. // or for misnested table nodes, to the foster parent.
  1205. if lastNode.Parent != nil {
  1206. lastNode.Parent.RemoveChild(lastNode)
  1207. }
  1208. switch commonAncestor.DataAtom {
  1209. case a.Table, a.Tbody, a.Tfoot, a.Thead, a.Tr:
  1210. p.fosterParent(lastNode)
  1211. case a.Template:
  1212. // TODO: remove namespace checking
  1213. if commonAncestor.Namespace == "html" {
  1214. commonAncestor = commonAncestor.LastChild
  1215. }
  1216. fallthrough
  1217. default:
  1218. commonAncestor.AppendChild(lastNode)
  1219. }
  1220. // Steps 15-17. Reparent nodes from the furthest block's children
  1221. // to a clone of the formatting element.
  1222. clone := formattingElement.clone()
  1223. reparentChildren(clone, furthestBlock)
  1224. furthestBlock.AppendChild(clone)
  1225. // Step 18. Fix up the list of active formatting elements.
  1226. if oldLoc := p.afe.index(formattingElement); oldLoc != -1 && oldLoc < bookmark {
  1227. // Move the bookmark with the rest of the list.
  1228. bookmark--
  1229. }
  1230. p.afe.remove(formattingElement)
  1231. p.afe.insert(bookmark, clone)
  1232. // Step 19. Fix up the stack of open elements.
  1233. p.oe.remove(formattingElement)
  1234. p.oe.insert(p.oe.index(furthestBlock)+1, clone)
  1235. }
  1236. }
  1237. // inBodyEndTagOther performs the "any other end tag" algorithm for inBodyIM.
  1238. // "Any other end tag" handling from 12.2.6.5 The rules for parsing tokens in foreign content
  1239. // https://html.spec.whatwg.org/multipage/syntax.html#parsing-main-inforeign
  1240. func (p *parser) inBodyEndTagOther(tagAtom a.Atom) {
  1241. for i := len(p.oe) - 1; i >= 0; i-- {
  1242. if p.oe[i].DataAtom == tagAtom {
  1243. p.oe = p.oe[:i]
  1244. break
  1245. }
  1246. if isSpecialElement(p.oe[i]) {
  1247. break
  1248. }
  1249. }
  1250. }
  1251. // Section 12.2.6.4.8.
  1252. func textIM(p *parser) bool {
  1253. switch p.tok.Type {
  1254. case ErrorToken:
  1255. p.oe.pop()
  1256. case TextToken:
  1257. d := p.tok.Data
  1258. if n := p.oe.top(); n.DataAtom == a.Textarea && n.FirstChild == nil {
  1259. // Ignore a newline at the start of a <textarea> block.
  1260. if d != "" && d[0] == '\r' {
  1261. d = d[1:]
  1262. }
  1263. if d != "" && d[0] == '\n' {
  1264. d = d[1:]
  1265. }
  1266. }
  1267. if d == "" {
  1268. return true
  1269. }
  1270. p.addText(d)
  1271. return true
  1272. case EndTagToken:
  1273. p.oe.pop()
  1274. }
  1275. p.im = p.originalIM
  1276. p.originalIM = nil
  1277. return p.tok.Type == EndTagToken
  1278. }
  1279. // Section 12.2.6.4.9.
  1280. func inTableIM(p *parser) bool {
  1281. switch p.tok.Type {
  1282. case ErrorToken:
  1283. // Stop parsing.
  1284. return true
  1285. case TextToken:
  1286. p.tok.Data = strings.Replace(p.tok.Data, "\x00", "", -1)
  1287. switch p.oe.top().DataAtom {
  1288. case a.Table, a.Tbody, a.Tfoot, a.Thead, a.Tr:
  1289. if strings.Trim(p.tok.Data, whitespace) == "" {
  1290. p.addText(p.tok.Data)
  1291. return true
  1292. }
  1293. }
  1294. case StartTagToken:
  1295. switch p.tok.DataAtom {
  1296. case a.Caption:
  1297. p.clearStackToContext(tableScope)
  1298. p.afe = append(p.afe, &scopeMarker)
  1299. p.addElement()
  1300. p.im = inCaptionIM
  1301. return true
  1302. case a.Colgroup:
  1303. p.clearStackToContext(tableScope)
  1304. p.addElement()
  1305. p.im = inColumnGroupIM
  1306. return true
  1307. case a.Col:
  1308. p.parseImpliedToken(StartTagToken, a.Colgroup, a.Colgroup.String())
  1309. return false
  1310. case a.Tbody, a.Tfoot, a.Thead:
  1311. p.clearStackToContext(tableScope)
  1312. p.addElement()
  1313. p.im = inTableBodyIM
  1314. return true
  1315. case a.Td, a.Th, a.Tr:
  1316. p.parseImpliedToken(StartTagToken, a.Tbody, a.Tbody.String())
  1317. return false
  1318. case a.Table:
  1319. if p.popUntil(tableScope, a.Table) {
  1320. p.resetInsertionMode()
  1321. return false
  1322. }
  1323. // Ignore the token.
  1324. return true
  1325. case a.Style, a.Script, a.Template:
  1326. return inHeadIM(p)
  1327. case a.Input:
  1328. for _, t := range p.tok.Attr {
  1329. if t.Key == "type" && strings.ToLower(t.Val) == "hidden" {
  1330. p.addElement()
  1331. p.oe.pop()
  1332. return true
  1333. }
  1334. }
  1335. // Otherwise drop down to the default action.
  1336. case a.Form:
  1337. if p.oe.contains(a.Template) || p.form != nil {
  1338. // Ignore the token.
  1339. return true
  1340. }
  1341. p.addElement()
  1342. p.form = p.oe.pop()
  1343. case a.Select:
  1344. p.reconstructActiveFormattingElements()
  1345. switch p.top().DataAtom {
  1346. case a.Table, a.Tbody, a.Tfoot, a.Thead, a.Tr:
  1347. p.fosterParenting = true
  1348. }
  1349. p.addElement()
  1350. p.fosterParenting = false
  1351. p.framesetOK = false
  1352. p.im = inSelectInTableIM
  1353. return true
  1354. }
  1355. case EndTagToken:
  1356. switch p.tok.DataAtom {
  1357. case a.Table:
  1358. if p.popUntil(tableScope, a.Table) {
  1359. p.resetInsertionMode()
  1360. return true
  1361. }
  1362. // Ignore the token.
  1363. return true
  1364. case a.Body, a.Caption, a.Col, a.Colgroup, a.Html, a.Tbody, a.Td, a.Tfoot, a.Th, a.Thead, a.Tr:
  1365. // Ignore the token.
  1366. return true
  1367. case a.Template:
  1368. return inHeadIM(p)
  1369. }
  1370. case CommentToken:
  1371. p.addChild(&Node{
  1372. Type: CommentNode,
  1373. Data: p.tok.Data,
  1374. })
  1375. return true
  1376. case DoctypeToken:
  1377. // Ignore the token.
  1378. return true
  1379. }
  1380. p.fosterParenting = true
  1381. defer func() { p.fosterParenting = false }()
  1382. return inBodyIM(p)
  1383. }
  1384. // Section 12.2.6.4.11.
  1385. func inCaptionIM(p *parser) bool {
  1386. switch p.tok.Type {
  1387. case StartTagToken:
  1388. switch p.tok.DataAtom {
  1389. case a.Caption, a.Col, a.Colgroup, a.Tbody, a.Td, a.Tfoot, a.Thead, a.Tr:
  1390. if p.popUntil(tableScope, a.Caption) {
  1391. p.clearActiveFormattingElements()
  1392. p.im = inTableIM
  1393. return false
  1394. } else {
  1395. // Ignore the token.
  1396. return true
  1397. }
  1398. case a.Select:
  1399. p.reconstructActiveFormattingElements()
  1400. p.addElement()
  1401. p.framesetOK = false
  1402. p.im = inSelectInTableIM
  1403. return true
  1404. }
  1405. case EndTagToken:
  1406. switch p.tok.DataAtom {
  1407. case a.Caption:
  1408. if p.popUntil(tableScope, a.Caption) {
  1409. p.clearActiveFormattingElements()
  1410. p.im = inTableIM
  1411. }
  1412. return true
  1413. case a.Table:
  1414. if p.popUntil(tableScope, a.Caption) {
  1415. p.clearActiveFormattingElements()
  1416. p.im = inTableIM
  1417. return false
  1418. } else {
  1419. // Ignore the token.
  1420. return true
  1421. }
  1422. case a.Body, a.Col, a.Colgroup, a.Html, a.Tbody, a.Td, a.Tfoot, a.Th, a.Thead, a.Tr:
  1423. // Ignore the token.
  1424. return true
  1425. }
  1426. }
  1427. return inBodyIM(p)
  1428. }
  1429. // Section 12.2.6.4.12.
  1430. func inColumnGroupIM(p *parser) bool {
  1431. switch p.tok.Type {
  1432. case TextToken:
  1433. s := strings.TrimLeft(p.tok.Data, whitespace)
  1434. if len(s) < len(p.tok.Data) {
  1435. // Add the initial whitespace to the current node.
  1436. p.addText(p.tok.Data[:len(p.tok.Data)-len(s)])
  1437. if s == "" {
  1438. return true
  1439. }
  1440. p.tok.Data = s
  1441. }
  1442. case CommentToken:
  1443. p.addChild(&Node{
  1444. Type: CommentNode,
  1445. Data: p.tok.Data,
  1446. })
  1447. return true
  1448. case DoctypeToken:
  1449. // Ignore the token.
  1450. return true
  1451. case StartTagToken:
  1452. switch p.tok.DataAtom {
  1453. case a.Html:
  1454. return inBodyIM(p)
  1455. case a.Col:
  1456. p.addElement()
  1457. p.oe.pop()
  1458. p.acknowledgeSelfClosingTag()
  1459. return true
  1460. case a.Template:
  1461. return inHeadIM(p)
  1462. }
  1463. case EndTagToken:
  1464. switch p.tok.DataAtom {
  1465. case a.Colgroup:
  1466. if p.oe.top().DataAtom == a.Colgroup {
  1467. p.oe.pop()
  1468. p.im = inTableIM
  1469. }
  1470. return true
  1471. case a.Col:
  1472. // Ignore the token.
  1473. return true
  1474. case a.Template:
  1475. return inHeadIM(p)
  1476. }
  1477. }
  1478. if p.oe.top().DataAtom != a.Colgroup {
  1479. return true
  1480. }
  1481. p.oe.pop()
  1482. p.im = inTableIM
  1483. return false
  1484. }
  1485. // Section 12.2.6.4.13.
  1486. func inTableBodyIM(p *parser) bool {
  1487. switch p.tok.Type {
  1488. case StartTagToken:
  1489. switch p.tok.DataAtom {
  1490. case a.Tr:
  1491. p.clearStackToContext(tableBodyScope)
  1492. p.addElement()
  1493. p.im = inRowIM
  1494. return true
  1495. case a.Td, a.Th:
  1496. p.parseImpliedToken(StartTagToken, a.Tr, a.Tr.String())
  1497. return false
  1498. case a.Caption, a.Col, a.Colgroup, a.Tbody, a.Tfoot, a.Thead:
  1499. if p.popUntil(tableScope, a.Tbody, a.Thead, a.Tfoot) {
  1500. p.im = inTableIM
  1501. return false
  1502. }
  1503. // Ignore the token.
  1504. return true
  1505. }
  1506. case EndTagToken:
  1507. switch p.tok.DataAtom {
  1508. case a.Tbody, a.Tfoot, a.Thead:
  1509. if p.elementInScope(tableScope, p.tok.DataAtom) {
  1510. p.clearStackToContext(tableBodyScope)
  1511. p.oe.pop()
  1512. p.im = inTableIM
  1513. }
  1514. return true
  1515. case a.Table:
  1516. if p.popUntil(tableScope, a.Tbody, a.Thead, a.Tfoot) {
  1517. p.im = inTableIM
  1518. return false
  1519. }
  1520. // Ignore the token.
  1521. return true
  1522. case a.Body, a.Caption, a.Col, a.Colgroup, a.Html, a.Td, a.Th, a.Tr:
  1523. // Ignore the token.
  1524. return true
  1525. }
  1526. case CommentToken:
  1527. p.addChild(&Node{
  1528. Type: CommentNode,
  1529. Data: p.tok.Data,
  1530. })
  1531. return true
  1532. }
  1533. return inTableIM(p)
  1534. }
  1535. // Section 12.2.6.4.14.
  1536. func inRowIM(p *parser) bool {
  1537. switch p.tok.Type {
  1538. case StartTagToken:
  1539. switch p.tok.DataAtom {
  1540. case a.Td, a.Th:
  1541. p.clearStackToContext(tableRowScope)
  1542. p.addElement()
  1543. p.afe = append(p.afe, &scopeMarker)
  1544. p.im = inCellIM
  1545. return true
  1546. case a.Caption, a.Col, a.Colgroup, a.Tbody, a.Tfoot, a.Thead, a.Tr:
  1547. if p.popUntil(tableScope, a.Tr) {
  1548. p.im = inTableBodyIM
  1549. return false
  1550. }
  1551. // Ignore the token.
  1552. return true
  1553. }
  1554. case EndTagToken:
  1555. switch p.tok.DataAtom {
  1556. case a.Tr:
  1557. if p.popUntil(tableScope, a.Tr) {
  1558. p.im = inTableBodyIM
  1559. return true
  1560. }
  1561. // Ignore the token.
  1562. return true
  1563. case a.Table:
  1564. if p.popUntil(tableScope, a.Tr) {
  1565. p.im = inTableBodyIM
  1566. return false
  1567. }
  1568. // Ignore the token.
  1569. return true
  1570. case a.Tbody, a.Tfoot, a.Thead:
  1571. if p.elementInScope(tableScope, p.tok.DataAtom) {
  1572. p.parseImpliedToken(EndTagToken, a.Tr, a.Tr.String())
  1573. return false
  1574. }
  1575. // Ignore the token.
  1576. return true
  1577. case a.Body, a.Caption, a.Col, a.Colgroup, a.Html, a.Td, a.Th:
  1578. // Ignore the token.
  1579. return true
  1580. }
  1581. }
  1582. return inTableIM(p)
  1583. }
  1584. // Section 12.2.6.4.15.
  1585. func inCellIM(p *parser) bool {
  1586. switch p.tok.Type {
  1587. case StartTagToken:
  1588. switch p.tok.DataAtom {
  1589. case a.Caption, a.Col, a.Colgroup, a.Tbody, a.Td, a.Tfoot, a.Th, a.Thead, a.Tr:
  1590. if p.popUntil(tableScope, a.Td, a.Th) {
  1591. // Close the cell and reprocess.
  1592. p.clearActiveFormattingElements()
  1593. p.im = inRowIM
  1594. return false
  1595. }
  1596. // Ignore the token.
  1597. return true
  1598. case a.Select:
  1599. p.reconstructActiveFormattingElements()
  1600. p.addElement()
  1601. p.framesetOK = false
  1602. p.im = inSelectInTableIM
  1603. return true
  1604. }
  1605. case EndTagToken:
  1606. switch p.tok.DataAtom {
  1607. case a.Td, a.Th:
  1608. if !p.popUntil(tableScope, p.tok.DataAtom) {
  1609. // Ignore the token.
  1610. return true
  1611. }
  1612. p.clearActiveFormattingElements()
  1613. p.im = inRowIM
  1614. return true
  1615. case a.Body, a.Caption, a.Col, a.Colgroup, a.Html:
  1616. // Ignore the token.
  1617. return true
  1618. case a.Table, a.Tbody, a.Tfoot, a.Thead, a.Tr:
  1619. if !p.elementInScope(tableScope, p.tok.DataAtom) {
  1620. // Ignore the token.
  1621. return true
  1622. }
  1623. // Close the cell and reprocess.
  1624. p.popUntil(tableScope, a.Td, a.Th)
  1625. p.clearActiveFormattingElements()
  1626. p.im = inRowIM
  1627. return false
  1628. }
  1629. }
  1630. return inBodyIM(p)
  1631. }
  1632. // Section 12.2.6.4.16.
  1633. func inSelectIM(p *parser) bool {
  1634. switch p.tok.Type {
  1635. case ErrorToken:
  1636. // Stop parsing.
  1637. return true
  1638. case TextToken:
  1639. p.addText(strings.Replace(p.tok.Data, "\x00", "", -1))
  1640. case StartTagToken:
  1641. switch p.tok.DataAtom {
  1642. case a.Html:
  1643. return inBodyIM(p)
  1644. case a.Option:
  1645. if p.top().DataAtom == a.Option {
  1646. p.oe.pop()
  1647. }
  1648. p.addElement()
  1649. case a.Optgroup:
  1650. if p.top().DataAtom == a.Option {
  1651. p.oe.pop()
  1652. }
  1653. if p.top().DataAtom == a.Optgroup {
  1654. p.oe.pop()
  1655. }
  1656. p.addElement()
  1657. case a.Select:
  1658. p.tok.Type = EndTagToken
  1659. return false
  1660. case a.Input, a.Keygen, a.Textarea:
  1661. if p.elementInScope(selectScope, a.Select) {
  1662. p.parseImpliedToken(EndTagToken, a.Select, a.Select.String())
  1663. return false
  1664. }
  1665. // In order to properly ignore <textarea>, we need to change the tokenizer mode.
  1666. p.tokenizer.NextIsNotRawText()
  1667. // Ignore the token.
  1668. return true
  1669. case a.Script, a.Template:
  1670. return inHeadIM(p)
  1671. }
  1672. case EndTagToken:
  1673. switch p.tok.DataAtom {
  1674. case a.Option:
  1675. if p.top().DataAtom == a.Option {
  1676. p.oe.pop()
  1677. }
  1678. case a.Optgroup:
  1679. i := len(p.oe) - 1
  1680. if p.oe[i].DataAtom == a.Option {
  1681. i--
  1682. }
  1683. if p.oe[i].DataAtom == a.Optgroup {
  1684. p.oe = p.oe[:i]
  1685. }
  1686. case a.Select:
  1687. if p.popUntil(selectScope, a.Select) {
  1688. p.resetInsertionMode()
  1689. }
  1690. case a.Template:
  1691. return inHeadIM(p)
  1692. }
  1693. case CommentToken:
  1694. p.addChild(&Node{
  1695. Type: CommentNode,
  1696. Data: p.tok.Data,
  1697. })
  1698. case DoctypeToken:
  1699. // Ignore the token.
  1700. return true
  1701. }
  1702. return true
  1703. }
  1704. // Section 12.2.6.4.17.
  1705. func inSelectInTableIM(p *parser) bool {
  1706. switch p.tok.Type {
  1707. case StartTagToken, EndTagToken:
  1708. switch p.tok.DataAtom {
  1709. case a.Caption, a.Table, a.Tbody, a.Tfoot, a.Thead, a.Tr, a.Td, a.Th:
  1710. if p.tok.Type == StartTagToken || p.elementInScope(tableScope, p.tok.DataAtom) {
  1711. p.parseImpliedToken(EndTagToken, a.Select, a.Select.String())
  1712. return false
  1713. } else {
  1714. // Ignore the token.
  1715. return true
  1716. }
  1717. }
  1718. }
  1719. return inSelectIM(p)
  1720. }
  1721. // Section 12.2.6.4.18.
  1722. func inTemplateIM(p *parser) bool {
  1723. switch p.tok.Type {
  1724. case TextToken, CommentToken, DoctypeToken:
  1725. return inBodyIM(p)
  1726. case StartTagToken:
  1727. switch p.tok.DataAtom {
  1728. case a.Base, a.Basefont, a.Bgsound, a.Link, a.Meta, a.Noframes, a.Script, a.Style, a.Template, a.Title:
  1729. return inHeadIM(p)
  1730. case a.Caption, a.Colgroup, a.Tbody, a.Tfoot, a.Thead:
  1731. p.templateStack.pop()
  1732. p.templateStack = append(p.templateStack, inTableIM)
  1733. p.im = inTableIM
  1734. return false
  1735. case a.Col:
  1736. p.templateStack.pop()
  1737. p.templateStack = append(p.templateStack, inColumnGroupIM)
  1738. p.im = inColumnGroupIM
  1739. return false
  1740. case a.Tr:
  1741. p.templateStack.pop()
  1742. p.templateStack = append(p.templateStack, inTableBodyIM)
  1743. p.im = inTableBodyIM
  1744. return false
  1745. case a.Td, a.Th:
  1746. p.templateStack.pop()
  1747. p.templateStack = append(p.templateStack, inRowIM)
  1748. p.im = inRowIM
  1749. return false
  1750. default:
  1751. p.templateStack.pop()
  1752. p.templateStack = append(p.templateStack, inBodyIM)
  1753. p.im = inBodyIM
  1754. return false
  1755. }
  1756. case EndTagToken:
  1757. switch p.tok.DataAtom {
  1758. case a.Template:
  1759. return inHeadIM(p)
  1760. default:
  1761. // Ignore the token.
  1762. return true
  1763. }
  1764. }
  1765. if !p.oe.contains(a.Template) {
  1766. // Ignore the token.
  1767. return true
  1768. }
  1769. p.popUntil(defaultScope, a.Template)
  1770. p.clearActiveFormattingElements()
  1771. p.templateStack.pop()
  1772. p.resetInsertionMode()
  1773. return false
  1774. }
  1775. // Section 12.2.6.4.19.
  1776. func afterBodyIM(p *parser) bool {
  1777. switch p.tok.Type {
  1778. case ErrorToken:
  1779. // Stop parsing.
  1780. return true
  1781. case TextToken:
  1782. s := strings.TrimLeft(p.tok.Data, whitespace)
  1783. if len(s) == 0 {
  1784. // It was all whitespace.
  1785. return inBodyIM(p)
  1786. }
  1787. case StartTagToken:
  1788. if p.tok.DataAtom == a.Html {
  1789. return inBodyIM(p)
  1790. }
  1791. case EndTagToken:
  1792. if p.tok.DataAtom == a.Html {
  1793. if !p.fragment {
  1794. p.im = afterAfterBodyIM
  1795. }
  1796. return true
  1797. }
  1798. case CommentToken:
  1799. // The comment is attached to the <html> element.
  1800. if len(p.oe) < 1 || p.oe[0].DataAtom != a.Html {
  1801. panic("html: bad parser state: <html> element not found, in the after-body insertion mode")
  1802. }
  1803. p.oe[0].AppendChild(&Node{
  1804. Type: CommentNode,
  1805. Data: p.tok.Data,
  1806. })
  1807. return true
  1808. }
  1809. p.im = inBodyIM
  1810. return false
  1811. }
  1812. // Section 12.2.6.4.20.
  1813. func inFramesetIM(p *parser) bool {
  1814. switch p.tok.Type {
  1815. case CommentToken:
  1816. p.addChild(&Node{
  1817. Type: CommentNode,
  1818. Data: p.tok.Data,
  1819. })
  1820. case TextToken:
  1821. // Ignore all text but whitespace.
  1822. s := strings.Map(func(c rune) rune {
  1823. switch c {
  1824. case ' ', '\t', '\n', '\f', '\r':
  1825. return c
  1826. }
  1827. return -1
  1828. }, p.tok.Data)
  1829. if s != "" {
  1830. p.addText(s)
  1831. }
  1832. case StartTagToken:
  1833. switch p.tok.DataAtom {
  1834. case a.Html:
  1835. return inBodyIM(p)
  1836. case a.Frameset:
  1837. p.addElement()
  1838. case a.Frame:
  1839. p.addElement()
  1840. p.oe.pop()
  1841. p.acknowledgeSelfClosingTag()
  1842. case a.Noframes:
  1843. return inHeadIM(p)
  1844. case a.Template:
  1845. // TODO: remove this divergence from the HTML5 spec.
  1846. //
  1847. // See https://bugs.chromium.org/p/chromium/issues/detail?id=829668
  1848. return inTemplateIM(p)
  1849. }
  1850. case EndTagToken:
  1851. switch p.tok.DataAtom {
  1852. case a.Frameset:
  1853. if p.oe.top().DataAtom != a.Html {
  1854. p.oe.pop()
  1855. if p.oe.top().DataAtom != a.Frameset {
  1856. p.im = afterFramesetIM
  1857. return true
  1858. }
  1859. }
  1860. }
  1861. default:
  1862. // Ignore the token.
  1863. }
  1864. return true
  1865. }
  1866. // Section 12.2.6.4.21.
  1867. func afterFramesetIM(p *parser) bool {
  1868. switch p.tok.Type {
  1869. case CommentToken:
  1870. p.addChild(&Node{
  1871. Type: CommentNode,
  1872. Data: p.tok.Data,
  1873. })
  1874. case TextToken:
  1875. // Ignore all text but whitespace.
  1876. s := strings.Map(func(c rune) rune {
  1877. switch c {
  1878. case ' ', '\t', '\n', '\f', '\r':
  1879. return c
  1880. }
  1881. return -1
  1882. }, p.tok.Data)
  1883. if s != "" {
  1884. p.addText(s)
  1885. }
  1886. case StartTagToken:
  1887. switch p.tok.DataAtom {
  1888. case a.Html:
  1889. return inBodyIM(p)
  1890. case a.Noframes:
  1891. return inHeadIM(p)
  1892. }
  1893. case EndTagToken:
  1894. switch p.tok.DataAtom {
  1895. case a.Html:
  1896. p.im = afterAfterFramesetIM
  1897. return true
  1898. }
  1899. default:
  1900. // Ignore the token.
  1901. }
  1902. return true
  1903. }
  1904. // Section 12.2.6.4.22.
  1905. func afterAfterBodyIM(p *parser) bool {
  1906. switch p.tok.Type {
  1907. case ErrorToken:
  1908. // Stop parsing.
  1909. return true
  1910. case TextToken:
  1911. s := strings.TrimLeft(p.tok.Data, whitespace)
  1912. if len(s) == 0 {
  1913. // It was all whitespace.
  1914. return inBodyIM(p)
  1915. }
  1916. case StartTagToken:
  1917. if p.tok.DataAtom == a.Html {
  1918. return inBodyIM(p)
  1919. }
  1920. case CommentToken:
  1921. p.doc.AppendChild(&Node{
  1922. Type: CommentNode,
  1923. Data: p.tok.Data,
  1924. })
  1925. return true
  1926. case DoctypeToken:
  1927. return inBodyIM(p)
  1928. }
  1929. p.im = inBodyIM
  1930. return false
  1931. }
  1932. // Section 12.2.6.4.23.
  1933. func afterAfterFramesetIM(p *parser) bool {
  1934. switch p.tok.Type {
  1935. case CommentToken:
  1936. p.doc.AppendChild(&Node{
  1937. Type: CommentNode,
  1938. Data: p.tok.Data,
  1939. })
  1940. case TextToken:
  1941. // Ignore all text but whitespace.
  1942. s := strings.Map(func(c rune) rune {
  1943. switch c {
  1944. case ' ', '\t', '\n', '\f', '\r':
  1945. return c
  1946. }
  1947. return -1
  1948. }, p.tok.Data)
  1949. if s != "" {
  1950. p.tok.Data = s
  1951. return inBodyIM(p)
  1952. }
  1953. case StartTagToken:
  1954. switch p.tok.DataAtom {
  1955. case a.Html:
  1956. return inBodyIM(p)
  1957. case a.Noframes:
  1958. return inHeadIM(p)
  1959. }
  1960. case DoctypeToken:
  1961. return inBodyIM(p)
  1962. default:
  1963. // Ignore the token.
  1964. }
  1965. return true
  1966. }
  1967. const whitespaceOrNUL = whitespace + "\x00"
  1968. // Section 12.2.6.5
  1969. func parseForeignContent(p *parser) bool {
  1970. switch p.tok.Type {
  1971. case TextToken:
  1972. if p.framesetOK {
  1973. p.framesetOK = strings.TrimLeft(p.tok.Data, whitespaceOrNUL) == ""
  1974. }
  1975. p.tok.Data = strings.Replace(p.tok.Data, "\x00", "\ufffd", -1)
  1976. p.addText(p.tok.Data)
  1977. case CommentToken:
  1978. p.addChild(&Node{
  1979. Type: CommentNode,
  1980. Data: p.tok.Data,
  1981. })
  1982. case StartTagToken:
  1983. b := breakout[p.tok.Data]
  1984. if p.tok.DataAtom == a.Font {
  1985. loop:
  1986. for _, attr := range p.tok.Attr {
  1987. switch attr.Key {
  1988. case "color", "face", "size":
  1989. b = true
  1990. break loop
  1991. }
  1992. }
  1993. }
  1994. if b {
  1995. for i := len(p.oe) - 1; i >= 0; i-- {
  1996. n := p.oe[i]
  1997. if n.Namespace == "" || htmlIntegrationPoint(n) || mathMLTextIntegrationPoint(n) {
  1998. p.oe = p.oe[:i+1]
  1999. break
  2000. }
  2001. }
  2002. return false
  2003. }
  2004. switch p.top().Namespace {
  2005. case "math":
  2006. adjustAttributeNames(p.tok.Attr, mathMLAttributeAdjustments)
  2007. case "svg":
  2008. // Adjust SVG tag names. The tokenizer lower-cases tag names, but
  2009. // SVG wants e.g. "foreignObject" with a capital second "O".
  2010. if x := svgTagNameAdjustments[p.tok.Data]; x != "" {
  2011. p.tok.DataAtom = a.Lookup([]byte(x))
  2012. p.tok.Data = x
  2013. }
  2014. adjustAttributeNames(p.tok.Attr, svgAttributeAdjustments)
  2015. default:
  2016. panic("html: bad parser state: unexpected namespace")
  2017. }
  2018. adjustForeignAttributes(p.tok.Attr)
  2019. namespace := p.top().Namespace
  2020. p.addElement()
  2021. p.top().Namespace = namespace
  2022. if namespace != "" {
  2023. // Don't let the tokenizer go into raw text mode in foreign content
  2024. // (e.g. in an SVG <title> tag).
  2025. p.tokenizer.NextIsNotRawText()
  2026. }
  2027. if p.hasSelfClosingToken {
  2028. p.oe.pop()
  2029. p.acknowledgeSelfClosingTag()
  2030. }
  2031. case EndTagToken:
  2032. for i := len(p.oe) - 1; i >= 0; i-- {
  2033. if p.oe[i].Namespace == "" {
  2034. return p.im(p)
  2035. }
  2036. if strings.EqualFold(p.oe[i].Data, p.tok.Data) {
  2037. p.oe = p.oe[:i]
  2038. break
  2039. }
  2040. }
  2041. return true
  2042. default:
  2043. // Ignore the token.
  2044. }
  2045. return true
  2046. }
  2047. // Section 12.2.6.
  2048. func (p *parser) inForeignContent() bool {
  2049. if len(p.oe) == 0 {
  2050. return false
  2051. }
  2052. n := p.oe[len(p.oe)-1]
  2053. if n.Namespace == "" {
  2054. return false
  2055. }
  2056. if mathMLTextIntegrationPoint(n) {
  2057. if p.tok.Type == StartTagToken && p.tok.DataAtom != a.Mglyph && p.tok.DataAtom != a.Malignmark {
  2058. return false
  2059. }
  2060. if p.tok.Type == TextToken {
  2061. return false
  2062. }
  2063. }
  2064. if n.Namespace == "math" && n.DataAtom == a.AnnotationXml && p.tok.Type == StartTagToken && p.tok.DataAtom == a.Svg {
  2065. return false
  2066. }
  2067. if htmlIntegrationPoint(n) && (p.tok.Type == StartTagToken || p.tok.Type == TextToken) {
  2068. return false
  2069. }
  2070. if p.tok.Type == ErrorToken {
  2071. return false
  2072. }
  2073. return true
  2074. }
  2075. // parseImpliedToken parses a token as though it had appeared in the parser's
  2076. // input.
  2077. func (p *parser) parseImpliedToken(t TokenType, dataAtom a.Atom, data string) {
  2078. realToken, selfClosing := p.tok, p.hasSelfClosingToken
  2079. p.tok = Token{
  2080. Type: t,
  2081. DataAtom: dataAtom,
  2082. Data: data,
  2083. }
  2084. p.hasSelfClosingToken = false
  2085. p.parseCurrentToken()
  2086. p.tok, p.hasSelfClosingToken = realToken, selfClosing
  2087. }
  2088. // parseCurrentToken runs the current token through the parsing routines
  2089. // until it is consumed.
  2090. func (p *parser) parseCurrentToken() {
  2091. if p.tok.Type == SelfClosingTagToken {
  2092. p.hasSelfClosingToken = true
  2093. p.tok.Type = StartTagToken
  2094. }
  2095. consumed := false
  2096. for !consumed {
  2097. if p.inForeignContent() {
  2098. consumed = parseForeignContent(p)
  2099. } else {
  2100. consumed = p.im(p)
  2101. }
  2102. }
  2103. if p.hasSelfClosingToken {
  2104. // This is a parse error, but ignore it.
  2105. p.hasSelfClosingToken = false
  2106. }
  2107. }
  2108. func (p *parser) parse() error {
  2109. // Iterate until EOF. Any other error will cause an early return.
  2110. var err error
  2111. for err != io.EOF {
  2112. // CDATA sections are allowed only in foreign content.
  2113. n := p.oe.top()
  2114. p.tokenizer.AllowCDATA(n != nil && n.Namespace != "")
  2115. // Read and parse the next token.
  2116. p.tokenizer.Next()
  2117. p.tok = p.tokenizer.Token()
  2118. if p.tok.Type == ErrorToken {
  2119. err = p.tokenizer.Err()
  2120. if err != nil && err != io.EOF {
  2121. return err
  2122. }
  2123. }
  2124. p.parseCurrentToken()
  2125. }
  2126. return nil
  2127. }
  2128. // Parse returns the parse tree for the HTML from the given Reader.
  2129. // The input is assumed to be UTF-8 encoded.
  2130. func Parse(r io.Reader) (*Node, error) {
  2131. p := &parser{
  2132. tokenizer: NewTokenizer(r),
  2133. doc: &Node{
  2134. Type: DocumentNode,
  2135. },
  2136. scripting: true,
  2137. framesetOK: true,
  2138. im: initialIM,
  2139. }
  2140. err := p.parse()
  2141. if err != nil {
  2142. return nil, err
  2143. }
  2144. return p.doc, nil
  2145. }
  2146. // ParseFragment parses a fragment of HTML and returns the nodes that were
  2147. // found. If the fragment is the InnerHTML for an existing element, pass that
  2148. // element in context.
  2149. func ParseFragment(r io.Reader, context *Node) ([]*Node, error) {
  2150. contextTag := ""
  2151. if context != nil {
  2152. if context.Type != ElementNode {
  2153. return nil, errors.New("html: ParseFragment of non-element Node")
  2154. }
  2155. // The next check isn't just context.DataAtom.String() == context.Data because
  2156. // it is valid to pass an element whose tag isn't a known atom. For example,
  2157. // DataAtom == 0 and Data = "tagfromthefuture" is perfectly consistent.
  2158. if context.DataAtom != a.Lookup([]byte(context.Data)) {
  2159. return nil, fmt.Errorf("html: inconsistent Node: DataAtom=%q, Data=%q", context.DataAtom, context.Data)
  2160. }
  2161. contextTag = context.DataAtom.String()
  2162. }
  2163. p := &parser{
  2164. tokenizer: NewTokenizerFragment(r, contextTag),
  2165. doc: &Node{
  2166. Type: DocumentNode,
  2167. },
  2168. scripting: true,
  2169. fragment: true,
  2170. context: context,
  2171. }
  2172. root := &Node{
  2173. Type: ElementNode,
  2174. DataAtom: a.Html,
  2175. Data: a.Html.String(),
  2176. }
  2177. p.doc.AppendChild(root)
  2178. p.oe = nodeStack{root}
  2179. if context != nil && context.DataAtom == a.Template {
  2180. p.templateStack = append(p.templateStack, inTemplateIM)
  2181. }
  2182. p.resetInsertionMode()
  2183. for n := context; n != nil; n = n.Parent {
  2184. if n.Type == ElementNode && n.DataAtom == a.Form {
  2185. p.form = n
  2186. break
  2187. }
  2188. }
  2189. err := p.parse()
  2190. if err != nil {
  2191. return nil, err
  2192. }
  2193. parent := p.doc
  2194. if context != nil {
  2195. parent = root
  2196. }
  2197. var result []*Node
  2198. for c := parent.FirstChild; c != nil; {
  2199. next := c.NextSibling
  2200. parent.RemoveChild(c)
  2201. result = append(result, c)
  2202. c = next
  2203. }
  2204. return result, nil
  2205. }