Home | History | Annotate | Download | only in dom
      1 /*
      2  * Copyright (C) 2013 Google Inc. All rights reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions are
      6  * met:
      7  *
      8  *     * Redistributions of source code must retain the above copyright
      9  * notice, this list of conditions and the following disclaimer.
     10  *     * Redistributions in binary form must reproduce the above
     11  * copyright notice, this list of conditions and the following disclaimer
     12  * in the documentation and/or other materials provided with the
     13  * distribution.
     14  *     * Neither the name of Google Inc. nor the names of its
     15  * contributors may be used to endorse or promote products derived from
     16  * this software without specific prior written permission.
     17  *
     18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     29  */
     30 
     31 #ifndef ElementData_h
     32 #define ElementData_h
     33 
     34 #include "core/dom/Attribute.h"
     35 #include "core/dom/SpaceSplitString.h"
     36 #include "wtf/text/AtomicString.h"
     37 
     38 namespace WebCore {
     39 
     40 class Attr;
     41 class ShareableElementData;
     42 class StylePropertySet;
     43 class UniqueElementData;
     44 
     45 class ElementData : public RefCounted<ElementData> {
     46     WTF_MAKE_FAST_ALLOCATED;
     47 public:
     48     // Override RefCounted's deref() to ensure operator delete is called on
     49     // the appropriate subclass type.
     50     void deref();
     51 
     52     void clearClass() const { m_classNames.clear(); }
     53     void setClass(const AtomicString& className, bool shouldFoldCase) const { m_classNames.set(className, shouldFoldCase); }
     54     const SpaceSplitString& classNames() const { return m_classNames; }
     55 
     56     const AtomicString& idForStyleResolution() const { return m_idForStyleResolution; }
     57     void setIdForStyleResolution(const AtomicString& newId) const { m_idForStyleResolution = newId; }
     58 
     59     const StylePropertySet* inlineStyle() const { return m_inlineStyle.get(); }
     60 
     61     const StylePropertySet* presentationAttributeStyle() const;
     62 
     63     size_t length() const;
     64     bool isEmpty() const { return !length(); }
     65 
     66     const Attribute* attributeItem(unsigned index) const;
     67     const Attribute* getAttributeItem(const QualifiedName&) const;
     68     size_t getAttributeItemIndex(const QualifiedName&, bool shouldIgnoreCase = false) const;
     69     size_t getAttributeItemIndex(const AtomicString& name, bool shouldIgnoreAttributeCase) const;
     70     size_t getAttrIndex(Attr*) const;
     71 
     72     bool hasID() const { return !m_idForStyleResolution.isNull(); }
     73     bool hasClass() const { return !m_classNames.isNull(); }
     74 
     75     bool isEquivalent(const ElementData* other) const;
     76 
     77     bool isUnique() const { return m_isUnique; }
     78 
     79 protected:
     80     ElementData();
     81     explicit ElementData(unsigned arraySize);
     82     ElementData(const ElementData&, bool isUnique);
     83 
     84     unsigned m_isUnique : 1;
     85     unsigned m_arraySize : 28;
     86     mutable unsigned m_presentationAttributeStyleIsDirty : 1;
     87     mutable unsigned m_styleAttributeIsDirty : 1;
     88     mutable unsigned m_animatedSVGAttributesAreDirty : 1;
     89 
     90     mutable RefPtr<StylePropertySet> m_inlineStyle;
     91     mutable SpaceSplitString m_classNames;
     92     mutable AtomicString m_idForStyleResolution;
     93 
     94 private:
     95     friend class Element;
     96     friend class ShareableElementData;
     97     friend class UniqueElementData;
     98     friend class SVGElement;
     99 
    100     void destroy();
    101 
    102     const Attribute* attributeBase() const;
    103     const Attribute* getAttributeItem(const AtomicString& name, bool shouldIgnoreAttributeCase) const;
    104     size_t getAttributeItemIndexSlowCase(const AtomicString& name, bool shouldIgnoreAttributeCase) const;
    105 
    106     PassRefPtr<UniqueElementData> makeUniqueCopy() const;
    107 };
    108 
    109 #if COMPILER(MSVC)
    110 #pragma warning(push)
    111 #pragma warning(disable: 4200) // Disable "zero-sized array in struct/union" warning
    112 #endif
    113 
    114 class ShareableElementData : public ElementData {
    115 public:
    116     static PassRefPtr<ShareableElementData> createWithAttributes(const Vector<Attribute>&);
    117 
    118     explicit ShareableElementData(const Vector<Attribute>&);
    119     explicit ShareableElementData(const UniqueElementData&);
    120     ~ShareableElementData();
    121 
    122     Attribute m_attributeArray[0];
    123 };
    124 
    125 #if COMPILER(MSVC)
    126 #pragma warning(pop)
    127 #endif
    128 
    129 class UniqueElementData : public ElementData {
    130 public:
    131     static PassRefPtr<UniqueElementData> create();
    132     PassRefPtr<ShareableElementData> makeShareableCopy() const;
    133 
    134     // These functions do no error/duplicate checking.
    135     void addAttribute(const QualifiedName&, const AtomicString&);
    136     void removeAttribute(size_t index);
    137 
    138     Attribute* attributeItem(unsigned index);
    139     Attribute* getAttributeItem(const QualifiedName&);
    140 
    141     UniqueElementData();
    142     explicit UniqueElementData(const ShareableElementData&);
    143     explicit UniqueElementData(const UniqueElementData&);
    144 
    145     mutable RefPtr<StylePropertySet> m_presentationAttributeStyle;
    146     Vector<Attribute, 4> m_attributeVector;
    147 };
    148 
    149 inline void ElementData::deref()
    150 {
    151     if (!derefBase())
    152         return;
    153     destroy();
    154 }
    155 
    156 inline size_t ElementData::length() const
    157 {
    158     if (isUnique())
    159         return static_cast<const UniqueElementData*>(this)->m_attributeVector.size();
    160     return m_arraySize;
    161 }
    162 
    163 inline const StylePropertySet* ElementData::presentationAttributeStyle() const
    164 {
    165     if (!m_isUnique)
    166         return 0;
    167     return static_cast<const UniqueElementData*>(this)->m_presentationAttributeStyle.get();
    168 }
    169 
    170 inline const Attribute* ElementData::getAttributeItem(const AtomicString& name, bool shouldIgnoreAttributeCase) const
    171 {
    172     size_t index = getAttributeItemIndex(name, shouldIgnoreAttributeCase);
    173     if (index != kNotFound)
    174         return attributeItem(index);
    175     return 0;
    176 }
    177 
    178 inline const Attribute* ElementData::attributeBase() const
    179 {
    180     if (m_isUnique)
    181         return static_cast<const UniqueElementData*>(this)->m_attributeVector.begin();
    182     return static_cast<const ShareableElementData*>(this)->m_attributeArray;
    183 }
    184 
    185 inline size_t ElementData::getAttributeItemIndex(const QualifiedName& name, bool shouldIgnoreCase) const
    186 {
    187     const Attribute* begin = attributeBase();
    188     // Cache length for performance as ElementData::length() contains a conditional branch.
    189     unsigned len = length();
    190     for (unsigned i = 0; i < len; ++i) {
    191         const Attribute& attribute = begin[i];
    192         if (attribute.name().matchesPossiblyIgnoringCase(name, shouldIgnoreCase))
    193             return i;
    194     }
    195     return kNotFound;
    196 }
    197 
    198 // We use a boolean parameter instead of calling shouldIgnoreAttributeCase so that the caller
    199 // can tune the behavior (hasAttribute is case sensitive whereas getAttribute is not).
    200 inline size_t ElementData::getAttributeItemIndex(const AtomicString& name, bool shouldIgnoreAttributeCase) const
    201 {
    202     // Cache length for performance as ElementData::length() contains a conditional branch.
    203     unsigned len = length();
    204     bool doSlowCheck = shouldIgnoreAttributeCase;
    205 
    206     // Optimize for the case where the attribute exists and its name exactly matches.
    207     const Attribute* begin = attributeBase();
    208     for (unsigned i = 0; i < len; ++i) {
    209         const Attribute& attribute = begin[i];
    210         // FIXME: Why check the prefix? Namespaces should be all that matter.
    211         // Most attributes (all of HTML and CSS) have no namespace.
    212         if (!attribute.name().hasPrefix()) {
    213             if (name == attribute.localName())
    214                 return i;
    215         } else {
    216             doSlowCheck = true;
    217         }
    218     }
    219 
    220     if (doSlowCheck)
    221         return getAttributeItemIndexSlowCase(name, shouldIgnoreAttributeCase);
    222     return kNotFound;
    223 }
    224 
    225 inline const Attribute* ElementData::getAttributeItem(const QualifiedName& name) const
    226 {
    227     const Attribute* begin = attributeBase();
    228     for (unsigned i = 0; i < length(); ++i) {
    229         const Attribute& attribute = begin[i];
    230         if (attribute.name().matches(name))
    231             return &attribute;
    232     }
    233     return 0;
    234 }
    235 
    236 inline const Attribute* ElementData::attributeItem(unsigned index) const
    237 {
    238     RELEASE_ASSERT(index < length());
    239     return attributeBase() + index;
    240 }
    241 
    242 inline void UniqueElementData::addAttribute(const QualifiedName& attributeName, const AtomicString& value)
    243 {
    244     m_attributeVector.append(Attribute(attributeName, value));
    245 }
    246 
    247 inline void UniqueElementData::removeAttribute(size_t index)
    248 {
    249     m_attributeVector.remove(index);
    250 }
    251 
    252 inline Attribute* UniqueElementData::attributeItem(unsigned index)
    253 {
    254     return &m_attributeVector.at(index);
    255 }
    256 
    257 } // namespace WebCore
    258 
    259 #endif // ElementData_h
    260