summaryrefslogtreecommitdiffstats
path: root/chromium/third_party/WebKit/Source/core/dom/ElementData.h
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/third_party/WebKit/Source/core/dom/ElementData.h')
-rw-r--r--chromium/third_party/WebKit/Source/core/dom/ElementData.h148
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