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.length())
     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 isEmpty();
    102 
    103     unsigned len = length();
    104     if (len != other->length())
    105         return false;
    106 
    107     for (unsigned i = 0; i < len; i++) {
    108         const Attribute* attribute = attributeItem(i);
    109         const Attribute* otherAttr = other->getAttributeItem(attribute->name());
    110         if (!otherAttr || attribute->value() != otherAttr->value())
    111             return false;
    112     }
    113 
    114     return true;
    115 }
    116 
    117 size_t ElementData::getAttrIndex(Attr* attr) const
    118 {
    119     // This relies on the fact that Attr's QualifiedName == the Attribute's name.
    120     for (unsigned i = 0; i < length(); ++i) {
    121         if (attributeItem(i)->name() == attr->qualifiedName())
    122             return i;
    123     }
    124     return kNotFound;
    125 }
    126 
    127 size_t ElementData::getAttributeItemIndexSlowCase(const AtomicString& name, bool shouldIgnoreAttributeCase) const
    128 {
    129     // Continue to checking case-insensitively and/or full namespaced names if necessary:
    130     for (unsigned i = 0; i < length(); ++i) {
    131         const Attribute* attribute = attributeItem(i);
    132         // FIXME: Why check the prefix? Namespace is all that should matter
    133         // and all HTML/SVG attributes have a null namespace!
    134         if (!attribute->name().hasPrefix()) {
    135             if (shouldIgnoreAttributeCase && equalIgnoringCase(name, attribute->localName()))
    136                 return i;
    137         } else {
    138             // FIXME: Would be faster to do this comparison without calling toString, which
    139             // generates a temporary string by concatenation. But this branch is only reached
    140             // if the attribute name has a prefix, which is rare in HTML.
    141             if (equalPossiblyIgnoringCase(name, attribute->name().toString(), shouldIgnoreAttributeCase))
    142                 return i;
    143         }
    144     }
    145     return kNotFound;
    146 }
    147 
    148 ShareableElementData::ShareableElementData(const Vector<Attribute>& attributes)
    149     : ElementData(attributes.size())
    150 {
    151     for (unsigned i = 0; i < m_arraySize; ++i)
    152         new (&m_attributeArray[i]) Attribute(attributes[i]);
    153 }
    154 
    155 ShareableElementData::~ShareableElementData()
    156 {
    157     for (unsigned i = 0; i < m_arraySize; ++i)
    158         m_attributeArray[i].~Attribute();
    159 }
    160 
    161 ShareableElementData::ShareableElementData(const UniqueElementData& other)
    162     : ElementData(other, false)
    163 {
    164     ASSERT(!other.m_presentationAttributeStyle);
    165 
    166     if (other.m_inlineStyle) {
    167         ASSERT(!other.m_inlineStyle->hasCSSOMWrapper());
    168         m_inlineStyle = other.m_inlineStyle->immutableCopyIfNeeded();
    169     }
    170 
    171     for (unsigned i = 0; i < m_arraySize; ++i)
    172         new (&m_attributeArray[i]) Attribute(other.m_attributeVector.at(i));
    173 }
    174 
    175 PassRefPtr<ShareableElementData> ShareableElementData::createWithAttributes(const Vector<Attribute>& attributes)
    176 {
    177     void* slot = WTF::fastMalloc(sizeForShareableElementDataWithAttributeCount(attributes.size()));
    178     return adoptRef(new (slot) ShareableElementData(attributes));
    179 }
    180 
    181 UniqueElementData::UniqueElementData()
    182 {
    183 }
    184 
    185 UniqueElementData::UniqueElementData(const UniqueElementData& other)
    186     : ElementData(other, true)
    187     , m_presentationAttributeStyle(other.m_presentationAttributeStyle)
    188     , m_attributeVector(other.m_attributeVector)
    189 {
    190     m_inlineStyle = other.m_inlineStyle ? other.m_inlineStyle->mutableCopy() : 0;
    191 }
    192 
    193 UniqueElementData::UniqueElementData(const ShareableElementData& other)
    194     : ElementData(other, true)
    195 {
    196     // An ShareableElementData should never have a mutable inline StylePropertySet attached.
    197     ASSERT(!other.m_inlineStyle || !other.m_inlineStyle->isMutable());
    198     m_inlineStyle = other.m_inlineStyle;
    199 
    200     m_attributeVector.reserveCapacity(other.length());
    201     for (unsigned i = 0; i < other.length(); ++i)
    202         m_attributeVector.uncheckedAppend(other.m_attributeArray[i]);
    203 }
    204 
    205 PassRefPtr<UniqueElementData> UniqueElementData::create()
    206 {
    207     return adoptRef(new UniqueElementData);
    208 }
    209 
    210 PassRefPtr<ShareableElementData> UniqueElementData::makeShareableCopy() const
    211 {
    212     void* slot = WTF::fastMalloc(sizeForShareableElementDataWithAttributeCount(m_attributeVector.size()));
    213     return adoptRef(new (slot) ShareableElementData(*this));
    214 }
    215 
    216 Attribute* UniqueElementData::getAttributeItem(const QualifiedName& name)
    217 {
    218     for (unsigned i = 0; i < length(); ++i) {
    219         if (m_attributeVector.at(i).name().matches(name))
    220             return &m_attributeVector.at(i);
    221     }
    222     return 0;
    223 }
    224 
    225 } // namespace WebCore
    226