2 * This file is part of the DOM implementation for KDE.
4 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
5 * (C) 1999 Antti Koivisto (koivisto@kde.org)
6 * Copyright (C) 2004 Apple Computer, Inc.
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.
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.
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.
24 // -------------------------------------------------------------------------
26 //#define DEBUG_LAYOUT
29 //#define UNSUPPORTED_ATTR
32 #include "html/html_elementimpl.h"
33 #include "html/html_documentimpl.h"
34 #include "html/htmltokenizer.h"
36 #include "misc/htmlhashes.h"
37 #include "editing/visible_text.h"
39 #include "khtmlview.h"
40 #include "khtml_part.h"
42 #include "dom/dom_exception.h"
43 #include "rendering/render_object.h"
44 #include "rendering/render_replaced.h"
45 #include "css/css_valueimpl.h"
46 #include "css/css_stylesheetimpl.h"
47 #include "css/cssproperties.h"
48 #include "css/cssvalues.h"
49 #include "css/css_ruleimpl.h"
50 #include "xml/dom_textimpl.h"
51 #include "xml/dom2_eventsimpl.h"
52 #include "editing/markup.h"
57 using namespace khtml;
59 CSSMappedAttributeDeclarationImpl::~CSSMappedAttributeDeclarationImpl() {
60 if (m_entryType != ePersistent)
61 HTMLElementImpl::removeMappedAttributeDecl(m_entryType, m_attrName, m_attrValue);
64 QPtrDict<QPtrDict<QPtrDict<CSSMappedAttributeDeclarationImpl> > >* HTMLElementImpl::m_mappedAttributeDecls = 0;
66 CSSMappedAttributeDeclarationImpl* HTMLElementImpl::getMappedAttributeDecl(MappedAttributeEntry entryType, AttributeImpl* attr)
68 if (!m_mappedAttributeDecls)
71 QPtrDict<QPtrDict<CSSMappedAttributeDeclarationImpl> >* attrNameDict = m_mappedAttributeDecls->find((void*)entryType);
73 QPtrDict<CSSMappedAttributeDeclarationImpl>* attrValueDict = attrNameDict->find((void*)attr->id());
75 return attrValueDict->find(attr->value().implementation());
80 void HTMLElementImpl::setMappedAttributeDecl(MappedAttributeEntry entryType, AttributeImpl* attr, CSSMappedAttributeDeclarationImpl* decl)
82 if (!m_mappedAttributeDecls)
83 m_mappedAttributeDecls = new QPtrDict<QPtrDict<QPtrDict<CSSMappedAttributeDeclarationImpl> > >;
85 QPtrDict<CSSMappedAttributeDeclarationImpl>* attrValueDict = 0;
86 QPtrDict<QPtrDict<CSSMappedAttributeDeclarationImpl> >* attrNameDict = m_mappedAttributeDecls->find((void*)entryType);
88 attrNameDict = new QPtrDict<QPtrDict<CSSMappedAttributeDeclarationImpl> >;
89 attrNameDict->setAutoDelete(true);
90 m_mappedAttributeDecls->insert((void*)entryType, attrNameDict);
93 attrValueDict = attrNameDict->find((void*)attr->id());
95 attrValueDict = new QPtrDict<CSSMappedAttributeDeclarationImpl>;
96 if (entryType == ePersistent)
97 attrValueDict->setAutoDelete(true);
98 attrNameDict->insert((void*)attr->id(), attrValueDict);
100 attrValueDict->replace(attr->value().implementation(), decl);
103 void HTMLElementImpl::removeMappedAttributeDecl(MappedAttributeEntry entryType, NodeImpl::Id attrName, const AtomicString& attrValue)
105 if (!m_mappedAttributeDecls)
108 QPtrDict<QPtrDict<CSSMappedAttributeDeclarationImpl> >* attrNameDict = m_mappedAttributeDecls->find((void*)entryType);
111 QPtrDict<CSSMappedAttributeDeclarationImpl>* attrValueDict = attrNameDict->find((void*)attrName);
114 attrValueDict->remove(attrValue.implementation());
117 void HTMLElementImpl::invalidateStyleAttribute()
119 m_isStyleAttributeValid = false;
122 void HTMLElementImpl::updateStyleAttributeIfNeeded() const
124 if (!m_isStyleAttributeValid) {
125 m_isStyleAttributeValid = true;
126 m_synchronizingStyleAttribute = true;
127 if (m_inlineStyleDecl)
128 const_cast<HTMLElementImpl*>(this)->setAttribute(ATTR_STYLE, m_inlineStyleDecl->cssText());
129 m_synchronizingStyleAttribute = false;
133 HTMLAttributeImpl::~HTMLAttributeImpl()
136 m_styleDecl->deref();
139 AttributeImpl* HTMLAttributeImpl::clone(bool preserveDecl) const
141 return new HTMLAttributeImpl(m_id, _value, preserveDecl ? m_styleDecl : 0);
144 HTMLNamedAttrMapImpl::HTMLNamedAttrMapImpl(ElementImpl *e)
145 :NamedAttrMapImpl(e), m_mappedAttributeCount(0)
148 void HTMLNamedAttrMapImpl::clearAttributes()
151 m_mappedAttributeCount = 0;
152 NamedAttrMapImpl::clearAttributes();
155 bool HTMLNamedAttrMapImpl::isHTMLAttributeMap() const
160 int HTMLNamedAttrMapImpl::declCount() const
163 for (uint i = 0; i < length(); i++) {
164 HTMLAttributeImpl* attr = attributeItem(i);
171 bool HTMLNamedAttrMapImpl::mapsEquivalent(const HTMLNamedAttrMapImpl* otherMap) const
173 // The # of decls must match.
174 if (declCount() != otherMap->declCount())
177 // The values for each decl must match.
178 for (uint i = 0; i < length(); i++) {
179 HTMLAttributeImpl* attr = attributeItem(i);
181 AttributeImpl* otherAttr = otherMap->getAttributeItem(attr->id());
182 if (!otherAttr || (attr->value() != otherAttr->value()))
189 void HTMLNamedAttrMapImpl::parseClassAttribute(const DOMString& classStr)
192 if (!element->hasClass())
195 DOMString classAttr = element->getDocument()->inCompatMode() ?
196 (classStr.implementation()->isLower() ? classStr : DOMString(classStr.implementation()->lower())) :
199 if (classAttr.find(' ') == -1 && classAttr.find('\n') == -1)
200 m_classList.setString(AtomicString(classAttr));
202 QString val = classAttr.string();
203 val.replace('\n', ' ');
204 QStringList list = QStringList::split(' ', val);
206 AtomicStringList* curr = 0;
207 for (QStringList::Iterator it = list.begin(); it != list.end(); ++it) {
208 const QString& singleClass = *it;
209 if (!singleClass.isEmpty()) {
211 curr->setNext(new AtomicStringList(AtomicString(singleClass)));
215 m_classList.setString(AtomicString(singleClass));
223 // ------------------------------------------------------------------
225 HTMLElementImpl::HTMLElementImpl(DocumentPtr *doc)
228 m_inlineStyleDecl = 0;
229 m_isStyleAttributeValid = true;
230 m_synchronizingStyleAttribute = false;
233 HTMLElementImpl::~HTMLElementImpl()
235 destroyInlineStyleDecl();
238 AttributeImpl* HTMLElementImpl::createAttribute(NodeImpl::Id id, DOMStringImpl* value)
240 return new HTMLAttributeImpl(id, value);
243 bool HTMLElementImpl::isInline() const
246 return ElementImpl::isInline();
281 return ElementImpl::isInline();
285 void HTMLElementImpl::createInlineStyleDecl()
287 m_inlineStyleDecl = new CSSMutableStyleDeclarationImpl;
288 m_inlineStyleDecl->ref();
289 m_inlineStyleDecl->setParent(getDocument()->elementSheet());
290 m_inlineStyleDecl->setNode(this);
291 m_inlineStyleDecl->setStrictParsing(!getDocument()->inCompatMode());
294 void HTMLElementImpl::destroyInlineStyleDecl()
296 if (m_inlineStyleDecl) {
297 m_inlineStyleDecl->setNode(0);
298 m_inlineStyleDecl->setParent(0);
299 m_inlineStyleDecl->deref();
300 m_inlineStyleDecl = 0;
304 NodeImpl *HTMLElementImpl::cloneNode(bool deep)
306 HTMLElementImpl *clone = static_cast<HTMLElementImpl *>(getDocument()->createHTMLElement(localNamePart(id())));
311 *clone->attributes() = *namedAttrMap;
313 if (m_inlineStyleDecl)
314 *clone->getInlineStyleDecl() = *m_inlineStyleDecl;
317 cloneChildNodes(clone);
322 void HTMLElementImpl::attributeChanged(AttributeImpl* attr, bool preserveDecls)
324 HTMLAttributeImpl* htmlAttr = static_cast<HTMLAttributeImpl*>(attr);
325 if (htmlAttr->decl() && !preserveDecls) {
326 htmlAttr->setDecl(0);
329 static_cast<HTMLNamedAttrMapImpl*>(namedAttrMap)->declRemoved();
332 bool checkDecl = true;
333 MappedAttributeEntry entry;
334 bool needToParse = mapToEntry(attr->id(), entry);
336 if (htmlAttr->decl()) {
339 static_cast<HTMLNamedAttrMapImpl*>(namedAttrMap)->declAdded();
343 else if (!attr->isNull() && entry != eNone) {
344 CSSMappedAttributeDeclarationImpl* decl = getMappedAttributeDecl(entry, attr);
346 htmlAttr->setDecl(decl);
349 static_cast<HTMLNamedAttrMapImpl*>(namedAttrMap)->declAdded();
356 parseHTMLAttribute(htmlAttr);
358 if (checkDecl && htmlAttr->decl()) {
359 // Add the decl to the table in the appropriate spot.
360 setMappedAttributeDecl(entry, attr, htmlAttr->decl());
361 htmlAttr->decl()->setMappedState(entry, attr->id(), attr->value());
362 htmlAttr->decl()->setParent(0);
363 htmlAttr->decl()->setNode(0);
365 static_cast<HTMLNamedAttrMapImpl*>(namedAttrMap)->declAdded();
369 bool HTMLElementImpl::mapToEntry(NodeImpl::Id attr, MappedAttributeEntry& result) const
374 case ATTR_CONTENTEDITABLE:
380 return !m_synchronizingStyleAttribute;
389 void HTMLElementImpl::parseHTMLAttribute(HTMLAttributeImpl *attr)
391 DOMString indexstring;
395 if (strcasecmp(attr->value(), "middle" ) == 0)
396 addCSSProperty(attr, CSS_PROP_TEXT_ALIGN, "center");
398 addCSSProperty(attr, CSS_PROP_TEXT_ALIGN, attr->value());
400 // the core attributes...
403 setHasID(!attr->isNull());
406 namedAttrMap->setID(nullAtom);
407 else if (getDocument()->inCompatMode() && !attr->value().implementation()->isLower())
408 namedAttrMap->setID(AtomicString(attr->value().domString().lower()));
410 namedAttrMap->setID(attr->value());
416 setHasClass(!attr->isNull());
417 if (namedAttrMap) static_cast<HTMLNamedAttrMapImpl*>(namedAttrMap)->parseClassAttribute(attr->value());
420 case ATTR_CONTENTEDITABLE:
421 setContentEditable(attr);
424 setHasStyle(!attr->isNull());
426 destroyInlineStyleDecl();
428 getInlineStyleDecl()->parseDeclaration(attr->value());
429 m_isStyleAttributeValid = true;
433 indexstring=getAttribute(ATTR_TABINDEX);
434 if (indexstring.length())
435 setTabIndex(indexstring.toInt());
441 addCSSProperty(attr, CSS_PROP_DIRECTION, attr->value());
442 addCSSProperty(attr, CSS_PROP_UNICODE_BIDI, CSS_VAL_EMBED);
446 setHTMLEventListener(EventImpl::KHTML_CLICK_EVENT,
447 getDocument()->createHTMLEventListener(attr->value().string(), this));
449 case ATTR_ONCONTEXTMENU:
450 setHTMLEventListener(EventImpl::CONTEXTMENU_EVENT,
451 getDocument()->createHTMLEventListener(attr->value().string(), this));
453 case ATTR_ONDBLCLICK:
454 setHTMLEventListener(EventImpl::KHTML_DBLCLICK_EVENT,
455 getDocument()->createHTMLEventListener(attr->value().string(), this));
457 case ATTR_ONMOUSEDOWN:
458 setHTMLEventListener(EventImpl::MOUSEDOWN_EVENT,
459 getDocument()->createHTMLEventListener(attr->value().string(), this));
461 case ATTR_ONMOUSEMOVE:
462 setHTMLEventListener(EventImpl::MOUSEMOVE_EVENT,
463 getDocument()->createHTMLEventListener(attr->value().string(), this));
465 case ATTR_ONMOUSEOUT:
466 setHTMLEventListener(EventImpl::MOUSEOUT_EVENT,
467 getDocument()->createHTMLEventListener(attr->value().string(), this));
469 case ATTR_ONMOUSEOVER:
470 setHTMLEventListener(EventImpl::MOUSEOVER_EVENT,
471 getDocument()->createHTMLEventListener(attr->value().string(), this));
474 setHTMLEventListener(EventImpl::MOUSEUP_EVENT,
475 getDocument()->createHTMLEventListener(attr->value().string(), this));
477 case ATTR_ONMOUSEWHEEL:
478 setHTMLEventListener(EventImpl::MOUSEWHEEL_EVENT,
479 getDocument()->createHTMLEventListener(attr->value().string(), this));
482 setHTMLEventListener(EventImpl::DOMFOCUSIN_EVENT,
483 getDocument()->createHTMLEventListener(attr->value().string(), this));
486 setHTMLEventListener(EventImpl::KEYDOWN_EVENT,
487 getDocument()->createHTMLEventListener(attr->value().string(), this));
489 case ATTR_ONKEYPRESS:
490 setHTMLEventListener(EventImpl::KEYPRESS_EVENT,
491 getDocument()->createHTMLEventListener(attr->value().string(), this));
494 setHTMLEventListener(EventImpl::KEYUP_EVENT,
495 getDocument()->createHTMLEventListener(attr->value().string(), this));
498 setHTMLEventListener(EventImpl::SCROLL_EVENT,
499 getDocument()->createHTMLEventListener(attr->value().string(), this));
501 case ATTR_ONBEFORECUT:
502 setHTMLEventListener(EventImpl::BEFORECUT_EVENT,
503 getDocument()->createHTMLEventListener(attr->value().string(), this));
506 setHTMLEventListener(EventImpl::CUT_EVENT,
507 getDocument()->createHTMLEventListener(attr->value().string(), this));
509 case ATTR_ONBEFORECOPY:
510 setHTMLEventListener(EventImpl::BEFORECOPY_EVENT,
511 getDocument()->createHTMLEventListener(attr->value().string(), this));
514 setHTMLEventListener(EventImpl::COPY_EVENT,
515 getDocument()->createHTMLEventListener(attr->value().string(), this));
517 case ATTR_ONBEFOREPASTE:
518 setHTMLEventListener(EventImpl::BEFOREPASTE_EVENT,
519 getDocument()->createHTMLEventListener(attr->value().string(), this));
522 setHTMLEventListener(EventImpl::PASTE_EVENT,
523 getDocument()->createHTMLEventListener(attr->value().string(), this));
525 case ATTR_ONDRAGENTER:
526 setHTMLEventListener(EventImpl::DRAGENTER_EVENT,
527 getDocument()->createHTMLEventListener(attr->value().string(), this));
529 case ATTR_ONDRAGOVER:
530 setHTMLEventListener(EventImpl::DRAGOVER_EVENT,
531 getDocument()->createHTMLEventListener(attr->value().string(), this));
533 case ATTR_ONDRAGLEAVE:
534 setHTMLEventListener(EventImpl::DRAGLEAVE_EVENT,
535 getDocument()->createHTMLEventListener(attr->value().string(), this));
538 setHTMLEventListener(EventImpl::DROP_EVENT,
539 getDocument()->createHTMLEventListener(attr->value().string(), this));
541 case ATTR_ONDRAGSTART:
542 setHTMLEventListener(EventImpl::DRAGSTART_EVENT,
543 getDocument()->createHTMLEventListener(attr->value().string(), this));
546 setHTMLEventListener(EventImpl::DRAG_EVENT,
547 getDocument()->createHTMLEventListener(attr->value().string(), this));
550 setHTMLEventListener(EventImpl::DRAGEND_EVENT,
551 getDocument()->createHTMLEventListener(attr->value().string(), this));
553 case ATTR_ONSELECTSTART:
554 setHTMLEventListener(EventImpl::SELECTSTART_EVENT,
555 getDocument()->createHTMLEventListener(attr->value().string(), this));
557 // other misc attributes
559 #ifdef UNSUPPORTED_ATTR
560 kdDebug(6030) << "UATTR: <" << this->nodeName().string() << "> ["
561 << attr->name().string() << "]=[" << attr->value().string() << "]" << endl;
567 void HTMLElementImpl::createAttributeMap() const
569 namedAttrMap = new HTMLNamedAttrMapImpl(const_cast<HTMLElementImpl*>(this));
573 CSSMutableStyleDeclarationImpl* HTMLElementImpl::getInlineStyleDecl()
575 if (!m_inlineStyleDecl)
576 createInlineStyleDecl();
577 return m_inlineStyleDecl;
580 CSSMutableStyleDeclarationImpl* HTMLElementImpl::additionalAttributeStyleDecl()
585 const AtomicStringList* HTMLElementImpl::getClassList() const
587 return namedAttrMap ? static_cast<HTMLNamedAttrMapImpl*>(namedAttrMap)->getClassList() : 0;
590 static inline bool isHexDigit( const QChar &c ) {
591 return ( c >= '0' && c <= '9' ) ||
592 ( c >= 'a' && c <= 'f' ) ||
593 ( c >= 'A' && c <= 'F' );
596 static inline int toHex( const QChar &c ) {
597 return ( (c >= '0' && c <= '9')
598 ? (c.unicode() - '0')
599 : ( ( c >= 'a' && c <= 'f' )
600 ? (c.unicode() - 'a' + 10)
601 : ( ( c >= 'A' && c <= 'F' )
602 ? (c.unicode() - 'A' + 10)
606 void HTMLElementImpl::addCSSProperty(HTMLAttributeImpl* attr, int id, const DOMString &value)
608 if (!attr->decl()) createMappedDecl(attr);
609 attr->decl()->setProperty(id, value, false);
612 void HTMLElementImpl::addCSSProperty(HTMLAttributeImpl* attr, int id, int value)
614 if (!attr->decl()) createMappedDecl(attr);
615 attr->decl()->setProperty(id, value, false);
618 void HTMLElementImpl::addCSSStringProperty(HTMLAttributeImpl* attr, int id, const DOMString &value, CSSPrimitiveValue::UnitTypes type)
620 if (!attr->decl()) createMappedDecl(attr);
621 attr->decl()->setStringProperty(id, value, type, false);
624 void HTMLElementImpl::addCSSImageProperty(HTMLAttributeImpl* attr, int id, const DOMString &URL)
626 if (!attr->decl()) createMappedDecl(attr);
627 attr->decl()->setImageProperty(id, URL, false);
630 void HTMLElementImpl::addCSSLength(HTMLAttributeImpl* attr, int id, const DOMString &value)
632 // FIXME: This function should not spin up the CSS parser, but should instead just figure out the correct
633 // length unit and make the appropriate parsed value.
634 if (!attr->decl()) createMappedDecl(attr);
636 // strip attribute garbage..
637 DOMStringImpl* v = value.implementation();
641 while ( l < v->l && v->s[l].unicode() <= ' ') l++;
643 for ( ;l < v->l; l++ ) {
644 char cc = v->s[l].latin1();
645 if ( cc > '9' || ( cc < '0' && cc != '*' && cc != '%' && cc != '.') )
649 attr->decl()->setLengthProperty(id, DOMString( v->s, l ), false);
654 attr->decl()->setLengthProperty(id, value, false);
657 /* color parsing that tries to match as close as possible IE 6. */
658 void HTMLElementImpl::addHTMLColor(HTMLAttributeImpl* attr, int id, const DOMString &c)
660 // this is the only case no color gets applied in IE.
664 if (!attr->decl()) createMappedDecl(attr);
666 if (attr->decl()->setProperty(id, c, false) )
669 QString color = c.string();
670 // not something that fits the specs.
672 // we're emulating IEs color parser here. It maps transparent to black, otherwise it tries to build a rgb value
673 // out of everyhting you put in. The algorithm is experimentally determined, but seems to work for all test cases I have.
675 // the length of the color value is rounded up to the next
676 // multiple of 3. each part of the rgb triple then gets one third
679 // Each triplet is parsed byte by byte, mapping
680 // each number to a hex value (0-9a-fA-F to their values
681 // everything else to 0).
683 // The highest non zero digit in all triplets is remembered, and
684 // used as a normalization point to normalize to values between 0
687 if ( color.lower() != "transparent" ) {
688 if ( color[0] == '#' )
689 color.remove( 0, 1 );
690 int basicLength = (color.length() + 2) / 3;
691 if ( basicLength > 1 ) {
692 // IE ignores colors with three digits or less
693 // qDebug("trying to fix up color '%s'. basicLength=%d, length=%d",
694 // color.latin1(), basicLength, color.length() );
695 int colors[3] = { 0, 0, 0 };
698 int maxDigit = basicLength-1;
699 while ( component < 3 ) {
700 // search forward for digits in the string
702 while ( pos < (int)color.length() && numDigits < basicLength ) {
703 int hex = toHex( color[pos] );
704 colors[component] = (colors[component] << 4);
706 colors[component] += hex;
707 maxDigit = kMin( maxDigit, numDigits );
712 while ( numDigits++ < basicLength )
713 colors[component] <<= 4;
716 maxDigit = basicLength - maxDigit;
717 // qDebug("color is %x %x %x, maxDigit=%d", colors[0], colors[1], colors[2], maxDigit );
719 // normalize to 00-ff. The highest filled digit counts, minimum is 2 digits
721 colors[0] >>= 4*maxDigit;
722 colors[1] >>= 4*maxDigit;
723 colors[2] >>= 4*maxDigit;
724 // qDebug("normalized color is %x %x %x", colors[0], colors[1], colors[2] );
725 // assert( colors[0] < 0x100 && colors[1] < 0x100 && colors[2] < 0x100 );
727 color.sprintf("#%02x%02x%02x", colors[0], colors[1], colors[2] );
728 // qDebug( "trying to add fixed color string '%s'", color.latin1() );
729 if ( attr->decl()->setProperty(id, DOMString(color), false) )
733 attr->decl()->setProperty(id, CSS_VAL_BLACK, false);
736 void HTMLElementImpl::createMappedDecl(HTMLAttributeImpl* attr)
738 CSSMappedAttributeDeclarationImpl* decl = new CSSMappedAttributeDeclarationImpl(0);
740 decl->setParent(getDocument()->elementSheet());
742 decl->setStrictParsing(false); // Mapped attributes are just always quirky.
745 DOMString HTMLElementImpl::innerHTML() const
747 return createMarkup(this, ChildrenOnly);
750 DOMString HTMLElementImpl::outerHTML() const
752 return createMarkup(this);
755 DOMString HTMLElementImpl::innerText() const
757 // We need to update layout, since plainText uses line boxes in the render tree.
758 getDocument()->updateLayout();
759 return plainText(Range(const_cast<HTMLElementImpl *>(this), 0,
760 const_cast<HTMLElementImpl *>(this), childNodeCount()));
763 DOMString HTMLElementImpl::outerText() const
765 // Getting outerText is the same as getting innerText, only
766 // setting is different. You would think this should get the plain
767 // text for the outer range, but this is wrong, <br> for instance
768 // would return different values for inner and outer text by such
769 // a rule, but it doesn't in WinIE, and we want to match that.
773 DocumentFragmentImpl *HTMLElementImpl::createContextualFragment(const DOMString &html)
775 // the following is in accordance with the definition as used by IE
776 if( endTagRequirement(id()) == FORBIDDEN )
778 // IE disallows innerHTML on inline elements. I don't see why we should have this restriction, as our
779 // dhtml engine can cope with it. Lars
780 //if ( isInline() ) return false;
792 if ( !getDocument()->isHTMLDocument() )
795 DocumentFragmentImpl *fragment = new DocumentFragmentImpl( docPtr() );
798 HTMLTokenizer tok(docPtr(), fragment);
799 tok.setForceSynchronous(true); // disable asynchronous parsing
800 tok.write( html.string(), true );
802 assert(!tok.processingData()); // make sure we're done (see 3963151)
805 // Exceptions are ignored because none ought to happen here.
806 int ignoredExceptionCode;
808 // we need to pop <html> and <body> elements and remove <head> to
809 // accomadate folks passing complete HTML documents to make the
810 // child of an element.
813 for (NodeImpl *node = fragment->firstChild(); node != NULL; node = nextNode) {
814 nextNode = node->nextSibling();
816 if (node->id() == ID_HTML || node->id() == ID_BODY) {
817 NodeImpl *firstChild = node->firstChild();
818 if (firstChild != NULL) {
819 nextNode = firstChild;
822 for (NodeImpl *child = firstChild; child != NULL; child = nextChild) {
823 nextChild = child->nextSibling();
825 node->removeChild(child, ignoredExceptionCode);
826 fragment->insertBefore(child, node, ignoredExceptionCode);
829 fragment->removeChild(node, ignoredExceptionCode);
830 } else if (node->id() == ID_HEAD) {
831 fragment->removeChild(node, ignoredExceptionCode);
833 // Important to do this deref after removeChild, because if the only thing
834 // keeping a node around is a parent that is non-0, removeChild will not
835 // delete the node. This works fine in JavaScript because there's always
836 // a ref of the node, but here in C++ we need to do it explicitly.
840 // Trick to get the fragment back to the floating state, with 0
841 // refs but not destroyed.
842 fragment->setParent(this);
844 fragment->setParent(0);
849 void HTMLElementImpl::setInnerHTML(const DOMString &html, int &exception)
851 DocumentFragmentImpl *fragment = createContextualFragment( html );
852 if (fragment == NULL) {
853 exception = DOMException::NO_MODIFICATION_ALLOWED_ERR;
858 appendChild(fragment, exception);
861 void HTMLElementImpl::setOuterHTML(const DOMString &html, int &exception)
863 NodeImpl *p = parent();
864 if (!p || !p->isHTMLElement()) {
865 exception = DOMException::NO_MODIFICATION_ALLOWED_ERR;
868 HTMLElementImpl *parent = static_cast<HTMLElementImpl *>(p);
869 DocumentFragmentImpl *fragment = parent->createContextualFragment( html );
872 exception = DOMException::NO_MODIFICATION_ALLOWED_ERR;
877 parentNode()->replaceChild(fragment, this, exception);
882 void HTMLElementImpl::setInnerText(const DOMString &text, int &exception)
884 // following the IE specs.
885 if (endTagRequirement(id()) == FORBIDDEN) {
886 exception = DOMException::NO_MODIFICATION_ALLOWED_ERR;
890 // IE disallows innerText on inline elements. I don't see why we should have this restriction, as our
891 // dhtml engine can cope with it. Lars
892 //if ( isInline() ) return false;
904 exception = DOMException::NO_MODIFICATION_ALLOWED_ERR;
911 appendChild(new TextImpl(docPtr(), text), exception);
914 void HTMLElementImpl::setOuterText(const DOMString &text, int &exception)
916 // following the IE specs.
917 if( endTagRequirement(id()) == FORBIDDEN ) {
918 exception = DOMException::NO_MODIFICATION_ALLOWED_ERR;
932 exception = DOMException::NO_MODIFICATION_ALLOWED_ERR;
938 NodeImpl *parent = parentNode();
941 exception = DOMException::NO_MODIFICATION_ALLOWED_ERR;
945 TextImpl *t = new TextImpl(docPtr(), text);
946 parent->replaceChild(t, this, exception);
950 // is previous node a text node? if so, merge into it
951 NodeImpl *prev = t->previousSibling();
952 if (prev && prev->isTextNode()) {
953 TextImpl *textPrev = static_cast<TextImpl *>(prev);
954 textPrev->appendData(t->data(), exception);
957 t->parentNode()->removeChild(t, exception);
963 // is next node a text node? if so, merge it in
964 NodeImpl *next = t->nextSibling();
965 if (next && next->isTextNode()) {
966 TextImpl *textNext = static_cast<TextImpl *>(next);
967 t->appendData(textNext->data(), exception);
970 textNext->parentNode()->removeChild(textNext, exception);
977 DOMString HTMLElementImpl::namespaceURI() const
979 // For HTML documents, we treat HTML elements as having no namespace. But for XML documents
980 // the elements have the namespace defined in the XHTML spec
981 if (getDocument()->isHTMLDocument())
984 return XHTML_NAMESPACE;
987 void HTMLElementImpl::addHTMLAlignment(HTMLAttributeImpl* attr)
989 //qDebug("alignment is %s", alignment.string().latin1() );
990 // vertical alignment with respect to the current baseline of the text
991 // right or left means floating images
994 const AtomicString& alignment = attr->value();
995 if ( strcasecmp( alignment, "absmiddle" ) == 0 ) {
996 propvalign = CSS_VAL_MIDDLE;
997 } else if ( strcasecmp( alignment, "absbottom" ) == 0 ) {
998 propvalign = CSS_VAL_BOTTOM;
999 } else if ( strcasecmp( alignment, "left" ) == 0 ) {
1000 propfloat = CSS_VAL_LEFT;
1001 propvalign = CSS_VAL_TOP;
1002 } else if ( strcasecmp( alignment, "right" ) == 0 ) {
1003 propfloat = CSS_VAL_RIGHT;
1004 propvalign = CSS_VAL_TOP;
1005 } else if ( strcasecmp( alignment, "top" ) == 0 ) {
1006 propvalign = CSS_VAL_TOP;
1007 } else if ( strcasecmp( alignment, "middle" ) == 0 ) {
1008 propvalign = CSS_VAL__KHTML_BASELINE_MIDDLE;
1009 } else if ( strcasecmp( alignment, "center" ) == 0 ) {
1010 propvalign = CSS_VAL_MIDDLE;
1011 } else if ( strcasecmp( alignment, "bottom" ) == 0 ) {
1012 propvalign = CSS_VAL_BASELINE;
1013 } else if ( strcasecmp ( alignment, "texttop") == 0 ) {
1014 propvalign = CSS_VAL_TEXT_TOP;
1017 if ( propfloat != -1 )
1018 addCSSProperty( attr, CSS_PROP_FLOAT, propfloat );
1019 if ( propvalign != -1 )
1020 addCSSProperty( attr, CSS_PROP_VERTICAL_ALIGN, propvalign );
1023 bool HTMLElementImpl::isFocusable() const
1025 return isContentEditable() && parent() && !parent()->isContentEditable();
1028 bool HTMLElementImpl::isContentEditable() const
1030 if (getDocument()->part() && getDocument()->part()->isContentEditable())
1033 getDocument()->updateRendering();
1037 return parentNode()->isContentEditable();
1042 return renderer()->style()->userModify() == READ_WRITE;
1045 DOMString HTMLElementImpl::contentEditable() const
1047 getDocument()->updateRendering();
1052 switch (renderer()->style()->userModify()) {
1063 void HTMLElementImpl::setContentEditable(HTMLAttributeImpl* attr)
1065 KHTMLPart *part = getDocument()->part();
1066 const AtomicString& enabled = attr->value();
1067 if (enabled.isEmpty() || strcasecmp(enabled, "true") == 0) {
1068 addCSSProperty(attr, CSS_PROP__KHTML_USER_MODIFY, CSS_VAL_READ_WRITE);
1070 part->applyEditingStyleToElement(this);
1072 else if (strcasecmp(enabled, "false") == 0) {
1073 addCSSProperty(attr, CSS_PROP__KHTML_USER_MODIFY, CSS_VAL_READ_ONLY);
1075 part->removeEditingStyleFromElement(this);
1077 else if (strcasecmp(enabled, "inherit") == 0) {
1078 addCSSProperty(attr, CSS_PROP__KHTML_USER_MODIFY, CSS_VAL_INHERIT);
1080 part->removeEditingStyleFromElement(this);
1084 void HTMLElementImpl::setContentEditable(const DOMString &enabled) {
1085 if (enabled == "inherit") {
1087 removeAttribute(ATTR_CONTENTEDITABLE, exceptionCode);
1090 setAttribute(ATTR_CONTENTEDITABLE, enabled.isEmpty() ? "true" : enabled);
1093 void HTMLElementImpl::click(bool sendMouseEvents)
1097 RenderObject *r = renderer();
1099 r->absolutePosition(x,y);
1101 // send mousedown and mouseup before the click, if requested
1102 if (sendMouseEvents) {
1103 QMouseEvent pressEvt(QEvent::MouseButtonPress, QPoint(x,y), Qt::LeftButton, 0);
1104 dispatchMouseEvent(&pressEvt, EventImpl::MOUSEDOWN_EVENT);
1105 QMouseEvent upEvent(QEvent::MouseButtonRelease, QPoint(x,y), Qt::LeftButton, 0);
1106 dispatchMouseEvent(&upEvent, EventImpl::MOUSEUP_EVENT);
1109 // always send click
1110 QMouseEvent clickEvent(QEvent::MouseButtonRelease, QPoint(x,y), Qt::LeftButton, 0);
1111 dispatchMouseEvent(&clickEvent, EventImpl::KHTML_CLICK_EVENT);
1114 // accessKeyAction is used by the accessibility support code
1115 // to send events to elements that our JavaScript caller does
1116 // does not. The elements JS is interested in have subclasses
1117 // that override this method to direct the click appropriately.
1118 // Here in the base class, then, we only send the click if
1119 // the caller wants it to go to any HTMLElementImpl, and we say
1120 // to send the mouse events in addition to the click.
1121 void HTMLElementImpl::accessKeyAction(bool sendToAnyElement)
1123 if (sendToAnyElement)
1127 DOMString HTMLElementImpl::toString() const
1129 if (!hasChildNodes()) {
1130 DOMString result = openTagStartToString();
1133 if (endTagRequirement(id()) == REQUIRED) {
1135 result += tagName();
1142 return ElementImpl::toString();
1145 CSSStyleDeclarationImpl *HTMLElementImpl::style()
1147 return getInlineStyleDecl();
1150 DOMString HTMLElementImpl::idDOM() const
1152 return getAttribute(ATTR_ID);
1155 void HTMLElementImpl::setId(const DOMString &value)
1157 setAttribute(ATTR_ID, value);
1160 DOMString HTMLElementImpl::title() const
1162 return getAttribute(ATTR_TITLE);
1165 void HTMLElementImpl::setTitle(const DOMString &value)
1167 setAttribute(ATTR_TITLE, value);
1170 DOMString HTMLElementImpl::lang() const
1172 return getAttribute(ATTR_LANG);
1175 void HTMLElementImpl::setLang(const DOMString &value)
1177 setAttribute(ATTR_LANG, value);
1180 DOMString HTMLElementImpl::dir() const
1182 return getAttribute(ATTR_DIR);
1185 void HTMLElementImpl::setDir(const DOMString &value)
1187 setAttribute(ATTR_DIR, value);
1190 DOMString HTMLElementImpl::className() const
1192 return getAttribute(ATTR_CLASS);
1195 void HTMLElementImpl::setClassName(const DOMString &value)
1197 setAttribute(ATTR_CLASS, value);
1200 SharedPtr<HTMLCollectionImpl> HTMLElementImpl::children()
1202 return SharedPtr<HTMLCollectionImpl>(new HTMLCollectionImpl(this, HTMLCollectionImpl::NODE_CHILDREN));
1205 // -------------------------------------------------------------------------
1207 HTMLGenericElementImpl::HTMLGenericElementImpl(DocumentPtr *doc, ushort i)
1208 : HTMLElementImpl(doc)
1213 NodeImpl::Id HTMLGenericElementImpl::id() const