Suggested by Darin.
[WebKit-https.git] / WebCore / khtml / html / HTMLElementImpl.cpp
1 /**
2  * This file is part of the DOM implementation for KDE.
3  *
4  * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
5  *           (C) 1999 Antti Koivisto (koivisto@kde.org)
6  * Copyright (C) 2004, 2005, 2006 Apple Computer, Inc.
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Library General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Library General Public License for more details.
17  *
18  * You should have received a copy of the GNU Library General Public License
19  * along with this library; see the file COPYING.LIB.  If not, write to
20  * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21  * Boston, MA 02111-1307, USA.
22  *
23  */
24
25 #include "config.h"
26 #include "HTMLElementImpl.h"
27
28 #include "EventNames.h"
29 #include "Frame.h"
30 #include "css_ruleimpl.h"
31 #include "css_stylesheetimpl.h"
32 #include "css_valueimpl.h"
33 #include "cssproperties.h"
34 #include "cssvalues.h"
35 #include "dom2_events.h"
36 #include "dom2_eventsimpl.h"
37 #include "dom_exception.h"
38 #include "dom_textimpl.h"
39 #include "html_documentimpl.h"
40 #include "htmlfactory.h"
41 #include "htmlnames.h"
42 #include "htmltokenizer.h"
43 #include "markup.h"
44 #include "render_replaced.h"
45 #include "visible_text.h"
46 #include <kxmlcore/HashSet.h>
47
48 namespace WebCore {
49
50 using namespace EventNames;
51 using namespace HTMLNames;
52
53 HTMLElementImpl::HTMLElementImpl(const QualifiedName& tagName, DocumentImpl *doc)
54     : StyledElementImpl(tagName, doc)
55 {
56 }
57
58 HTMLElementImpl::~HTMLElementImpl()
59 {
60 }
61
62 DOMString HTMLElementImpl::nodeName() const
63 {
64     // FIXME: Would be nice to have an atomicstring lookup based off uppercase chars that does not have to copy
65     // the string on a hit in the hash.
66     if (getDocument()->isHTMLDocument())
67         return m_tagName.localName().impl()->upper();
68     return ElementImpl::nodeName();
69 }
70     
71 HTMLTagStatus HTMLElementImpl::endTagRequirement() const
72 {
73     if (hasLocalName(dtTag) || hasLocalName(ddTag))
74         return TagStatusOptional;
75
76     // Same values as <span>.  This way custom tag name elements will behave like inline spans.
77     return TagStatusRequired;
78 }
79
80 int HTMLElementImpl::tagPriority() const
81 {
82     if (hasLocalName(addressTag) || hasLocalName(ddTag) || hasLocalName(dtTag) || hasLocalName(noscriptTag))
83         return 3;
84     if (hasLocalName(centerTag) || hasLocalName(nobrTag))
85         return 5;
86     if (hasLocalName(noembedTag) || hasLocalName(noframesTag))
87         return 10;
88
89     // Same values as <span>.  This way custom tag name elements will behave like inline spans.
90     return 1;
91 }
92
93 PassRefPtr<NodeImpl> HTMLElementImpl::cloneNode(bool deep)
94 {
95     PassRefPtr<HTMLElementImpl> clone = HTMLElementFactory::createHTMLElement(m_tagName.localName(), getDocument(), 0, false);
96     if (!clone)
97         return 0;
98
99     if (namedAttrMap)
100         *clone->attributes() = *namedAttrMap;
101
102     if (m_inlineStyleDecl)
103         *clone->getInlineStyleDecl() = *m_inlineStyleDecl;
104
105     clone->copyNonAttributeProperties(this);
106
107     if (deep)
108         cloneChildNodes(clone.get());
109
110     return clone;
111 }
112
113 bool HTMLElementImpl::mapToEntry(const QualifiedName& attrName, MappedAttributeEntry& result) const
114 {
115     if (attrName == alignAttr ||
116         attrName == contenteditableAttr) {
117         result = eUniversal;
118         return false;
119     }
120     if (attrName == dirAttr) {
121         result = hasTagName(bdoTag) ? eBDO : eUniversal;
122         return false;
123     }
124
125     return StyledElementImpl::mapToEntry(attrName, result);
126 }
127     
128 void HTMLElementImpl::parseMappedAttribute(MappedAttributeImpl *attr)
129 {
130     if (attr->name() == idAttr || attr->name() == classAttr || attr->name() == styleAttr)
131         return StyledElementImpl::parseMappedAttribute(attr);
132
133     DOMString indexstring;
134     if (attr->name() == alignAttr) {
135         if (equalIgnoringCase(attr->value(), "middle"))
136             addCSSProperty(attr, CSS_PROP_TEXT_ALIGN, "center");
137         else
138             addCSSProperty(attr, CSS_PROP_TEXT_ALIGN, attr->value());
139     } else if (attr->name() == contenteditableAttr) {
140         setContentEditable(attr);
141     } else if (attr->name() == tabindexAttr) {
142         indexstring = getAttribute(tabindexAttr);
143         if (indexstring.length())
144             setTabIndex(indexstring.toInt());
145     } else if (attr->name() == langAttr) {
146         // FIXME: Implement
147     } else if (attr->name() == dirAttr) {
148         addCSSProperty(attr, CSS_PROP_DIRECTION, attr->value());
149         addCSSProperty(attr, CSS_PROP_UNICODE_BIDI, hasTagName(bdoTag) ? CSS_VAL_BIDI_OVERRIDE : CSS_VAL_EMBED);
150     }
151 // standard events
152     else if (attr->name() == onclickAttr) {
153         setHTMLEventListener(clickEvent, attr);
154     } else if (attr->name() == oncontextmenuAttr) {
155         setHTMLEventListener(contextmenuEvent, attr);
156     } else if (attr->name() == ondblclickAttr) {
157         setHTMLEventListener(khtmlDblclickEvent, attr);
158     } else if (attr->name() == onmousedownAttr) {
159         setHTMLEventListener(mousedownEvent, attr);
160     } else if (attr->name() == onmousemoveAttr) {
161         setHTMLEventListener(mousemoveEvent, attr);
162     } else if (attr->name() == onmouseoutAttr) {
163         setHTMLEventListener(mouseoutEvent, attr);
164     } else if (attr->name() == onmouseoverAttr) {
165         setHTMLEventListener(mouseoverEvent, attr);
166     } else if (attr->name() == onmouseupAttr) {
167         setHTMLEventListener(mouseupEvent, attr);
168     } else if (attr->name() == onmousewheelAttr) {
169         setHTMLEventListener(mousewheelEvent, attr);
170     } else if (attr->name() == onfocusAttr) {
171         setHTMLEventListener(DOMFocusInEvent, attr);
172     } else if (attr->name() == onblurAttr) {
173         setHTMLEventListener(DOMFocusOutEvent, attr);
174     } else if (attr->name() == onkeydownAttr) {
175         setHTMLEventListener(keydownEvent, attr);
176     } else if (attr->name() == onkeypressAttr) {
177         setHTMLEventListener(keypressEvent, attr);
178     } else if (attr->name() == onkeyupAttr) {
179         setHTMLEventListener(keyupEvent, attr);
180     } else if (attr->name() == onscrollAttr) {
181         setHTMLEventListener(scrollEvent, attr);
182     } else if (attr->name() == onbeforecutAttr) {
183         setHTMLEventListener(beforecutEvent, attr);
184     } else if (attr->name() == oncutAttr) {
185         setHTMLEventListener(cutEvent, attr);
186     } else if (attr->name() == onbeforecopyAttr) {
187         setHTMLEventListener(beforecopyEvent, attr);
188     } else if (attr->name() == oncopyAttr) {
189         setHTMLEventListener(copyEvent, attr);
190     } else if (attr->name() == onbeforepasteAttr) {
191         setHTMLEventListener(beforepasteEvent, attr);
192     } else if (attr->name() == onpasteAttr) {
193         setHTMLEventListener(pasteEvent, attr);
194     } else if (attr->name() == ondragenterAttr) {
195         setHTMLEventListener(dragenterEvent, attr);
196     } else if (attr->name() == ondragoverAttr) {
197         setHTMLEventListener(dragoverEvent, attr);
198     } else if (attr->name() == ondragleaveAttr) {
199         setHTMLEventListener(dragleaveEvent, attr);
200     } else if (attr->name() == ondropAttr) {
201         setHTMLEventListener(dropEvent, attr);
202     } else if (attr->name() == ondragstartAttr) {
203         setHTMLEventListener(dragstartEvent, attr);
204     } else if (attr->name() == ondragAttr) {
205         setHTMLEventListener(dragEvent, attr);
206     } else if (attr->name() == ondragendAttr) {
207         setHTMLEventListener(dragendEvent, attr);
208     } else if (attr->name() == onselectstartAttr) {
209         setHTMLEventListener(selectstartEvent, attr);
210     } 
211 }
212
213 DOMString HTMLElementImpl::innerHTML() const
214 {
215     return createMarkup(this, ChildrenOnly);
216 }
217
218 DOMString HTMLElementImpl::outerHTML() const
219 {
220     return createMarkup(this);
221 }
222
223 DOMString HTMLElementImpl::innerText() const
224 {
225     // We need to update layout, since plainText uses line boxes in the render tree.
226     getDocument()->updateLayoutIgnorePendingStylesheets();
227     return plainText(rangeOfContents(const_cast<HTMLElementImpl *>(this)).get());
228 }
229
230 DOMString HTMLElementImpl::outerText() const
231 {
232     // Getting outerText is the same as getting innerText, only
233     // setting is different. You would think this should get the plain
234     // text for the outer range, but this is wrong, <br> for instance
235     // would return different values for inner and outer text by such
236     // a rule, but it doesn't in WinIE, and we want to match that.
237     return innerText();
238 }
239
240 DocumentFragmentImpl *HTMLElementImpl::createContextualFragment(const DOMString &html)
241 {
242     // the following is in accordance with the definition as used by IE
243     if (endTagRequirement() == TagStatusForbidden)
244         return 0;
245
246     if (hasLocalName(colTag) || hasLocalName(colgroupTag) || hasLocalName(framesetTag) ||
247         hasLocalName(headTag) || hasLocalName(styleTag) || hasLocalName(titleTag))
248         return 0;
249
250     DocumentFragmentImpl *fragment = new DocumentFragmentImpl(getDocument());
251     fragment->ref();
252     
253     if (getDocument()->isHTMLDocument())
254          parseHTMLDocumentFragment(html, fragment);
255     else {
256         if (!parseXMLDocumentFragment(html, fragment, this)) {
257             // FIXME: We should propagate a syntax error exception out here.
258             fragment->deref();
259             return 0;
260         }
261     }
262
263     // Exceptions are ignored because none ought to happen here.
264     int ignoredExceptionCode;
265
266     // we need to pop <html> and <body> elements and remove <head> to
267     // accommodate folks passing complete HTML documents to make the
268     // child of an element.
269
270     RefPtr<NodeImpl> nextNode;
271     for (RefPtr<NodeImpl> node = fragment->firstChild(); node; node = nextNode) {
272         nextNode = node->nextSibling();
273         if (node->hasTagName(htmlTag) || node->hasTagName(bodyTag)) {
274             NodeImpl *firstChild = node->firstChild();
275             if (firstChild)
276                 nextNode = firstChild;
277             RefPtr<NodeImpl> nextChild;
278             for (RefPtr<NodeImpl> child = firstChild; child; child = nextChild) {
279                 nextChild = child->nextSibling();
280                 node->removeChild(child.get(), ignoredExceptionCode);
281                 assert(!ignoredExceptionCode);
282                 fragment->insertBefore(child, node.get(), ignoredExceptionCode);
283                 assert(!ignoredExceptionCode);
284             }
285             fragment->removeChild(node.get(), ignoredExceptionCode);
286             assert(!ignoredExceptionCode);
287         } else if (node->hasTagName(headTag)) {
288             fragment->removeChild(node.get(), ignoredExceptionCode);
289             assert(!ignoredExceptionCode);
290         }
291     }
292
293     // Trick to get the fragment back to the floating state, with 0
294     // refs but not destroyed.
295     fragment->setParent(this);
296     fragment->deref();
297     fragment->setParent(0);
298
299     return fragment;
300 }
301
302 void HTMLElementImpl::setInnerHTML(const DOMString &html, int &exception)
303 {
304     DocumentFragmentImpl *fragment = createContextualFragment(html);
305     if (fragment == NULL) {
306         exception = DOMException::NO_MODIFICATION_ALLOWED_ERR;
307         return;
308     }
309
310     removeChildren();
311     appendChild(fragment, exception);
312 }
313
314 void HTMLElementImpl::setOuterHTML(const DOMString &html, int &exception)
315 {
316     NodeImpl *p = parent();
317     if (!p || !p->isHTMLElement()) {
318         exception = DOMException::NO_MODIFICATION_ALLOWED_ERR;
319         return;
320     }
321     HTMLElementImpl *parent = static_cast<HTMLElementImpl *>(p);
322     DocumentFragmentImpl *fragment = parent->createContextualFragment(html);
323
324     if (!fragment) {
325         exception = DOMException::NO_MODIFICATION_ALLOWED_ERR;
326         return;
327     }
328     
329     ref();
330     parent->replaceChild(fragment, this, exception);
331     deref();
332 }
333
334
335 void HTMLElementImpl::setInnerText(const DOMString &text, int &exception)
336 {
337     // following the IE specs.
338     if (endTagRequirement() == TagStatusForbidden) {
339         exception = DOMException::NO_MODIFICATION_ALLOWED_ERR;
340         return;
341     }
342
343     if (hasLocalName(colTag) || hasLocalName(colgroupTag) || hasLocalName(framesetTag) ||
344         hasLocalName(headTag) || hasLocalName(htmlTag) || hasLocalName(tableTag) || 
345         hasLocalName(tbodyTag) || hasLocalName(tfootTag) || hasLocalName(theadTag) ||
346         hasLocalName(trTag)) {
347         exception = DOMException::NO_MODIFICATION_ALLOWED_ERR;
348         return;
349     }
350
351     removeChildren();
352     appendChild(new TextImpl(getDocument(), text), exception);
353 }
354
355 void HTMLElementImpl::setOuterText(const DOMString &text, int &exception)
356 {
357     // following the IE specs.
358     if (endTagRequirement() == TagStatusForbidden) {
359         exception = DOMException::NO_MODIFICATION_ALLOWED_ERR;
360         return;
361     }
362
363     if (hasLocalName(colTag) || hasLocalName(colgroupTag) || hasLocalName(framesetTag) ||
364         hasLocalName(headTag) || hasLocalName(htmlTag) || hasLocalName(tableTag) || 
365         hasLocalName(tbodyTag) || hasLocalName(tfootTag) || hasLocalName(theadTag) ||
366         hasLocalName(trTag)) {
367         exception = DOMException::NO_MODIFICATION_ALLOWED_ERR;
368         return;
369     }
370
371     NodeImpl *parent = parentNode();
372
373     if (!parent) {
374         exception = DOMException::NO_MODIFICATION_ALLOWED_ERR;
375         return;
376     }
377
378     TextImpl *t = new TextImpl(getDocument(), text);
379     ref();
380     parent->replaceChild(t, this, exception);
381     deref();
382     if (exception)
383         return;
384
385     // is previous node a text node? if so, merge into it
386     NodeImpl *prev = t->previousSibling();
387     if (prev && prev->isTextNode()) {
388         TextImpl *textPrev = static_cast<TextImpl *>(prev);
389         textPrev->appendData(t->data(), exception);
390         if (exception)
391             return;
392         t->remove(exception);
393         if (exception)
394             return;
395         t = textPrev;
396     }
397
398     // is next node a text node? if so, merge it in
399     NodeImpl *next = t->nextSibling();
400     if (next && next->isTextNode()) {
401         TextImpl *textNext = static_cast<TextImpl *>(next);
402         t->appendData(textNext->data(), exception);
403         if (exception)
404             return;
405         textNext->remove(exception);
406         if (exception)
407             return;
408     }
409 }
410
411 void HTMLElementImpl::addHTMLAlignment(MappedAttributeImpl* attr)
412 {
413     // vertical alignment with respect to the current baseline of the text
414     // right or left means floating images
415     int propfloat = -1;
416     int propvalign = -1;
417     const AtomicString& alignment = attr->value();
418     if (equalIgnoringCase(alignment, "absmiddle")) {
419         propvalign = CSS_VAL_MIDDLE;
420     } else if (equalIgnoringCase(alignment, "absbottom")) {
421         propvalign = CSS_VAL_BOTTOM;
422     } else if (equalIgnoringCase(alignment, "left")) {
423         propfloat = CSS_VAL_LEFT;
424         propvalign = CSS_VAL_TOP;
425     } else if (equalIgnoringCase(alignment, "right")) {
426         propfloat = CSS_VAL_RIGHT;
427         propvalign = CSS_VAL_TOP;
428     } else if (equalIgnoringCase(alignment, "top")) {
429         propvalign = CSS_VAL_TOP;
430     } else if (equalIgnoringCase(alignment, "middle")) {
431         propvalign = CSS_VAL__KHTML_BASELINE_MIDDLE;
432     } else if (equalIgnoringCase(alignment, "center")) {
433         propvalign = CSS_VAL_MIDDLE;
434     } else if (equalIgnoringCase(alignment, "bottom")) {
435         propvalign = CSS_VAL_BASELINE;
436     } else if (equalIgnoringCase(alignment, "texttop")) {
437         propvalign = CSS_VAL_TEXT_TOP;
438     }
439     
440     if ( propfloat != -1 )
441         addCSSProperty( attr, CSS_PROP_FLOAT, propfloat );
442     if ( propvalign != -1 )
443         addCSSProperty( attr, CSS_PROP_VERTICAL_ALIGN, propvalign );
444 }
445
446 bool HTMLElementImpl::isFocusable() const
447 {
448     return isContentEditable() && parent() && !parent()->isContentEditable();
449 }
450
451 bool HTMLElementImpl::isContentEditable() const 
452 {
453     if (getDocument()->frame() && getDocument()->frame()->isContentEditable())
454         return true;
455
456     getDocument()->updateRendering();
457
458     if (!renderer()) {
459         if (parentNode())
460             return parentNode()->isContentEditable();
461         else
462             return false;
463     }
464     
465     return renderer()->style()->userModify() == READ_WRITE;
466 }
467
468 DOMString HTMLElementImpl::contentEditable() const 
469 {
470     getDocument()->updateRendering();
471
472     if (!renderer())
473         return "false";
474     
475     switch (renderer()->style()->userModify()) {
476         case READ_WRITE:
477             return "true";
478         case READ_ONLY:
479             return "false";
480         default:
481             return "inherit";
482     }
483     return "inherit";
484 }
485
486 void HTMLElementImpl::setContentEditable(MappedAttributeImpl* attr) 
487 {
488     Frame *frame = getDocument()->frame();
489     const AtomicString& enabled = attr->value();
490     if (enabled.isEmpty() || equalIgnoringCase(enabled, "true")) {
491         addCSSProperty(attr, CSS_PROP__KHTML_USER_MODIFY, CSS_VAL_READ_WRITE);
492         if (frame)
493             frame->applyEditingStyleToElement(this);    
494     } else if (equalIgnoringCase(enabled, "false")) {
495         addCSSProperty(attr, CSS_PROP__KHTML_USER_MODIFY, CSS_VAL_READ_ONLY);
496         if (frame)
497             frame->removeEditingStyleFromElement(this);    
498     } else if (equalIgnoringCase(enabled, "inherit")) {
499         addCSSProperty(attr, CSS_PROP__KHTML_USER_MODIFY, CSS_VAL_INHERIT);
500         if (frame)
501             frame->removeEditingStyleFromElement(this);    
502     }
503 }
504
505 void HTMLElementImpl::setContentEditable(const DOMString &enabled)
506 {
507     if (enabled == "inherit") {
508         int exceptionCode;
509         removeAttribute(contenteditableAttr, exceptionCode);
510     }
511     else
512         setAttribute(contenteditableAttr, enabled.isEmpty() ? "true" : enabled);
513 }
514
515 void HTMLElementImpl::click(bool sendMouseEvents, bool showPressedLook)
516 {
517     // send mousedown and mouseup before the click, if requested
518     if (sendMouseEvents)
519         dispatchSimulatedMouseEvent(mousedownEvent);
520     setActive(true, showPressedLook);
521     if (sendMouseEvents)
522         dispatchSimulatedMouseEvent(mouseupEvent);
523     setActive(false);
524
525     // always send click
526     dispatchSimulatedMouseEvent(clickEvent);
527 }
528
529 // accessKeyAction is used by the accessibility support code
530 // to send events to elements that our JavaScript caller does
531 // does not.  The elements JS is interested in have subclasses
532 // that override this method to direct the click appropriately.
533 // Here in the base class, then, we only send the click if
534 // the caller wants it to go to any HTMLElementImpl, and we say
535 // to send the mouse events in addition to the click.
536 void HTMLElementImpl::accessKeyAction(bool sendToAnyElement)
537 {
538     if (sendToAnyElement)
539         click(true);
540 }
541
542 DOMString HTMLElementImpl::toString() const
543 {
544     if (!hasChildNodes() && getDocument()->isHTMLDocument()) {
545         DOMString result = openTagStartToString();
546         result += ">";
547
548         if (endTagRequirement() == TagStatusRequired) {
549             result += "</";
550             result += nodeName();
551             result += ">";
552         }
553
554         return result;
555     }
556
557     return ElementImpl::toString();
558 }
559
560 DOMString HTMLElementImpl::id() const
561 {
562     return getAttribute(idAttr);
563 }
564
565 void HTMLElementImpl::setId(const DOMString &value)
566 {
567     setAttribute(idAttr, value);
568 }
569
570 DOMString HTMLElementImpl::title() const
571 {
572     return getAttribute(titleAttr);
573 }
574
575 void HTMLElementImpl::setTitle(const DOMString &value)
576 {
577     setAttribute(titleAttr, value);
578 }
579
580 DOMString HTMLElementImpl::lang() const
581 {
582     return getAttribute(langAttr);
583 }
584
585 void HTMLElementImpl::setLang(const DOMString &value)
586 {
587     setAttribute(langAttr, value);
588 }
589
590 DOMString HTMLElementImpl::dir() const
591 {
592     return getAttribute(dirAttr);
593 }
594
595 void HTMLElementImpl::setDir(const DOMString &value)
596 {
597     setAttribute(dirAttr, value);
598 }
599
600 DOMString HTMLElementImpl::className() const
601 {
602     return getAttribute(classAttr);
603 }
604
605 void HTMLElementImpl::setClassName(const DOMString &value)
606 {
607     setAttribute(classAttr, value);
608 }
609
610 PassRefPtr<HTMLCollectionImpl> HTMLElementImpl::children()
611 {
612     return new HTMLCollectionImpl(this, HTMLCollectionImpl::NODE_CHILDREN);
613 }
614
615 // DOM Section 1.1.1
616 bool HTMLElementImpl::childAllowed(NodeImpl *newChild)
617 {
618     if (!ElementImpl::childAllowed(newChild))
619         return false;
620
621     // For XML documents, we are non-validating and do not check against a DTD, even for HTML elements.
622     if (!getDocument()->isHTMLDocument())
623         return true;
624
625     // Future-proof for XML content inside HTML documents (we may allow this some day).
626     if (newChild->isElementNode() && !newChild->isHTMLElement())
627         return true;
628
629     // Elements with forbidden tag status can never have children
630     if (endTagRequirement() == TagStatusForbidden)
631         return false;
632
633     // Comment nodes are always allowed.
634     if (newChild->isCommentNode())
635         return true;
636
637     // Now call checkDTD.
638     return checkDTD(newChild);
639 }
640
641 // DTD Stuff
642 // This unfortunate function is only needed when checking against the DTD.  Other languages (like SVG) won't need this.
643 bool HTMLElementImpl::isRecognizedTagName(const QualifiedName& tagName)
644 {
645     static HashSet<AtomicStringImpl*> tagList;
646     if (tagList.isEmpty()) {
647         #define ADD_TAG(name) tagList.add(name##Tag.localName().impl());
648         DOM_HTMLNAMES_FOR_EACH_TAG(ADD_TAG)
649     }
650     return tagList.contains(tagName.localName().impl());
651 }
652
653 // The terms inline and block are used here loosely.  Don't make the mistake of assuming all inlines or all blocks
654 // need to be in these two lists.
655 HashSet<AtomicStringImpl*>* inlineTagList()
656 {
657     static HashSet<AtomicStringImpl*> tagList;
658     if (tagList.isEmpty()) {
659         tagList.add(ttTag.localName().impl());
660         tagList.add(iTag.localName().impl());
661         tagList.add(bTag.localName().impl());
662         tagList.add(uTag.localName().impl());
663         tagList.add(sTag.localName().impl());
664         tagList.add(strikeTag.localName().impl());
665         tagList.add(bigTag.localName().impl());
666         tagList.add(smallTag.localName().impl());
667         tagList.add(emTag.localName().impl());
668         tagList.add(strongTag.localName().impl());
669         tagList.add(dfnTag.localName().impl());
670         tagList.add(codeTag.localName().impl());
671         tagList.add(sampTag.localName().impl());
672         tagList.add(kbdTag.localName().impl());
673         tagList.add(varTag.localName().impl());
674         tagList.add(citeTag.localName().impl());
675         tagList.add(abbrTag.localName().impl());
676         tagList.add(acronymTag.localName().impl());
677         tagList.add(aTag.localName().impl());
678         tagList.add(canvasTag.localName().impl());
679         tagList.add(imgTag.localName().impl());
680         tagList.add(appletTag.localName().impl());
681         tagList.add(objectTag.localName().impl());
682         tagList.add(embedTag.localName().impl());
683         tagList.add(fontTag.localName().impl());
684         tagList.add(basefontTag.localName().impl());
685         tagList.add(brTag.localName().impl());
686         tagList.add(scriptTag.localName().impl());
687         tagList.add(mapTag.localName().impl());
688         tagList.add(qTag.localName().impl());
689         tagList.add(subTag.localName().impl());
690         tagList.add(supTag.localName().impl());
691         tagList.add(spanTag.localName().impl());
692         tagList.add(bdoTag.localName().impl());
693         tagList.add(iframeTag.localName().impl());
694         tagList.add(inputTag.localName().impl());
695         tagList.add(keygenTag.localName().impl());
696         tagList.add(selectTag.localName().impl());
697         tagList.add(textareaTag.localName().impl());
698         tagList.add(labelTag.localName().impl());
699         tagList.add(buttonTag.localName().impl());
700         tagList.add(insTag.localName().impl());
701         tagList.add(delTag.localName().impl());
702         tagList.add(nobrTag.localName().impl());
703         tagList.add(wbrTag.localName().impl());
704     }
705     return &tagList;
706 }
707
708 HashSet<AtomicStringImpl*>* blockTagList()
709 {
710     static HashSet<AtomicStringImpl*> tagList;
711     if (tagList.isEmpty()) {
712         tagList.add(pTag.localName().impl());
713         tagList.add(h1Tag.localName().impl());
714         tagList.add(h2Tag.localName().impl());
715         tagList.add(h3Tag.localName().impl());
716         tagList.add(h4Tag.localName().impl());
717         tagList.add(h5Tag.localName().impl());
718         tagList.add(h6Tag.localName().impl());
719         tagList.add(ulTag.localName().impl());
720         tagList.add(olTag.localName().impl());
721         tagList.add(dirTag.localName().impl());
722         tagList.add(menuTag.localName().impl());
723         tagList.add(preTag.localName().impl());
724         tagList.add(plaintextTag.localName().impl());
725         tagList.add(xmpTag.localName().impl());
726         tagList.add(dlTag.localName().impl());
727         tagList.add(divTag.localName().impl());
728         tagList.add(layerTag.localName().impl());
729         tagList.add(centerTag.localName().impl());
730         tagList.add(noscriptTag.localName().impl());
731         tagList.add(noframesTag.localName().impl());
732         tagList.add(noembedTag.localName().impl());
733         tagList.add(nolayerTag.localName().impl());
734         tagList.add(blockquoteTag.localName().impl());
735         tagList.add(formTag.localName().impl());
736         tagList.add(isindexTag.localName().impl());
737         tagList.add(hrTag.localName().impl());
738         tagList.add(tableTag.localName().impl());
739         tagList.add(fieldsetTag.localName().impl());
740         tagList.add(addressTag.localName().impl());
741         tagList.add(liTag.localName().impl());
742         tagList.add(ddTag.localName().impl());
743         tagList.add(dtTag.localName().impl());
744         tagList.add(marqueeTag.localName().impl());
745     }
746     return &tagList;
747 }
748
749 bool HTMLElementImpl::inEitherTagList(const NodeImpl* newChild)
750 {
751     if (newChild->isTextNode())
752         return true;
753         
754     if (newChild->isHTMLElement()) {
755         const HTMLElementImpl* child = static_cast<const HTMLElementImpl*>(newChild);
756         if (inlineTagList()->contains(child->tagName().localName().impl()))
757             return true;
758         if (blockTagList()->contains(child->tagName().localName().impl()))
759             return true;
760         return !isRecognizedTagName(child->tagName()); // Accept custom html tags
761     }
762
763     return false;
764 }
765
766 bool HTMLElementImpl::inInlineTagList(const NodeImpl* newChild)
767 {
768     if (newChild->isTextNode())
769         return true;
770
771     if (newChild->isHTMLElement()) {
772         const HTMLElementImpl* child = static_cast<const HTMLElementImpl*>(newChild);
773         if (inlineTagList()->contains(child->tagName().localName().impl()))
774             return true;
775         return !isRecognizedTagName(child->tagName()); // Accept custom html tags
776     }
777
778     return false;
779 }
780
781 bool HTMLElementImpl::inBlockTagList(const NodeImpl* newChild)
782 {
783     if (newChild->isTextNode())
784         return true;
785             
786     if (newChild->isHTMLElement()) {
787         const HTMLElementImpl* child = static_cast<const HTMLElementImpl*>(newChild);
788         return (blockTagList()->contains(child->tagName().localName().impl()));
789     }
790
791     return false;
792 }
793
794 bool HTMLElementImpl::checkDTD(const NodeImpl* newChild)
795 {
796     if (hasTagName(addressTag) && newChild->hasTagName(pTag))
797         return true;
798     return inEitherTagList(newChild);
799 }
800
801 void HTMLElementImpl::setHTMLEventListener(const AtomicString& eventType, AttributeImpl* attr)
802 {
803     ElementImpl::setHTMLEventListener(eventType, getDocument()->createHTMLEventListener(attr->value(), this));
804 }
805
806 }