diff options
Diffstat (limited to 'chromium/third_party/WebKit/Source/core/dom/ElementData.h')
-rw-r--r-- | chromium/third_party/WebKit/Source/core/dom/ElementData.h | 148 |
1 files changed, 98 insertions, 50 deletions
diff --git a/chromium/third_party/WebKit/Source/core/dom/ElementData.h b/chromium/third_party/WebKit/Source/core/dom/ElementData.h index 2426667d6c2..0a8cc6202a0 100644 --- a/chromium/third_party/WebKit/Source/core/dom/ElementData.h +++ b/chromium/third_party/WebKit/Source/core/dom/ElementData.h @@ -1,5 +1,6 @@ /* * Copyright (C) 2013 Google Inc. All rights reserved. + * Copyright (C) 2014 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -42,6 +43,27 @@ class ShareableElementData; class StylePropertySet; class UniqueElementData; +class AttributeCollection { +public: + typedef const Attribute* const_iterator; + + AttributeCollection(const Attribute* array, unsigned size) + : m_array(array) + , m_size(size) + { } + + const_iterator begin() const { return m_array; } + const_iterator end() const { return m_array + m_size; } + + unsigned size() const { return m_size; } + +private: + const Attribute* m_array; + unsigned m_size; +}; + +// ElementData represents very common, but not necessarily unique to an element, +// data such as attributes, inline style, and parsed class names and ids. class ElementData : public RefCounted<ElementData> { WTF_MAKE_FAST_ALLOCATED; public: @@ -60,14 +82,17 @@ public: const StylePropertySet* presentationAttributeStyle() const; - size_t length() const; - bool isEmpty() const { return !length(); } + // This is not a trivial getter and its return value should be cached for performance. + size_t attributeCount() const; + bool hasAttributes() const { return !!attributeCount(); } + + AttributeCollection attributes() const; - const Attribute* attributeItem(unsigned index) const; - const Attribute* getAttributeItem(const QualifiedName&) const; - size_t getAttributeItemIndex(const QualifiedName&, bool shouldIgnoreCase = false) const; - size_t getAttributeItemIndex(const AtomicString& name, bool shouldIgnoreAttributeCase) const; - size_t getAttrIndex(Attr*) const; + const Attribute& attributeAt(unsigned index) const; + const Attribute* findAttributeByName(const QualifiedName&) const; + size_t findAttributeIndexByName(const QualifiedName&, bool shouldIgnoreCase = false) const; + size_t findAttributeIndexByName(const AtomicString& name, bool shouldIgnoreAttributeCase) const; + size_t findAttrNodeIndex(Attr*) const; bool hasID() const { return !m_idForStyleResolution.isNull(); } bool hasClass() const { return !m_classNames.isNull(); } @@ -81,6 +106,7 @@ protected: explicit ElementData(unsigned arraySize); ElementData(const ElementData&, bool isUnique); + // Keep the type in a bitfield instead of using virtual destructors to avoid adding a vtable. unsigned m_isUnique : 1; unsigned m_arraySize : 28; mutable unsigned m_presentationAttributeStyleIsDirty : 1; @@ -100,8 +126,8 @@ private: void destroy(); const Attribute* attributeBase() const; - const Attribute* getAttributeItem(const AtomicString& name, bool shouldIgnoreAttributeCase) const; - size_t getAttributeItemIndexSlowCase(const AtomicString& name, bool shouldIgnoreAttributeCase) const; + const Attribute* findAttributeByName(const AtomicString& name, bool shouldIgnoreAttributeCase) const; + size_t findAttributeIndexByNameSlowCase(const AtomicString& name, bool shouldIgnoreAttributeCase) const; PassRefPtr<UniqueElementData> makeUniqueCopy() const; }; @@ -111,7 +137,11 @@ private: #pragma warning(disable: 4200) // Disable "zero-sized array in struct/union" warning #endif -class ShareableElementData : public ElementData { +// SharableElementData is managed by ElementDataCache and is produced by +// the parser during page load for elements that have identical attributes. This +// is a memory optimization since it's very common for many elements to have +// duplicate sets of attributes (ex. the same classes). +class ShareableElementData FINAL : public ElementData { public: static PassRefPtr<ShareableElementData> createWithAttributes(const Vector<Attribute>&); @@ -126,22 +156,32 @@ public: #pragma warning(pop) #endif -class UniqueElementData : public ElementData { +// UniqueElementData is created when an element needs to mutate its attributes +// or gains presentation attribute style (ex. width="10"). It does not need to +// be created to fill in values in the ElementData that are derived from +// attributes. For example populating the m_inlineStyle from the style attribute +// doesn't require a UniqueElementData as all elements with the same style +// attribute will have the same inline style. +class UniqueElementData FINAL : public ElementData { public: static PassRefPtr<UniqueElementData> create(); PassRefPtr<ShareableElementData> makeShareableCopy() const; // These functions do no error/duplicate checking. - void addAttribute(const QualifiedName&, const AtomicString&); - void removeAttribute(size_t index); + void appendAttribute(const QualifiedName&, const AtomicString&); + void removeAttributeAt(size_t index); - Attribute* attributeItem(unsigned index); - Attribute* getAttributeItem(const QualifiedName&); + Attribute& attributeAt(unsigned index); + Attribute* findAttributeByName(const QualifiedName&); UniqueElementData(); explicit UniqueElementData(const ShareableElementData&); explicit UniqueElementData(const UniqueElementData&); + // FIXME: We might want to support sharing element data for elements with + // presentation attribute style. Lots of table cells likely have the same + // attributes. Most modern pages don't use presentation attributes though + // so this might not make sense. mutable RefPtr<StylePropertySet> m_presentationAttributeStyle; Vector<Attribute, 4> m_attributeVector; }; @@ -153,7 +193,7 @@ inline void ElementData::deref() destroy(); } -inline size_t ElementData::length() const +inline size_t ElementData::attributeCount() const { if (isUnique()) return static_cast<const UniqueElementData*>(this)->m_attributeVector.size(); @@ -167,11 +207,11 @@ inline const StylePropertySet* ElementData::presentationAttributeStyle() const return static_cast<const UniqueElementData*>(this)->m_presentationAttributeStyle.get(); } -inline const Attribute* ElementData::getAttributeItem(const AtomicString& name, bool shouldIgnoreAttributeCase) const +inline const Attribute* ElementData::findAttributeByName(const AtomicString& name, bool shouldIgnoreAttributeCase) const { - size_t index = getAttributeItemIndex(name, shouldIgnoreAttributeCase); + size_t index = findAttributeIndexByName(name, shouldIgnoreAttributeCase); if (index != kNotFound) - return attributeItem(index); + return &attributeAt(index); return 0; } @@ -182,76 +222,84 @@ inline const Attribute* ElementData::attributeBase() const return static_cast<const ShareableElementData*>(this)->m_attributeArray; } -inline size_t ElementData::getAttributeItemIndex(const QualifiedName& name, bool shouldIgnoreCase) const +inline size_t ElementData::findAttributeIndexByName(const QualifiedName& name, bool shouldIgnoreCase) const { - const Attribute* begin = attributeBase(); - // Cache length for performance as ElementData::length() contains a conditional branch. - unsigned len = length(); - for (unsigned i = 0; i < len; ++i) { - const Attribute& attribute = begin[i]; - if (attribute.name().matchesPossiblyIgnoringCase(name, shouldIgnoreCase)) - return i; + AttributeCollection attributes = this->attributes(); + AttributeCollection::const_iterator end = attributes.end(); + unsigned index = 0; + for (AttributeCollection::const_iterator it = attributes.begin(); it != end; ++it, ++index) { + if (it->name().matchesPossiblyIgnoringCase(name, shouldIgnoreCase)) + return index; } return kNotFound; } // We use a boolean parameter instead of calling shouldIgnoreAttributeCase so that the caller // can tune the behavior (hasAttribute is case sensitive whereas getAttribute is not). -inline size_t ElementData::getAttributeItemIndex(const AtomicString& name, bool shouldIgnoreAttributeCase) const +inline size_t ElementData::findAttributeIndexByName(const AtomicString& name, bool shouldIgnoreAttributeCase) const { - // Cache length for performance as ElementData::length() contains a conditional branch. - unsigned len = length(); bool doSlowCheck = shouldIgnoreAttributeCase; // Optimize for the case where the attribute exists and its name exactly matches. - const Attribute* begin = attributeBase(); - for (unsigned i = 0; i < len; ++i) { - const Attribute& attribute = begin[i]; + AttributeCollection attributes = this->attributes(); + AttributeCollection::const_iterator end = attributes.end(); + unsigned index = 0; + for (AttributeCollection::const_iterator it = attributes.begin(); it != end; ++it, ++index) { // FIXME: Why check the prefix? Namespaces should be all that matter. // Most attributes (all of HTML and CSS) have no namespace. - if (!attribute.name().hasPrefix()) { - if (name == attribute.localName()) - return i; + if (!it->name().hasPrefix()) { + if (name == it->localName()) + return index; } else { doSlowCheck = true; } } if (doSlowCheck) - return getAttributeItemIndexSlowCase(name, shouldIgnoreAttributeCase); + return findAttributeIndexByNameSlowCase(name, shouldIgnoreAttributeCase); return kNotFound; } -inline const Attribute* ElementData::getAttributeItem(const QualifiedName& name) const +inline AttributeCollection ElementData::attributes() const +{ + if (isUnique()) { + const Vector<Attribute, 4>& attributeVector = static_cast<const UniqueElementData*>(this)->m_attributeVector; + return AttributeCollection(attributeVector.data(), attributeVector.size()); + } + return AttributeCollection(static_cast<const ShareableElementData*>(this)->m_attributeArray, m_arraySize); +} + +inline const Attribute* ElementData::findAttributeByName(const QualifiedName& name) const { - const Attribute* begin = attributeBase(); - for (unsigned i = 0; i < length(); ++i) { - const Attribute& attribute = begin[i]; - if (attribute.name().matches(name)) - return &attribute; + AttributeCollection attributes = this->attributes(); + AttributeCollection::const_iterator end = attributes.end(); + for (AttributeCollection::const_iterator it = attributes.begin(); it != end; ++it) { + if (it->name().matches(name)) + return it; } return 0; } -inline const Attribute* ElementData::attributeItem(unsigned index) const +inline const Attribute& ElementData::attributeAt(unsigned index) const { - RELEASE_ASSERT(index < length()); - return attributeBase() + index; + RELEASE_ASSERT(index < attributeCount()); + ASSERT(attributeBase() + index); + return *(attributeBase() + index); } -inline void UniqueElementData::addAttribute(const QualifiedName& attributeName, const AtomicString& value) +inline void UniqueElementData::appendAttribute(const QualifiedName& attributeName, const AtomicString& value) { m_attributeVector.append(Attribute(attributeName, value)); } -inline void UniqueElementData::removeAttribute(size_t index) +inline void UniqueElementData::removeAttributeAt(size_t index) { m_attributeVector.remove(index); } -inline Attribute* UniqueElementData::attributeItem(unsigned index) +inline Attribute& UniqueElementData::attributeAt(unsigned index) { - return &m_attributeVector.at(index); + return m_attributeVector.at(index); } } // namespace WebCore |