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 #include "config.h"
     32 #include "core/dom/ElementData.h"
     33 
     34 #include "core/css/StylePropertySet.h"
     35 #include "core/dom/Attr.h"
     36 #include "core/dom/QualifiedName.h"
     37 #include "wtf/Vector.h"
     38 
     39 namespace WebCore {
     40 
     41 struct SameSizeAsElementData : public RefCounted<SameSizeAsElementData> {
     42     unsigned bitfield;
     43     void* refPtrs[3];
     44 };
     45 
     46 COMPILE_ASSERT(sizeof(ElementData) == sizeof(SameSizeAsElementData), element_attribute_data_should_stay_small);
     47 
     48 static size_t sizeForShareableElementDataWithAttributeCount(unsigned count)
     49 {
     50     return sizeof(ShareableElementData) + sizeof(Attribute) * count;
     51 }
     52 
     53 ElementData::ElementData()
     54     : m_isUnique(true)
     55     , m_arraySize(0)
     56     , m_presentationAttributeStyleIsDirty(false)
     57     , m_styleAttributeIsDirty(false)
     58     , m_animatedSVGAttributesAreDirty(false)
     59 {
     60 }
     61 
     62 ElementData::ElementData(unsigned arraySize)
     63     : m_isUnique(false)
     64     , m_arraySize(arraySize)
     65     , m_presentationAttributeStyleIsDirty(false)
     66     , m_styleAttributeIsDirty(false)
     67     , m_animatedSVGAttributesAreDirty(false)
     68 {
     69 }
     70 
     71 ElementData::ElementData(const ElementData& other, bool isUnique)
     72     : m_isUnique(isUnique)
     73     , m_arraySize(isUnique ? 0 : other.attributeCount())
     74     , m_presentationAttributeStyleIsDirty(other.m_presentationAttributeStyleIsDirty)
     75     , m_styleAttributeIsDirty(other.m_styleAttributeIsDirty)
     76     , m_animatedSVGAttributesAreDirty(other.m_animatedSVGAttributesAreDirty)
     77     , m_classNames(other.m_classNames)
     78     , m_idForStyleResolution(other.m_idForStyleResolution)
     79 {
     80     // NOTE: The inline style is copied by the subclass copy constructor since we don't know what to do with it here.
     81 }
     82 
     83 void ElementData::destroy()
     84 {
     85     if (m_isUnique)
     86         delete static_cast<UniqueElementData*>(this);
     87     else
     88         delete static_cast<ShareableElementData*>(this);
     89 }
     90 
     91 PassRefPtr<UniqueElementData> ElementData::makeUniqueCopy() const
     92 {
     93     if (isUnique())
     94         return adoptRef(new UniqueElementData(static_cast<const UniqueElementData&>(*this)));
     95     return adoptRef(new UniqueElementData(static_cast<const ShareableElementData&>(*this)));
     96 }
     97 
     98 bool ElementData::isEquivalent(const ElementData* other) const
     99 {
    100     if (!other)
    101         return !hasAttributes();
    102 
    103     AttributeCollection attributes = this->attributes();
    104     if (attributes.size() != other->attributeCount())
    105         return false;
    106 
    107     AttributeCollection::const_iterator end = attributes.end();
    108     for (AttributeCollection::const_iterator it = attributes.begin(); it != end; ++it) {
    109         const Attribute* otherAttr = other->findAttributeByName(it->name());
    110         if (!otherAttr || it->value() != otherAttr->value())
    111             return false;
    112     }
    113     return true;
    114 }
    115 
    116 size_t ElementData::findAttrNodeIndex(Attr* attr) const
    117 {
    118     // This relies on the fact that Attr's QualifiedName == the Attribute's name.
    119     AttributeCollection attributes = this->attributes();
    120     AttributeCollection::const_iterator end = attributes.end();
    121     unsigned index = 0;
    122     for (AttributeCollection::const_iterator it = attributes.begin(); it != end; ++it, ++index) {
    123         if (it->name() == attr->qualifiedName())
    124             return index;
    125     }
    126     return kNotFound;
    127 }
    128 
    129 size_t ElementData::findAttributeIndexByNameSlowCase(const AtomicString& name, bool shouldIgnoreAttributeCase) const
    130 {
    131     // Continue to checking case-insensitively and/or full namespaced names if necessary:
    132     AttributeCollection attributes = this->attributes();
    133     AttributeCollection::const_iterator end = attributes.end();
    134     unsigned index = 0;
    135     for (AttributeCollection::const_iterator it = attributes.begin(); it != end; ++it, ++index) {
    136         // FIXME: Why check the prefix? Namespace is all that should matter
    137         // and all HTML/SVG attributes have a null namespace!
    138         if (!it->name().hasPrefix()) {
    139             if (shouldIgnoreAttributeCase && equalIgnoringCase(name, it->localName()))
    140                 return index;
    141         } else {
    142             // FIXME: Would be faster to do this comparison without calling toString, which
    143             // generates a temporary string by concatenation. But this branch is only reached
    144             // if the attribute name has a prefix, which is rare in HTML.
    145             if (equalPossiblyIgnoringCase(name, it->name().toString(), shouldIgnoreAttributeCase))
    146                 return index;
    147         }
    148     }
    149     return kNotFound;
    150 }
    151 
    152 ShareableElementData::ShareableElementData(const Vector<Attribute>& attributes)
    153     : ElementData(attributes.size())
    154 {
    155     for (unsigned i = 0; i < m_arraySize; ++i)
    156         new (&m_attributeArray[i]) Attribute(attributes[i]);
    157 }
    158 
    159 ShareableElementData::~ShareableElementData()
    160 {
    161     for (unsigned i = 0; i < m_arraySize; ++i)
    162         m_attributeArray[i].~Attribute();
    163 }
    164 
    165 ShareableElementData::ShareableElementData(const UniqueElementData& other)
    166     : ElementData(other, false)
    167 {
    168     ASSERT(!other.m_presentationAttributeStyle);
    169 
    170     if (other.m_inlineStyle) {
    171         m_inlineStyle = other.m_inlineStyle->immutableCopyIfNeeded();
    172     }
    173 
    174     for (unsigned i = 0; i < m_arraySize; ++i)
    175         new (&m_attributeArray[i]) Attribute(other.m_attributeVector.at(i));
    176 }
    177 
    178 PassRefPtr<ShareableElementData> ShareableElementData::createWithAttributes(const Vector<Attribute>& attributes)
    179 {
    180     void* slot = WTF::fastMalloc(sizeForShareableElementDataWithAttributeCount(attributes.size()));
    181     return adoptRef(new (slot) ShareableElementData(attributes));
    182 }
    183 
    184 UniqueElementData::UniqueElementData()
    185 {
    186 }
    187 
    188 UniqueElementData::UniqueElementData(const UniqueElementData& other)
    189     : ElementData(other, true)
    190     , m_presentationAttributeStyle(other.m_presentationAttributeStyle)
    191     , m_attributeVector(other.m_attributeVector)
    192 {
    193     m_inlineStyle = other.m_inlineStyle ? other.m_inlineStyle->mutableCopy() : nullptr;
    194 }
    195 
    196 UniqueElementData::UniqueElementData(const ShareableElementData& other)
    197     : ElementData(other, true)
    198 {
    199     // An ShareableElementData should never have a mutable inline StylePropertySet attached.
    200     ASSERT(!other.m_inlineStyle || !other.m_inlineStyle->isMutable());
    201     m_inlineStyle = other.m_inlineStyle;
    202 
    203     unsigned length = other.attributeCount();
    204     m_attributeVector.reserveCapacity(length);
    205     for (unsigned i = 0; i < length; ++i)
    206         m_attributeVector.uncheckedAppend(other.m_attributeArray[i]);
    207 }
    208 
    209 PassRefPtr<UniqueElementData> UniqueElementData::create()
    210 {
    211     return adoptRef(new UniqueElementData);
    212 }
    213 
    214 PassRefPtr<ShareableElementData> UniqueElementData::makeShareableCopy() const
    215 {
    216     void* slot = WTF::fastMalloc(sizeForShareableElementDataWithAttributeCount(m_attributeVector.size()));
    217     return adoptRef(new (slot) ShareableElementData(*this));
    218 }
    219 
    220 Attribute* UniqueElementData::findAttributeByName(const QualifiedName& name)
    221 {
    222     unsigned length = m_attributeVector.size();
    223     for (unsigned i = 0; i < length; ++i) {
    224         if (m_attributeVector.at(i).name().matches(name))
    225             return &m_attributeVector.at(i);
    226     }
    227     return 0;
    228 }
    229 
    230 } // namespace WebCore
    231