Home | History | Annotate | Download | only in dom
      1 /*
      2  * Copyright (C) 1999 Lars Knoll (knoll (at) kde.org)
      3  *           (C) 1999 Antti Koivisto (koivisto (at) kde.org)
      4  *           (C) 2001 Peter Kelly (pmk (at) post.com)
      5  *           (C) 2001 Dirk Mueller (mueller (at) kde.org)
      6  * Copyright (C) 2003, 2004, 2005, 2006, 2008, 2010 Apple Inc. All rights reserved.
      7  *
      8  * This library is free software; you can redistribute it and/or
      9  * modify it under the terms of the GNU Library General Public
     10  * License as published by the Free Software Foundation; either
     11  * version 2 of the License, or (at your option) any later version.
     12  *
     13  * This library is distributed in the hope that it will be useful,
     14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     16  * Library General Public License for more details.
     17  *
     18  * You should have received a copy of the GNU Library General Public License
     19  * along with this library; see the file COPYING.LIB.  If not, write to
     20  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
     21  * Boston, MA 02110-1301, USA.
     22  *
     23  */
     24 
     25 #ifndef NamedNodeMap_h
     26 #define NamedNodeMap_h
     27 
     28 #include "Attribute.h"
     29 #include "SpaceSplitString.h"
     30 
     31 namespace WebCore {
     32 
     33 class Node;
     34 
     35 typedef int ExceptionCode;
     36 
     37 class NamedNodeMap : public RefCounted<NamedNodeMap> {
     38     friend class Element;
     39 public:
     40     static PassRefPtr<NamedNodeMap> create(Element* element = 0)
     41     {
     42         return adoptRef(new NamedNodeMap(element));
     43     }
     44 
     45     ~NamedNodeMap();
     46 
     47     // Public DOM interface.
     48 
     49     PassRefPtr<Node> getNamedItem(const String& name) const;
     50     PassRefPtr<Node> removeNamedItem(const String& name, ExceptionCode&);
     51 
     52     PassRefPtr<Node> getNamedItemNS(const String& namespaceURI, const String& localName) const;
     53     PassRefPtr<Node> removeNamedItemNS(const String& namespaceURI, const String& localName, ExceptionCode&);
     54 
     55     PassRefPtr<Node> getNamedItem(const QualifiedName& name) const;
     56     PassRefPtr<Node> removeNamedItem(const QualifiedName& name, ExceptionCode&);
     57     PassRefPtr<Node> setNamedItem(Node*, ExceptionCode&);
     58     PassRefPtr<Node> setNamedItemNS(Node*, ExceptionCode&);
     59 
     60     PassRefPtr<Node> item(unsigned index) const;
     61     size_t length() const { return m_attributes.size(); }
     62     bool isEmpty() const { return !length(); }
     63 
     64     // Internal interface.
     65 
     66     void setAttributes(const NamedNodeMap&);
     67 
     68     Attribute* attributeItem(unsigned index) const { return m_attributes[index].get(); }
     69     Attribute* getAttributeItem(const QualifiedName&) const;
     70 
     71     void copyAttributesToVector(Vector<RefPtr<Attribute> >&);
     72 
     73     void shrinkToLength() { m_attributes.shrinkCapacity(length()); }
     74     void reserveInitialCapacity(unsigned capacity) { m_attributes.reserveInitialCapacity(capacity); }
     75 
     76     // Used during parsing: only inserts if not already there. No error checking!
     77     void insertAttribute(PassRefPtr<Attribute> newAttribute, bool allowDuplicates)
     78     {
     79         ASSERT(!m_element);
     80         if (allowDuplicates || !getAttributeItem(newAttribute->name()))
     81             addAttribute(newAttribute);
     82     }
     83 
     84     const AtomicString& idForStyleResolution() const { return m_idForStyleResolution; }
     85     void setIdForStyleResolution(const AtomicString& newId) { m_idForStyleResolution = newId; }
     86 
     87     // FIXME: These two functions should be merged if possible.
     88     bool mapsEquivalent(const NamedNodeMap* otherMap) const;
     89     bool mappedMapsEquivalent(const NamedNodeMap* otherMap) const;
     90 
     91     // These functions do no error checking.
     92     void addAttribute(PassRefPtr<Attribute>);
     93     void removeAttribute(const QualifiedName&);
     94 
     95     Element* element() const { return m_element; }
     96 
     97     void clearClass() { m_classNames.clear(); }
     98     void setClass(const String&);
     99     const SpaceSplitString& classNames() const { return m_classNames; }
    100 
    101     bool hasMappedAttributes() const { return m_mappedAttributeCount > 0; }
    102     void declRemoved() { m_mappedAttributeCount--; }
    103     void declAdded() { m_mappedAttributeCount++; }
    104 
    105 private:
    106     NamedNodeMap(Element* element)
    107         : m_mappedAttributeCount(0)
    108         , m_element(element)
    109     {
    110     }
    111 
    112     void detachAttributesFromElement();
    113     void detachFromElement();
    114     Attribute* getAttributeItem(const String& name, bool shouldIgnoreAttributeCase) const;
    115     Attribute* getAttributeItemSlowCase(const String& name, bool shouldIgnoreAttributeCase) const;
    116     void clearAttributes();
    117     int declCount() const;
    118 
    119     int m_mappedAttributeCount;
    120     SpaceSplitString m_classNames;
    121     Element* m_element;
    122     Vector<RefPtr<Attribute> > m_attributes;
    123     AtomicString m_idForStyleResolution;
    124 };
    125 
    126 inline Attribute* NamedNodeMap::getAttributeItem(const QualifiedName& name) const
    127 {
    128     unsigned len = length();
    129     for (unsigned i = 0; i < len; ++i) {
    130         if (m_attributes[i]->name().matches(name))
    131             return m_attributes[i].get();
    132     }
    133     return 0;
    134 }
    135 
    136 // We use a boolean parameter instead of calling shouldIgnoreAttributeCase so that the caller
    137 // can tune the behavior (hasAttribute is case sensitive whereas getAttribute is not).
    138 inline Attribute* NamedNodeMap::getAttributeItem(const String& name, bool shouldIgnoreAttributeCase) const
    139 {
    140     unsigned len = length();
    141     bool doSlowCheck = shouldIgnoreAttributeCase;
    142 
    143     // Optimize for the case where the attribute exists and its name exactly matches.
    144     for (unsigned i = 0; i < len; ++i) {
    145         const QualifiedName& attrName = m_attributes[i]->name();
    146         if (!attrName.hasPrefix()) {
    147             if (name == attrName.localName())
    148                 return m_attributes[i].get();
    149         } else
    150             doSlowCheck = true;
    151     }
    152 
    153     if (doSlowCheck)
    154         return getAttributeItemSlowCase(name, shouldIgnoreAttributeCase);
    155     return 0;
    156 }
    157 
    158 } // namespace WebCore
    159 
    160 #endif // NamedNodeMap_h
    161