WebCore:
[WebKit-https.git] / WebCore / khtml / xml / dom_elementimpl.cpp
1 /**
2  * This file is part of the DOM implementation for KDE.
3  *
4  * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
5  *           (C) 1999 Antti Koivisto (koivisto@kde.org)
6  *           (C) 2001 Peter Kelly (pmk@post.com)
7  *           (C) 2001 Dirk Mueller (mueller@kde.org)
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Library General Public
11  * License as published by the Free Software Foundation; either
12  * version 2 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Library General Public License for more details.
18  *
19  * You should have received a copy of the GNU Library General Public License
20  * along with this library; see the file COPYING.LIB.  If not, write to
21  * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22  * Boston, MA 02111-1307, USA.
23  */
24
25 //#define EVENT_DEBUG
26 #include "dom/dom_exception.h"
27 #include "dom/dom_node.h"
28 #include "xml/dom_textimpl.h"
29 #include "xml/dom_docimpl.h"
30 #include "xml/dom2_eventsimpl.h"
31 #include "xml/dom_elementimpl.h"
32
33 #include "khtml_part.h"
34
35 #include "html/dtd.h"
36 #include "html/htmlparser.h"
37
38 #include "rendering/render_canvas.h"
39 #include "misc/htmlhashes.h"
40 #include "css/css_valueimpl.h"
41 #include "css/css_stylesheetimpl.h"
42 #include "css/cssstyleselector.h"
43 #include "xml/dom_selection.h"
44 #include "xml/dom_xmlimpl.h"
45
46 #include <qtextstream.h>
47 #include <kdebug.h>
48
49 using namespace DOM;
50 using namespace khtml;
51
52 AttributeImpl* AttributeImpl::clone(bool) const
53 {
54     AttributeImpl* result = new AttributeImpl(m_id, _value);
55     result->setPrefix(_prefix);
56     return result;
57 }
58
59 void AttributeImpl::allocateImpl(ElementImpl* e) {
60     _impl = new AttrImpl(e, e->docPtr(), this);
61 }
62
63 AttrImpl::AttrImpl(ElementImpl* element, DocumentPtr* docPtr, AttributeImpl* a)
64     : NodeBaseImpl(docPtr),
65       m_element(element),
66       m_attribute(a)
67 {
68     assert(!m_attribute->_impl);
69     m_attribute->_impl = this;
70     m_attribute->ref();
71     m_specified = true;
72 }
73
74 AttrImpl::~AttrImpl()
75 {
76     assert(m_attribute->_impl == this);
77     m_attribute->_impl = 0;
78     m_attribute->deref();
79 }
80
81 DOMString AttrImpl::nodeName() const
82 {
83     return getDocument()->attrName(m_attribute->id());
84 }
85
86 unsigned short AttrImpl::nodeType() const
87 {
88     return Node::ATTRIBUTE_NODE;
89 }
90
91 DOMString AttrImpl::prefix() const
92 {
93     return m_attribute->prefix();
94 }
95
96 void AttrImpl::setPrefix(const DOMString &_prefix, int &exceptioncode )
97 {
98     checkSetPrefix(_prefix, exceptioncode);
99     if (exceptioncode)
100         return;
101
102     m_attribute->setPrefix(_prefix.implementation());
103 }
104
105 DOMString AttrImpl::nodeValue() const {
106     return m_attribute->value();
107 }
108
109 void AttrImpl::setValue( const DOMString &v, int &exceptioncode )
110 {
111     exceptioncode = 0;
112
113     // ### according to the DOM docs, we should create an unparsed Text child
114     // node here
115     // do not interprete entities in the string, its literal!
116
117     // NO_MODIFICATION_ALLOWED_ERR: Raised when the node is readonly
118     if (isReadOnly()) {
119         exceptioncode = DOMException::NO_MODIFICATION_ALLOWED_ERR;
120         return;
121     }
122
123     // ### what to do on 0 ?
124     if (v.isNull()) {
125         exceptioncode = DOMException::DOMSTRING_SIZE_ERR;
126         return;
127     }
128
129     m_attribute->setValue(v.implementation());
130     if (m_element)
131         m_element->attributeChanged(m_attribute);
132 }
133
134 void AttrImpl::setNodeValue( const DOMString &v, int &exceptioncode )
135 {
136     exceptioncode = 0;
137     // NO_MODIFICATION_ALLOWED_ERR: taken care of by setValue()
138     setValue(v, exceptioncode);
139 }
140
141 NodeImpl *AttrImpl::cloneNode ( bool /*deep*/)
142 {
143     return new AttrImpl(0, docPtr(), m_attribute->clone());
144 }
145
146 // DOM Section 1.1.1
147 bool AttrImpl::childAllowed( NodeImpl *newChild )
148 {
149     if(!newChild)
150         return false;
151
152     return childTypeAllowed(newChild->nodeType());
153 }
154
155 bool AttrImpl::childTypeAllowed( unsigned short type )
156 {
157     switch (type) {
158         case Node::TEXT_NODE:
159         case Node::ENTITY_REFERENCE_NODE:
160             return true;
161             break;
162         default:
163             return false;
164     }
165 }
166
167 DOMString AttrImpl::toString() const
168 {
169     DOMString result;
170
171     result += nodeName();
172
173     // FIXME: substitute entities for any instances of " or ' --
174     // maybe easier to just use text value and ignore existing
175     // entity refs?
176
177     if (firstChild() != NULL) {
178         result += "=\"";
179
180         for (NodeImpl *child = firstChild(); child != NULL; child = child->nextSibling()) {
181             result += child->toString();
182         }
183         
184         result += "\"";
185     }
186
187     return result;
188 }
189
190 // -------------------------------------------------------------------------
191
192 ElementImpl::ElementImpl(DocumentPtr *doc)
193     : NodeBaseImpl(doc)
194 {
195     namedAttrMap = 0;
196     m_prefix = 0;
197 }
198
199 ElementImpl::~ElementImpl()
200 {
201     if (namedAttrMap) {
202         namedAttrMap->detachFromElement();
203         namedAttrMap->deref();
204     }
205
206     if (m_prefix)
207         m_prefix->deref();
208 }
209
210 void ElementImpl::removeAttribute( NodeImpl::Id id, int &exceptioncode )
211 {
212     if (namedAttrMap) {
213         namedAttrMap->removeNamedItem(id, exceptioncode);
214         if (exceptioncode == DOMException::NOT_FOUND_ERR) {
215             exceptioncode = 0;
216         }
217     }
218 }
219
220 void ElementImpl::setAttribute(NodeImpl::Id id, const DOMString &value)
221 {
222     int exceptioncode = 0;
223     setAttribute(id,value.implementation(),exceptioncode);
224 }
225
226 unsigned short ElementImpl::nodeType() const
227 {
228     return Node::ELEMENT_NODE;
229 }
230
231 const AtomicStringList* ElementImpl::getClassList() const
232 {
233     return 0;
234 }
235
236 const AtomicString& ElementImpl::getIDAttribute() const
237 {
238     return namedAttrMap ? namedAttrMap->id() : nullAtom;
239 }
240
241 const AtomicString& ElementImpl::getAttribute(NodeImpl::Id id) const
242 {
243     if (namedAttrMap) {
244         AttributeImpl* a = namedAttrMap->getAttributeItem(id);
245         if (a) return a->value();
246     }
247     return nullAtom;
248 }
249
250 const AtomicString& ElementImpl::getAttributeNS(const DOMString &namespaceURI,
251                                                 const DOMString &localName) const
252 {   
253     NodeImpl::Id id = getDocument()->attrId(namespaceURI.implementation(),
254                                             localName.implementation(), true);
255     if (!id) return nullAtom;
256     return getAttribute(id);
257 }
258
259 void ElementImpl::setAttribute(NodeImpl::Id id, DOMStringImpl* value, int &exceptioncode )
260 {
261     // allocate attributemap if necessary
262     AttributeImpl* old = attributes(false)->getAttributeItem(id);
263
264     // NO_MODIFICATION_ALLOWED_ERR: Raised when the node is readonly
265     if (namedAttrMap->isReadOnly()) {
266         exceptioncode = DOMException::NO_MODIFICATION_ALLOWED_ERR;
267         return;
268     }
269
270     if (id == ATTR_ID) {
271         updateId(old ? old->value() : nullAtom, value);
272     }
273     
274     if (old && !value)
275         namedAttrMap->removeAttribute(id);
276     else if (!old && value)
277         namedAttrMap->addAttribute(createAttribute(id, value));
278     else if (old && value) {
279         old->setValue(value);
280         attributeChanged(old);
281     }
282 }
283
284 AttributeImpl* ElementImpl::createAttribute(NodeImpl::Id id, DOMStringImpl* value)
285 {
286     return new AttributeImpl(id, value);
287 }
288
289 void ElementImpl::setAttributeMap( NamedAttrMapImpl* list )
290 {
291     // If setting the whole map changes the id attribute, we need to
292     // call updateId.
293
294     AttributeImpl *oldId = namedAttrMap ? namedAttrMap->getAttributeItem(ATTR_ID) : 0;
295     AttributeImpl *newId = list ? list->getAttributeItem(ATTR_ID) : 0;
296
297     if (oldId || newId) {
298         updateId(oldId ? oldId->value() : nullAtom, newId ? newId->value() : nullAtom);
299     }
300
301     if(namedAttrMap)
302         namedAttrMap->deref();
303
304     namedAttrMap = list;
305
306     if(namedAttrMap) {
307         namedAttrMap->ref();
308         namedAttrMap->element = this;
309         unsigned int len = namedAttrMap->length();
310         for(unsigned int i = 0; i < len; i++)
311             attributeChanged(namedAttrMap->attrs[i]);
312     }
313 }
314
315 bool ElementImpl::hasAttributes() const
316 {
317     return namedAttrMap && namedAttrMap->length() > 0;
318 }
319
320 NodeImpl *ElementImpl::cloneNode(bool deep)
321 {
322     // ### we loose the namespace here ... FIXME
323     int exceptioncode;
324     ElementImpl *clone = getDocument()->createElement(tagName(), exceptioncode);
325     if (!clone) return 0;
326
327     // clone attributes
328     if (namedAttrMap)
329         *(static_cast<NamedAttrMapImpl*>(clone->attributes())) = *namedAttrMap;
330
331     if (deep)
332         cloneChildNodes(clone);
333     return clone;
334 }
335
336 DOMString ElementImpl::nodeName() const
337 {
338     return tagName();
339 }
340
341 DOMString ElementImpl::tagName() const
342 {
343     DOMString tn = getDocument()->tagName(id());
344
345     if (m_prefix)
346         return DOMString(m_prefix) + ":" + tn;
347
348     return tn;
349 }
350
351 void ElementImpl::setPrefix( const DOMString &_prefix, int &exceptioncode )
352 {
353     checkSetPrefix(_prefix, exceptioncode);
354     if (exceptioncode)
355         return;
356
357     if (m_prefix)
358         m_prefix->deref();
359     m_prefix = _prefix.implementation();
360     if (m_prefix)
361         m_prefix->ref();
362 }
363
364 void ElementImpl::createAttributeMap() const
365 {
366     namedAttrMap = new NamedAttrMapImpl(const_cast<ElementImpl*>(this));
367     namedAttrMap->ref();
368 }
369
370 bool ElementImpl::isURLAttribute(AttributeImpl *attr) const
371 {
372     return false;
373     
374 }
375
376 RenderStyle *ElementImpl::styleForRenderer(RenderObject *parentRenderer)
377 {
378     return getDocument()->styleSelector()->styleForElement(this);
379 }
380
381 RenderObject *ElementImpl::createRenderer(RenderArena *arena, RenderStyle *style)
382 {
383     if (getDocument()->documentElement() == this && style->display() == NONE) {
384         // Ignore display: none on root elements.  Force a display of block in that case.
385         RenderBlock* result = new (arena) RenderBlock(this);
386         if (result) result->setStyle(style);
387         return result;
388     }
389     return RenderObject::createObject(this, style);
390 }
391
392 void ElementImpl::attach()
393 {
394 #if SPEED_DEBUG < 1
395     createRendererIfNeeded();
396 #endif
397     NodeBaseImpl::attach();
398
399     if (hasID()) {
400         NamedAttrMapImpl *attrs = attributes(true);
401         if (attrs) {
402             AttributeImpl *idAttr = attrs->getAttributeItem(ATTR_ID);
403             if (idAttr && !idAttr->isNull()) {
404                 updateId(nullAtom, idAttr->value());
405             }
406         }
407     }
408 }
409
410 void ElementImpl::detach()
411 {
412     if (hasID()) {
413         NamedAttrMapImpl *attrs = attributes(true);
414         if (attrs) {
415             AttributeImpl *idAttr = attrs->getAttributeItem(ATTR_ID);
416             if (idAttr && !idAttr->isNull()) {
417                 updateId(idAttr->value(), nullAtom);
418             }
419         }
420     }
421
422     NodeBaseImpl::detach();
423 }
424
425 void ElementImpl::recalcStyle( StyleChange change )
426 {
427     // ### should go away and be done in renderobject
428     RenderStyle* _style = m_render ? m_render->style() : 0;
429     bool hasParentRenderer = parent() ? parent()->renderer() : false;
430     
431 #if 0
432     const char* debug;
433     switch(change) {
434     case NoChange: debug = "NoChange";
435         break;
436     case NoInherit: debug= "NoInherit";
437         break;
438     case Inherit: debug = "Inherit";
439         break;
440     case Force: debug = "Force";
441         break;
442     }
443     qDebug("recalcStyle(%d: %s)[%p: %s]", change, debug, this, tagName().string().latin1());
444 #endif
445     if ( hasParentRenderer && (change >= Inherit || changed()) ) {
446         RenderStyle *newStyle = getDocument()->styleSelector()->styleForElement(this);
447         newStyle->ref();
448         StyleChange ch = diff( _style, newStyle );
449         if (ch == Detach) {
450             if (attached()) detach();
451             // ### Suboptimal. Style gets calculated again.
452             attach();
453             // attach recalulates the style for all children. No need to do it twice.
454             setChanged( false );
455             setHasChangedChild( false );
456             newStyle->deref(getDocument()->renderArena());
457             return;
458         }
459         else if (ch != NoChange) {
460             if( m_render && newStyle ) {
461                 //qDebug("--> setting style on render element bgcolor=%s", newStyle->backgroundColor().name().latin1());
462                 m_render->setStyle(newStyle);
463             }
464         }
465         newStyle->deref(getDocument()->renderArena());
466
467         if ( change != Force) {
468             if (getDocument()->usesDescendantRules())
469                 change = Force;
470             else
471                 change = ch;
472         }
473     }
474
475     NodeImpl *n;
476     for (n = _first; n; n = n->nextSibling()) {
477         //qDebug("    (%p) calling recalcStyle on child %s/%p, change=%d", this, n, n->isElementNode() ? ((ElementImpl *)n)->tagName().string().latin1() : n->isTextNode() ? "text" : "unknown", change );
478         if ( change >= Inherit || n->isTextNode() ||
479              n->hasChangedChild() || n->changed() )
480             n->recalcStyle( change );
481     }
482
483     setChanged( false );
484     setHasChangedChild( false );
485 }
486
487 // DOM Section 1.1.1
488 bool ElementImpl::childAllowed( NodeImpl *newChild )
489 {
490     if (!childTypeAllowed(newChild->nodeType()))
491         return false;
492
493     // For XML documents, we are non-validating and do not check against a DTD, even for HTML elements.
494     if (getDocument()->isHTMLDocument())
495         return checkChild(id(), newChild->id());
496     return true;
497 }
498
499 bool ElementImpl::childTypeAllowed( unsigned short type )
500 {
501     switch (type) {
502         case Node::ELEMENT_NODE:
503         case Node::TEXT_NODE:
504         case Node::COMMENT_NODE:
505         case Node::PROCESSING_INSTRUCTION_NODE:
506         case Node::CDATA_SECTION_NODE:
507         case Node::ENTITY_REFERENCE_NODE:
508             return true;
509             break;
510         default:
511             return false;
512     }
513 }
514
515 void ElementImpl::dispatchAttrRemovalEvent(AttributeImpl *attr)
516 {
517     if (!getDocument()->hasListenerType(DocumentImpl::DOMATTRMODIFIED_LISTENER))
518         return;
519     //int exceptioncode = 0;
520 //     dispatchEvent(new MutationEventImpl(EventImpl::DOMATTRMODIFIED_EVENT,true,false,attr,attr->value(),
521 //                attr->value(), getDocument()->attrName(attr->id()),MutationEvent::REMOVAL),exceptioncode);
522 }
523
524 void ElementImpl::dispatchAttrAdditionEvent(AttributeImpl *attr)
525 {
526     if (!getDocument()->hasListenerType(DocumentImpl::DOMATTRMODIFIED_LISTENER))
527         return;
528    // int exceptioncode = 0;
529 //     dispatchEvent(new MutationEventImpl(EventImpl::DOMATTRMODIFIED_EVENT,true,false,attr,attr->value(),
530 //                                         attr->value(),getDocument()->attrName(attr->id()),MutationEvent::ADDITION),exceptioncode);
531 }
532
533 DOMString ElementImpl::openTagStartToString() const
534 {
535     DOMString result = DOMString("<") + tagName();
536
537     NamedAttrMapImpl *attrMap = attributes(true);
538
539     if (attrMap) {
540         unsigned long numAttrs = attrMap->length();
541         for (unsigned long i = 0; i < numAttrs; i++) {
542             result += " ";
543
544             AttributeImpl *attribute = attrMap->attributeItem(i);
545             AttrImpl *attr = attribute->attrImpl();
546
547             if (attr) {
548                 result += attr->toString();
549             } else {
550                 result += getDocument()->attrName(attribute->id());
551                 if (!attribute->value().isNull()) {
552                     result += "=\"";
553                     // FIXME: substitute entities for any instances of " or '
554                     result += attribute->value();
555                     result += "\"";
556                 }
557             }
558         }
559     }
560
561     return result;
562 }
563
564 DOMString ElementImpl::toString() const
565 {
566     DOMString result = openTagStartToString();
567
568     if (hasChildNodes()) {
569         result += ">";
570
571         for (NodeImpl *child = firstChild(); child != NULL; child = child->nextSibling()) {
572             result += child->toString();
573         }
574
575         result += "</";
576         result += tagName();
577         result += ">";
578     } else {
579         result += " />";
580     }
581
582     return result;
583 }
584
585 void ElementImpl::updateId(const AtomicString& oldId, const AtomicString& newId)
586 {
587     if (!attached())
588         return;
589
590     if (oldId == newId)
591         return;
592
593     DocumentImpl* doc = getDocument();
594     if (!oldId.isEmpty())
595         doc->removeElementById(oldId, this);
596     if (!newId.isEmpty())
597         doc->addElementById(newId, this);
598 }
599
600 #ifndef NDEBUG
601 void ElementImpl::dump(QTextStream *stream, QString ind) const
602 {
603     if (namedAttrMap) {
604         for (uint i = 0; i < namedAttrMap->length(); i++) {
605             AttributeImpl *attr = namedAttrMap->attributeItem(i);
606             *stream << " " << DOMString(getDocument()->attrName(attr->id())).string().ascii()
607                     << "=\"" << DOMString(attr->value()).string().ascii() << "\"";
608         }
609     }
610
611     NodeBaseImpl::dump(stream,ind);
612 }
613 #endif
614
615 #ifndef NDEBUG
616 void ElementImpl::formatForDebugger(char *buffer, unsigned length) const
617 {
618     DOMString result;
619     DOMString s;
620     
621     s = nodeName();
622     if (s.length() > 0) {
623         result += s;
624     }
625           
626     s = getAttribute(ATTR_ID);
627     if (s.length() > 0) {
628         if (result.length() > 0)
629             result += "; ";
630         result += "id=";
631         result += s;
632     }
633           
634     s = getAttribute(ATTR_CLASS);
635     if (s.length() > 0) {
636         if (result.length() > 0)
637             result += "; ";
638         result += "class=";
639         result += s;
640     }
641           
642     strncpy(buffer, result.string().latin1(), length - 1);
643 }
644 #endif
645
646 // -------------------------------------------------------------------------
647
648 XMLElementImpl::XMLElementImpl(DocumentPtr *doc, DOMStringImpl *_tagName)
649     : ElementImpl(doc)
650 {
651     m_id = doc->document()->tagId(0 /* no namespace */, _tagName,  false /* allocate */);
652 }
653
654 XMLElementImpl::XMLElementImpl(DocumentPtr *doc, DOMStringImpl *_qualifiedName, DOMStringImpl *_namespaceURI)
655     : ElementImpl(doc)
656 {
657     int colonpos = -1;
658     for (uint i = 0; i < _qualifiedName->l; ++i)
659         if (_qualifiedName->s[i] == ':') {
660             colonpos = i;
661             break;
662         }
663
664     if (colonpos >= 0) {
665         // we have a prefix
666         DOMStringImpl* localName = _qualifiedName->copy();
667         localName->ref();
668         localName->remove(0,colonpos+1);
669         m_id = doc->document()->tagId(_namespaceURI, localName, false /* allocate */);
670         localName->deref();
671         m_prefix = _qualifiedName->copy();
672         m_prefix->ref();
673         m_prefix->truncate(colonpos);
674     }
675     else {
676         // no prefix
677         m_id = doc->document()->tagId(_namespaceURI, _qualifiedName, false /* allocate */);
678         m_prefix = 0;
679     }
680 }
681
682 XMLElementImpl::~XMLElementImpl()
683 {
684 }
685
686 DOMString XMLElementImpl::localName() const
687 {
688     return getDocument()->tagName(m_id);
689 }
690
691
692 NodeImpl *XMLElementImpl::cloneNode ( bool deep )
693 {
694     // ### we loose namespace here FIXME
695     // should pass id around
696     XMLElementImpl *clone = new XMLElementImpl(docPtr(), getDocument()->tagName(m_id).implementation());
697     clone->m_id = m_id;
698
699     // clone attributes
700     if(namedAttrMap)
701         *(static_cast<NamedAttrMapImpl*>(clone->attributes())) = *namedAttrMap;
702
703     if (deep)
704         cloneChildNodes(clone);
705
706     return clone;
707 }
708
709 // -------------------------------------------------------------------------
710
711 NamedAttrMapImpl::NamedAttrMapImpl(ElementImpl *e)
712     : element(e)
713 {
714     attrs = 0;
715     len = 0;
716 }
717
718 NamedAttrMapImpl::~NamedAttrMapImpl()
719 {
720     NamedAttrMapImpl::clearAttributes(); // virtual method, so qualify just to be explicit
721 }
722
723 bool NamedAttrMapImpl::isHTMLAttributeMap() const
724 {
725     return false;
726 }
727
728 AttrImpl *NamedAttrMapImpl::getNamedItem ( NodeImpl::Id id ) const
729 {
730     AttributeImpl* a = getAttributeItem(id);
731     if (!a) return 0;
732
733     if (!a->attrImpl())
734         a->allocateImpl(element);
735
736     return a->attrImpl();
737 }
738
739 Node NamedAttrMapImpl::setNamedItem ( NodeImpl* arg, int &exceptioncode )
740 {
741     if (!element) {
742         exceptioncode = DOMException::NOT_FOUND_ERR;
743         return 0;
744     }
745
746     // NO_MODIFICATION_ALLOWED_ERR: Raised if this map is readonly.
747     if (isReadOnly()) {
748         exceptioncode = DOMException::NO_MODIFICATION_ALLOWED_ERR;
749         return 0;
750     }
751
752     // WRONG_DOCUMENT_ERR: Raised if arg was created from a different document than the one that created this map.
753     if (arg->getDocument() != element->getDocument()) {
754         exceptioncode = DOMException::WRONG_DOCUMENT_ERR;
755         return 0;
756     }
757
758     // Not mentioned in spec: throw a HIERARCHY_REQUEST_ERROR if the user passes in a non-attribute node
759     if (!arg->isAttributeNode()) {
760         exceptioncode = DOMException::HIERARCHY_REQUEST_ERR;
761         return 0;
762     }
763     AttrImpl *attr = static_cast<AttrImpl*>(arg);
764
765     AttributeImpl* a = attr->attrImpl();
766     AttributeImpl* old = getAttributeItem(a->id());
767     if (old == a) return arg; // we know about it already
768
769     // INUSE_ATTRIBUTE_ERR: Raised if arg is an Attr that is already an attribute of another Element object.
770     // The DOM user must explicitly clone Attr nodes to re-use them in other elements.
771     if (attr->ownerElement()) {
772         exceptioncode = DOMException::INUSE_ATTRIBUTE_ERR;
773         return 0;
774     }
775
776     if (a->id() == ATTR_ID) {
777         element->updateId(old ? old->value() : nullAtom, a->value());
778     }
779
780     // ### slightly inefficient - resizes attribute array twice.
781     Node r;
782     if (old) {
783         if (!old->attrImpl())
784             old->allocateImpl(element);
785         r = old->_impl;
786         removeAttribute(a->id());
787     }
788
789     addAttribute(a);
790     return r;
791 }
792
793 // The DOM2 spec doesn't say that removeAttribute[NS] throws NOT_FOUND_ERR
794 // if the attribute is not found, but at this level we have to throw NOT_FOUND_ERR
795 // because of removeNamedItem, removeNamedItemNS, and removeAttributeNode.
796 Node NamedAttrMapImpl::removeNamedItem ( NodeImpl::Id id, int &exceptioncode )
797 {
798     // ### should this really be raised when the attribute to remove isn't there at all?
799     // NO_MODIFICATION_ALLOWED_ERR: Raised when the node is readonly
800     if (isReadOnly()) {
801         exceptioncode = DOMException::NO_MODIFICATION_ALLOWED_ERR;
802         return Node();
803     }
804
805     AttributeImpl* a = getAttributeItem(id);
806     if (!a) {
807         exceptioncode = DOMException::NOT_FOUND_ERR;
808         return Node();
809     }
810
811     if (!a->attrImpl())  a->allocateImpl(element);
812     Node r(a->attrImpl());
813
814     if (id == ATTR_ID) {
815         element->updateId(a->value(), nullAtom);
816     }
817
818     removeAttribute(id);
819     return r;
820 }
821
822 AttrImpl *NamedAttrMapImpl::item ( unsigned long index ) const
823 {
824     if (index >= len)
825         return 0;
826
827     if (!attrs[index]->attrImpl())
828         attrs[index]->allocateImpl(element);
829
830     return attrs[index]->attrImpl();
831 }
832
833 AttributeImpl* NamedAttrMapImpl::getAttributeItem(NodeImpl::Id id) const
834 {
835     bool matchAnyNamespace = (namespacePart(id) == anyNamespace);
836     for (unsigned long i = 0; i < len; ++i) {
837         if (attrs[i]->id() == id)
838             return attrs[i];
839         else if (matchAnyNamespace) {
840             if (localNamePart(attrs[i]->id()) == localNamePart(id))
841                 return attrs[i];
842         }
843     }
844     return 0;
845 }
846
847 NodeImpl::Id NamedAttrMapImpl::mapId(const DOMString& namespaceURI,
848                                      const DOMString& localName, bool readonly)
849 {
850     assert(element);
851     if (!element) return 0;
852     return element->getDocument()->attrId(namespaceURI.implementation(),
853                                             localName.implementation(), readonly);
854 }
855
856 void NamedAttrMapImpl::clearAttributes()
857 {
858     if (attrs) {
859         uint i;
860         for (i = 0; i < len; i++) {
861             if (attrs[i]->_impl)
862                 attrs[i]->_impl->m_element = 0;
863             attrs[i]->deref();
864         }
865         delete [] attrs;
866         attrs = 0;
867     }
868     len = 0;
869 }
870
871 void NamedAttrMapImpl::detachFromElement()
872 {
873     // we allow a NamedAttrMapImpl w/o an element in case someone still has a reference
874     // to if after the element gets deleted - but the map is now invalid
875     element = 0;
876     clearAttributes();
877 }
878
879 NamedAttrMapImpl& NamedAttrMapImpl::operator=(const NamedAttrMapImpl& other)
880 {
881     // clone all attributes in the other map, but attach to our element
882     if (!element) return *this;
883
884     // If assigning the map changes the id attribute, we need to call
885     // updateId.
886
887     AttributeImpl *oldId = getAttributeItem(ATTR_ID);
888     AttributeImpl *newId = other.getAttributeItem(ATTR_ID);
889
890     if (oldId || newId) {
891         element->updateId(oldId ? oldId->value() : nullAtom, newId ? newId->value() : nullAtom);
892     }
893
894     clearAttributes();
895     len = other.len;
896     attrs = new AttributeImpl* [len];
897
898     // first initialize attrs vector, then call attributeChanged on it
899     // this allows attributeChanged to use getAttribute
900     for (uint i = 0; i < len; i++) {
901         attrs[i] = other.attrs[i]->clone();
902         attrs[i]->ref();
903     }
904
905     // FIXME: This is wasteful.  The class list could be preserved on a copy, and we
906     // wouldn't have to waste time reparsing the attribute.
907     // The derived class, HTMLNamedAttrMapImpl, which manages a parsed class list for the CLASS attribute,
908     // will update its member variable when parse attribute is called.
909     for(uint i = 0; i < len; i++)
910         element->attributeChanged(attrs[i], true);
911
912     return *this;
913 }
914
915 void NamedAttrMapImpl::addAttribute(AttributeImpl *attr)
916 {
917     // Add the attribute to the list
918     AttributeImpl **newAttrs = new AttributeImpl* [len+1];
919     if (attrs) {
920       for (uint i = 0; i < len; i++)
921         newAttrs[i] = attrs[i];
922       delete [] attrs;
923     }
924     attrs = newAttrs;
925     attrs[len++] = attr;
926     attr->ref();
927
928     AttrImpl * const attrImpl = attr->_impl;
929     if (attrImpl)
930         attrImpl->m_element = element;
931
932     // Notify the element that the attribute has been added, and dispatch appropriate mutation events
933     // Note that element may be null here if we are called from insertAttr() during parsing
934     if (element) {
935         element->attributeChanged(attr);
936         element->dispatchAttrAdditionEvent(attr);
937         element->dispatchSubtreeModifiedEvent();
938     }
939 }
940
941 void NamedAttrMapImpl::removeAttribute(NodeImpl::Id id)
942 {
943     unsigned long index = len+1;
944     for (unsigned long i = 0; i < len; ++i)
945         if (attrs[i]->id() == id) {
946             index = i;
947             break;
948         }
949
950     if (index >= len) return;
951
952     // Remove the attribute from the list
953     AttributeImpl* attr = attrs[index];
954     if (attrs[index]->_impl)
955         attrs[index]->_impl->m_element = 0;
956     if (len == 1) {
957         delete [] attrs;
958         attrs = 0;
959         len = 0;
960     }
961     else {
962         AttributeImpl **newAttrs = new AttributeImpl* [len-1];
963         uint i;
964         for (i = 0; i < uint(index); i++)
965             newAttrs[i] = attrs[i];
966         len--;
967         for (; i < len; i++)
968             newAttrs[i] = attrs[i+1];
969         delete [] attrs;
970         attrs = newAttrs;
971     }
972
973     // Notify the element that the attribute has been removed
974     // dispatch appropriate mutation events
975     if (element && !attr->_value.isNull()) {
976         AtomicString value = attr->_value;
977         attr->_value = nullAtom;
978         element->attributeChanged(attr);
979         attr->_value = value;
980     }
981     if (element) {
982         element->dispatchAttrRemovalEvent(attr);
983         element->dispatchSubtreeModifiedEvent();
984     }
985     attr->deref();
986 }
987