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