b074135dd03e45fb0dcdc9b1b4fa2272ce1842cb
[WebKit-https.git] / WebCore / html / HTMLParser.cpp
1 /*
2     This file is part of the KDE libraries
3
4     Copyright (C) 1997 Martin Jones (mjones@kde.org)
5               (C) 1997 Torben Weis (weis@kde.org)
6               (C) 1999,2001 Lars Knoll (knoll@kde.org)
7               (C) 2000,2001 Dirk Mueller (mueller@kde.org)
8     Copyright (C) 2004, 2005, 2006 Apple Computer, Inc.
9
10     This library is free software; you can redistribute it and/or
11     modify it under the terms of the GNU Library General Public
12     License as published by the Free Software Foundation; either
13     version 2 of the License, or (at your option) any later version.
14
15     This library is distributed in the hope that it will be useful,
16     but WITHOUT ANY WARRANTY; without even the implied warranty of
17     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18     Library General Public License for more details.
19
20     You should have received a copy of the GNU Library General Public License
21     along with this library; see the file COPYING.LIB.  If not, write to
22     the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
23     Boston, MA 02111-1307, USA.
24 */
25
26 #include "config.h"
27 #include "HTMLParser.h"
28
29 #include "CSSPropertyNames.h"
30 #include "CSSValueKeywords.h"
31 #include "Comment.h"
32 #include "DocumentFragment.h"
33 #include "Frame.h"
34 #include "HTMLCanvasElement.h"
35 #include "HTMLElementFactory.h"
36 #include "HTMLFormElement.h"
37 #include "HTMLIsIndexElement.h"
38 #include "HTMLTokenizer.h"
39 #include "LocalizedStrings.h"
40 #include "Text.h"
41 #include "html_baseimpl.h"
42 #include "html_blockimpl.h"
43 #include "html_headimpl.h"
44 #include "html_listimpl.h"
45 #include "html_objectimpl.h"
46 #include "html_tableimpl.h"
47
48 namespace WebCore {
49
50 using namespace HTMLNames;
51
52 /**
53  * @internal
54  */
55 class HTMLStackElem
56 {
57 public:
58     HTMLStackElem(const AtomicString& _tagName,
59                   int _level,
60                   Node *_node,
61                   HTMLStackElem * _next
62         )
63         :
64         tagName(_tagName),
65         level(_level),
66         strayTableContent(false),
67         node(_node),
68         next(_next)
69         { }
70
71     AtomicString tagName;
72     int level;
73     bool strayTableContent;
74     RefPtr<Node> node;
75     HTMLStackElem* next;
76 };
77
78 /**
79  * @internal
80  *
81  * The parser parses tokenized input into the document, building up the
82  * document tree. If the document is wellformed, parsing it is
83  * straightforward.
84  * Unfortunately, people can't write wellformed HTML documents, so the parser
85  * has to be tolerant about errors.
86  *
87  * We have to take care of the following error conditions:
88  * 1. The element being added is explicitly forbidden inside some outer tag.
89  *    In this case we should close all tags up to the one, which forbids
90  *    the element, and add it afterwards.
91  * 2. We are not allowed to add the element directly. It could be, that
92  *    the person writing the document forgot some tag inbetween (or that the
93  *    tag inbetween is optional...) This could be the case with the following
94  *    tags: HTML HEAD BODY TBODY TR TD LI (did I forget any?)
95  * 3. We wan't to add a block element inside to an inline element. Close all
96  *    inline elements up to the next higher block element.
97  * 4. If this doesn't help close elements, until we are allowed to add the
98  *    element or ignore the tag.
99  *
100  */
101 HTMLParser::HTMLParser(Document* doc) 
102     : document(doc)
103     , current(0)
104     , currentIsReferenced(false)
105     , blockStack(0)
106     , m_fragment(false)
107 {
108     reset();
109 }
110
111 HTMLParser::HTMLParser(DocumentFragment* frag)
112     : document(frag->document())
113     , current(0)
114     , currentIsReferenced(false)
115     , blockStack(0)
116     , m_fragment(true)
117 {
118     reset();
119     setCurrent(frag);
120     inBody = true;
121 }
122
123 HTMLParser::~HTMLParser()
124 {
125     freeBlock();
126
127     setCurrent(0);
128 }
129
130 void HTMLParser::reset()
131 {
132     setCurrent(doc());
133
134     freeBlock();
135
136     inBody = false;
137     haveFrameSet = false;
138     haveContent = false;
139     inSelect = false;
140     inStrayTableContent = 0;
141     
142     form = 0;
143     map = 0;
144     head = 0;
145     end = false;
146     isindex = 0;
147     
148     discard_until = nullAtom;
149 }
150
151 void HTMLParser::setCurrent(Node *newCurrent) 
152 {
153     bool newCurrentIsReferenced = newCurrent && newCurrent != doc();
154     if (newCurrentIsReferenced) 
155         newCurrent->ref(); 
156     if (currentIsReferenced) 
157         current->deref(); 
158     current = newCurrent;
159     currentIsReferenced = newCurrentIsReferenced;
160 }
161
162 PassRefPtr<Node> HTMLParser::parseToken(Token *t)
163 {
164     if (!discard_until.isNull()) {
165         if (t->tagName == discard_until && !t->beginTag)
166             discard_until = nullAtom;
167
168         // do not skip </iframe>
169         if (!discard_until.isNull() || (current->localName() != t->tagName))
170             return 0;
171     }
172
173     // Apparently some sites use </br> instead of <br>.  Be compatible with IE and Firefox and treat this like <br>.
174     if (t->isCloseTag(brTag) && doc()->inCompatMode())
175         t->beginTag = true;
176
177     if (!t->beginTag) {
178         processCloseTag(t);
179         return 0;
180     }
181
182     // ignore spaces, if we're not inside a paragraph or other inline code
183     if (t->tagName == textAtom && t->text) {
184         if (inBody && !skipMode() && current->localName() != styleTag && current->localName() != titleTag && 
185             current->localName() != scriptTag && !t->text->containsOnlyWhitespace()) 
186             haveContent = true;
187     }
188
189     RefPtr<Node> n = getNode(t);
190     // just to be sure, and to catch currently unimplemented stuff
191     if (!n)
192         return 0;
193
194     // set attributes
195     if (n->isHTMLElement()) {
196         HTMLElement* e = static_cast<HTMLElement*>(n.get());
197         e->setAttributeMap(t->attrs.get());
198
199         // take care of optional close tags
200         if (e->endTagRequirement() == TagStatusOptional)
201             popBlock(t->tagName);
202             
203         if (isHeaderTag(t->tagName))
204             // Do not allow two header tags to be nested if the intervening tags are inlines.
205             popNestedHeaderTag();
206     }
207
208     if (!insertNode(n.get(), t->flat)) {
209         // we couldn't insert the node
210
211         if (n->isElementNode()) {
212             Element* e = static_cast<Element*>(n.get());
213             e->setAttributeMap(0);
214         }
215
216         if (map == n)
217             map = 0;
218
219         if (form == n)
220             form = 0;
221
222         if (head == n)
223             head = 0;
224
225         return 0;
226     }
227     return n;
228 }
229
230 static bool isTableSection(Node* n)
231 {
232     return n->hasTagName(tbodyTag) || n->hasTagName(tfootTag) || n->hasTagName(theadTag);
233 }
234
235 static bool isTablePart(Node* n)
236 {
237     return n->hasTagName(trTag) || n->hasTagName(tdTag) || n->hasTagName(thTag) ||
238            isTableSection(n);
239 }
240
241 static bool isTableRelated(Node* n)
242 {
243     return n->hasTagName(tableTag) || isTablePart(n);
244 }
245
246 bool HTMLParser::insertNode(Node *n, bool flat)
247 {
248     RefPtr<Node> protectNode(n);
249
250     const AtomicString& localName = n->localName();
251     int tagPriority = n->isHTMLElement() ? static_cast<HTMLElement*>(n)->tagPriority() : 0;
252         
253     // let's be stupid and just try to insert it.
254     // this should work if the document is well-formed
255     Node *newNode = current->addChild(n);
256     if (newNode) {
257         // don't push elements without end tags (e.g., <img>) on the stack
258         bool parentAttached = current->attached();
259         if (tagPriority > 0 && !flat) {
260             pushBlock(localName, tagPriority);
261             if (newNode == current)
262                 popBlock(localName);
263             else
264                 setCurrent(newNode);
265             if (parentAttached && !n->attached() && !m_fragment)
266                 n->attach();
267         } else {
268             if (parentAttached && !n->attached() && !m_fragment)
269                 n->attach();
270             if (n->maintainsState()) {
271                 doc()->registerMaintainsState(n);
272                 DeprecatedStringList &states = doc()->restoreState();
273                 if (!states.isEmpty())
274                     n->restoreState(states);
275             }
276             n->closeRenderer();
277         }
278
279         return true;
280     } else
281         return handleError(n, flat, localName, tagPriority); // Try to handle the error.
282 }
283
284 bool HTMLParser::handleError(Node* n, bool flat, const AtomicString& localName, int tagPriority)
285 {
286     // Error handling code.  This is just ad hoc handling of specific parent/child combinations.
287     HTMLElement *e;
288     bool handled = false;
289
290     // 1. Check out the element's tag name to decide how to deal with errors.
291     if (n->isTextNode()) {
292         if (current->hasTagName(selectTag))
293             return false;
294     } else if (n->isHTMLElement()) {
295         HTMLElement* h = static_cast<HTMLElement*>(n);
296         if (h->hasLocalName(trTag) || h->hasLocalName(thTag) || h->hasLocalName(tdTag)) {
297             if (inStrayTableContent && !isTableRelated(current)) {
298                 // pop out to the nearest enclosing table-related tag.
299                 while (blockStack && !isTableRelated(current))
300                     popOneBlock();
301                 return insertNode(n);
302             }
303         } else if (h->hasLocalName(headTag)) {
304             if (!current->isDocumentNode() && !current->hasTagName(htmlTag))
305                 return false;
306         } else if (h->hasLocalName(metaTag) || h->hasLocalName(linkTag) || h->hasLocalName(baseTag)) {
307             if (!head)
308                 createHead();
309             if (head) {
310                 if (head->addChild(n)) {
311                     if (!n->attached() && !m_fragment)
312                         n->attach();
313                     return true;
314                 } else
315                     return false;
316             }
317         } else if (h->hasLocalName(htmlTag)) {
318             if (!current->isDocumentNode() ) {
319                 if (doc()->firstChild()->hasTagName(htmlTag)) {
320                     // we have another <HTML> element.... apply attributes to existing one
321                     // make sure we don't overwrite already existing attributes
322                     NamedAttrMap *map = static_cast<Element*>(n)->attributes(true);
323                     Element *existingHTML = static_cast<Element*>(doc()->firstChild());
324                     NamedAttrMap *bmap = existingHTML->attributes(false);
325                     for (unsigned l = 0; map && l < map->length(); ++l) {
326                         Attribute* it = map->attributeItem(l);
327                         if (!bmap->getAttributeItem(it->name()))
328                             existingHTML->setAttribute(it->name(), it->value());
329                     }
330                 }
331                 return false;
332             }
333         } else if (h->hasLocalName(titleTag) || h->hasLocalName(styleTag)) {
334             if (!head)
335                 createHead();
336             if (head) {
337                 Node *newNode = head->addChild(n);
338                 if (newNode) {
339                     pushBlock(localName, tagPriority);
340                     setCurrent(newNode);
341                     if (!n->attached() && !m_fragment)
342                         n->attach();
343                 } else {
344                     setSkipMode(styleTag);
345                     return false;
346                 }
347                 return true;
348             } else if(inBody) {
349                 setSkipMode(styleTag);
350                 return false;
351             }
352         } else if (h->hasLocalName(bodyTag)) {
353             if (inBody && doc()->body()) {
354                 // we have another <BODY> element.... apply attributes to existing one
355                 // make sure we don't overwrite already existing attributes
356                 // some sites use <body bgcolor=rightcolor>...<body bgcolor=wrongcolor>
357                 NamedAttrMap *map = static_cast<Element*>(n)->attributes(true);
358                 Element *existingBody = doc()->body();
359                 NamedAttrMap *bmap = existingBody->attributes(false);
360                 for (unsigned l = 0; map && l < map->length(); ++l) {
361                     Attribute* it = map->attributeItem(l);
362                     if (!bmap->getAttributeItem(it->name()))
363                         existingBody->setAttribute(it->name(), it->value());
364                 }
365                 return false;
366             }
367             else if (!current->isDocumentNode())
368                 return false;
369         } else if (h->hasLocalName(inputTag)) {
370             if (equalIgnoringCase(h->getAttribute(typeAttr), "hidden") && form) {
371                 form->addChild(n);
372                 if (!n->attached() && !m_fragment)
373                     n->attach();
374                 return true;
375             }
376         } else if (h->hasLocalName(ddTag) || h->hasLocalName(dtTag)) {
377             e = new HTMLDListElement(document);
378             if (insertNode(e)) {
379                 insertNode(n);
380                 return true;
381             }
382         } else if (h->hasLocalName(areaTag)) {
383             if (map) {
384                 map->addChild(n);
385                 if (!n->attached() && !m_fragment)
386                     n->attach();
387                 handled = true;
388                 return true;
389             }
390             return false;
391         } else if (h->hasLocalName(captionTag)) {
392             if (isTablePart(current)) {
393                 Node* tsection = current;
394                 if (current->hasTagName(trTag))
395                     tsection = current->parent();
396                 else if (current->hasTagName(tdTag) || current->hasTagName(thTag))
397                     tsection = current->parent()->parent();
398                 Node* table = tsection->parent();
399                 ExceptionCode ec = 0;
400                 table->insertBefore(n, tsection, ec);
401                 pushBlock(localName, tagPriority);
402                 setCurrent(n);
403                 inStrayTableContent++;
404                 blockStack->strayTableContent = true;
405                 return true;
406             }
407         } else if (h->hasLocalName(theadTag) || h->hasLocalName(tbodyTag) ||
408                    h->hasLocalName(tfootTag) || h->hasLocalName(colgroupTag)) {
409             if (isTableRelated(current)) {
410                 while (blockStack && isTablePart(current))
411                     popOneBlock();
412                 return insertNode(n);
413             }
414         }
415     }
416     
417     // 2. Next we examine our currently active element to do some further error handling.
418     if (current->isHTMLElement()) {
419         HTMLElement* h = static_cast<HTMLElement*>(current);
420         const AtomicString& currentTagName = current->localName();
421         if (h->hasLocalName(htmlTag)) {
422             HTMLElement* elt = n->isHTMLElement() ? static_cast<HTMLElement*>(n) : 0;
423             if (elt && (elt->hasLocalName(scriptTag) || elt->hasLocalName(styleTag) ||
424                 elt->hasLocalName(metaTag) || elt->hasLocalName(linkTag) ||
425                 elt->hasLocalName(objectTag) || elt->hasLocalName(embedTag) ||
426                 elt->hasLocalName(titleTag) || elt->hasLocalName(isindexTag) ||
427                 elt->hasLocalName(baseTag))) {
428                 if (!head) {
429                     head = new HTMLHeadElement(document);
430                     e = head;
431                     insertNode(e);
432                     handled = true;
433                 }
434             } else {
435                 if (n->isTextNode()) {
436                     Text *t = static_cast<Text *>(n);
437                     if (t->containsOnlyWhitespace())
438                         return false;
439                 }
440                 if (!haveFrameSet) {
441                     e = new HTMLBodyElement(document);
442                     startBody();
443                     insertNode(e);
444                     handled = true;
445                 }
446             }
447         } else if (h->hasLocalName(headTag)) {
448             if (n->hasTagName(htmlTag))
449                 return false;
450             else {
451                 // This means the body starts here...
452                 if (!haveFrameSet) {
453                     popBlock(currentTagName);
454                     e = new HTMLBodyElement(document);
455                     startBody();
456                     insertNode(e);
457                     handled = true;
458                 }
459             }
460         } else if (h->hasLocalName(addressTag) || h->hasLocalName(dlTag) || h->hasLocalName(dtTag)
461                    || h->hasLocalName(fontTag) || h->hasLocalName(styleTag) || h->hasLocalName(titleTag)) {
462             popBlock(currentTagName);
463             handled = true;
464         } else if (h->hasLocalName(captionTag)) {
465             // Illegal content in a caption. Close the caption and try again.
466             popBlock(currentTagName);
467             if (isTablePart(n))
468                 return insertNode(n, flat);
469         } else if (h->hasLocalName(tableTag) || h->hasLocalName(trTag) || isTableSection(h)) {
470             if (n->hasTagName(tableTag)) {
471                 popBlock(localName); // end the table
472                 handled = true;      // ...and start a new one
473             } else {
474                 bool possiblyMoveStrayContent = true;
475                 ExceptionCode ec = 0;
476                 if (n->isTextNode()) {
477                     Text *t = static_cast<Text *>(n);
478                     if (t->containsOnlyWhitespace())
479                         return false;
480                     StringImpl *i = t->string();
481                     unsigned int pos = 0;
482                     while (pos < i->length() && ((*i)[pos] == ' ' || (*i)[pos] == QChar(0xa0)))
483                         pos++;
484                     if (pos == i->length())
485                         possiblyMoveStrayContent = false;
486                 }
487                 if (possiblyMoveStrayContent) {
488                     Node *node = current;
489                     Node *parent = node->parentNode();
490                     Node *grandparent = parent->parentNode();
491
492                     if (n->isTextNode() ||
493                         (h->hasLocalName(trTag) &&
494                          isTableSection(parent) && grandparent->hasTagName(tableTag)) ||
495                          ((!n->hasTagName(tdTag) && !n->hasTagName(thTag) &&
496                            !n->hasTagName(formTag) && !n->hasTagName(scriptTag)) && isTableSection(node) &&
497                          parent->hasTagName(tableTag))) {
498                         node = (node->hasTagName(tableTag)) ? node :
499                                 ((node->hasTagName(trTag)) ? grandparent : parent);
500                         Node *parent = node->parentNode();
501                         parent->insertBefore(n, node, ec);
502                         if (!ec) {
503                             if (n->isHTMLElement() && tagPriority > 0 && 
504                                 !flat && static_cast<HTMLElement*>(n)->endTagRequirement() != TagStatusForbidden)
505                             {
506                                 pushBlock(localName, tagPriority);
507                                 setCurrent(n);
508                                 inStrayTableContent++;
509                                 blockStack->strayTableContent = true;
510                             }
511                             return true;
512                         }
513                     }
514
515                     if (!ec) {
516                         if (current->hasTagName(trTag))
517                             e = new HTMLTableCellElement(tdTag, document);
518                         else if (current->hasTagName(tableTag))
519                             e = new HTMLTableSectionElement(tbodyTag, document, true); // implicit 
520                         else
521                             e = new HTMLTableRowElement(document);
522                         
523                         insertNode(e);
524                         handled = true;
525                     }
526                 }
527             }
528         } else if (h->hasLocalName(objectTag)) {
529             setSkipMode(objectTag);
530             return false;
531         } else if (h->hasLocalName(ulTag) || h->hasLocalName(olTag) ||
532                  h->hasLocalName(dirTag) || h->hasLocalName(menuTag)) {
533             e = new HTMLDivElement(document);
534             insertNode(e);
535             handled = true;
536         } else if (h->hasLocalName(selectTag)) {
537             if (isInline(n))
538                 return false;
539         } else if (h->hasLocalName(pTag) || isHeaderTag(currentTagName)) {
540             if (!isInline(n)) {
541                 popBlock(currentTagName);
542                 handled = true;
543             }
544         } else if (h->hasLocalName(optionTag) || h->hasLocalName(optgroupTag)) {
545             if (localName == optgroupTag) {
546                 popBlock(currentTagName);
547                 handled = true;
548             } else if (localName == selectTag) {
549                 // IE treats a nested select as </select>. Let's do the same
550                 popBlock(localName);
551             }
552         } else if (h->hasLocalName(colgroupTag)) {
553             if (!n->isTextNode()) {
554                 popBlock(currentTagName);
555                 handled = true;
556             }
557         } else if (!h->hasLocalName(bodyTag)) {
558             if (isInline(current)) {
559                 popInlineBlocks();
560                 handled = true;
561             }
562         }
563     } else if (current->isDocumentNode()) {
564         if (current->firstChild() == 0) {
565             e = new HTMLHtmlElement(document);
566             insertNode(e);
567             handled = true;
568         }
569     }
570
571     // 3. If we couldn't handle the error, just return false and attempt to error-correct again.
572     if (!handled)
573         return false;
574     return insertNode(n);
575 }
576
577 typedef bool (HTMLParser::*CreateErrorCheckFunc)(Token* t, RefPtr<Node>&);
578 typedef HashMap<AtomicStringImpl*, CreateErrorCheckFunc> FunctionMap;
579
580 bool HTMLParser::textCreateErrorCheck(Token* t, RefPtr<Node>& result)
581 {
582     result = new Text(document, t->text.get());
583     return false;
584 }
585
586 bool HTMLParser::commentCreateErrorCheck(Token* t, RefPtr<Node>& result)
587 {
588     result = new Comment(document, t->text.get());
589     return false;
590 }
591
592 bool HTMLParser::headCreateErrorCheck(Token* t, RefPtr<Node>& result)
593 {
594     if (!head || current->localName() == htmlTag) {
595         head = new HTMLHeadElement(document);
596         result = head;
597     }
598     return false;
599 }
600
601 bool HTMLParser::bodyCreateErrorCheck(Token* t, RefPtr<Node>& result)
602 {
603     // body no longer allowed if we have a frameset
604     if (haveFrameSet)
605         return false;
606     popBlock(headTag);
607     startBody();
608     return true;
609 }
610
611 bool HTMLParser::framesetCreateErrorCheck(Token* t, RefPtr<Node>& result)
612 {
613     popBlock(headTag);
614     if (inBody && !haveFrameSet && !haveContent) {
615         popBlock(bodyTag);
616         // ### actually for IE document.body returns the now hidden "body" element
617         // we can't implement that behaviour now because it could cause too many
618         // regressions and the headaches are not worth the work as long as there is
619         // no site actually relying on that detail (Dirk)
620         if (doc()->body())
621             doc()->body()->setAttribute(styleAttr, "display:none");
622         inBody = false;
623     }
624     if ((haveContent || haveFrameSet) && current->localName() == htmlTag)
625         return false;
626     haveFrameSet = true;
627     startBody();
628     return true;
629 }
630
631 bool HTMLParser::iframeCreateErrorCheck(Token* t, RefPtr<Node>& result)
632 {
633     // a bit of a special case, since the frame is inlined
634     setSkipMode(iframeTag);
635     return true;
636 }
637
638 bool HTMLParser::formCreateErrorCheck(Token* t, RefPtr<Node>& result)
639 {
640     // Only create a new form if we're not already inside one.
641     // This is consistent with other browsers' behavior.
642     if (!form) {
643         form = new HTMLFormElement(document);
644         result = form;
645     }
646     return false;
647 }
648
649 bool HTMLParser::isindexCreateErrorCheck(Token* t, RefPtr<Node>& result)
650 {
651     Node *n = handleIsindex(t);
652     if (!inBody) {
653         isindex = n;
654     } else {
655         t->flat = true;
656         result = n;
657     }
658     return false;
659 }
660
661 bool HTMLParser::selectCreateErrorCheck(Token* t, RefPtr<Node>& result)
662 {
663     inSelect = true;
664     return true;
665 }
666
667 bool HTMLParser::ddCreateErrorCheck(Token* t, RefPtr<Node>& result)
668 {
669     popBlock(dtTag);
670     popBlock(ddTag);
671     return true;
672 }
673
674 bool HTMLParser::dtCreateErrorCheck(Token* t, RefPtr<Node>& result)
675 {
676     popBlock(ddTag);
677     popBlock(dtTag);
678     return true;
679 }
680
681 bool HTMLParser::nestedCreateErrorCheck(Token* t, RefPtr<Node>& result)
682 {
683     popBlock(t->tagName);
684     return true;
685 }
686
687 bool HTMLParser::nestedStyleCreateErrorCheck(Token* t, RefPtr<Node>& result)
688 {
689     return allowNestedRedundantTag(t->tagName);
690 }
691
692 bool HTMLParser::tableCellCreateErrorCheck(Token* t, RefPtr<Node>& result)
693 {
694     popBlock(tdTag);
695     popBlock(thTag);
696     return true;
697 }
698
699 bool HTMLParser::tableSectionCreateErrorCheck(Token* t, RefPtr<Node>& result)
700 {
701     popBlock(theadTag);
702     popBlock(tbodyTag);
703     popBlock(tfootTag);
704     return true;
705 }
706
707 bool HTMLParser::noembedCreateErrorCheck(Token* t, RefPtr<Node>& result)
708 {
709     setSkipMode(noembedTag);
710     return true;
711 }
712
713 bool HTMLParser::noframesCreateErrorCheck(Token* t, RefPtr<Node>& result)
714 {
715     setSkipMode(noframesTag);
716     return true;
717 }
718
719 bool HTMLParser::noscriptCreateErrorCheck(Token* t, RefPtr<Node>& result)
720 {
721     if (!m_fragment && document->frame()->jScriptEnabled())
722         setSkipMode(noscriptTag);
723     return true;
724 }
725
726 bool HTMLParser::mapCreateErrorCheck(Token* t, RefPtr<Node>& result)
727 {
728     map = new HTMLMapElement(document);
729     result = map;
730     return false;
731 }
732
733 PassRefPtr<Node> HTMLParser::getNode(Token* t)
734 {
735     // Init our error handling table.
736     static FunctionMap gFunctionMap;
737     if (gFunctionMap.isEmpty()) {
738         gFunctionMap.set(textAtom.impl(), &HTMLParser::textCreateErrorCheck);
739         gFunctionMap.set(commentAtom.impl(), &HTMLParser::commentCreateErrorCheck);
740         gFunctionMap.set(headTag.localName().impl(), &HTMLParser::headCreateErrorCheck);
741         gFunctionMap.set(bodyTag.localName().impl(), &HTMLParser::bodyCreateErrorCheck);
742         gFunctionMap.set(framesetTag.localName().impl(), &HTMLParser::framesetCreateErrorCheck);
743         gFunctionMap.set(iframeTag.localName().impl(), &HTMLParser::iframeCreateErrorCheck);
744         gFunctionMap.set(formTag.localName().impl(), &HTMLParser::formCreateErrorCheck);
745         gFunctionMap.set(isindexTag.localName().impl(), &HTMLParser::isindexCreateErrorCheck);
746         gFunctionMap.set(selectTag.localName().impl(), &HTMLParser::selectCreateErrorCheck);
747         gFunctionMap.set(ddTag.localName().impl(), &HTMLParser::ddCreateErrorCheck);
748         gFunctionMap.set(dtTag.localName().impl(), &HTMLParser::dtCreateErrorCheck);
749         gFunctionMap.set(liTag.localName().impl(), &HTMLParser::nestedCreateErrorCheck);
750         gFunctionMap.set(aTag.localName().impl(), &HTMLParser::nestedCreateErrorCheck);
751         gFunctionMap.set(buttonTag.localName().impl(), &HTMLParser::nestedCreateErrorCheck);
752         gFunctionMap.set(nobrTag.localName().impl(), &HTMLParser::nestedCreateErrorCheck);
753         gFunctionMap.set(wbrTag.localName().impl(), &HTMLParser::nestedCreateErrorCheck);
754         gFunctionMap.set(trTag.localName().impl(), &HTMLParser::nestedCreateErrorCheck);
755         gFunctionMap.set(tdTag.localName().impl(), &HTMLParser::tableCellCreateErrorCheck);
756         gFunctionMap.set(thTag.localName().impl(), &HTMLParser::tableCellCreateErrorCheck);
757         gFunctionMap.set(tbodyTag.localName().impl(), &HTMLParser::tableSectionCreateErrorCheck);
758         gFunctionMap.set(theadTag.localName().impl(), &HTMLParser::tableSectionCreateErrorCheck);
759         gFunctionMap.set(tfootTag.localName().impl(), &HTMLParser::tableSectionCreateErrorCheck);
760         gFunctionMap.set(ttTag.localName().impl(), &HTMLParser::nestedStyleCreateErrorCheck);
761         gFunctionMap.set(uTag.localName().impl(), &HTMLParser::nestedStyleCreateErrorCheck);
762         gFunctionMap.set(bTag.localName().impl(), &HTMLParser::nestedStyleCreateErrorCheck);
763         gFunctionMap.set(iTag.localName().impl(), &HTMLParser::nestedStyleCreateErrorCheck);
764         gFunctionMap.set(sTag.localName().impl(), &HTMLParser::nestedStyleCreateErrorCheck);
765         gFunctionMap.set(strikeTag.localName().impl(), &HTMLParser::nestedStyleCreateErrorCheck);
766         gFunctionMap.set(bigTag.localName().impl(), &HTMLParser::nestedStyleCreateErrorCheck);
767         gFunctionMap.set(smallTag.localName().impl(), &HTMLParser::nestedStyleCreateErrorCheck);
768         gFunctionMap.set(noembedTag.localName().impl(), &HTMLParser::noembedCreateErrorCheck);
769         gFunctionMap.set(noframesTag.localName().impl(), &HTMLParser::noframesCreateErrorCheck);
770         gFunctionMap.set(noscriptTag.localName().impl(), &HTMLParser::noscriptCreateErrorCheck);
771         gFunctionMap.set(mapTag.localName().impl(), &HTMLParser::mapCreateErrorCheck);
772     }
773
774     bool proceed = true;
775     RefPtr<Node> result;
776     if (CreateErrorCheckFunc errorCheckFunc = gFunctionMap.get(t->tagName.impl()))
777         proceed = (this->*errorCheckFunc)(t, result);
778     if (proceed)
779         result = HTMLElementFactory::createHTMLElement(t->tagName, doc(), form);
780     return result.release();
781 }
782
783 #define MAX_REDUNDANT 20
784
785 bool HTMLParser::allowNestedRedundantTag(const AtomicString& _tagName)
786 {
787     // www.liceo.edu.mx is an example of a site that achieves a level of nesting of
788     // about 1500 tags, all from a bunch of <b>s.  We will only allow at most 20
789     // nested tags of the same type before just ignoring them all together.
790     int i = 0;
791     for (HTMLStackElem* curr = blockStack;
792          i < MAX_REDUNDANT && curr && curr->tagName == _tagName;
793          curr = curr->next, i++);
794     return i != MAX_REDUNDANT;
795 }
796
797 void HTMLParser::processCloseTag(Token *t)
798 {
799     // Support for really broken html.
800     // we never close the body tag, since some stupid web pages close it before the actual end of the doc.
801     // let's rely on the end() call to close things.
802     if (t->tagName == htmlTag || t->tagName == bodyTag)
803         return;
804     
805     if (t->tagName == formTag)
806         form = 0;
807     else if (t->tagName == mapTag)
808         map = 0;
809     else if (t->tagName == selectTag)
810         inSelect = false;
811         
812     HTMLStackElem* oldElem = blockStack;
813     popBlock(t->tagName);
814     if (oldElem == blockStack && t->tagName == pTag) {
815         // We encountered a stray </p>.  Amazingly Gecko, WinIE, and MacIE all treat
816         // this as a valid break, i.e., <p></p>.  So go ahead and make the empty
817         // paragraph.
818         t->beginTag = true;
819         parseToken(t);
820         popBlock(t->tagName);
821     }
822 }
823
824 bool HTMLParser::isHeaderTag(const AtomicString& tagName)
825 {
826     static HashSet<AtomicStringImpl*> headerTags;
827     if (headerTags.isEmpty()) {
828         headerTags.add(h1Tag.localName().impl());
829         headerTags.add(h2Tag.localName().impl());
830         headerTags.add(h3Tag.localName().impl());
831         headerTags.add(h4Tag.localName().impl());
832         headerTags.add(h5Tag.localName().impl());
833         headerTags.add(h6Tag.localName().impl());
834     }
835     
836     return headerTags.contains(tagName.impl());
837 }
838
839 void HTMLParser::popNestedHeaderTag()
840 {
841     // This function only cares about checking for nested headers that have only inlines in between them.
842     Node* currNode = current;
843     for (HTMLStackElem* curr = blockStack; curr; curr = curr->next) {
844         if (isHeaderTag(curr->tagName)) {
845             popBlock(curr->tagName);
846             return;
847         }
848         if (currNode && !isInline(currNode))
849             return;
850         currNode = curr->node.get();
851     }
852 }
853
854 bool HTMLParser::isInline(Node* node) const
855 {
856     if (node->isTextNode())
857         return true;
858
859     if (node->isHTMLElement()) {
860         HTMLElement* e = static_cast<HTMLElement*>(node);
861         if (e->hasLocalName(aTag) || e->hasLocalName(fontTag) || e->hasLocalName(ttTag) ||
862             e->hasLocalName(uTag) || e->hasLocalName(bTag) || e->hasLocalName(iTag) ||
863             e->hasLocalName(sTag) || e->hasLocalName(strikeTag) || e->hasLocalName(bigTag) ||
864             e->hasLocalName(smallTag) || e->hasLocalName(emTag) || e->hasLocalName(strongTag) ||
865             e->hasLocalName(dfnTag) || e->hasLocalName(codeTag) || e->hasLocalName(sampTag) ||
866             e->hasLocalName(kbdTag) || e->hasLocalName(varTag) || e->hasLocalName(citeTag) ||
867             e->hasLocalName(abbrTag) || e->hasLocalName(acronymTag) || e->hasLocalName(subTag) ||
868             e->hasLocalName(supTag) || e->hasLocalName(spanTag) || e->hasLocalName(nobrTag) ||
869             e->hasLocalName(wbrTag) || e->hasLocalName(noframesTag) || e->hasLocalName(nolayerTag) ||
870             e->hasLocalName(noembedTag) || (e->hasLocalName(noscriptTag) && !m_fragment && document->frame()->jScriptEnabled()))
871             return true;
872     }
873     
874     return false;
875 }
876
877 bool HTMLParser::isResidualStyleTag(const AtomicString& tagName)
878 {
879     static HashSet<AtomicStringImpl*> residualStyleTags;
880     if (residualStyleTags.isEmpty()) {
881         residualStyleTags.add(aTag.localName().impl());
882         residualStyleTags.add(fontTag.localName().impl());
883         residualStyleTags.add(ttTag.localName().impl());
884         residualStyleTags.add(uTag.localName().impl());
885         residualStyleTags.add(bTag.localName().impl());
886         residualStyleTags.add(iTag.localName().impl());
887         residualStyleTags.add(sTag.localName().impl());
888         residualStyleTags.add(strikeTag.localName().impl());
889         residualStyleTags.add(bigTag.localName().impl());
890         residualStyleTags.add(smallTag.localName().impl());
891         residualStyleTags.add(emTag.localName().impl());
892         residualStyleTags.add(strongTag.localName().impl());
893         residualStyleTags.add(dfnTag.localName().impl());
894         residualStyleTags.add(codeTag.localName().impl());
895         residualStyleTags.add(sampTag.localName().impl());
896         residualStyleTags.add(kbdTag.localName().impl());
897         residualStyleTags.add(varTag.localName().impl());
898         residualStyleTags.add(nobrTag.localName().impl());
899         residualStyleTags.add(wbrTag.localName().impl());
900     }
901     
902     return residualStyleTags.contains(tagName.impl());
903 }
904
905 bool HTMLParser::isAffectedByResidualStyle(const AtomicString& tagName)
906 {
907     if (isResidualStyleTag(tagName))
908         return true;
909
910     static HashSet<AtomicStringImpl*> affectedBlockTags;
911     if (affectedBlockTags.isEmpty()) {
912         affectedBlockTags.add(addressTag.localName().impl());
913         affectedBlockTags.add(blockquoteTag.localName().impl());
914         affectedBlockTags.add(centerTag.localName().impl());
915         affectedBlockTags.add(ddTag.localName().impl());
916         affectedBlockTags.add(divTag.localName().impl());
917         affectedBlockTags.add(dlTag.localName().impl());
918         affectedBlockTags.add(dtTag.localName().impl());
919         affectedBlockTags.add(formTag.localName().impl());
920         affectedBlockTags.add(h1Tag.localName().impl());
921         affectedBlockTags.add(h2Tag.localName().impl());
922         affectedBlockTags.add(h3Tag.localName().impl());
923         affectedBlockTags.add(h4Tag.localName().impl());
924         affectedBlockTags.add(h5Tag.localName().impl());
925         affectedBlockTags.add(h6Tag.localName().impl());
926         affectedBlockTags.add(liTag.localName().impl());
927         affectedBlockTags.add(listingTag.localName().impl());
928         affectedBlockTags.add(olTag.localName().impl());
929         affectedBlockTags.add(pTag.localName().impl());
930         affectedBlockTags.add(preTag.localName().impl());
931         affectedBlockTags.add(ulTag.localName().impl());
932     }
933     
934     return affectedBlockTags.contains(tagName.impl());
935 }
936
937 void HTMLParser::handleResidualStyleCloseTagAcrossBlocks(HTMLStackElem* elem)
938 {
939     // Find the element that crosses over to a higher level.   For now, if there is more than
940     // one, we will just give up and not attempt any sort of correction.  It's highly unlikely that
941     // there will be more than one, since <p> tags aren't allowed to be nested.
942     ExceptionCode ec = 0;
943     HTMLStackElem* curr = blockStack;
944     HTMLStackElem* maxElem = 0;
945     HTMLStackElem* prev = 0;
946     HTMLStackElem* prevMaxElem = 0;
947     while (curr && curr != elem) {
948         if (curr->level > elem->level) {
949             if (maxElem)
950                 return;
951             maxElem = curr;
952             prevMaxElem = prev;
953         }
954
955         prev = curr;
956         curr = curr->next;
957     }
958
959     if (!curr || !maxElem || !isAffectedByResidualStyle(maxElem->tagName)) return;
960
961     Node* residualElem = prev->node.get();
962     Node* blockElem = prevMaxElem ? prevMaxElem->node.get() : current;
963     Node* parentElem = elem->node.get();
964
965     // Check to see if the reparenting that is going to occur is allowed according to the DOM.
966     // FIXME: We should either always allow it or perform an additional fixup instead of
967     // just bailing here.
968     // Example: <p><font><center>blah</font></center></p> isn't doing a fixup right now.
969     if (!parentElem->childAllowed(blockElem))
970         return;
971     
972     if (maxElem->node->parentNode() != elem->node) {
973         // Walk the stack and remove any elements that aren't residual style tags.  These
974         // are basically just being closed up.  Example:
975         // <font><span>Moo<p>Goo</font></p>.
976         // In the above example, the <span> doesn't need to be reopened.  It can just close.
977         HTMLStackElem* currElem = maxElem->next;
978         HTMLStackElem* prevElem = maxElem;
979         while (currElem != elem) {
980             HTMLStackElem* nextElem = currElem->next;
981             if (!isResidualStyleTag(currElem->tagName)) {
982                 prevElem->next = nextElem;
983                 prevElem->node = currElem->node;
984                 delete currElem;
985             }
986             else
987                 prevElem = currElem;
988             currElem = nextElem;
989         }
990         
991         // We have to reopen residual tags in between maxElem and elem.  An example of this case is:
992         // <font><i>Moo<p>Foo</font>.
993         // In this case, we need to transform the part before the <p> into:
994         // <font><i>Moo</i></font><i>
995         // so that the <i> will remain open.  This involves the modification of elements
996         // in the block stack.
997         // This will also affect how we ultimately reparent the block, since we want it to end up
998         // under the reopened residual tags (e.g., the <i> in the above example.)
999         Node* prevNode = 0;
1000         currElem = maxElem;
1001         while (currElem->node != residualElem) {
1002             if (isResidualStyleTag(currElem->node->localName())) {
1003                 // Create a clone of this element.
1004                 RefPtr<Node> currNode = currElem->node->cloneNode(false);
1005
1006                 // Change the stack element's node to point to the clone.
1007                 currElem->node = currNode;
1008                 
1009                 // Attach the previous node as a child of this new node.
1010                 if (prevNode)
1011                     currNode->appendChild(prevNode, ec);
1012                 else // The new parent for the block element is going to be the innermost clone.
1013                     parentElem = currNode.get();
1014                                 
1015                 prevNode = currNode.get();
1016             }
1017             
1018             currElem = currElem->next;
1019         }
1020
1021         // Now append the chain of new residual style elements if one exists.
1022         if (prevNode)
1023             elem->node->appendChild(prevNode, ec);
1024     }
1025          
1026     // Check if the block is still in the tree. If it isn't, then we don't
1027     // want to remove it from its parent (that would crash) or insert it into
1028     // a new parent later. See http://bugzilla.opendarwin.org/show_bug.cgi?id=6778
1029     bool isBlockStillInTree = blockElem->parentNode();
1030
1031     // We need to make a clone of |residualElem| and place it just inside |blockElem|.
1032     // All content of |blockElem| is reparented to be under this clone.  We then
1033     // reparent |blockElem| using real DOM calls so that attachment/detachment will
1034     // be performed to fix up the rendering tree.
1035     // So for this example: <b>...<p>Foo</b>Goo</p>
1036     // The end result will be: <b>...</b><p><b>Foo</b>Goo</p>
1037     //
1038     // Step 1: Remove |blockElem| from its parent, doing a batch detach of all the kids.
1039     if (form)
1040         form->setPreserveAcrossRemove(true);
1041     if (isBlockStillInTree)
1042         blockElem->parentNode()->removeChild(blockElem, ec);
1043
1044     // Step 2: Clone |residualElem|.
1045     RefPtr<Node> newNode = residualElem->cloneNode(false); // Shallow clone. We don't pick up the same kids.
1046
1047     // Step 3: Place |blockElem|'s children under |newNode|.  Remove all of the children of |blockElem|
1048     // before we've put |newElem| into the document.  That way we'll only do one attachment of all
1049     // the new content (instead of a bunch of individual attachments).
1050     Node* currNode = blockElem->firstChild();
1051     while (currNode) {
1052         Node* nextNode = currNode->nextSibling();
1053         newNode->appendChild(currNode, ec);
1054         currNode = nextNode;
1055     }
1056
1057     // Step 4: Place |newNode| under |blockElem|.  |blockElem| is still out of the document, so no
1058     // attachment can occur yet.
1059     blockElem->appendChild(newNode.release(), ec);
1060     
1061     // Step 5: Reparent |blockElem|.  Now the full attachment of the fixed up tree takes place.
1062     if (isBlockStillInTree)
1063         parentElem->appendChild(blockElem, ec);
1064         
1065     // Step 6: Elide |elem|, since it is effectively no longer open.  Also update
1066     // the node associated with the previous stack element so that when it gets popped,
1067     // it doesn't make the residual element the next current node.
1068     HTMLStackElem* currElem = maxElem;
1069     HTMLStackElem* prevElem = 0;
1070     while (currElem != elem) {
1071         prevElem = currElem;
1072         currElem = currElem->next;
1073     }
1074     prevElem->next = elem->next;
1075     prevElem->node = elem->node;
1076     delete elem;
1077     
1078     // Step 7: Reopen intermediate inlines, e.g., <b><p><i>Foo</b>Goo</p>.
1079     // In the above example, Goo should stay italic.
1080     curr = blockStack;
1081     HTMLStackElem* residualStyleStack = 0;
1082     while (curr && curr != maxElem) {
1083         // We will actually schedule this tag for reopening
1084         // after we complete the close of this entire block.
1085         Node* currNode = current;
1086         if (isResidualStyleTag(curr->tagName)) {
1087             // We've overloaded the use of stack elements and are just reusing the
1088             // struct with a slightly different meaning to the variables.  Instead of chaining
1089             // from innermost to outermost, we build up a list of all the tags we need to reopen
1090             // from the outermost to the innermost, i.e., residualStyleStack will end up pointing
1091             // to the outermost tag we need to reopen.
1092             // We also set curr->node to be the actual element that corresponds to the ID stored in
1093             // curr->id rather than the node that you should pop to when the element gets pulled off
1094             // the stack.
1095             popOneBlock(false);
1096             curr->node = currNode;
1097             curr->next = residualStyleStack;
1098             residualStyleStack = curr;
1099         }
1100         else
1101             popOneBlock();
1102
1103         curr = blockStack;
1104     }
1105
1106     reopenResidualStyleTags(residualStyleStack, 0); // FIXME: Deal with stray table content some day
1107                                                     // if it becomes necessary to do so.
1108                                                     
1109     if (form)
1110         form->setPreserveAcrossRemove(false);
1111 }
1112
1113 void HTMLParser::reopenResidualStyleTags(HTMLStackElem* elem, Node* malformedTableParent)
1114 {
1115     // Loop for each tag that needs to be reopened.
1116     while (elem) {
1117         // Create a shallow clone of the DOM node for this element.
1118         RefPtr<Node> newNode = elem->node->cloneNode(false); 
1119
1120         // Append the new node. In the malformed table case, we need to insert before the table,
1121         // which will be the last child.
1122         ExceptionCode ec = 0;
1123         if (malformedTableParent)
1124             malformedTableParent->insertBefore(newNode, malformedTableParent->lastChild(), ec);
1125         else
1126             current->appendChild(newNode, ec);
1127         // FIXME: Is it really OK to ignore the exceptions here?
1128
1129         // Now push a new stack element for this node we just created.
1130         pushBlock(elem->tagName, elem->level);
1131
1132         // Set our strayTableContent boolean if needed, so that the reopened tag also knows
1133         // that it is inside a malformed table.
1134         blockStack->strayTableContent = malformedTableParent != 0;
1135         if (blockStack->strayTableContent)
1136             inStrayTableContent++;
1137
1138         // Clear our malformed table parent variable.
1139         malformedTableParent = 0;
1140
1141         // Update |current| manually to point to the new node.
1142         setCurrent(newNode.get());
1143         
1144         // Advance to the next tag that needs to be reopened.
1145         HTMLStackElem* next = elem->next;
1146         delete elem;
1147         elem = next;
1148     }
1149 }
1150
1151 void HTMLParser::pushBlock(const AtomicString& tagName, int _level)
1152 {
1153     HTMLStackElem *Elem = new HTMLStackElem(tagName, _level, current, blockStack);
1154     blockStack = Elem;
1155 }
1156
1157 void HTMLParser::popBlock(const AtomicString& _tagName)
1158 {
1159     HTMLStackElem *Elem = blockStack;
1160     
1161     int maxLevel = 0;
1162
1163     while (Elem && (Elem->tagName != _tagName)) {
1164         if (maxLevel < Elem->level)
1165             maxLevel = Elem->level;
1166         Elem = Elem->next;
1167     }
1168
1169     if (!Elem)
1170         return;
1171
1172     if (maxLevel > Elem->level) {
1173         // We didn't match because the tag is in a different scope, e.g.,
1174         // <b><p>Foo</b>.  Try to correct the problem.
1175         if (!isResidualStyleTag(_tagName))
1176             return;
1177         return handleResidualStyleCloseTagAcrossBlocks(Elem);
1178     }
1179
1180     bool isAffectedByStyle = isAffectedByResidualStyle(Elem->tagName);
1181     HTMLStackElem* residualStyleStack = 0;
1182     Node* malformedTableParent = 0;
1183     
1184     Elem = blockStack;
1185     while (Elem) {
1186         if (Elem->tagName == _tagName) {
1187             int strayTable = inStrayTableContent;
1188             popOneBlock();
1189             Elem = 0;
1190
1191             // This element was the root of some malformed content just inside an implicit or
1192             // explicit <tbody> or <tr>.
1193             // If we end up needing to reopen residual style tags, the root of the reopened chain
1194             // must also know that it is the root of malformed content inside a <tbody>/<tr>.
1195             if (strayTable && (inStrayTableContent < strayTable) && residualStyleStack) {
1196                 Node* curr = current;
1197                 while (curr && !curr->hasTagName(tableTag))
1198                     curr = curr->parentNode();
1199                 malformedTableParent = curr ? curr->parentNode() : 0;
1200             }
1201         }
1202         else {
1203             if (form && Elem->tagName == formTag)
1204                 // A <form> is being closed prematurely (and this is
1205                 // malformed HTML).  Set an attribute on the form to clear out its
1206                 // bottom margin.
1207                 form->setMalformed(true);
1208
1209             // Schedule this tag for reopening
1210             // after we complete the close of this entire block.
1211             Node* currNode = current;
1212             if (isAffectedByStyle && isResidualStyleTag(Elem->tagName)) {
1213                 // We've overloaded the use of stack elements and are just reusing the
1214                 // struct with a slightly different meaning to the variables.  Instead of chaining
1215                 // from innermost to outermost, we build up a list of all the tags we need to reopen
1216                 // from the outermost to the innermost, i.e., residualStyleStack will end up pointing
1217                 // to the outermost tag we need to reopen.
1218                 // We also set Elem->node to be the actual element that corresponds to the ID stored in
1219                 // Elem->id rather than the node that you should pop to when the element gets pulled off
1220                 // the stack.
1221                 popOneBlock(false);
1222                 Elem->next = residualStyleStack;
1223                 Elem->node = currNode;
1224                 residualStyleStack = Elem;
1225             }
1226             else
1227                 popOneBlock();
1228             Elem = blockStack;
1229         }
1230     }
1231
1232     reopenResidualStyleTags(residualStyleStack, malformedTableParent);
1233 }
1234
1235 void HTMLParser::popOneBlock(bool delBlock)
1236 {
1237     HTMLStackElem *Elem = blockStack;
1238
1239     // we should never get here, but some bad html might cause it.
1240     if (!Elem) return;
1241     
1242     if (current && Elem->node != current) {
1243         if (current->maintainsState() && doc()) {
1244             doc()->registerMaintainsState(current);
1245             DeprecatedStringList &states = doc()->restoreState();
1246             if (!states.isEmpty())
1247                 current->restoreState(states);
1248         }
1249         
1250         // A few elements (<applet>, <object>) need to know when all child elements (<param>s) are available:
1251         current->closeRenderer();
1252     }
1253
1254     blockStack = Elem->next;
1255     setCurrent(Elem->node.get());
1256
1257     if (Elem->strayTableContent)
1258         inStrayTableContent--;
1259     
1260     if (delBlock)
1261         delete Elem;
1262 }
1263
1264 void HTMLParser::popInlineBlocks()
1265 {
1266     while (blockStack && isInline(current))
1267         popOneBlock();
1268 }
1269
1270 void HTMLParser::freeBlock()
1271 {
1272     while (blockStack)
1273         popOneBlock();
1274 }
1275
1276 void HTMLParser::createHead()
1277 {
1278     if (head || !doc()->firstChild())
1279         return;
1280
1281     head = new HTMLHeadElement(document);
1282     HTMLElement* body = doc()->body();
1283     ExceptionCode ec = 0;
1284     doc()->firstChild()->insertBefore(head, body, ec);
1285     if (ec)
1286         head = 0;
1287 }
1288
1289 Node* HTMLParser::handleIsindex(Token* t)
1290 {
1291     Node* n = new HTMLDivElement(document);
1292
1293     NamedMappedAttrMap* attrs = t->attrs.get();
1294
1295     RefPtr<HTMLIsIndexElement> isIndex = new HTMLIsIndexElement(document, form);
1296     isIndex->setAttributeMap(attrs);
1297     isIndex->setAttribute(typeAttr, "khtml_isindex");
1298
1299     String text = searchableIndexIntroduction();
1300     if (attrs) {
1301         if (Attribute *a = attrs->getAttributeItem(promptAttr))
1302             text = a->value().domString() + " ";
1303         t->attrs = 0;
1304     }
1305
1306     n->addChild(new HTMLHRElement(document));
1307     n->addChild(new Text(document, text));
1308     n->addChild(isIndex.get());
1309     n->addChild(new HTMLHRElement(document));
1310
1311     return n;
1312 }
1313
1314 void HTMLParser::startBody()
1315 {
1316     if(inBody) return;
1317
1318     inBody = true;
1319
1320     if (isindex) {
1321         insertNode(isindex.get(), true /* don't decend into this node */);
1322         isindex = 0;
1323     }
1324 }
1325
1326 void HTMLParser::finished()
1327 {
1328     // In the case of a completely empty document, here's the place to create the HTML element.
1329     if (current && current->isDocumentNode() && !current->firstChild())
1330         insertNode(new HTMLHtmlElement(document));
1331
1332     // This ensures that "current" is not left pointing to a node when the document is destroyed.
1333     freeBlock();
1334     setCurrent(0);
1335
1336     // Warning, this may delete the tokenizer and parser, so don't try to do anything else after this.
1337     if (!m_fragment)
1338         document->finishedParsing();
1339 }
1340
1341 }