Commit 86d6cb5f authored by kling@webkit.org's avatar kling@webkit.org

Decouple Attr logic from ElementAttributeData.

<http://webkit.org/b/101126>

Reviewed by Antti Koivisto.

Move all logic dealing with Attr DOM nodes from ElementAttributeData to Element.
This makes more sense since an Attr is tied to a single Element, but an ElementAttributeData
can be shared by any number of Elements at a given time.

Also updated naming convention from just "Attr" to "Attr node" in the code I was touching.
"Attr" is way too generic, and has been historically confused with WebCore::Attribute a lot.

* dom/Element.h:
* dom/ElementAttributeData.h:
* dom/Element.cpp:
(WebCore::attrNodeListMap):
(WebCore::attrNodeListForElement):
(WebCore::ensureAttrNodeListForElement):
(WebCore::removeAttrNodeListForElement):
(WebCore::findAttrNodeInList):
(WebCore::Element::~Element):
(WebCore::Element::detachAttribute):
(WebCore::Element::setAttributeNode):
(WebCore::Element::removeAttributeInternal):
(WebCore::Element::getAttributeNode):
(WebCore::Element::getAttributeNodeNS):
(WebCore::Element::normalizeAttributes):
(WebCore::Element::attrIfExists):
(WebCore::Element::ensureAttr):
(WebCore::Element::detachAttrNodeFromElementWithValue):
(WebCore::Element::detachAllAttrNodesFromElement):
(WebCore::Element::cloneAttributesFromElement):

    Move everything Attr-related into Element.cpp while simplifying some loops and remove
    conditions that are no longer needed as they used to depend on having an attributeData().

* dom/Node.h:
(WebCore::Node::hasSyntheticAttrChildNodes):
(WebCore::Node::setHasSyntheticAttrChildNodes):

    Renamed the hasAttrList() node flag to hasSyntheticAttrChildNodes().

* dom/Attr.cpp:
(WebCore::Attr::detachFromElementWithValue):

    Remove awkward indirection and let the call site deal with removing the Attr node from
    the Element's list of Attr nodes.

* dom/ElementAttributeData.cpp:
(WebCore::ElementAttributeData::clearAttributes):

    Remove now-unused Element* argument.

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@133492 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent 062c3fed
2012-11-05 Andreas Kling <kling@webkit.org>
Decouple Attr logic from ElementAttributeData.
<http://webkit.org/b/101126>
Reviewed by Antti Koivisto.
Move all logic dealing with Attr DOM nodes from ElementAttributeData to Element.
This makes more sense since an Attr is tied to a single Element, but an ElementAttributeData
can be shared by any number of Elements at a given time.
Also updated naming convention from just "Attr" to "Attr node" in the code I was touching.
"Attr" is way too generic, and has been historically confused with WebCore::Attribute a lot.
* dom/Element.h:
* dom/ElementAttributeData.h:
* dom/Element.cpp:
(WebCore::attrNodeListMap):
(WebCore::attrNodeListForElement):
(WebCore::ensureAttrNodeListForElement):
(WebCore::removeAttrNodeListForElement):
(WebCore::findAttrNodeInList):
(WebCore::Element::~Element):
(WebCore::Element::detachAttribute):
(WebCore::Element::setAttributeNode):
(WebCore::Element::removeAttributeInternal):
(WebCore::Element::getAttributeNode):
(WebCore::Element::getAttributeNodeNS):
(WebCore::Element::normalizeAttributes):
(WebCore::Element::attrIfExists):
(WebCore::Element::ensureAttr):
(WebCore::Element::detachAttrNodeFromElementWithValue):
(WebCore::Element::detachAllAttrNodesFromElement):
(WebCore::Element::cloneAttributesFromElement):
Move everything Attr-related into Element.cpp while simplifying some loops and remove
conditions that are no longer needed as they used to depend on having an attributeData().
* dom/Node.h:
(WebCore::Node::hasSyntheticAttrChildNodes):
(WebCore::Node::setHasSyntheticAttrChildNodes):
Renamed the hasAttrList() node flag to hasSyntheticAttrChildNodes().
* dom/Attr.cpp:
(WebCore::Attr::detachFromElementWithValue):
Remove awkward indirection and let the call site deal with removing the Attr node from
the Element's list of Attr nodes.
* dom/ElementAttributeData.cpp:
(WebCore::ElementAttributeData::clearAttributes):
Remove now-unused Element* argument.
2012-11-05 Hans Muller <hmuller@adobe.com>
[CSS Exclusions] Polygon edges should span colinear vertices
......@@ -218,7 +218,6 @@ void Attr::detachFromElementWithValue(const AtomicString& value)
{
ASSERT(m_element);
ASSERT(m_standaloneValue.isNull());
m_element->attributeData()->removeAttr(m_element, qualifiedName());
m_standaloneValue = value;
m_element = 0;
}
......
......@@ -124,6 +124,52 @@ private:
StyleResolver* m_pushedStyleResolver;
};
typedef Vector<RefPtr<Attr> > AttrNodeList;
typedef HashMap<Element*, OwnPtr<AttrNodeList> > AttrNodeListMap;
static AttrNodeListMap& attrNodeListMap()
{
DEFINE_STATIC_LOCAL(AttrNodeListMap, map, ());
return map;
}
static AttrNodeList* attrNodeListForElement(Element* element)
{
if (!element->hasSyntheticAttrChildNodes())
return 0;
ASSERT(attrNodeListMap().contains(element));
return attrNodeListMap().get(element);
}
static AttrNodeList* ensureAttrNodeListForElement(Element* element)
{
if (element->hasSyntheticAttrChildNodes()) {
ASSERT(attrNodeListMap().contains(element));
return attrNodeListMap().get(element);
}
ASSERT(!attrNodeListMap().contains(element));
element->setHasSyntheticAttrChildNodes(true);
AttrNodeListMap::AddResult result = attrNodeListMap().add(element, adoptPtr(new AttrNodeList));
return result.iterator->value.get();
}
static void removeAttrNodeListForElement(Element* element)
{
ASSERT(element->hasSyntheticAttrChildNodes());
ASSERT(attrNodeListMap().contains(element));
attrNodeListMap().remove(element);
element->setHasSyntheticAttrChildNodes(false);
}
static Attr* findAttrNodeInList(AttrNodeList* attrNodeList, const QualifiedName& name)
{
for (unsigned i = 0; i < attrNodeList->size(); ++i) {
if (attrNodeList->at(i)->qualifiedName() == name)
return attrNodeList->at(i).get();
}
return 0;
}
PassRefPtr<Element> Element::create(const QualifiedName& tagName, Document* document)
{
return adoptRef(new Element(tagName, document, CreateElement));
......@@ -145,10 +191,8 @@ Element::~Element()
elementRareData()->m_shadow.clear();
}
if (hasAttrList()) {
ASSERT(m_attributeData);
m_attributeData->detachAttrObjectsFromElement(this);
}
if (hasSyntheticAttrChildNodes())
detachAllAttrNodesFromElement();
}
inline ElementRareData* Element::elementRareData() const
......@@ -207,14 +251,14 @@ PassRefPtr<Attr> Element::detachAttribute(size_t index)
const Attribute* attribute = attributeData()->attributeItem(index);
ASSERT(attribute);
RefPtr<Attr> attr = attrIfExists(attribute->name());
if (attr)
attr->detachFromElementWithValue(attribute->value());
RefPtr<Attr> attrNode = attrIfExists(attribute->name());
if (attrNode)
detachAttrNodeFromElementWithValue(attrNode.get(), attribute->value());
else
attr = Attr::create(document(), attribute->name(), attribute->value());
attrNode = Attr::create(document(), attribute->name(), attribute->value());
removeAttributeInternal(index, NotInSynchronizationOfLazyAttribute);
return attr.release();
return attrNode.release();
}
void Element::removeAttribute(const QualifiedName& name)
......@@ -1484,20 +1528,20 @@ void Element::formatForDebugger(char* buffer, unsigned length) const
}
#endif
PassRefPtr<Attr> Element::setAttributeNode(Attr* attr, ExceptionCode& ec)
PassRefPtr<Attr> Element::setAttributeNode(Attr* attrNode, ExceptionCode& ec)
{
if (!attr) {
if (!attrNode) {
ec = TYPE_MISMATCH_ERR;
return 0;
}
RefPtr<Attr> oldAttr = attrIfExists(attr->qualifiedName());
if (oldAttr.get() == attr)
return attr; // This Attr is already attached to the element.
RefPtr<Attr> oldAttrNode = attrIfExists(attrNode->qualifiedName());
if (oldAttrNode.get() == attrNode)
return attrNode; // This Attr is already attached to the element.
// INUSE_ATTRIBUTE_ERR: Raised if node is an Attr that is already an attribute of another Element object.
// The DOM user must explicitly clone Attr nodes to re-use them in other elements.
if (attr->ownerElement()) {
if (attrNode->ownerElement()) {
ec = INUSE_ATTRIBUTE_ERR;
return 0;
}
......@@ -1505,17 +1549,20 @@ PassRefPtr<Attr> Element::setAttributeNode(Attr* attr, ExceptionCode& ec)
updateInvalidAttributes();
ElementAttributeData* attributeData = mutableAttributeData();
size_t index = attributeData->getAttributeItemIndex(attr->qualifiedName());
size_t index = attributeData->getAttributeItemIndex(attrNode->qualifiedName());
if (index != notFound) {
if (oldAttr)
oldAttr->detachFromElementWithValue(attributeData->attributeItem(index)->value());
if (oldAttrNode)
detachAttrNodeFromElementWithValue(oldAttrNode.get(), attributeData->attributeItem(index)->value());
else
oldAttr = Attr::create(document(), attr->qualifiedName(), attributeData->attributeItem(index)->value());
oldAttrNode = Attr::create(document(), attrNode->qualifiedName(), attributeData->attributeItem(index)->value());
}
setAttributeInternal(index, attr->qualifiedName(), attr->value(), NotInSynchronizationOfLazyAttribute);
attributeData->setAttr(this, attr->qualifiedName(), attr);
return oldAttr.release();
setAttributeInternal(index, attrNode->qualifiedName(), attrNode->value(), NotInSynchronizationOfLazyAttribute);
attrNode->attachToElement(this);
ensureAttrNodeListForElement(this)->append(attrNode);
return oldAttrNode.release();
}
PassRefPtr<Attr> Element::setAttributeNodeNS(Attr* attr, ExceptionCode& ec)
......@@ -1588,10 +1635,8 @@ void Element::removeAttributeInternal(size_t index, SynchronizationOfLazyAttribu
willModifyAttribute(name, valueBeingRemoved, nullAtom);
}
if (hasAttrList()) {
if (RefPtr<Attr> attr = attributeData->attrIfExists(this, name))
attr->detachFromElementWithValue(attributeData->attributeItem(index)->value());
}
if (RefPtr<Attr> attrNode = attrIfExists(name))
detachAttrNodeFromElementWithValue(attrNode.get(), attributeData->attributeItem(index)->value());
attributeData->removeAttribute(index);
......@@ -1633,7 +1678,10 @@ PassRefPtr<Attr> Element::getAttributeNode(const AtomicString& name)
const ElementAttributeData* attributeData = updatedAttributeData();
if (!attributeData)
return 0;
return attributeData->getAttributeNode(name, shouldIgnoreAttributeCase(this), this);
const Attribute* attribute = attributeData->getAttributeItem(name, shouldIgnoreAttributeCase(this));
if (!attribute)
return 0;
return ensureAttr(attribute->name());
}
PassRefPtr<Attr> Element::getAttributeNodeNS(const AtomicString& namespaceURI, const AtomicString& localName)
......@@ -1641,7 +1689,10 @@ PassRefPtr<Attr> Element::getAttributeNodeNS(const AtomicString& namespaceURI, c
const ElementAttributeData* attributeData = updatedAttributeData();
if (!attributeData)
return 0;
return attributeData->getAttributeNode(QualifiedName(nullAtom, localName, namespaceURI), this);
const Attribute* attribute = attributeData->getAttributeItem(QualifiedName(nullAtom, localName, namespaceURI));
if (!attribute)
return 0;
return ensureAttr(attribute->name());
}
bool Element::hasAttribute(const AtomicString& name) const
......@@ -1877,15 +1928,10 @@ void Element::cancelFocusAppearanceUpdate()
void Element::normalizeAttributes()
{
if (!hasAttrList())
return;
const ElementAttributeData* attributeData = updatedAttributeData();
ASSERT(attributeData);
for (size_t i = 0; i < attributeData->length(); ++i) {
if (RefPtr<Attr> attr = attrIfExists(attributeData->attributeItem(i)->name()))
attr->normalize();
updateInvalidAttributes();
if (AttrNodeList* attrNodeList = attrNodeListForElement(this)) {
for (unsigned i = 0; i < attrNodeList->size(); ++i)
attrNodeList->at(i)->normalize();
}
}
......@@ -2335,16 +2381,51 @@ void Element::setSavedLayerScrollOffset(const IntSize& size)
PassRefPtr<Attr> Element::attrIfExists(const QualifiedName& name)
{
if (!hasAttrList())
return 0;
ASSERT(attributeData());
return attributeData()->attrIfExists(this, name);
if (AttrNodeList* attrNodeList = attrNodeListForElement(this))
return findAttrNodeInList(attrNodeList, name);
return 0;
}
PassRefPtr<Attr> Element::ensureAttr(const QualifiedName& name)
{
ASSERT(attributeData());
return attributeData()->ensureAttr(this, name);
AttrNodeList* attrNodeList = ensureAttrNodeListForElement(this);
RefPtr<Attr> attrNode = findAttrNodeInList(attrNodeList, name);
if (!attrNode) {
attrNode = Attr::create(this, name);
attrNodeList->append(attrNode);
}
return attrNode.release();
}
void Element::detachAttrNodeFromElementWithValue(Attr* attrNode, const AtomicString& value)
{
ASSERT(hasSyntheticAttrChildNodes());
attrNode->detachFromElementWithValue(value);
AttrNodeList* attrNodeList = attrNodeListForElement(this);
for (unsigned i = 0; i < attrNodeList->size(); ++i) {
if (attrNodeList->at(i)->qualifiedName() == attrNode->qualifiedName()) {
attrNodeList->remove(i);
if (attrNodeList->isEmpty())
removeAttrNodeListForElement(this);
return;
}
}
ASSERT_NOT_REACHED();
}
void Element::detachAllAttrNodesFromElement()
{
AttrNodeList* attrNodeList = attrNodeListForElement(this);
ASSERT(attrNodeList);
for (unsigned i = 0; i < attributeCount(); ++i) {
const Attribute* attribute = attributeItem(i);
if (RefPtr<Attr> attrNode = findAttrNodeInList(attrNodeList, attribute->name()))
attrNode->detachFromElementWithValue(attribute->value());
}
removeAttrNodeListForElement(this);
}
bool Element::willRecalcStyle(StyleChange)
......@@ -2368,10 +2449,13 @@ PassRefPtr<RenderStyle> Element::customStyleForRenderer()
void Element::cloneAttributesFromElement(const Element& other)
{
if (hasSyntheticAttrChildNodes())
detachAllAttrNodesFromElement();
if (const ElementAttributeData* attributeData = other.updatedAttributeData())
mutableAttributeData()->cloneDataFrom(*attributeData, other, *this);
else if (m_attributeData) {
m_attributeData->clearAttributes(this);
m_attributeData->clearAttributes();
m_attributeData.clear();
}
}
......
......@@ -528,6 +528,9 @@ private:
ElementRareData* elementRareData() const;
ElementRareData* ensureElementRareData();
void detachAllAttrNodesFromElement();
void detachAttrNodeFromElementWithValue(Attr*, const AtomicString& value);
RefPtr<ElementAttributeData> m_attributeData;
};
......
......@@ -87,101 +87,6 @@ PassRefPtr<ElementAttributeData> ElementAttributeData::makeMutableCopy() const
return adoptRef(new MutableElementAttributeData(static_cast<const ImmutableElementAttributeData&>(*this)));
}
typedef Vector<RefPtr<Attr> > AttrList;
typedef HashMap<Element*, OwnPtr<AttrList> > AttrListMap;
static AttrListMap& attrListMap()
{
DEFINE_STATIC_LOCAL(AttrListMap, map, ());
return map;
}
static AttrList* attrListForElement(Element* element)
{
ASSERT(element);
if (!element->hasAttrList())
return 0;
ASSERT(attrListMap().contains(element));
return attrListMap().get(element);
}
static AttrList* ensureAttrListForElement(Element* element)
{
ASSERT(element);
if (element->hasAttrList()) {
ASSERT(attrListMap().contains(element));
return attrListMap().get(element);
}
ASSERT(!attrListMap().contains(element));
element->setHasAttrList();
AttrListMap::AddResult result = attrListMap().add(element, adoptPtr(new AttrList));
return result.iterator->value.get();
}
static void removeAttrListForElement(Element* element)
{
ASSERT(element);
ASSERT(element->hasAttrList());
ASSERT(attrListMap().contains(element));
attrListMap().remove(element);
element->clearHasAttrList();
}
static Attr* findAttrInList(AttrList* attrList, const QualifiedName& name)
{
for (unsigned i = 0; i < attrList->size(); ++i) {
if (attrList->at(i)->qualifiedName() == name)
return attrList->at(i).get();
}
return 0;
}
PassRefPtr<Attr> ElementAttributeData::attrIfExists(Element* element, const QualifiedName& name) const
{
if (AttrList* attrList = attrListForElement(element))
return findAttrInList(attrList, name);
return 0;
}
PassRefPtr<Attr> ElementAttributeData::ensureAttr(Element* element, const QualifiedName& name) const
{
AttrList* attrList = ensureAttrListForElement(element);
RefPtr<Attr> attr = findAttrInList(attrList, name);
if (!attr) {
attr = Attr::create(element, name);
attrList->append(attr);
}
return attr.release();
}
void ElementAttributeData::setAttr(Element* element, const QualifiedName& name, Attr* attr) const
{
AttrList* attrList = ensureAttrListForElement(element);
if (findAttrInList(attrList, name))
return;
attrList->append(attr);
attr->attachToElement(element);
}
void ElementAttributeData::removeAttr(Element* element, const QualifiedName& name) const
{
AttrList* attrList = attrListForElement(element);
ASSERT(attrList);
for (unsigned i = 0; i < attrList->size(); ++i) {
if (attrList->at(i)->qualifiedName() == name) {
attrList->remove(i);
if (attrList->isEmpty())
removeAttrListForElement(element);
return;
}
}
ASSERT_NOT_REACHED();
}
StylePropertySet* ElementAttributeData::ensureInlineStyle(StyledElement* element)
{
ASSERT(isMutable());
......@@ -258,20 +163,6 @@ bool ElementAttributeData::isEquivalent(const ElementAttributeData* other) const
return true;
}
void ElementAttributeData::detachAttrObjectsFromElement(Element* element) const
{
ASSERT(element->hasAttrList());
for (unsigned i = 0; i < length(); ++i) {
const Attribute* attribute = attributeItem(i);
if (RefPtr<Attr> attr = attrIfExists(element, attribute->name()))
attr->detachFromElementWithValue(attribute->value());
}
// The loop above should have cleaned out this element's Attr map.
ASSERT(!element->hasAttrList());
}
void ElementAttributeData::reportMemoryUsage(MemoryObjectInfo* memoryObjectInfo) const
{
size_t actualSize = m_isMutable ? sizeof(ElementAttributeData) : sizeForImmutableElementAttributeDataWithAttributeCount(m_arraySize);
......@@ -322,7 +213,7 @@ void ElementAttributeData::cloneDataFrom(const ElementAttributeData& sourceData,
if (!oldName.isNull() || !newName.isNull())
targetElement.updateName(oldName, newName);
clearAttributes(&targetElement);
clearAttributes();
if (sourceData.isMutable())
mutableAttributeVector() = sourceData.mutableAttributeVector();
......@@ -347,33 +238,11 @@ void ElementAttributeData::cloneDataFrom(const ElementAttributeData& sourceData,
}
}
void ElementAttributeData::clearAttributes(Element* element)
void ElementAttributeData::clearAttributes()
{
ASSERT(isMutable());
if (element->hasAttrList())
detachAttrObjectsFromElement(element);
clearClass();
mutableAttributeVector().clear();
}
PassRefPtr<Attr> ElementAttributeData::getAttributeNode(const String& name, bool shouldIgnoreAttributeCase, Element* element) const
{
ASSERT(element);
const Attribute* attribute = getAttributeItem(name, shouldIgnoreAttributeCase);
if (!attribute)
return 0;
return ensureAttr(element, attribute->name());
}
PassRefPtr<Attr> ElementAttributeData::getAttributeNode(const QualifiedName& name, Element* element) const
{
ASSERT(element);
const Attribute* attribute = getAttributeItem(name);
if (!attribute)
return 0;
return ensureAttr(element, attribute->name());
}
}
......@@ -33,7 +33,6 @@
namespace WebCore {
class Attr;
class Element;
class ImmutableElementAttributeData;
class MutableElementAttributeData;
......@@ -69,9 +68,6 @@ public:
size_t length() const;
bool isEmpty() const { return !length(); }
PassRefPtr<Attr> getAttributeNode(const String&, bool shouldIgnoreAttributeCase, Element*) const;
PassRefPtr<Attr> getAttributeNode(const QualifiedName&, Element*) const;
// Internal interface.
const Attribute* attributeItem(unsigned index) const;
const Attribute* getAttributeItem(const QualifiedName&) const;
......@@ -89,12 +85,6 @@ public:
bool isEquivalent(const ElementAttributeData* other) const;
void setAttr(Element*, const QualifiedName&, Attr*) const;
void removeAttr(Element*, const QualifiedName&) const;
PassRefPtr<Attr> attrIfExists(Element*, const QualifiedName&) const;
PassRefPtr<Attr> ensureAttr(Element*, const QualifiedName&) const;
void detachAttrObjectsFromElement(Element*) const;
void reportMemoryUsage(MemoryObjectInfo*) const;
bool isMutable() const { return m_isMutable; }
......@@ -129,7 +119,7 @@ private:
const Attribute* getAttributeItem(const AtomicString& name, bool shouldIgnoreAttributeCase) const;
size_t getAttributeItemIndexSlowCase(const AtomicString& name, bool shouldIgnoreAttributeCase) const;
void cloneDataFrom(const ElementAttributeData& sourceData, const Element& sourceElement, Element& targetElement);
void clearAttributes(Element*);
void clearAttributes();
PassRefPtr<ElementAttributeData> makeMutableCopy() const;
......
......@@ -237,9 +237,11 @@ public:
bool isDocumentNode() const;
bool isShadowRoot() const { return getFlag(IsShadowRootFlag); }
bool inNamedFlow() const { return getFlag(InNamedFlowFlag); }
bool hasAttrList() const { return getFlag(HasAttrListFlag); }
bool hasCustomCallbacks() const { return getFlag(HasCustomCallbacksFlag); }
bool hasSyntheticAttrChildNodes() const { return getFlag(HasSyntheticAttrChildNodesFlag); }
void setHasSyntheticAttrChildNodes(bool flag) { setFlag(flag, HasSyntheticAttrChildNodesFlag); }
// If this node is in a shadow tree, returns its shadow host. Otherwise, returns 0.
Element* shadowHost() const;
// If this node is in a shadow tree, returns its shadow host. Otherwise, returns this.
......@@ -355,9 +357,6 @@ public:
void setInNamedFlow() { setFlag(InNamedFlowFlag); }
void clearInNamedFlow() { clearFlag(InNamedFlowFlag); }
void setHasAttrList() { setFlag(HasAttrListFlag); }
void clearHasAttrList() { clearFlag(HasAttrListFlag); }
bool hasScopedHTMLStyleChild() const { return getFlag(HasScopedHTMLStyleChildFlag); }
void setHasScopedHTMLStyleChild(bool flag) { setFlag(flag, HasScopedHTMLStyleChildFlag); }
......@@ -733,7 +732,7 @@ private:
DefaultNodeFlags = IsParsingChildrenFinishedFlag | IsStyleAttributeValidFlag,
#endif
InNamedFlowFlag = 1 << 26,
HasAttrListFlag = 1 << 27,
HasSyntheticAttrChildNodesFlag = 1 << 27,
HasCustomCallbacksFlag = 1 << 28,
HasScopedHTMLStyleChildFlag = 1 << 29,
HasEventTargetDataFlag = 1 << 30,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment