File indexing completed on 2024-05-05 16:11:38

0001 /**
0002  * This file is part of the DOM implementation for KDE.
0003  *
0004  * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
0005  *           (C) 1999 Antti Koivisto (koivisto@kde.org)
0006  *           (C) 2001 Peter Kelly (pmk@post.com)
0007  *           (C) 2001 Dirk Mueller (mueller@kde.org)
0008  *           (C) 2004, 2005, 2006, 2007 Apple Inc. All rights reserved.
0009  *           (C) 2005, 2008 Maksim Orlovich (maksim@kde.org)
0010  *           (C) 2006 Allan Sandfeld Jensen (kde@carewolf.com)
0011  *
0012  * This library is free software; you can redistribute it and/or
0013  * modify it under the terms of the GNU Library General Public
0014  * License as published by the Free Software Foundation; either
0015  * version 2 of the License, or (at your option) any later version.
0016  *
0017  * This library is distributed in the hope that it will be useful,
0018  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0019  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0020  * Library General Public License for more details.
0021  *
0022  * You should have received a copy of the GNU Library General Public License
0023  * along with this library; see the file COPYING.LIB.  If not, write to
0024  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0025  * Boston, MA 02110-1301, USA.
0026  */
0027 
0028 //#define EVENT_DEBUG
0029 
0030 #include "dom_elementimpl.h"
0031 
0032 #include <dom/dom_exception.h>
0033 #include <dom/dom_node.h>
0034 #include <dom/html_image.h>
0035 #include "dom_textimpl.h"
0036 #include "dom_docimpl.h"
0037 #include "dom2_eventsimpl.h"
0038 #include "dom_restyler.h"
0039 #include "dom_xmlimpl.h"
0040 
0041 #include <html/dtd.h>
0042 #include <html/htmlparser.h>
0043 #include <html/html_imageimpl.h>
0044 
0045 #include <rendering/render_canvas.h>
0046 #include <css/css_valueimpl.h>
0047 #include <css/css_stylesheetimpl.h>
0048 #include <css/cssstyleselector.h>
0049 #include <css/cssvalues.h>
0050 #include <css/cssproperties.h>
0051 #include <khtml_part.h>
0052 #include <khtmlview.h>
0053 
0054 #include <editing/editing_p.h>
0055 #include <editing/editor.h>
0056 
0057 #include <QTextStream>
0058 #include <QTextDocument>
0059 #include "khtml_debug.h"
0060 #include <stdlib.h>
0061 
0062 #include <wtf/HashMap.h>
0063 
0064 // ### support default attributes
0065 // ### dispatch mutation events
0066 // ### check for INVALID_CHARACTER_ERR where appropriate
0067 
0068 using namespace khtml;
0069 
0070 namespace DOM
0071 {
0072 
0073 AttrImpl::AttrImpl(ElementImpl *element, DocumentImpl *docPtr, NamespaceName namespacename, LocalName localName, PrefixName prefix, DOMStringImpl *value)
0074     : NodeBaseImpl(docPtr)
0075 {
0076     m_value = value;
0077     m_value->ref();
0078 
0079     m_namespace = namespacename;
0080     m_localName = localName;
0081     m_prefix = prefix;
0082 
0083     // When creating the text node initially, we want element = 0,
0084     // so we don't attempt to update the getElementById cache or
0085     // call parseAttribute, etc. This is because we're normally lazily,
0086     // from previous attributes, so there is nothing really changing
0087     m_element = nullptr;
0088     createTextChild();
0089     m_element = element;
0090 }
0091 
0092 AttrImpl::~AttrImpl()
0093 {
0094     m_value->deref();
0095 }
0096 
0097 DOMString AttrImpl::nodeName() const
0098 {
0099     return name();
0100 }
0101 
0102 unsigned short AttrImpl::nodeType() const
0103 {
0104     return Node::ATTRIBUTE_NODE;
0105 }
0106 
0107 DOMString AttrImpl::prefix() const
0108 {
0109     return m_prefix.toString();
0110 }
0111 
0112 void AttrImpl::setPrefix(const DOMString &_prefix, int &exceptioncode)
0113 {
0114     checkSetPrefix(_prefix, exceptioncode);
0115     if (exceptioncode) {
0116         return;
0117     }
0118 
0119     m_prefix = PrefixName::fromString(_prefix);
0120 }
0121 
0122 DOMString AttrImpl::namespaceURI() const
0123 {
0124     if (m_htmlCompat) {
0125         return DOMString();
0126     }
0127     return m_namespace.toString();
0128 }
0129 
0130 DOMString AttrImpl::localName() const
0131 {
0132     return m_localName.toString();
0133 }
0134 
0135 DOMString AttrImpl::nodeValue() const
0136 {
0137     return m_value;
0138 }
0139 
0140 DOMString AttrImpl::name() const
0141 {
0142     DOMString n = m_localName.toString();
0143 
0144     // compat mode always return attribute names in lowercase.
0145     // that's not formally in the specification, but common
0146     // practice - a w3c erratum to DOM L2 is pending.
0147     if (m_htmlCompat) {
0148         n = n.lower();
0149     }
0150 
0151     DOMString p = m_prefix.toString();
0152     if (!p.isEmpty()) {
0153         return p + DOMString(":") + n;
0154     }
0155 
0156     return n;
0157 }
0158 
0159 void AttrImpl::createTextChild()
0160 {
0161     // add a text node containing the attribute value
0162     if (m_value->length() > 0) {
0163         TextImpl *textNode = ownerDocument()->createTextNode(m_value);
0164 
0165         // We want to use addChild and not appendChild here to avoid triggering
0166         // mutation events. childrenChanged() will still be called.
0167         addChild(textNode);
0168     }
0169 }
0170 
0171 void AttrImpl::childrenChanged()
0172 {
0173     NodeBaseImpl::childrenChanged();
0174 
0175     // update value
0176     DOMStringImpl *oldVal = m_value;
0177     m_value = new DOMStringImpl((QChar *)nullptr, 0);
0178     m_value->ref();
0179     for (NodeImpl *n = firstChild(); n; n = n->nextSibling()) {
0180         DOMStringImpl *data = static_cast<const TextImpl *>(n)->string();
0181         m_value->append(data);
0182     }
0183 
0184     if (m_element) {
0185         int curr = id();
0186         if (curr == ATTR_ID) {
0187             m_element->updateId(oldVal, m_value);
0188         }
0189         m_element->parseAttribute(this);
0190         m_element->attributeChanged(curr);
0191     }
0192 
0193     oldVal->deref();
0194 }
0195 
0196 void AttrImpl::setValue(const DOMString &v, int &exceptioncode)
0197 {
0198     exceptioncode = 0;
0199 
0200     // do not interpret entities in the string, it is literal!
0201 
0202     // NO_MODIFICATION_ALLOWED_ERR: Raised when the node is readonly
0203     if (isReadOnly()) {
0204         exceptioncode = DOMException::NO_MODIFICATION_ALLOWED_ERR;
0205         return;
0206     }
0207 
0208     // ### what to do on 0 ?
0209     if (v.isNull()) {
0210         exceptioncode = DOMException::DOMSTRING_SIZE_ERR;
0211         return;
0212     }
0213 
0214     if (m_value == v.implementation()) {
0215         return;
0216     }
0217 
0218     int e = 0;
0219     removeChildren();
0220     appendChild(ownerDocument()->createTextNode(v.implementation()), e);
0221 }
0222 
0223 void AttrImpl::rewriteValue(const DOMString &newValue)
0224 {
0225     int ec;
0226 
0227     // We want to avoid any notifications, so temporarily set m_element to 0
0228     ElementImpl *saveElement = m_element;
0229     m_element = nullptr;
0230     setValue(newValue, ec);
0231     m_element = saveElement;
0232 }
0233 
0234 void AttrImpl::setNodeValue(const DOMString &v, int &exceptioncode)
0235 {
0236     exceptioncode = 0;
0237     // NO_MODIFICATION_ALLOWED_ERR: taken care of by setValue()
0238     setValue(v, exceptioncode);
0239 }
0240 
0241 WTF::PassRefPtr<NodeImpl> AttrImpl::cloneNode(bool /*deep*/)
0242 {
0243     AttrImpl *attr = new AttrImpl(nullptr, docPtr(), m_namespace, m_localName, m_prefix, m_value);
0244     attr->setHTMLCompat(m_htmlCompat);
0245     return attr;
0246 }
0247 
0248 // DOM Section 1.1.1
0249 bool AttrImpl::childAllowed(NodeImpl *newChild)
0250 {
0251     if (!newChild) {
0252         return false;
0253     }
0254 
0255     return childTypeAllowed(newChild->nodeType());
0256 }
0257 
0258 bool AttrImpl::childTypeAllowed(unsigned short type)
0259 {
0260     switch (type) {
0261     case Node::TEXT_NODE:
0262     case Node::ENTITY_REFERENCE_NODE:
0263         return true;
0264         break;
0265     default:
0266         return false;
0267     }
0268 }
0269 
0270 DOMString AttrImpl::toString() const
0271 {
0272     DOMString result;
0273 
0274     result += nodeName();
0275 
0276     // FIXME: substitute entities for any instances of " or ' --
0277     // maybe easier to just use text value and ignore existing
0278     // entity refs?
0279 
0280     if (!nodeValue().isEmpty()) {
0281         //remove the else once the AttributeImpl changes are merged
0282         result += "=\"";
0283         result += nodeValue();
0284         result += "\"";
0285     }
0286 
0287     return result;
0288 }
0289 
0290 void AttrImpl::setElement(ElementImpl *element)
0291 {
0292     m_element = element;
0293 }
0294 
0295 // -------------------------------------------------------------------------
0296 
0297 void AttributeImpl::setValue(DOMStringImpl *value, ElementImpl *element)
0298 {
0299     assert(value);
0300     if (m_localName.id()) {
0301         if (m_data.value == value) {
0302             return;
0303         }
0304 
0305         if (element && id() == ATTR_ID) {
0306             element->updateId(m_data.value, value);
0307         }
0308 
0309         m_data.value->deref();
0310         m_data.value = value;
0311         m_data.value->ref();
0312 
0313         if (element) {
0314             element->parseAttribute(this);
0315             element->attributeChanged(id());
0316         }
0317     } else {
0318         int exceptioncode = 0;
0319         m_data.attr->setValue(value, exceptioncode);
0320         // AttrImpl::setValue() calls parseAttribute()
0321     }
0322 }
0323 
0324 void AttributeImpl::rewriteValue(const DOMString &newValue)
0325 {
0326     if (m_localName.id()) {
0327         // We may have m_data.value == null if we were given a normalized value
0328         // off a removeAttribute (which would call parseNullAttribute()).
0329         // Ignore such requests.
0330         if (!m_data.value) {
0331             return;
0332         }
0333 
0334         DOMStringImpl *value = newValue.implementation();
0335         if (m_data.value == value) {
0336             return;
0337         }
0338 
0339         m_data.value->deref();
0340         m_data.value = value;
0341         m_data.value->ref();
0342     } else {
0343         m_data.attr->rewriteValue(newValue);
0344     }
0345 }
0346 
0347 AttrImpl *AttributeImpl::createAttr(ElementImpl *element, DocumentImpl *docPtr)
0348 {
0349     if (m_localName.id()) {
0350         AttrImpl *attr = new AttrImpl(element, docPtr, m_namespace, m_localName, m_prefix, m_data.value);
0351         if (!attr) {
0352             return nullptr;
0353         }
0354         attr->setHTMLCompat(element->htmlCompat());
0355         m_data.value->deref();
0356         m_data.attr = attr;
0357         m_data.attr->ref();
0358         m_localName = emptyLocalName; /* "has implementation" flag */
0359     }
0360 
0361     return m_data.attr;
0362 }
0363 
0364 void AttributeImpl::free()
0365 {
0366     if (m_localName.id()) {
0367         m_data.value->deref();
0368     } else {
0369         m_data.attr->setElement(nullptr);
0370         m_data.attr->deref();
0371     }
0372 }
0373 
0374 // -------------------------------------------------------------------------
0375 
0376 class ElementRareDataImpl
0377 {
0378 public:
0379     ElementRareDataImpl();
0380     void resetComputedStyle();
0381     short tabIndex() const
0382     {
0383         return m_tabIndex;
0384     }
0385     void setTabIndex(short _tabIndex)
0386     {
0387         m_tabIndex = _tabIndex;
0388         m_hasTabIndex = true;
0389     }
0390 
0391     RenderStyle *m_computedStyle;
0392     signed short m_tabIndex;
0393     bool m_hasTabIndex;
0394 };
0395 
0396 typedef WTF::HashMap<const ElementImpl *, ElementRareDataImpl *> ElementRareDataMap;
0397 
0398 static ElementRareDataMap &rareDataMap()
0399 {
0400     static ElementRareDataMap *dataMap = new ElementRareDataMap;
0401     return *dataMap;
0402 }
0403 
0404 static ElementRareDataImpl *rareDataFromMap(const ElementImpl *element)
0405 {
0406     return rareDataMap().get(element);
0407 }
0408 
0409 inline ElementRareDataImpl::ElementRareDataImpl()
0410     : m_computedStyle(nullptr), m_tabIndex(0), m_hasTabIndex(false)
0411 {}
0412 
0413 void ElementRareDataImpl::resetComputedStyle()
0414 {
0415     if (!m_computedStyle) {
0416         return;
0417     }
0418     m_computedStyle->deref();
0419     m_computedStyle = nullptr;
0420 }
0421 
0422 // -------------------------------------------------------------------------
0423 
0424 ElementImpl::ElementImpl(DocumentImpl *doc)
0425     : NodeBaseImpl(doc)
0426 {
0427     namedAttrMap = nullptr;
0428     m_style.inlineDecls = nullptr;
0429     m_prefix = emptyPrefixName;
0430 }
0431 
0432 ElementImpl::~ElementImpl()
0433 {
0434     if (namedAttrMap) {
0435         namedAttrMap->detachFromElement();
0436         namedAttrMap->deref();
0437     }
0438 
0439     if (m_style.inlineDecls) {
0440         if (CSSStyleDeclarationImpl *ild = inlineStyleDecls()) {
0441             // remove inline declarations
0442             ild->setNode(nullptr);
0443             ild->setParent(nullptr);
0444             ild->deref();
0445         }
0446         if (CSSStyleDeclarationImpl *ncd = nonCSSStyleDecls()) {
0447             // remove presentational declarations
0448             ncd->setNode(nullptr);
0449             ncd->setParent(nullptr);
0450             ncd->deref();
0451             delete m_style.combinedDecls;
0452         }
0453     }
0454 
0455     if (!m_elementHasRareData) {
0456         ASSERT(!rareDataMap().contains(this));
0457     } else {
0458         ElementRareDataMap &dataMap = rareDataMap();
0459         ElementRareDataMap::iterator it = dataMap.find(this);
0460         ASSERT(it != dataMap.end());
0461         delete it->second;
0462         dataMap.remove(it);
0463     }
0464 }
0465 
0466 ElementRareDataImpl *ElementImpl::rareData()
0467 {
0468     return m_elementHasRareData ? rareDataFromMap(this) : nullptr;
0469 }
0470 
0471 const ElementRareDataImpl *ElementImpl::rareData() const
0472 {
0473     return m_elementHasRareData ? rareDataFromMap(this) : nullptr;
0474 }
0475 
0476 ElementRareDataImpl *ElementImpl::createRareData()
0477 {
0478     if (m_elementHasRareData) {
0479         return rareDataMap().get(this);
0480     }
0481     ASSERT(!rareDataMap().contains(this));
0482     ElementRareDataImpl *data = new ElementRareDataImpl();
0483     rareDataMap().set(this, data);
0484     m_elementHasRareData = true;
0485     return data;
0486 }
0487 
0488 void ElementImpl::removeAttribute(NodeImpl::Id id, int &exceptioncode)
0489 {
0490     if (namedAttrMap) {
0491         namedAttrMap->removeNamedItem(id, emptyPrefixName, false, exceptioncode);
0492         if (exceptioncode == DOMException::NOT_FOUND_ERR) {
0493             exceptioncode = 0;
0494         }
0495     }
0496 }
0497 
0498 unsigned short ElementImpl::nodeType() const
0499 {
0500     return Node::ELEMENT_NODE;
0501 }
0502 
0503 DOMString ElementImpl::localName() const
0504 {
0505     return LocalName::fromId(id()).toString();
0506 }
0507 
0508 DOMString ElementImpl::tagName() const
0509 {
0510     DOMString tn = LocalName::fromId(id()).toString();
0511 
0512     if (m_htmlCompat) {
0513         tn = tn.upper();
0514     }
0515 
0516     DOMString prefix = m_prefix.toString();
0517     if (!prefix.isEmpty()) {
0518         return prefix + DOMString(":") + tn;
0519     }
0520 
0521     return tn;
0522 }
0523 
0524 DOMString ElementImpl::nonCaseFoldedTagName() const
0525 {
0526     DOMString tn = LocalName::fromId(id()).toString();
0527 
0528     DOMString prefix = m_prefix.toString();
0529     if (!prefix.isEmpty()) {
0530         return prefix + DOMString(":") + tn;
0531     }
0532 
0533     return tn;
0534 }
0535 
0536 /*DOMStringImpl* ElementImpl::getAttributeImpl(NodeImpl::Id id, PrefixName prefix, bool nsAware) const
0537 {
0538     return namedAttrMap ? namedAttrMap->getValue(id, prefix, nsAware) : 0;
0539 }*/
0540 
0541 void ElementImpl::setAttribute(NodeImpl::Id id, const PrefixName &prefix, bool nsAware, const DOMString &value, int &exceptioncode)
0542 {
0543     // NO_MODIFICATION_ALLOWED_ERR: Raised when the node is readonly
0544     if (isReadOnly()) {
0545         exceptioncode = DOMException::NO_MODIFICATION_ALLOWED_ERR;
0546         return;
0547     }
0548     attributes()->setValue(id, value.implementation(), prefix, nsAware);
0549 }
0550 
0551 void ElementImpl::setAttributeNS(const DOMString &namespaceURI, const DOMString &qualifiedName,
0552                                  const DOMString &value, int &exceptioncode)
0553 {
0554     // NO_MODIFICATION_ALLOWED_ERR: Raised when the node is readonly
0555     if (isReadOnly()) {
0556         exceptioncode = DOMException::NO_MODIFICATION_ALLOWED_ERR;
0557         return;
0558     }
0559     int colonPos;
0560     if (!DOM::checkQualifiedName(qualifiedName, namespaceURI, &colonPos,
0561                                  false/*nameCanBeNull*/, false/*nameCanBeEmpty*/,
0562                                  &exceptioncode)) {
0563         return;
0564     }
0565     LocalName localname;
0566     PrefixName prefixname;
0567     splitPrefixLocalName(qualifiedName, prefixname, localname, m_htmlCompat, colonPos);
0568     NamespaceName namespacename = NamespaceName::fromString(namespaceURI);
0569     attributes()->setValue(makeId(namespacename.id(), localname.id()), value.implementation(), prefixname, true /*nsAware*/);
0570 }
0571 
0572 void ElementImpl::setAttribute(NodeImpl::Id id, const DOMString &value)
0573 {
0574     int exceptioncode = 0;
0575     setAttribute(id, emptyPrefixName, false, value, exceptioncode);
0576 }
0577 
0578 void ElementImpl::setBooleanAttribute(NodeImpl::Id id, bool b)
0579 {
0580     if (b) {
0581         setAttribute(id, "1");
0582     } else {
0583         int ec;
0584         removeAttribute(id, ec);
0585     }
0586 }
0587 
0588 void ElementImpl::setAttributeMap(NamedAttrMapImpl *list)
0589 {
0590     // If setting the whole map changes the id attribute, we need to
0591     // call updateId.
0592     DOMStringImpl *oldId = namedAttrMap ? namedAttrMap->getValue(ATTR_ID) : nullptr;
0593     DOMStringImpl *newId = list ? list->getValue(ATTR_ID) : nullptr;
0594 
0595     if (oldId || newId) {
0596         updateId(oldId, newId);
0597     }
0598 
0599     if (namedAttrMap) {
0600         namedAttrMap->detachFromElement();
0601         namedAttrMap->deref();
0602     }
0603 
0604     namedAttrMap = list;
0605 
0606     if (namedAttrMap) {
0607         namedAttrMap->ref();
0608         assert(namedAttrMap->m_element == nullptr);
0609         namedAttrMap->setElement(this);
0610         unsigned len = namedAttrMap->length();
0611         for (unsigned i = 0; i < len; i++) {
0612             parseAttribute(&namedAttrMap->m_attrs[i]);
0613             attributeChanged(namedAttrMap->m_attrs[i].id());
0614         }
0615     }
0616 }
0617 
0618 WTF::PassRefPtr<NodeImpl> ElementImpl::cloneNode(bool deep)
0619 {
0620     WTF::RefPtr<ElementImpl> clone; // Make sure to guard...
0621     clone = document()->createElementNS(namespaceURI(), nonCaseFoldedTagName() /* includes prefix*/);
0622     if (!clone) {
0623         return nullptr;
0624     }
0625     finishCloneNode(clone.get(), deep);
0626     return clone;
0627 }
0628 
0629 void ElementImpl::finishCloneNode(ElementImpl *clone, bool deep)
0630 {
0631     // clone attributes
0632     if (namedAttrMap || m_needsStyleAttributeUpdate) {
0633         clone->attributes()->copyAttributes(attributes(true));
0634     }
0635 
0636     assert(!m_needsStyleAttributeUpdate);   // ensured by previous line
0637 
0638     // clone individual style rules
0639     if (m_style.inlineDecls) {
0640         if (m_hasCombinedStyle) {
0641             if (!clone->m_hasCombinedStyle) {
0642                 clone->createNonCSSDecl();
0643             }
0644             if (m_style.combinedDecls->inlineDecls) {
0645                 *(clone->getInlineStyleDecls()) = *m_style.combinedDecls->inlineDecls;
0646             }
0647             *clone->m_style.combinedDecls->nonCSSDecls = *m_style.combinedDecls->nonCSSDecls;
0648         } else {
0649             *(clone->getInlineStyleDecls()) = *m_style.inlineDecls;
0650         }
0651     }
0652 
0653     // ### fold above style cloning into this function?
0654     clone->copyNonAttributeProperties(this);
0655 
0656     if (deep) {
0657         cloneChildNodes(clone);
0658     }
0659 
0660     // copy over our compatibility mode.
0661     clone->setHTMLCompat(htmlCompat());
0662 }
0663 
0664 bool ElementImpl::hasAttributes() const
0665 {
0666     return namedAttrMap && namedAttrMap->length() > 0;
0667 }
0668 
0669 bool ElementImpl::hasAttribute(const DOMString &name) const
0670 {
0671     LocalName localname;
0672     PrefixName prefixname;
0673     splitPrefixLocalName(name, prefixname, localname, m_htmlCompat);
0674     if (!localname.id()) {
0675         return false;
0676     }
0677     if (!namedAttrMap) {
0678         return false;
0679     }
0680     return namedAttrMap->getValue(makeId(emptyNamespace, localname.id()), prefixname, false) != nullptr;
0681 }
0682 
0683 bool ElementImpl::hasAttributeNS(const DOMString &namespaceURI,
0684                                  const DOMString &localName) const
0685 {
0686     NamespaceName namespacename = NamespaceName::fromString(namespaceURI);
0687     LocalName localname = LocalName::fromString(localName, m_htmlCompat ? IDS_NormalizeLower : IDS_CaseSensitive);
0688     NodeImpl::Id id = makeId(namespacename.id(), localname.id());
0689     if (!id) {
0690         return false;
0691     }
0692     if (!namedAttrMap) {
0693         return false;
0694     }
0695     return namedAttrMap->getValue(id, emptyPrefixName, true) != nullptr;
0696 }
0697 
0698 DOMString ElementImpl::getAttribute(const DOMString &name)
0699 {
0700     LocalName localname;
0701     PrefixName prefixname;
0702     splitPrefixLocalName(name, prefixname, localname, m_htmlCompat);
0703     if (!localname.id()) {
0704         return DOMString();
0705     }
0706     return getAttribute(makeId(emptyNamespace, localname.id()), prefixname, false /*nsAware*/);
0707 }
0708 
0709 void ElementImpl::setAttribute(const DOMString &name, const DOMString &value, int &exceptioncode)
0710 {
0711     int colon;
0712     if (!DOM::checkQualifiedName(name, "", &colon, false/*nameCanBeNull*/, false/*nameCanBeEmpty*/, &exceptioncode)) {
0713         return;
0714     }
0715     LocalName localname;
0716     PrefixName prefixname;
0717     splitPrefixLocalName(name, prefixname, localname, m_htmlCompat, colon);
0718     setAttribute(makeId(emptyNamespace, localname.id()), prefixname, false, value.implementation(), exceptioncode);
0719 }
0720 
0721 void ElementImpl::removeAttribute(const DOMString &name, int &exceptioncode)
0722 {
0723     LocalName localname;
0724     PrefixName prefixname;
0725     splitPrefixLocalName(name, prefixname, localname, m_htmlCompat);
0726 
0727     // FIXME what if attributes(false) == 0?
0728     attributes(false)->removeNamedItem(makeId(emptyNamespace, localname.id()), prefixname, false, exceptioncode);
0729 
0730     // it's allowed to remove attributes that don't exist.
0731     if (exceptioncode == DOMException::NOT_FOUND_ERR) {
0732         exceptioncode = 0;
0733     }
0734 }
0735 
0736 AttrImpl *ElementImpl::getAttributeNode(const DOMString &name)
0737 {
0738     LocalName localname;
0739     PrefixName prefixname;
0740     splitPrefixLocalName(name, prefixname, localname, m_htmlCompat);
0741 
0742     if (!localname.id()) {
0743         return nullptr;
0744     }
0745     if (!namedAttrMap) {
0746         return nullptr;
0747     }
0748 
0749     return static_cast<AttrImpl *>(attributes()->getNamedItem(makeId(emptyNamespace, localname.id()), prefixname, false));
0750 }
0751 
0752 Attr ElementImpl::setAttributeNode(AttrImpl *newAttr, int &exceptioncode)
0753 {
0754     if (!newAttr) {
0755         exceptioncode = DOMException::NOT_FOUND_ERR;
0756         return nullptr;
0757     }
0758     Attr r = attributes(false)->setNamedItem(newAttr, emptyPrefixName, true, exceptioncode);
0759     if (!exceptioncode) {
0760         newAttr->setOwnerElement(this);
0761     }
0762     return r;
0763 }
0764 
0765 Attr ElementImpl::removeAttributeNode(AttrImpl *oldAttr, int &exceptioncode)
0766 {
0767     if (!oldAttr || oldAttr->ownerElement() != this) {
0768         exceptioncode = DOMException::NOT_FOUND_ERR;
0769         return nullptr;
0770     }
0771 
0772     if (isReadOnly()) {
0773         exceptioncode = DOMException::NO_MODIFICATION_ALLOWED_ERR;
0774         return nullptr;
0775     }
0776 
0777     if (!namedAttrMap) {
0778         exceptioncode = DOMException::NOT_FOUND_ERR;
0779         return nullptr;
0780     }
0781 
0782     return attributes(false)->removeAttr(oldAttr);
0783 }
0784 
0785 DOMString ElementImpl::getAttributeNS(const DOMString &namespaceURI,
0786                                       const DOMString &localName,
0787                                       int &exceptioncode)
0788 {
0789     if (!localName.implementation()) {
0790         exceptioncode = DOMException::NOT_FOUND_ERR;
0791         return DOMString();
0792     }
0793 
0794     LocalName localname = LocalName::fromString(localName, m_htmlCompat ? IDS_NormalizeLower : IDS_CaseSensitive);
0795     NamespaceName namespacename = NamespaceName::fromString(namespaceURI);
0796 
0797     NodeImpl::Id id = makeId(namespacename.id(), localname.id());
0798     return getAttribute(id, emptyPrefixName, true);
0799 }
0800 
0801 void ElementImpl::removeAttributeNS(const DOMString &namespaceURI,
0802                                     const DOMString &localName,
0803                                     int &exceptioncode)
0804 {
0805     if (!localName.implementation()) {
0806         exceptioncode = DOMException::NOT_FOUND_ERR;
0807         return;
0808     }
0809 
0810     NamespaceName namespacename = NamespaceName::fromString(namespaceURI);
0811     LocalName localname = LocalName::fromString(localName, m_htmlCompat ? IDS_NormalizeLower : IDS_CaseSensitive);
0812 
0813     NodeImpl::Id id = makeId(namespacename.id(), localname.id());
0814     attributes(false)->removeNamedItem(id, emptyPrefixName, true, exceptioncode);
0815 }
0816 
0817 AttrImpl *ElementImpl::getAttributeNodeNS(const DOMString &namespaceURI,
0818         const DOMString &localName,
0819         int &exceptioncode)
0820 {
0821     if (!localName.implementation()) {
0822         exceptioncode = DOMException::NOT_FOUND_ERR;
0823         return nullptr;
0824     }
0825 
0826     NamespaceName namespacename = NamespaceName::fromString(namespaceURI);
0827     LocalName localname = LocalName::fromString(localName, m_htmlCompat ? IDS_NormalizeLower : IDS_CaseSensitive);
0828 
0829     NodeImpl::Id id = makeId(namespacename.id(), localname.id());
0830     if (!attributes(true)) {
0831         return nullptr;
0832     }
0833     return static_cast<AttrImpl *>(attributes()->getNamedItem(id, emptyPrefixName, true));
0834 }
0835 
0836 Attr ElementImpl::setAttributeNodeNS(AttrImpl *newAttr, int &exceptioncode)
0837 {
0838     if (!newAttr) {
0839         exceptioncode = DOMException::NOT_FOUND_ERR;
0840         return nullptr;
0841     }
0842     // WRONG_DOCUMENT_ERR and INUSE_ATTRIBUTE_ERR are already tested & thrown by setNamedItem
0843     Attr r = attributes(false)->setNamedItem(newAttr, emptyPrefixName, true, exceptioncode);
0844     if (!exceptioncode) {
0845         newAttr->setOwnerElement(this);
0846     }
0847     return r;
0848 }
0849 
0850 DOMString ElementImpl::nodeName() const
0851 {
0852     return tagName();
0853 }
0854 
0855 DOMString ElementImpl::namespaceURI() const
0856 {
0857     return NamespaceName::fromId(namespacePart(id())).toString();
0858 }
0859 
0860 void ElementImpl::setPrefix(const DOMString &_prefix, int &exceptioncode)
0861 {
0862     checkSetPrefix(_prefix, exceptioncode);
0863     if (exceptioncode) {
0864         return;
0865     }
0866     m_prefix = PrefixName::fromString(_prefix);
0867 }
0868 
0869 short ElementImpl::tabIndex() const
0870 {
0871     return m_elementHasRareData ? rareData()->tabIndex() : 0;
0872 }
0873 
0874 void ElementImpl::setTabIndex(short _tabIndex)
0875 {
0876     createRareData()->setTabIndex(_tabIndex);
0877 }
0878 
0879 void ElementImpl::setNoTabIndex()
0880 {
0881     if (!m_elementHasRareData) {
0882         return;
0883     }
0884     rareData()->m_hasTabIndex = false;
0885 }
0886 
0887 bool ElementImpl::hasTabIndex() const
0888 {
0889     return m_elementHasRareData ? rareData()->m_hasTabIndex : false;
0890 }
0891 
0892 void ElementImpl::defaultEventHandler(EventImpl *e)
0893 {
0894     if (!e->defaultHandled() && document()->part() && e->id() == EventImpl::KEYPRESS_EVENT && e->isKeyRelatedEvent()) {
0895         const KHTMLPart *part = document()->part();
0896         bool isContentEditableElement = part->isEditable() || (focused() && isContentEditable());
0897         if (isContentEditableElement || part->isCaretMode()) {
0898             if (document()->view() && document()->view()->caretKeyPressEvent(static_cast<KeyEventBaseImpl *>(e)->qKeyEvent())) {
0899                 e->setDefaultHandled();
0900                 return;
0901             }
0902             if (isContentEditableElement && part->editor()->handleKeyEvent(static_cast<KeyEventBaseImpl *>(e)->qKeyEvent())) {
0903                 e->setDefaultHandled();
0904                 return;
0905             }
0906         }
0907     }
0908 
0909     if (m_render && m_render->scrollsOverflow()) {
0910         switch (e->id()) {
0911         case EventImpl::KEYDOWN_EVENT:
0912         case EventImpl::KEYUP_EVENT:
0913         case EventImpl::KEYPRESS_EVENT:
0914             if (!focused() || e->target() != this) {
0915                 break;
0916             }
0917         // fall through
0918         case EventImpl::KHTML_MOUSEWHEEL_EVENT:
0919             if (m_render->handleEvent(*e)) {
0920                 e->setDefaultHandled();
0921             }
0922         default:
0923             break;
0924         }
0925     }
0926 }
0927 
0928 void ElementImpl::createAttributeMap() const
0929 {
0930     namedAttrMap = new NamedAttrMapImpl(const_cast<ElementImpl *>(this));
0931     namedAttrMap->ref();
0932 }
0933 
0934 RenderStyle *ElementImpl::styleForRenderer(RenderObject * /*parentRenderer*/)
0935 {
0936     return document()->styleSelector()->styleForElement(this);
0937 }
0938 
0939 RenderObject *ElementImpl::createRenderer(RenderArena *arena, RenderStyle *style)
0940 {
0941     if (document()->documentElement() == this && style->display() == NONE) {
0942         // Ignore display: none on root elements.  Force a display of block in that case.
0943         RenderBlock *result = new(arena) RenderBlock(this);
0944         if (result) {
0945             result->setStyle(style);
0946         }
0947         return result;
0948     }
0949     return RenderObject::createObject(this, style);
0950 }
0951 
0952 void ElementImpl::attach()
0953 {
0954     assert(!attached());
0955     assert(!m_render);
0956     assert(parentNode());
0957 
0958 #if SPEED_DEBUG < 1
0959     createRendererIfNeeded();
0960 #endif
0961 
0962     NodeBaseImpl::attach();
0963 }
0964 
0965 void ElementImpl::close()
0966 {
0967     NodeImpl::close();
0968 
0969     // Trigger all the addChild changes as one large dynamic appendChildren change
0970     if (attached()) {
0971         backwardsStructureChanged();
0972     }
0973 }
0974 
0975 void ElementImpl::detach()
0976 {
0977     document()->dynamicDomRestyler().resetDependencies(this);
0978 
0979     if (ElementRareDataImpl *rd = rareData()) {
0980         rd->resetComputedStyle();
0981     }
0982 
0983     NodeBaseImpl::detach();
0984 }
0985 
0986 void ElementImpl::structureChanged()
0987 {
0988     NodeBaseImpl::structureChanged();
0989 
0990     if (!document()->renderer()) {
0991         return;    // the document is about to be destroyed
0992     }
0993 
0994     document()->dynamicDomRestyler().restyleDependent(this, StructuralDependency);
0995     // In theory BackwardsStructurualDependencies are indifferent to prepend,
0996     // but it's too rare to optimize.
0997     document()->dynamicDomRestyler().restyleDependent(this, BackwardsStructuralDependency);
0998 }
0999 
1000 void ElementImpl::backwardsStructureChanged()
1001 {
1002     NodeBaseImpl::backwardsStructureChanged();
1003 
1004     if (!document()->renderer()) {
1005         return;    // the document is about to be destroyed
1006     }
1007 
1008     // Most selectors are not affected by append. Fire the few that are.
1009     document()->dynamicDomRestyler().restyleDependent(this, BackwardsStructuralDependency);
1010 }
1011 
1012 void ElementImpl::attributeChanged(NodeImpl::Id id)
1013 {
1014     if (!document()->renderer()) {
1015         return;    // the document is about to be destroyed
1016     }
1017 
1018 #if 0 // one-one dependencies for attributes disabled
1019     document()->dynamicDomRestyler().restyleDependent(this, AttributeDependency);
1020 #endif
1021     if (document()->dynamicDomRestyler().checkDependency(id, PersonalDependency)) {
1022         setChanged(true);
1023     }
1024     if (document()->dynamicDomRestyler().checkDependency(id, AncestorDependency)) {
1025         setChangedAscendentAttribute(true);
1026     }
1027     if (document()->dynamicDomRestyler().checkDependency(id, PredecessorDependency) && parent())
1028         // Any element that dependt on a predecessors attribute, also depend structurally on parent
1029     {
1030         parent()->structureChanged();
1031     }
1032 }
1033 
1034 void ElementImpl::recalcStyle(StyleChange change)
1035 {
1036     // ### should go away and be done in renderobject
1037     RenderStyle *_style = m_render ? m_render->style() : nullptr;
1038     bool hasParentRenderer = parent() ? parent()->attached() : false;
1039 
1040     if ((change > NoChange || changed())) {
1041         if (ElementRareDataImpl *rd = rareData()) {
1042             rd->resetComputedStyle();
1043         }
1044     }
1045 
1046 #if 0
1047     const char *debug;
1048     switch (change) {
1049     case NoChange: debug = "NoChange";
1050         break;
1051     case NoInherit: debug = "NoInherit";
1052         break;
1053     case Inherit: debug = "Inherit";
1054         break;
1055     case Force: debug = "Force";
1056         break;
1057     }
1058     qDebug("recalcStyle(%d: %s, changed: %d)[%p: %s]", change, debug, changed(), this, tagName().string().toLatin1().constData());
1059 #endif
1060     if (hasParentRenderer && (change >= Inherit || changed() || (change == NoInherit && affectedByNoInherit()))) {
1061         RenderStyle *newStyle = document()->styleSelector()->styleForElement(this);
1062         newStyle->ref();
1063         StyleChange ch = diff(_style, newStyle);
1064         if (ch == Detach) {
1065             if (attached()) {
1066                 detach();
1067             }
1068             // ### Suboptimal. Style gets calculated again.
1069             attach();
1070             // attach recalulates the style for all children. No need to do it twice.
1071             setChanged(false);
1072             setHasChangedChild(false);
1073             newStyle->deref();
1074             return;
1075         } else if (ch != NoChange) {
1076             if (m_render) {
1077                 m_render->setStyle(newStyle);
1078             }
1079         }
1080         newStyle->deref();
1081 
1082         if (change != Force) {
1083             change = ch;
1084         }
1085     }
1086     // If a changed attribute has ancestor dependencies, restyle all children
1087     if (changedAscendentAttribute()) {
1088         change = Force;
1089         setChangedAscendentAttribute(false);
1090     }
1091 
1092     NodeImpl *n;
1093     for (n = _first; n; n = n->nextSibling()) {
1094         if (change >= Inherit || n->hasChangedChild() || n->changed() ||
1095                 (change == NoInherit && n->affectedByNoInherit())
1096            ) {
1097             //qDebug("    (%p) calling recalcStyle on child %p/%s, change=%d", this, n, n->isElementNode() ? ((ElementImpl *)n)->tagName().string().toLatin1().constData() : n->isTextNode() ? "text" : "unknown", change );
1098             n->recalcStyle(change);
1099         }
1100     }
1101 
1102     setChanged(false);
1103     setHasChangedChild(false);
1104 }
1105 
1106 bool ElementImpl::isFocusableImpl(FocusType ft) const
1107 {
1108     if (m_render && m_render->scrollsOverflow()) {
1109         return true;
1110     }
1111 
1112     // See WAI-ARIA 1.0, UA implementor's guide, 3.1 for the rules this
1113     // implements.
1114     if (hasTabIndex()) {
1115         int ti = tabIndex();
1116 
1117         // Negative things are focusable, but not in taborder
1118         if (ti < 0) {
1119             return (ft != FT_Tab);
1120         } else { // ... while everything else is completely focusable
1121             return true;
1122         }
1123     }
1124 
1125     // Only make editable elements selectable if its parent element
1126     // is not editable. FIXME: this is not 100% right as non-editable elements
1127     // within editable elements are focusable too.
1128     return isContentEditable() && !(parentNode() && parentNode()->isContentEditable());
1129 }
1130 
1131 bool ElementImpl::isContentEditable() const
1132 {
1133     if (document()->part() && document()->part()->isEditable()) {
1134         return true;
1135     }
1136 
1137     // document()->updateRendering();
1138 
1139     if (!renderer()) {
1140         if (parentNode()) {
1141             return parentNode()->isContentEditable();
1142         } else {
1143             return false;
1144         }
1145     }
1146 
1147     return renderer()->style()->userInput() == UI_ENABLED;
1148 }
1149 
1150 void ElementImpl::setContentEditable(bool enabled)
1151 {
1152     // FIXME: the approach is flawed, better use an enum instead of bool
1153     int value;
1154     if (enabled) {
1155         value = CSS_VAL_ENABLED;
1156     } else {
1157         // Intelligently use "none" or "disabled", depending on the type of
1158         // element
1159         // FIXME: intelligence not impl'd yet
1160         value = CSS_VAL_NONE;
1161 
1162         // FIXME: reset caret if it is in this node or a child
1163     }/*end if*/
1164     // FIXME: use addCSSProperty when I get permission to move it here
1165 //    qCDebug(KHTML_LOG) << "CSS_PROP__KHTML_USER_INPUT: "<< value;
1166     getInlineStyleDecls()->setProperty(CSS_PROP__KHTML_USER_INPUT, value, false);
1167     setChanged();
1168 }
1169 
1170 // DOM Section 1.1.1
1171 bool ElementImpl::childAllowed(NodeImpl *newChild)
1172 {
1173     if (!childTypeAllowed(newChild->nodeType())) {
1174         return false;
1175     }
1176 
1177     // ### check xml element allowedness according to DTD
1178 
1179     // If either this node or the other node is an XML element node, allow regardless (we don't do DTD checks for XML
1180     // yet)
1181     if (isXMLElementNode() || newChild->isXMLElementNode()) {
1182         return true;
1183     } else {
1184         return checkChild(id(), newChild->id(), document()->inStrictMode());
1185     }
1186 }
1187 
1188 bool ElementImpl::childTypeAllowed(unsigned short type)
1189 {
1190     switch (type) {
1191     case Node::ELEMENT_NODE:
1192     case Node::TEXT_NODE:
1193     case Node::COMMENT_NODE:
1194     case Node::PROCESSING_INSTRUCTION_NODE:
1195     case Node::CDATA_SECTION_NODE:
1196     case Node::ENTITY_REFERENCE_NODE:
1197         return true;
1198         break;
1199     default:
1200         return false;
1201     }
1202 }
1203 
1204 void ElementImpl::scrollIntoView(bool /*alignToTop*/)
1205 {
1206     // ###
1207     qCWarning(KHTML_LOG) << "non-standard scrollIntoView() not implemented";
1208 }
1209 
1210 void ElementImpl::createNonCSSDecl()
1211 {
1212     assert(!m_hasCombinedStyle);
1213     CSSInlineStyleDeclarationImpl *ild = m_style.inlineDecls;
1214     m_style.combinedDecls = new CombinedStyleDecl;
1215     m_style.combinedDecls->inlineDecls = ild;
1216     CSSStyleDeclarationImpl *ncd = new CSSStyleDeclarationImpl(nullptr);
1217     m_style.combinedDecls->nonCSSDecls = ncd;
1218     ncd->ref();
1219     ncd->setParent(document()->elementSheet());
1220     ncd->setNode(this);
1221     ncd->setStrictParsing(false);
1222     m_hasCombinedStyle = true;
1223 }
1224 
1225 CSSInlineStyleDeclarationImpl *ElementImpl::getInlineStyleDecls()
1226 {
1227     if (!inlineStyleDecls()) {
1228         createInlineDecl();
1229     }
1230     return inlineStyleDecls();
1231 }
1232 
1233 void ElementImpl::createInlineDecl()
1234 {
1235     assert(!m_style.inlineDecls || (m_hasCombinedStyle && !m_style.combinedDecls->inlineDecls));
1236 
1237     CSSInlineStyleDeclarationImpl *dcl = new CSSInlineStyleDeclarationImpl(nullptr);
1238     dcl->ref();
1239     dcl->setParent(document()->elementSheet());
1240     dcl->setNode(this);
1241     dcl->setStrictParsing(!document()->inCompatMode());
1242     if (m_hasCombinedStyle) {
1243         m_style.combinedDecls->inlineDecls = dcl;
1244     } else {
1245         m_style.inlineDecls = dcl;
1246     }
1247 }
1248 
1249 void ElementImpl::dispatchAttrRemovalEvent(NodeImpl::Id /*id*/, DOMStringImpl * /*value*/)
1250 {
1251     // ### enable this stuff again
1252     if (!document()->hasListenerType(DocumentImpl::DOMATTRMODIFIED_LISTENER)) {
1253         return;
1254     }
1255     //int exceptioncode = 0;
1256     //dispatchEvent(new MutationEventImpl(EventImpl::DOMATTRMODIFIED_EVENT,true,false,attr,attr->value(),
1257     //attr->value(), document()->attrName(attr->id()),MutationEvent::REMOVAL),exceptioncode);
1258 }
1259 
1260 void ElementImpl::dispatchAttrAdditionEvent(NodeImpl::Id /*id*/, DOMStringImpl * /*value*/)
1261 {
1262     // ### enable this stuff again
1263     if (!document()->hasListenerType(DocumentImpl::DOMATTRMODIFIED_LISTENER)) {
1264         return;
1265     }
1266     //int exceptioncode = 0;
1267     //dispatchEvent(new MutationEventImpl(EventImpl::DOMATTRMODIFIED_EVENT,true,false,attr,attr->value(),
1268     //attr->value(),document()->attrName(attr->id()),MutationEvent::ADDITION),exceptioncode);
1269 }
1270 
1271 void ElementImpl::updateId(DOMStringImpl *oldId, DOMStringImpl *newId)
1272 {
1273     if (!inDocument()) {
1274         return;
1275     }
1276 
1277     if (oldId && oldId->l) {
1278         removeId(DOMString(oldId));
1279     }
1280 
1281     if (newId && newId->l) {
1282         addId(DOMString(newId));
1283     }
1284 }
1285 
1286 void ElementImpl::removeId(const DOMString &id)
1287 {
1288     document()->getElementByIdCache().remove(id, this);
1289 }
1290 
1291 void ElementImpl::addId(const DOMString &id)
1292 {
1293     document()->getElementByIdCache().add(id, this);
1294 }
1295 
1296 void ElementImpl::insertedIntoDocument()
1297 {
1298     // need to do superclass processing first so inDocument() is true
1299     // by the time we reach updateId
1300     NodeBaseImpl::insertedIntoDocument();
1301 
1302     if (hasID()) {
1303         DOMString id = getAttribute(ATTR_ID);
1304         updateId(nullptr, id.implementation());
1305     }
1306 }
1307 
1308 void ElementImpl::removedFromDocument()
1309 {
1310     if (hasID()) {
1311         DOMString id = getAttribute(ATTR_ID);
1312         updateId(id.implementation(), nullptr);
1313     }
1314 
1315     NodeBaseImpl::removedFromDocument();
1316 }
1317 
1318 DOMString ElementImpl::openTagStartToString(bool expandurls) const
1319 {
1320     DOMString result = DOMString("<") + nonCaseFoldedTagName();
1321 
1322     NamedAttrMapImpl *attrMap = attributes(true);
1323 
1324     if (attrMap) {
1325         unsigned numAttrs = attrMap->length();
1326         for (unsigned i = 0; i < numAttrs; i++) {
1327             result += " ";
1328 
1329             const AttributeImpl &attribute = attrMap->attributeAt(i);
1330             AttrImpl *attr = attribute.attr();
1331 
1332             if (attr) {
1333                 result += attr->toString();
1334             } else {
1335                 //FIXME: should use prefix too and depends on html/xhtml case
1336                 PrefixName prefix = attribute.m_prefix;
1337                 DOMString current;
1338                 if (prefix.id()) {
1339                     current = prefix.toString() + DOMString(":") + attribute.localName();
1340                 } else {
1341                     current = attribute.localName();
1342                 }
1343                 if (m_htmlCompat) {
1344                     current = current.lower();
1345                 }
1346                 result += current;
1347                 if (!attribute.value().isNull()) {
1348                     result += "=\"";
1349                     // FIXME: substitute entities for any instances of " or '
1350                     // Expand out all urls, i.e. the src and href attributes
1351                     if (expandurls && (attribute.id() == ATTR_SRC || attribute.id() == ATTR_HREF))
1352                         if (document()) {
1353                             //We need to sanitize the urls - strip out the passwords.
1354                             //FIXME:   are src=  and href=  the only places that might have a password and need to be sanitized?
1355                             QUrl safeURL(document()->completeURL(attribute.value().string()));
1356                             safeURL.setPassword(QString());
1357                             result += safeURL.toDisplayString().toHtmlEscaped();
1358                         } else {
1359                             qCWarning(KHTML_LOG) << "document() returned false";
1360                             result += attribute.value();
1361                         }
1362                     else {
1363                         result += attribute.value();
1364                     }
1365                     result += "\"";
1366                 }
1367             }
1368         }
1369     }
1370 
1371     return result;
1372 }
1373 DOMString ElementImpl::selectionToString(NodeImpl *selectionStart, NodeImpl *selectionEnd, int startOffset, int endOffset, bool &found) const
1374 {
1375     DOMString result = openTagStartToString();
1376 
1377     if (hasChildNodes()) {
1378         result += ">";
1379 
1380         for (NodeImpl *child = firstChild(); child != nullptr; child = child->nextSibling()) {
1381             result += child->selectionToString(selectionStart, selectionEnd, startOffset, endOffset, found); // this might set found to true
1382             if (child == selectionEnd) {
1383                 found = true;
1384             }
1385             if (found) {
1386                 break;
1387             }
1388         }
1389 
1390         result += "</";
1391         result += nonCaseFoldedTagName();
1392         result += ">";
1393     } else {
1394         result += " />";
1395     }
1396 
1397     return result;
1398 }
1399 
1400 DOMString ElementImpl::toString() const
1401 {
1402     QString result = openTagStartToString().string(); //Accumulate in QString, since DOMString can't append well.
1403 
1404     if (hasChildNodes()) {
1405         result += ">";
1406 
1407         for (NodeImpl *child = firstChild(); child != nullptr; child = child->nextSibling()) {
1408             DOMString kid = child->toString();
1409             result += QString::fromRawData(kid.unicode(), kid.length());
1410         }
1411 
1412         result += "</";
1413         result += nonCaseFoldedTagName().string();
1414         result += ">";
1415     } else if (result.length() == 1) {
1416         // ensure we do not get results like < /> can happen when serialize document
1417         result = "";
1418     } else {
1419         result += " />";
1420     }
1421 
1422     return result;
1423 }
1424 
1425 RenderStyle *ElementImpl::computedStyle()
1426 {
1427     if (m_render && m_render->style()) {
1428         return m_render->style();
1429     }
1430 
1431     if (!attached())
1432         // FIXME: Try to do better than this. Ensure that styleForElement() works for elements that are not in the
1433         // document tree and figure out when to destroy the computed style for such elements.
1434     {
1435         return nullptr;
1436     }
1437 
1438     ElementRareDataImpl *rd = createRareData();
1439     if (!rd->m_computedStyle) {
1440         rd->m_computedStyle = document()->styleSelector()->styleForElement(this, parent() ? parent()->computedStyle() : nullptr);
1441         rd->m_computedStyle->ref();
1442     }
1443     return rd->m_computedStyle;
1444 }
1445 
1446 // ElementTraversal API
1447 ElementImpl *ElementImpl::firstElementChild() const
1448 {
1449     NodeImpl *n = firstChild();
1450     while (n && !n->isElementNode()) {
1451         n = n->nextSibling();
1452     }
1453     return static_cast<ElementImpl *>(n);
1454 }
1455 
1456 ElementImpl *ElementImpl::lastElementChild() const
1457 {
1458     NodeImpl *n = lastChild();
1459     while (n && !n->isElementNode()) {
1460         n = n->previousSibling();
1461     }
1462     return static_cast<ElementImpl *>(n);
1463 }
1464 
1465 ElementImpl *ElementImpl::previousElementSibling() const
1466 {
1467     NodeImpl *n = previousSibling();
1468     while (n && !n->isElementNode()) {
1469         n = n->previousSibling();
1470     }
1471     return static_cast<ElementImpl *>(n);
1472 }
1473 
1474 ElementImpl *ElementImpl::nextElementSibling() const
1475 {
1476     NodeImpl *n = nextSibling();
1477     while (n && !n->isElementNode()) {
1478         n = n->nextSibling();
1479     }
1480     return static_cast<ElementImpl *>(n);
1481 }
1482 
1483 unsigned ElementImpl::childElementCount() const
1484 {
1485     unsigned count = 0;
1486     NodeImpl *n = firstChild();
1487     while (n) {
1488         count += n->isElementNode();
1489         n = n->nextSibling();
1490     }
1491     return count;
1492 }
1493 
1494 void ElementImpl::blur()
1495 {
1496     if (document()->focusNode() == this) {
1497         document()->setFocusNode(nullptr);
1498     }
1499 }
1500 
1501 void ElementImpl::focus()
1502 {
1503     document()->setFocusNode(this);
1504 }
1505 
1506 void ElementImpl::synchronizeStyleAttribute() const
1507 {
1508     assert(inlineStyleDecls() && m_needsStyleAttributeUpdate);
1509     m_needsStyleAttributeUpdate = false;
1510     DOMString value = inlineStyleDecls()->cssText();
1511     attributes()->setValueWithoutElementUpdate(ATTR_STYLE, value.implementation());
1512 }
1513 
1514 // -------------------------------------------------------------------------
1515 
1516 XMLElementImpl::XMLElementImpl(DocumentImpl *doc, NamespaceName namespacename, LocalName localName, PrefixName prefix)
1517     : ElementImpl(doc)
1518 {
1519     // Called from createElement(). In this case localName, prefix, and namespaceURI all need to be null.
1520     m_localName = localName;
1521     m_namespace = namespacename;
1522     m_prefix = prefix;
1523 }
1524 
1525 XMLElementImpl::~XMLElementImpl()
1526 {
1527 }
1528 
1529 WTF::PassRefPtr<NodeImpl> XMLElementImpl::cloneNode(bool deep)
1530 {
1531     WTF::RefPtr<ElementImpl> clone = new XMLElementImpl(docPtr(), NamespaceName::fromId(namespacePart(id())), LocalName::fromId(localNamePart(id())), m_prefix);
1532     finishCloneNode(clone.get(), deep);
1533     return clone;
1534 }
1535 
1536 void XMLElementImpl::parseAttribute(AttributeImpl *attr)
1537 {
1538     if (attr->id() == ATTR_ID) {
1539         setHasID();
1540         document()->incDOMTreeVersion(DocumentImpl::TV_IDNameHref);
1541     }
1542 
1543     // Note: we do not want to handle ATTR_CLASS here, since the
1544     // class concept applies only to specific languages, like
1545     // HTML and SVG, not generic XML.
1546 }
1547 
1548 // -------------------------------------------------------------------------
1549 
1550 NamedAttrMapImpl::NamedAttrMapImpl(ElementImpl *element)
1551     : m_element(element)
1552 {
1553 }
1554 
1555 NamedAttrMapImpl::~NamedAttrMapImpl()
1556 {
1557     unsigned len = m_attrs.size();
1558     for (unsigned i = 0; i < len; i++) {
1559         m_attrs[i].free();
1560     }
1561     m_attrs.clear();
1562 }
1563 
1564 NodeImpl *NamedAttrMapImpl::getNamedItem(NodeImpl::Id id, const PrefixName &prefix, bool nsAware)
1565 {
1566     if (!m_element) {
1567         return nullptr;
1568     }
1569 
1570     int index = find(id, prefix, nsAware);
1571     return (index < 0) ? nullptr : m_attrs[index].createAttr(m_element, m_element->docPtr());
1572 }
1573 
1574 Node NamedAttrMapImpl::removeNamedItem(NodeImpl::Id id, const PrefixName &prefix, bool nsAware, int &exceptioncode)
1575 {
1576     if (!m_element) {
1577         exceptioncode = DOMException::NOT_FOUND_ERR;
1578         return nullptr;
1579     }
1580 
1581     // NO_MODIFICATION_ALLOWED_ERR: Raised when the node is readonly
1582     if (isReadOnly()) {
1583         exceptioncode = DOMException::NO_MODIFICATION_ALLOWED_ERR;
1584         return nullptr;
1585     }
1586     int index = find(id, prefix, nsAware);
1587     if (index < 0) {
1588         exceptioncode = DOMException::NOT_FOUND_ERR;
1589         return nullptr;
1590     }
1591 
1592     id = m_attrs[index].id();
1593     if (id == ATTR_ID) {
1594         m_element->updateId(m_attrs[index].val(), nullptr);
1595     }
1596     Node removed(m_attrs[index].createAttr(m_element, m_element->docPtr()));
1597     m_attrs[index].free(); // Also sets the remove'd ownerElement to 0
1598     m_attrs.remove(index);
1599     m_element->parseNullAttribute(id, prefix);
1600     m_element->attributeChanged(id);
1601     return removed;
1602 }
1603 
1604 Node NamedAttrMapImpl::setNamedItem(NodeImpl *arg, const PrefixName &prefix, bool nsAware, int &exceptioncode)
1605 {
1606     if (!m_element || !arg) {
1607         exceptioncode = DOMException::NOT_FOUND_ERR;
1608         return nullptr;
1609     }
1610 
1611     // NO_MODIFICATION_ALLOWED_ERR: Raised if this map is readonly.
1612     if (isReadOnly()) {
1613         exceptioncode = DOMException::NO_MODIFICATION_ALLOWED_ERR;
1614         return nullptr;
1615     }
1616 
1617     // WRONG_DOCUMENT_ERR: Raised if arg was created from a different document than the one that created this map.
1618     if (arg->document() != m_element->document()) {
1619         exceptioncode = DOMException::WRONG_DOCUMENT_ERR;
1620         return nullptr;
1621     }
1622 
1623     // HIERARCHY_REQUEST_ERR: Raised if an attempt is made to add a node doesn't belong in this NamedNodeMap
1624     if (!arg->isAttributeNode()) {
1625         exceptioncode = DOMException::HIERARCHY_REQUEST_ERR;
1626         return nullptr;
1627     }
1628     AttrImpl *attr = static_cast<AttrImpl *>(arg);
1629 
1630     // INUSE_ATTRIBUTE_ERR: Raised if arg is an Attr that is already an attribute of another Element object.
1631     // The DOM user must explicitly clone Attr nodes to re-use them in other elements.
1632     if (attr->ownerElement() && attr->ownerElement() != m_element) {
1633         exceptioncode = DOMException::INUSE_ATTRIBUTE_ERR;
1634         return nullptr;
1635     }
1636 
1637     if (attr->ownerElement() == m_element) {
1638         // Already have this attribute.
1639         // DOMTS core-1 test "hc_elementreplaceattributewithself" says we should return it.
1640         return attr;
1641     }
1642 
1643     int index = find(attr->id(), prefix, nsAware);
1644     if (index >= 0) {
1645         if (attr->id() == ATTR_ID) {
1646             m_element->updateId(m_attrs[index].val(), attr->val());
1647         }
1648 
1649         Node replaced = m_attrs[index].createAttr(m_element, m_element->docPtr());
1650         m_attrs[index].free();
1651         m_attrs[index].m_localName = emptyLocalName; /* "has implementation" flag */
1652         m_attrs[index].m_data.attr = attr;
1653         m_attrs[index].m_data.attr->ref();
1654         attr->setElement(m_element);
1655         m_element->parseAttribute(&m_attrs[index]);
1656         m_element->attributeChanged(m_attrs[index].id());
1657         // ### dispatch mutation events
1658         return replaced;
1659     }
1660 
1661     // No existing attribute; add to list
1662     AttributeImpl attribute;
1663     attribute.m_localName = emptyLocalName; /* "has implementation" flag */
1664     attribute.m_namespace = NamespaceName::fromId(0);
1665     attribute.m_prefix = emptyPrefixName;
1666     attribute.m_data.attr = attr;
1667     attribute.m_data.attr->ref();
1668     m_attrs.append(attribute);
1669 
1670     attr->setElement(m_element);
1671     if (attr->id() == ATTR_ID) {
1672         m_element->updateId(nullptr, attr->val());
1673     }
1674     m_element->parseAttribute(&m_attrs.last());
1675     m_element->attributeChanged(m_attrs.last().id());
1676     // ### dispatch mutation events
1677 
1678     return nullptr;
1679 }
1680 
1681 NodeImpl *NamedAttrMapImpl::item(unsigned index)
1682 {
1683     return (index >= m_attrs.size()) ? nullptr : m_attrs[index].createAttr(m_element, m_element->docPtr());
1684 }
1685 
1686 NodeImpl::Id NamedAttrMapImpl::idAt(unsigned index) const
1687 {
1688     assert(index < m_attrs.size());
1689     return m_attrs[index].id();
1690 }
1691 
1692 DOMStringImpl *NamedAttrMapImpl::valueAt(unsigned index) const
1693 {
1694     assert(index < m_attrs.size());
1695     return m_attrs[index].val();
1696 }
1697 
1698 DOMStringImpl *NamedAttrMapImpl::getValue(NodeImpl::Id id, const PrefixName &prefix, bool nsAware) const
1699 {
1700     int index = find(id, prefix, nsAware);
1701     return index < 0 ? nullptr : m_attrs[index].val();
1702 }
1703 
1704 void NamedAttrMapImpl::setValue(NodeImpl::Id id, DOMStringImpl *value, const PrefixName &prefix, bool nsAware)
1705 {
1706     if (!id) {
1707         return;
1708     }
1709     // Passing in a null value here causes the attribute to be removed. This is a khtml extension
1710     // (the spec does not specify what to do in this situation).
1711     int exceptioncode = 0;
1712     if (!value) {
1713         removeNamedItem(id, prefix, nsAware, exceptioncode);
1714         return;
1715     }
1716     int index = find(id, prefix, nsAware);
1717     if (index >= 0) {
1718         if (m_attrs[index].attr()) {
1719             m_attrs[index].attr()->setPrefix(prefix.toString(), exceptioncode);
1720         } else {
1721             m_attrs[index].m_prefix = prefix;
1722         }
1723         m_attrs[index].setValue(value, m_element);
1724         // ### dispatch mutation events
1725         return;
1726     }
1727 
1728     AttributeImpl attr;
1729     attr.m_localName = LocalName::fromId(localNamePart(id));
1730     attr.m_namespace = NamespaceName::fromId(namespacePart(id));
1731     attr.m_prefix = prefix;
1732     attr.m_data.value = value;
1733     attr.m_data.value->ref();
1734     m_attrs.append(attr);
1735 
1736     if (m_element) {
1737         if (id == ATTR_ID) {
1738             m_element->updateId(nullptr, value);
1739         }
1740         m_element->parseAttribute(&m_attrs.last());
1741         m_element->attributeChanged(m_attrs.last().id());
1742     }
1743     // ### dispatch mutation events
1744 }
1745 
1746 Attr NamedAttrMapImpl::removeAttr(AttrImpl *attr)
1747 {
1748     unsigned len = m_attrs.size();
1749     for (unsigned i = 0; i < len; i++) {
1750         if (m_attrs[i].attr() == attr) {
1751             NodeImpl::Id id = m_attrs[i].id();
1752             if (id == ATTR_ID) {
1753                 m_element->updateId(attr->val(), nullptr);
1754             }
1755             Node removed(m_attrs[i].createAttr(m_element, m_element->docPtr()));
1756             m_attrs[i].free();
1757             m_attrs.remove(i);
1758             m_element->parseNullAttribute(id, PrefixName::fromString(attr->prefix()));
1759             m_element->attributeChanged(id);
1760             // ### dispatch mutation events
1761             return removed;
1762         }
1763     }
1764 
1765     return nullptr;
1766 }
1767 
1768 void NamedAttrMapImpl::copyAttributes(NamedAttrMapImpl *other)
1769 {
1770     assert(m_element);
1771     unsigned i;
1772     unsigned len = m_attrs.size();
1773     for (i = 0; i < len; i++) {
1774         if (m_attrs[i].id() == ATTR_ID) {
1775             m_element->updateId(m_attrs[i].val(), nullptr);
1776         }
1777         m_attrs[i].free();
1778     }
1779     m_attrs.resize(other->length());
1780     len = m_attrs.size();
1781     for (i = 0; i < len; i++) {
1782         m_attrs[i].m_localName = other->m_attrs[i].m_localName;
1783         m_attrs[i].m_prefix = other->m_attrs[i].m_prefix;
1784         m_attrs[i].m_namespace = other->m_attrs[i].m_namespace;
1785         if (m_attrs[i].m_localName.id()) {
1786             m_attrs[i].m_data.value = other->m_attrs[i].m_data.value;
1787             m_attrs[i].m_data.value->ref();
1788         } else {
1789             WTF::RefPtr<NodeImpl> clonedAttr = other->m_attrs[i].m_data.attr->cloneNode(true);
1790             m_attrs[i].m_data.attr = static_cast<AttrImpl *>(clonedAttr.get());
1791             m_attrs[i].m_data.attr->ref();
1792             m_attrs[i].m_data.attr->setElement(m_element);
1793         }
1794         if (m_attrs[i].id() == ATTR_ID) {
1795             m_element->updateId(nullptr, m_attrs[i].val());
1796         }
1797         m_element->parseAttribute(&m_attrs[i]);
1798         m_element->attributeChanged(m_attrs[i].id());
1799     }
1800 }
1801 
1802 int NamedAttrMapImpl::find(NodeImpl::Id id, const PrefixName &prefix, bool nsAware) const
1803 {
1804     //qCDebug(KHTML_LOG) << "In find:" << getPrintableName(id) << "[" << prefix.toString() << prefix.id() << "]" << nsAware;
1805     //qCDebug(KHTML_LOG) << "m_attrs.size()" << m_attrs.size();
1806     unsigned len = m_attrs.size();
1807     for (unsigned i = 0; i < len; ++i) {
1808         //qCDebug(KHTML_LOG) << "check attr[" << i << "]" << getPrintableName(m_attrs[i].id()) << "prefix:" << m_attrs[i].prefix();
1809         if (nsAware && namespacePart(id) == anyNamespace && localNamePart(id) == localNamePart(m_attrs[i].id())) {
1810             return i;
1811         }
1812         if ((nsAware && id == m_attrs[i].id()) || (!nsAware && localNamePart(id) == localNamePart(m_attrs[i].id()) && prefix == m_attrs[i].prefixName())) {
1813             //qCDebug(KHTML_LOG) << "attribute matched: exiting...";
1814             return i;
1815         }
1816     }
1817     //qCDebug(KHTML_LOG) << "attribute doesn't match: exiting... with -1";
1818     return -1;
1819 }
1820 
1821 void NamedAttrMapImpl::setElement(ElementImpl *element)
1822 {
1823     assert(!m_element);
1824     m_element = element;
1825 
1826     unsigned len = m_attrs.size();
1827     for (unsigned i = 0; i < len; i++)
1828         if (m_attrs[i].attr()) {
1829             m_attrs[i].attr()->setElement(element);
1830         }
1831 }
1832 
1833 void NamedAttrMapImpl::detachFromElement()
1834 {
1835     // This makes the map invalid; nothing can really be done with it now since it's not
1836     // associated with an element. But we have to keep it around in memory in case there
1837     // are still references to it.
1838     m_element = nullptr;
1839     unsigned len = m_attrs.size();
1840     for (unsigned i = 0; i < len; i++) {
1841         m_attrs[i].free();
1842     }
1843     m_attrs.clear();
1844 }
1845 
1846 void NamedAttrMapImpl::setClass(const DOMString &string)
1847 {
1848     if (!m_element) {
1849         return;
1850     }
1851 
1852     if (!m_element->hasClass()) {
1853         m_classNames.clear();
1854         return;
1855     }
1856 
1857     m_classNames.parseClassAttribute(string, m_element->document()->htmlMode() != DocumentImpl::XHtml &&
1858                                      m_element->document()->inCompatMode());
1859 }
1860 
1861 void NamedAttrMapImpl::setValueWithoutElementUpdate(NodeImpl::Id id, DOMStringImpl *value)
1862 {
1863     // FIXME properly fix case value == 0
1864     int index = find(id, emptyPrefixName, true);
1865     if (index >= 0) {
1866         m_attrs[index].rewriteValue(value ? value : DOMStringImpl::empty());
1867         return;
1868     }
1869 
1870     if (!value) {
1871         return;
1872     }
1873 
1874     AttributeImpl attr;
1875     attr.m_localName = LocalName::fromId(localNamePart(id));
1876     attr.m_namespace = NamespaceName::fromId(namespacePart(id));
1877     attr.m_prefix = emptyPrefixName;
1878     attr.m_data.value = value;
1879     attr.m_data.value->ref();
1880     m_attrs.append(attr);
1881 }
1882 
1883 }