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  *           (C) 2003, 2004, 2005, 2006, 2007 Apple Inc. All rights reserved.
9  *
10  * This library is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Library General Public
12  * License as published by the Free Software Foundation; either
13  * version 2 of the License, or (at your option) any later version.
14  *
15  * This library is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  * Library General Public License for more details.
19  *
20  * You should have received a copy of the GNU Library General Public License
21  * along with this library; see the file COPYING.LIB.  If not, write to
22  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
23  * Boston, MA 02110-1301, USA.
24  *
25  */
26 #ifndef _DOM_ELEMENTImpl_h_
27 #define _DOM_ELEMENTImpl_h_
28 
29 #include "dom_nodeimpl.h"
30 #include "dom/dom_exception.h"
31 #include "dom/dom_element.h"
32 #include "xml/dom_stringimpl.h"
33 #include "misc/shared.h"
34 #include "wtf/Vector.h"
35 #include "xml/ClassNames.h"
36 
37 // WebCore SVG
38 #include "dom/QualifiedName.h"
39 // End WebCore SVG
40 
41 namespace khtml
42 {
43 class CSSStyleSelector;
44 }
45 
46 namespace DOM
47 {
48 
49 class ElementImpl;
50 class DocumentImpl;
51 class NamedAttrMapImpl;
52 class ElementRareDataImpl;
53 class CSSInlineStyleDeclarationImpl;
54 
55 // Attr can have Text and EntityReference children
56 // therefore it has to be a fullblown Node. The plan
57 // is to dynamically allocate a textchild and store the
58 // resulting nodevalue in the AttributeImpl upon
59 // destruction. however, this is not yet implemented.
60 class AttrImpl : public NodeBaseImpl
61 {
62     friend class ElementImpl;
63     friend class NamedAttrMapImpl;
64 
65 public:
66     AttrImpl(ElementImpl *element, DocumentImpl *docPtr, NamespaceName namespaceName, LocalName localName, PrefixName prefix, DOMStringImpl *value);
67     ~AttrImpl();
68 
69 private:
70     AttrImpl(const AttrImpl &other);
71     AttrImpl &operator = (const AttrImpl &other);
72     void createTextChild();
73 public:
74 
75     // DOM methods & attributes for Attr
specified()76     bool specified() const
77     {
78         return true; /* we don't yet support default attributes*/
79     }
ownerElement()80     ElementImpl *ownerElement() const
81     {
82         return m_element;
83     }
setOwnerElement(ElementImpl * impl)84     void setOwnerElement(ElementImpl *impl)
85     {
86         m_element = impl;
87     }
88     DOMString name() const;
89 
90     //DOMString value() const;
91     void setValue(const DOMString &v, int &exceptioncode);
92 
93     // DOM methods overridden from  parent classes
94     DOMString nodeName() const override;
95     unsigned short nodeType() const override;
96     DOMString prefix() const override;
97     void setPrefix(const DOMString &refix, int &exceptioncode) override;
98     DOMString namespaceURI() const override;
99     DOMString localName() const override;
100 
prefixName()101     inline const PrefixName &prefixName() const
102     {
103         return m_prefix;
104     }
105 
106     DOMString nodeValue() const override;
107     void setNodeValue(const DOMString &, int &exceptioncode) override;
108     WTF::PassRefPtr<NodeImpl> cloneNode(bool deep) override;
109 
110     // Other methods (not part of DOM)
isAttributeNode()111     bool isAttributeNode() const override
112     {
113         return true;
114     }
115     bool childAllowed(NodeImpl *newChild) override;
116     bool childTypeAllowed(unsigned short type) override;
id()117     NodeImpl::Id id() const override
118     {
119         return makeId(m_namespace.id(), m_localName.id());
120     }
121     void childrenChanged() override;
122 
123     // non-virtual id, for faster attribute look-ups
fastId()124     inline NodeImpl::Id fastId() const
125     {
126         return makeId(m_namespace.id(), m_localName.id());
127     }
128 
129     // This is used for when the value is normalized on setting by
130     // parseAttribute; it silently updates it w/o issuing any events, etc.
131     // Doesn't work for ATTR_ID!
132     void rewriteValue(const DOMString &newValue);
133 
134     DOMString toString() const override;
135 
136     void setElement(ElementImpl *element);
val()137     DOMStringImpl *val() const
138     {
139         return m_value;
140     }
141 
142 protected:
143     ElementImpl *m_element;
144     LocalName m_localName;
145     NamespaceName m_namespace;
146     PrefixName m_prefix;
147     DOMStringImpl *m_value;
148 };
149 
150 // Mini version of AttrImpl internal to NamedAttrMapImpl.
151 // Stores either the id (LocalName and NamespaceName) and value of an attribute
152 // (in the case of m_localName.id() != 0), or a pointer to an AttrImpl (if m_localName.id() == 0)
153 // The latter case only happens when the Attr node is requested by some DOM
154 // code or is an XML attribute.
155 // In most cases the id and value is all we need to store, which is more
156 // memory efficient.
157 // FIXME: update comment - no longer create mini version for only html attributes
158 struct AttributeImpl {
idAttributeImpl159     inline NodeImpl::Id id() const
160     {
161         return m_localName.id() ? makeId(m_namespace.id(), m_localName.id()) : m_data.attr->fastId();
162     }
valAttributeImpl163     DOMStringImpl *val() const
164     {
165         if (m_localName.id()) {
166             return m_data.value;
167         } else {
168             return m_data.attr->val();
169         }
170     }
valueAttributeImpl171     DOMString value() const
172     {
173         return val();
174     }
attrAttributeImpl175     AttrImpl *attr() const
176     {
177         return m_localName.id() ? nullptr : m_data.attr;
178     }
namespaceURIAttributeImpl179     DOMString namespaceURI() const
180     {
181         return m_localName.id() ? m_namespace.toString() : m_data.attr->namespaceURI();
182     }
prefixAttributeImpl183     DOMString prefix() const
184     {
185         return m_localName.id() ? m_prefix.toString() : m_data.attr->prefix();
186     }
localNameAttributeImpl187     DOMString localName() const
188     {
189         return m_localName.id() ? m_localName.toString() : m_data.attr->localName();
190     }
prefixNameAttributeImpl191     const PrefixName &prefixName() const
192     {
193         return m_localName.id() ? m_prefix : m_data.attr->prefixName();
194     }
195 
196     // for WebCore api compat
nameAttributeImpl197     QualifiedName name() const
198     {
199         return m_localName.id() ? QualifiedName(m_prefix, m_localName, m_namespace) : QualifiedName(id(), PrefixName::fromString(prefix()));
200     }
201 
202     void setValue(DOMStringImpl *value, ElementImpl *element);
203     AttrImpl *createAttr(ElementImpl *element, DocumentImpl *docPtr);
204     void free();
205 
206     // See the description for AttrImpl.
207     void rewriteValue(const DOMString &newValue);
208 
209     LocalName m_localName;
210     NamespaceName m_namespace;
211     PrefixName m_prefix;
212     union {
213         DOMStringImpl *value;
214         AttrImpl *attr;
215     } m_data;
216 };
217 
218 struct CombinedStyleDecl {
219     DOM::CSSInlineStyleDeclarationImpl *inlineDecls;
220     DOM::CSSStyleDeclarationImpl *nonCSSDecls;
221 };
222 
223 class ElementImpl : public NodeBaseImpl
224 {
225     friend class DocumentImpl;
226     friend class NamedAttrMapImpl;
227     friend class AttrImpl;
228     friend class NodeImpl;
229     friend class khtml::CSSStyleSelector;
230 public:
231     ElementImpl(DocumentImpl *doc);
232     ~ElementImpl();
233 
234     // stuff for WebCore DOM & SVG api compatibility
hasTagName(const QualifiedName & name)235     bool hasTagName(const QualifiedName &name) const override
236     {
237         return qualifiedName() == name;/*should be matches here*/
238     }
qualifiedName()239     QualifiedName qualifiedName() const
240     {
241         return QualifiedName(id(), m_prefix);
242     }
style()243     CSSInlineStyleDeclarationImpl *style()
244     {
245         return getInlineStyleDecls();
246     }
setAttribute(const QualifiedName & name,const DOMString & value)247     void setAttribute(const QualifiedName &name, const DOMString &value)
248     {
249         setAttribute(name.id(), value); /* is it enough for SVG or should the full setAttribute() be called? */
250     }
hasAttribute(const QualifiedName & name)251     bool hasAttribute(const QualifiedName &name) const
252     {
253         return hasAttribute(name.tagName());
254     }
getAttribute(const QualifiedName & name)255     DOMString getAttribute(const QualifiedName &name) const
256     {
257         int ec;
258         return const_cast<ElementImpl *>(this)->getAttributeNS(name.namespaceURI(), name.localName(), ec);
259     }
getAttributeNS(const DOMString & namespaceURI,const DOMString & localName,int & exceptionCode)260     DOMString getAttributeNS(const DOMString &namespaceURI, const DOMString &localName, int &exceptionCode) const
261     {
262         return const_cast<ElementImpl *>(this)->getAttributeNS(namespaceURI, localName, exceptionCode);
263     }
264     // FIXME: get rid of const_cast hacks (the const qualifiers of getAttribute should be reviewed
265     // as for external API it should look like const,hower we can replace AttributeImpl (small version)
266     // with normal AttrImpl (NodeImpl)
267     // END OF FIXME
268     // enf of WC api compatibility stuff
269 
270     //Higher-level DOM stuff
271     bool hasAttributes() const override;
272     bool hasAttribute(const DOMString &name) const;
273     bool hasAttributeNS(const DOMString &namespaceURI, const DOMString &localName) const;
274     DOMString getAttribute(const DOMString &name);
275     void setAttribute(const DOMString &name, const DOMString &value, int &exceptioncode);
276     void removeAttribute(const DOMString &name, int &exceptioncode);
277     void removeAttribute(NodeImpl::Id id, int &exceptioncode);
278     AttrImpl *getAttributeNode(const DOMString &name);
279     Attr setAttributeNode(AttrImpl *newAttr, int &exceptioncode);
280     Attr removeAttributeNode(AttrImpl *oldAttr, int &exceptioncode);
281 
282     DOMString getAttributeNS(const DOMString &namespaceURI, const DOMString &localName, int &exceptioncode);
283     void removeAttributeNS(const DOMString &namespaceURI, const DOMString &localName, int &exceptioncode);
284     AttrImpl *getAttributeNodeNS(const DOMString &namespaceURI, const DOMString &localName, int &exceptioncode);
285     Attr setAttributeNodeNS(AttrImpl *newAttr, int &exceptioncode);
286 
287     // At this level per WAI-ARIA
288     void blur();
289     void focus();
290 
291     //Lower-level implementation primitives
292     inline DOMString getAttribute(NodeImpl::Id id, const PrefixName &prefix = emptyPrefixName, bool nsAware = false) const
293     {
294         return DOMString(getAttributeImpl(id, prefix, nsAware));
295     }
296     inline DOMStringImpl *getAttributeImpl(NodeImpl::Id id, const PrefixName &prefix = emptyPrefixName, bool nsAware = false) const;
297     void setAttribute(NodeImpl::Id id, const PrefixName &prefix, bool nsAware, const DOMString &value, int &exceptioncode);
298     void setAttributeNS(const DOMString &namespaceURI, const DOMString &localName, const DOMString &value, int &exceptioncode);
299 
300     inline DOMStringImpl *getAttributeImplById(NodeImpl::Id id) const;
301 
302     // WebCore API
getIDAttribute()303     DOMString getIDAttribute() const
304     {
305         return getAttribute(ATTR_ID);
306     }
307     // End
308 
309     bool hasAttribute(NodeImpl::Id id, const PrefixName &prefix = emptyPrefixName, bool nsAware = false) const
310     {
311         return getAttributeImpl(id, prefix, nsAware) != nullptr;
312     }
prefix()313     DOMString prefix() const override
314     {
315         return m_prefix.toString();
316     }
317     void setPrefix(const DOMString &_prefix, int &exceptioncode) override;
318     DOMString namespaceURI() const override;
prefixName()319     inline const PrefixName &prefixName() const
320     {
321         return m_prefix;
322     }
323 
324     short tabIndex() const override;
325     void setTabIndex(short _tabIndex);
326     void setNoTabIndex();
327     bool hasTabIndex() const;
328 
329     // DOM methods overridden from  parent classes
330     virtual DOMString tagName() const;
331     DOMString localName() const override;
332 
333     // Internal version of tagName for elements that doesn't
334     // do case normalization
335     DOMString nonCaseFoldedTagName() const;
336 
337     unsigned short nodeType() const override;
338     WTF::PassRefPtr<NodeImpl> cloneNode(bool deep) override;
339     DOMString nodeName() const override;
340     NodeImpl::Id id() const override = 0;
isElementNode()341     bool isElementNode() const override
342     {
343         return true;
344     }
345     void insertedIntoDocument() override;
346     void removedFromDocument() override;
347 
348     // ElementTraversal API
349     ElementImpl *firstElementChild() const;
350     ElementImpl *lastElementChild() const;
351     ElementImpl *previousElementSibling() const;
352     ElementImpl *nextElementSibling() const;
353     unsigned childElementCount() const;
354 
355     // convenience methods which ignore exceptions
356     void setAttribute(NodeImpl::Id id, const DOMString &value);
357     void setBooleanAttribute(NodeImpl::Id id, bool b);
358 
359     NamedAttrMapImpl *attributes(bool readonly = false) const
360     {
361         if (m_needsStyleAttributeUpdate) {
362             synchronizeStyleAttribute();
363         }
364         if (!readonly && !namedAttrMap) {
365             createAttributeMap();
366         }
367         return namedAttrMap;
368     }
369 
370     //This is always called, whenever an attribute changed
parseAttribute(AttributeImpl *)371     virtual void parseAttribute(AttributeImpl *) {}
parseNullAttribute(NodeImpl::Id id,PrefixName prefix)372     void parseNullAttribute(NodeImpl::Id id, PrefixName prefix)
373     {
374         AttributeImpl aimpl;
375         aimpl.m_localName = LocalName::fromId(localNamePart(id));
376         aimpl.m_namespace = NamespaceName::fromId(namespacePart(id));
377         aimpl.m_prefix = prefix;
378         aimpl.m_data.value = nullptr;
379         parseAttribute(&aimpl);
380     }
381 
parseAttribute(AttrImpl * fullAttr)382     void parseAttribute(AttrImpl *fullAttr)
383     {
384         AttributeImpl aimpl;
385         aimpl.m_localName = emptyLocalName;
386         aimpl.m_data.attr = fullAttr;
387         parseAttribute(&aimpl);
388     }
389 
390     inline const ClassNames &classNames() const;
391 
392     // not part of the DOM
393     void setAttributeMap(NamedAttrMapImpl *list);
394 
395     // State of the element.
state()396     QString state() override
397     {
398         return QString();
399     }
400 
copyNonAttributeProperties(const ElementImpl *)401     virtual void copyNonAttributeProperties(const ElementImpl * /*source*/) {}
402 
403     void attach() override;
404     void close() override;
405     void detach() override;
406     void structureChanged() override;
407     void backwardsStructureChanged() override;
408     virtual void attributeChanged(NodeImpl::Id attrId);
409     // for WebCore API compatibility
attributeChanged(AttributeImpl * attribute,bool)410     virtual void attributeChanged(AttributeImpl *attribute, bool /*preserveDecls*/)
411     {
412         attributeChanged(attribute->id());
413     }
414 
415     void defaultEventHandler(EventImpl *evt) override;
416 
417     khtml::RenderStyle *styleForRenderer(khtml::RenderObject *parent) override;
418     khtml::RenderObject *createRenderer(khtml::RenderArena *, khtml::RenderStyle *) override;
419     void recalcStyle(StyleChange = NoChange) override;
420     khtml::RenderStyle *computedStyle() override;
421 
mouseEventHandler(MouseEvent *,bool)422     virtual void mouseEventHandler(MouseEvent * /*ev*/, bool /*inside*/) {}
423 
424     bool childAllowed(NodeImpl *newChild) override;
425     bool childTypeAllowed(unsigned short type) override;
inlineStyleDecls()426     DOM::CSSInlineStyleDeclarationImpl *inlineStyleDecls() const
427     {
428         return m_hasCombinedStyle ? m_style.combinedDecls->inlineDecls : m_style.inlineDecls;
429     }
nonCSSStyleDecls()430     DOM::CSSStyleDeclarationImpl *nonCSSStyleDecls() const
431     {
432         return m_hasCombinedStyle ? m_style.combinedDecls->nonCSSDecls : nullptr;
433     }
434     DOM::CSSInlineStyleDeclarationImpl *getInlineStyleDecls();
435 
436     void dispatchAttrRemovalEvent(NodeImpl::Id id, DOMStringImpl *value);
437     void dispatchAttrAdditionEvent(NodeImpl::Id id, DOMStringImpl *value);
438 
439     DOMString toString() const override;
440     DOMString selectionToString(NodeImpl *selectionStart, NodeImpl *selectionEnd, int startOffset, int endOffset, bool &found) const override;
441 
442     bool isFocusableImpl(FocusType ft) const override;
443     bool isContentEditable() const override;
444     void setContentEditable(bool enabled);
445 
446     void scrollIntoView(bool alignToTop);
447 
448     /** Returns the opening tag and properties.
449      *  Examples:  '<b', '<img alt="hello" src="image.png"
450      *
451      *  For security reasons, passwords are stripped out of all src= and
452      *  href=  tags if expandurls is turned on.
453      *
454      *  @param expandurls If this is set then in the above example, it would give
455      *                    src="http://website.com/image.png".  Note that the password
456      *                    is stripped out of the url.
457      *
458      *  DOM::RangeImpl uses this which is why it is public.
459      */
460     DOMString openTagStartToString(bool expandurls = false) const;
461 
462     void updateId(DOMStringImpl *oldId, DOMStringImpl *newId);
463     //Called when mapping from id to this node in document should be removed
464     virtual void removeId(const DOMString &id);
465     //Called when mapping from id to this node in document should be added
466     virtual void addId(const DOMString &id);
467 
468     // Synchronize style attribute after it was changed via CSSOM
469     void synchronizeStyleAttribute() const;
470 
471 protected:
472     void createAttributeMap() const;
473     void createInlineDecl(); // for inline styles
474     void createNonCSSDecl(); // for presentational styles
475     void finishCloneNode(ElementImpl *clone, bool deep);
476 
477 private:
478     // There is some information such as computed style for display:none
479     // elements that is needed only for a few elements. We store it
480     // in one of these.
481     ElementRareDataImpl *rareData();
482     const ElementRareDataImpl *rareData() const;
483     ElementRareDataImpl *createRareData();
484 
485 protected: // member variables
486     mutable NamedAttrMapImpl *namedAttrMap;
487 
488     union {
489         DOM::CSSInlineStyleDeclarationImpl *inlineDecls;
490         CombinedStyleDecl *combinedDecls;
491     } m_style;
492     PrefixName m_prefix;
493 };
494 
495 class XMLElementImpl : public ElementImpl
496 {
497 
498 public:
499     XMLElementImpl(DocumentImpl *doc, NamespaceName namespacename, LocalName localName, PrefixName prefix);
500     ~XMLElementImpl();
501 
502     void parseAttribute(AttributeImpl *attr) override;
503 
504     WTF::PassRefPtr<NodeImpl> cloneNode(bool deep) override;
505 
506     // Other methods (not part of DOM)
isXMLElementNode()507     bool isXMLElementNode() const override
508     {
509         return true;
510     }
id()511     Id id() const override
512     {
513         return makeId(m_namespace.id(), m_localName.id());
514     }
515 
516 protected:
517     LocalName m_localName;
518     NamespaceName m_namespace;
519 };
520 
521 // the map of attributes of an element
522 class NamedAttrMapImpl : public NamedNodeMapImpl
523 {
524     friend class ElementImpl;
525 public:
526     NamedAttrMapImpl(ElementImpl *element);
527     virtual ~NamedAttrMapImpl();
528 
529     // DOM methods & attributes for NamedNodeMap
530     NodeImpl *getNamedItem(NodeImpl::Id id, const PrefixName &prefix = emptyPrefixName, bool nsAware = false) override;
531     Node removeNamedItem(NodeImpl::Id id, const PrefixName &prefix, bool nsAware, int &exceptioncode) override;
532     Node setNamedItem(NodeImpl *arg, const PrefixName &prefix, bool nsAware, int &exceptioncode) override;
533 
534     // for WebCore api compat
getNamedItem(const QualifiedName & name)535     virtual NodeImpl *getNamedItem(const QualifiedName &name)
536     {
537         return getNamedItem(name.id(), name.prefixId(), true);
538     }
539 
540     NodeImpl *item(unsigned index) override;
length()541     unsigned length() const override
542     {
543         return m_attrs.size();
544     }
545 
546     // Other methods (not part of DOM)
isReadOnly()547     bool isReadOnly() override
548     {
549         return false;
550     }
htmlCompat()551     bool htmlCompat() override
552     {
553         return m_element ? m_element->m_htmlCompat : false;
554     }
555 
attributeAt(unsigned index)556     AttributeImpl &attributeAt(unsigned index)
557     {
558         return m_attrs[index];
559     }
attributeAt(unsigned index)560     const AttributeImpl &attributeAt(unsigned index) const
561     {
562         return m_attrs[index];
563     }
attrAt(unsigned index)564     AttrImpl *attrAt(unsigned index) const
565     {
566         return m_attrs[index].attr();
567     }
568     // ### replace idAt and getValueAt with attrAt
569     NodeImpl::Id idAt(unsigned index) const;
570     DOMStringImpl *valueAt(unsigned index) const;
571     DOMStringImpl *getValue(NodeImpl::Id id, const PrefixName &prefix = emptyPrefixName, bool nsAware = false) const;
572     void setValue(NodeImpl::Id id, DOMStringImpl *value, const PrefixName &prefix = emptyPrefixName, bool nsAware = false);
573     Attr removeAttr(AttrImpl *attr);
574     void copyAttributes(NamedAttrMapImpl *other);
575     void setElement(ElementImpl *element);
576     void detachFromElement();
577 
578     int find(NodeImpl::Id id, const PrefixName &prefix, bool nsAware) const;
579     inline DOMStringImpl *fastFind(NodeImpl::Id id) const;
580 
clearClass()581     inline void clearClass()
582     {
583         m_classNames.clear();
584     }
585     void setClass(const DOMString &string);
classNames()586     inline const ClassNames &classNames() const
587     {
588         return m_classNames;
589     }
590 
591     // Rewrites value if attribute already exists or adds a new attribute otherwise
592     // @important: any changes won't be propagated to parent Element
593     void setValueWithoutElementUpdate(NodeImpl::Id id, DOMStringImpl *value);
594 
595 protected:
596     ElementImpl *m_element;
597     WTF::Vector<AttributeImpl> m_attrs;
598     ClassNames m_classNames;
599 };
600 
601 // ------------  inline DOM helper functions ---------------
602 
checkQualifiedName(const DOMString & qualifiedName,const DOMString & namespaceURI,int * colonPos,bool nameCanBeNull,bool nameCanBeEmpty,int * pExceptioncode)603 inline bool checkQualifiedName(const DOMString &qualifiedName, const DOMString &namespaceURI, int *colonPos,
604                                bool nameCanBeNull, bool nameCanBeEmpty, int *pExceptioncode)
605 {
606 
607     // Not mentioned in spec: throw NAMESPACE_ERR if no qualifiedName supplied
608     if (!nameCanBeNull && qualifiedName.isNull()) {
609         if (pExceptioncode) {
610             *pExceptioncode = DOMException::NAMESPACE_ERR;
611         }
612         return false;
613     }
614 
615     // INVALID_CHARACTER_ERR: Raised if the specified qualified name contains an illegal character.
616     if (!qualifiedName.isNull() && !Element::khtmlValidQualifiedName(qualifiedName)
617             && (!qualifiedName.isEmpty() || !nameCanBeEmpty)) {
618         if (pExceptioncode) {
619             *pExceptioncode = DOMException::INVALID_CHARACTER_ERR;
620         }
621         return false;
622     }
623 
624     // NAMESPACE_ERR:
625     // - Raised if the qualifiedName is malformed,
626     // - if the qualifiedName has a prefix and the namespaceURI is null, or
627     // - if the qualifiedName is null and the namespaceURI is different from null
628     // - if the qualifiedName has a prefix that is "xml" and the namespaceURI is different
629     //   from "http://www.w3.org/XML/1998/namespace" [Namespaces].
630     int colonpos = -1;
631     uint i;
632     DOMStringImpl *qname = qualifiedName.implementation();
633     for (i = 0; i < (qname ? qname->l : 0); i++) {
634         if ((*qname)[i] == QLatin1Char(':')) {
635             colonpos = i;
636             break;
637         }
638     }
639 
640     bool hasXMLPrefix = colonpos == 3 && (*qname)[0] == QLatin1Char('x') &&
641                         (*qname)[1] == QLatin1Char('m') && (*qname)[2] == QLatin1Char('l');
642     bool hasXMLNSPrefix = colonpos == 5 && (*qname)[0] == QLatin1Char('x') &&
643                           (*qname)[1] == QLatin1Char('m') && (*qname)[2] == QLatin1Char('l') &&
644                           (*qname)[3] == QLatin1Char('n') && (*qname)[4] == QLatin1Char('s');
645 
646     if ((!qualifiedName.isNull() && Element::khtmlMalformedQualifiedName(qualifiedName)) ||
647             (colonpos >= 0 && namespaceURI.isNull()) ||
648             colonpos == 0 || // prefix has to consist of at least a letter
649             (qualifiedName.isNull() && !namespaceURI.isNull()) ||
650             (hasXMLPrefix && namespaceURI != XML_NAMESPACE) ||
651             (hasXMLNSPrefix && namespaceURI != XMLNS_NAMESPACE) ||
652             (namespaceURI == XMLNS_NAMESPACE && !hasXMLNSPrefix && qualifiedName != "xmlns")) {
653         if (pExceptioncode) {
654             *pExceptioncode = DOMException::NAMESPACE_ERR;
655         }
656         return false;
657     }
658     if (colonPos) {
659         *colonPos = colonpos;
660     }
661     return true;
662 }
663 
664 inline void splitPrefixLocalName(DOMStringImpl *qualifiedName, DOMString &prefix, DOMString &localName, int colonPos = -2)
665 {
666     if (colonPos == -2)
667         for (uint i = 0; i < qualifiedName->l; ++i)
668             if (qualifiedName->s[i] == QLatin1Char(':')) {
669                 colonPos = i;
670                 break;
671             }
672     if (colonPos >= 0) {
673         prefix = qualifiedName->copy();
674         localName = prefix.split(colonPos + 1);
675         prefix.implementation()->truncate(colonPos);
676     } else {
677         localName = qualifiedName;
678     }
679 }
680 
681 inline void splitPrefixLocalName(const DOMString &qualifiedName, PrefixName &prefix, LocalName &localName, bool htmlCompat = false, int colonPos = -2)
682 {
683     DOMString localname, prefixname;
684     splitPrefixLocalName(qualifiedName.implementation(), prefixname, localname, colonPos);
685     if (htmlCompat) {
686         prefix = PrefixName::fromString(prefixname, khtml::IDS_NormalizeLower);
687         localName = LocalName::fromString(localname, khtml::IDS_NormalizeLower);
688     } else {
689         prefix = PrefixName::fromString(prefixname);
690         localName = LocalName::fromString(localname);
691     }
692 }
693 
694 // methods that could be very hot and therefore need to be inlined
getAttributeImpl(NodeImpl::Id id,const PrefixName & prefix,bool nsAware)695 inline DOMStringImpl *ElementImpl::getAttributeImpl(NodeImpl::Id id, const PrefixName &prefix, bool nsAware) const
696 {
697     if (m_needsStyleAttributeUpdate && (id == ATTR_STYLE)) {
698         synchronizeStyleAttribute();
699     }
700     return namedAttrMap ? namedAttrMap->getValue(id, prefix, nsAware) : nullptr;
701 }
702 
classNames()703 inline const ClassNames &ElementImpl::classNames() const
704 {
705     // hasClass() should be called on element first as in CSSStyleSelector::checkSimpleSelector
706     return namedAttrMap->classNames();
707 }
708 
getAttributeImplById(NodeImpl::Id id)709 inline DOMStringImpl *ElementImpl::getAttributeImplById(NodeImpl::Id id) const
710 {
711     return namedAttrMap ? namedAttrMap->fastFind(id) : nullptr;
712 }
713 
fastFind(NodeImpl::Id id)714 inline DOMStringImpl *NamedAttrMapImpl::fastFind(NodeImpl::Id id) const
715 {
716     unsigned mask = anyQName;
717     if (namespacePart(id) == anyNamespace) {
718         mask = anyLocalName;
719         id = localNamePart(id);
720     }
721     unsigned len = m_attrs.size();
722     for (unsigned i = 0; i < len; ++i)
723         if (id == (m_attrs[i].id() & mask)) {
724             return m_attrs[i].val();
725         }
726     return nullptr;
727 }
728 
729 } //namespace
730 
731 #endif
732