https://bugs.webkit.org/show_bug.cgi?id=77574
Reviewed by Ryosuke Niwa.
Source/WebCore:
The method Element::attributes() was being used for multiple things in our
codebase: (1) as the getter for NamedNodeMap exposed to DOM, (2) as a way to other WebCore
code get the "attribute storage" (currently inside NamedNodeMap), and (3) as a way to
get the attribute storage creating one if necessary.
This commit separate the jobs in different functions:
1) attributes() keeps being the DOM getter, and loses its boolean parameter.
2) updatedAttributes() updates the invalid attributes and returns the attribute
storage. If we don't have one, return 0.
3) ensureUpdatedAttributes() updates the invalid attributes and forces the
creation of attribute storage to return.
There is also another way to get to the attribute storage currently, via
attributeMap(), which doesn't update the attributes for possible changes in Style
or SVG attributes.
Note that the new functions are not available in Node class, so C++ code manipulating
attributes should cast to Element.
This separation also made easier to spot and fix some places where we do not
need to create the attribute storage if it doesn't exist.
No new tests, this commit shouldn't change the behavior of existing code.
* css/SelectorChecker.cpp:
(WebCore::SelectorChecker::checkOneSelector):
* dom/DatasetDOMStringMap.cpp:
(WebCore::DatasetDOMStringMap::getNames):
(WebCore::DatasetDOMStringMap::item):
(WebCore::DatasetDOMStringMap::contains):
* dom/Document.cpp:
(WebCore::Document::importNode):
* dom/Element.cpp:
(WebCore::Element::setAttribute):
(WebCore::Element::hasAttributes):
(WebCore::Element::setAttributeNode):
(WebCore::Element::setAttributeNodeNS):
(WebCore::Element::removeAttributeNode):
(WebCore::Element::getAttributeNode):
(WebCore::Element::getAttributeNodeNS):
(WebCore::Element::hasAttribute):
(WebCore::Element::hasAttributeNS):
(WebCore::Element::normalizeAttributes):
* dom/Element.h:
(Element):
(WebCore::Element::attributes):
(WebCore::Element::ensureAttributeData):
(WebCore::Element::ensureUpdatedAttributes):
(WebCore::Element::updatedAttributes):
(WebCore::Element::setAttributesFromElement):
(WebCore::Element::ensureAttributeMap): Made const to be reused by ensureUpdatedAttributes().
(WebCore::Element::updateInvalidAttributes):
(WebCore):
* dom/NamedNodeMap.cpp:
(WebCore::NamedNodeMap::mapsEquivalent): Having no attributes is equivalent to
not having an attribute storage because the attribute storage is lazily created.
* dom/Node.cpp:
(WebCore::Node::isEqualNode): Do not force the creation of attribute storage to
compare two nodes.
(WebCore::Node::isDefaultNamespace): Use updatedAttributes(). Since we iterate
using length, it's OK if the attribute storage is empty.
(WebCore::Node::lookupNamespaceURI): Ditto.
(WebCore::Node::lookupNamespacePrefix): Ditto.
(WebCore::Node::compareDocumentPosition): Ditto.
* editing/ApplyStyleCommand.cpp:
(WebCore::hasNoAttributeOrOnlyStyleAttribute):
(WebCore::isEmptyFontTag):
* editing/CompositeEditCommand.cpp:
(WebCore::CompositeEditCommand::isRemovableBlock): Use isElementNode() explicitly
to identify non-Element nodes, then use hasAttributes() if is Element.
* editing/InsertParagraphSeparatorCommand.cpp:
(WebCore::highestVisuallyEquivalentDivBelowRoot):
* editing/MarkupAccumulator.cpp:
(WebCore::MarkupAccumulator::appendElement): Do not create the attribute storage
unnecessarily.
* editing/htmlediting.cpp:
(WebCore::areIdenticalElements): Do not create the attribute storage
unnecessarily. Use mapsEquivalent() for comparing the attributes.
* editing/markup.cpp:
(WebCore::completeURLs): Do not create the attribute storage unnecessarily.
(WebCore::StyledMarkupAccumulator::appendElement): Ditto.
(WebCore::isPlainTextMarkup): hasAttributes() will avoid creating the attribute
storage unnecessarily.
* html/HTMLEmbedElement.cpp:
(WebCore::HTMLEmbedElement::parametersForPlugin):
* html/HTMLObjectElement.cpp:
(WebCore::HTMLObjectElement::parametersForPlugin):
* html/HTMLParamElement.cpp:
(WebCore::HTMLParamElement::isURLAttribute): Do not create the attribute storage
unnecessarily.
* html/parser/HTMLConstructionSite.cpp:
(WebCore::HTMLConstructionSite::mergeAttributesFromTokenIntoElement): Use
ensureUpdatedAttributes() since we will add new attributes.
(WebCore):
* inspector/InspectorCSSAgent.cpp:
(WebCore::InspectorCSSAgent::buildArrayForAttributeStyles):
* inspector/InspectorDOMAgent.cpp:
(WebCore::InspectorDOMAgent::setAttributesAsText):
(WebCore::InspectorDOMAgent::performSearch):
(WebCore::InspectorDOMAgent::buildArrayForElementAttributes):
* page/PageSerializer.cpp:
(WebCore::isCharsetSpecifyingNode): Do not assume attributeMap will exist.
* svg/properties/SVGAnimatedPropertySynchronizer.h: Use ensureUpdatedAttributes()
since we will add new attributes.
* xml/XPathFunctions.cpp:
(WebCore::XPath::FunLang::evaluate): Do not create the attribute storage
unnecessarily.
* xml/XPathNodeSet.cpp:
(WebCore::XPath::NodeSet::traversalSort):
* xml/XPathStep.cpp:
(WebCore::XPath::Step::nodesInAxis): Use isElementNode() instead of comparing
nodeType() manually. Do not create the attribute storage unnecessarily.
* xml/parser/XMLDocumentParserLibxml2.cpp:
(WebCore::XMLDocumentParser::XMLDocumentParser): Do not create the attribute
storage unnecessarily.
* xml/parser/XMLDocumentParserQt.cpp:
(WebCore::XMLDocumentParser::XMLDocumentParser): Ditto.
* xml/parser/XMLTreeBuilder.cpp:
(WebCore::XMLTreeBuilder::XMLTreeBuilder): Ditto.
Source/WebKit/chromium:
* src/WebPageSerializerImpl.cpp:
(WebKit::WebPageSerializerImpl::openTagToString): use updatedAttributes().
Source/WebKit/qt:
* Api/qwebelement.cpp:
(QWebElement::attributeNames): use updateAttributes().
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@106515
268f45cc-cd09-0410-ab3c-
d52691b4dbfc
+2012-02-01 Caio Marcelo de Oliveira Filho <caio.oliveira@openbossa.org>
+
+ Avoid creating NamedNodeMap unnecessarily
+ https://bugs.webkit.org/show_bug.cgi?id=77574
+
+ Reviewed by Ryosuke Niwa.
+
+ The method Element::attributes() was being used for multiple things in our
+ codebase: (1) as the getter for NamedNodeMap exposed to DOM, (2) as a way to other WebCore
+ code get the "attribute storage" (currently inside NamedNodeMap), and (3) as a way to
+ get the attribute storage creating one if necessary.
+
+ This commit separate the jobs in different functions:
+
+ 1) attributes() keeps being the DOM getter, and loses its boolean parameter.
+
+ 2) updatedAttributes() updates the invalid attributes and returns the attribute
+ storage. If we don't have one, return 0.
+
+ 3) ensureUpdatedAttributes() updates the invalid attributes and forces the
+ creation of attribute storage to return.
+
+ There is also another way to get to the attribute storage currently, via
+ attributeMap(), which doesn't update the attributes for possible changes in Style
+ or SVG attributes.
+
+ Note that the new functions are not available in Node class, so C++ code manipulating
+ attributes should cast to Element.
+
+ This separation also made easier to spot and fix some places where we do not
+ need to create the attribute storage if it doesn't exist.
+
+ No new tests, this commit shouldn't change the behavior of existing code.
+
+ * css/SelectorChecker.cpp:
+ (WebCore::SelectorChecker::checkOneSelector):
+ * dom/DatasetDOMStringMap.cpp:
+ (WebCore::DatasetDOMStringMap::getNames):
+ (WebCore::DatasetDOMStringMap::item):
+ (WebCore::DatasetDOMStringMap::contains):
+ * dom/Document.cpp:
+ (WebCore::Document::importNode):
+ * dom/Element.cpp:
+ (WebCore::Element::setAttribute):
+ (WebCore::Element::hasAttributes):
+ (WebCore::Element::setAttributeNode):
+ (WebCore::Element::setAttributeNodeNS):
+ (WebCore::Element::removeAttributeNode):
+ (WebCore::Element::getAttributeNode):
+ (WebCore::Element::getAttributeNodeNS):
+ (WebCore::Element::hasAttribute):
+ (WebCore::Element::hasAttributeNS):
+ (WebCore::Element::normalizeAttributes):
+ * dom/Element.h:
+ (Element):
+ (WebCore::Element::attributes):
+ (WebCore::Element::ensureAttributeData):
+ (WebCore::Element::ensureUpdatedAttributes):
+ (WebCore::Element::updatedAttributes):
+ (WebCore::Element::setAttributesFromElement):
+ (WebCore::Element::ensureAttributeMap): Made const to be reused by ensureUpdatedAttributes().
+ (WebCore::Element::updateInvalidAttributes):
+ (WebCore):
+ * dom/NamedNodeMap.cpp:
+ (WebCore::NamedNodeMap::mapsEquivalent): Having no attributes is equivalent to
+ not having an attribute storage because the attribute storage is lazily created.
+ * dom/Node.cpp:
+ (WebCore::Node::isEqualNode): Do not force the creation of attribute storage to
+ compare two nodes.
+ (WebCore::Node::isDefaultNamespace): Use updatedAttributes(). Since we iterate
+ using length, it's OK if the attribute storage is empty.
+ (WebCore::Node::lookupNamespaceURI): Ditto.
+ (WebCore::Node::lookupNamespacePrefix): Ditto.
+ (WebCore::Node::compareDocumentPosition): Ditto.
+ * editing/ApplyStyleCommand.cpp:
+ (WebCore::hasNoAttributeOrOnlyStyleAttribute):
+ (WebCore::isEmptyFontTag):
+ * editing/CompositeEditCommand.cpp:
+ (WebCore::CompositeEditCommand::isRemovableBlock): Use isElementNode() explicitly
+ to identify non-Element nodes, then use hasAttributes() if is Element.
+ * editing/InsertParagraphSeparatorCommand.cpp:
+ (WebCore::highestVisuallyEquivalentDivBelowRoot):
+ * editing/MarkupAccumulator.cpp:
+ (WebCore::MarkupAccumulator::appendElement): Do not create the attribute storage
+ unnecessarily.
+ * editing/htmlediting.cpp:
+ (WebCore::areIdenticalElements): Do not create the attribute storage
+ unnecessarily. Use mapsEquivalent() for comparing the attributes.
+ * editing/markup.cpp:
+ (WebCore::completeURLs): Do not create the attribute storage unnecessarily.
+ (WebCore::StyledMarkupAccumulator::appendElement): Ditto.
+ (WebCore::isPlainTextMarkup): hasAttributes() will avoid creating the attribute
+ storage unnecessarily.
+ * html/HTMLEmbedElement.cpp:
+ (WebCore::HTMLEmbedElement::parametersForPlugin):
+ * html/HTMLObjectElement.cpp:
+ (WebCore::HTMLObjectElement::parametersForPlugin):
+ * html/HTMLParamElement.cpp:
+ (WebCore::HTMLParamElement::isURLAttribute): Do not create the attribute storage
+ unnecessarily.
+ * html/parser/HTMLConstructionSite.cpp:
+ (WebCore::HTMLConstructionSite::mergeAttributesFromTokenIntoElement): Use
+ ensureUpdatedAttributes() since we will add new attributes.
+ (WebCore):
+ * inspector/InspectorCSSAgent.cpp:
+ (WebCore::InspectorCSSAgent::buildArrayForAttributeStyles):
+ * inspector/InspectorDOMAgent.cpp:
+ (WebCore::InspectorDOMAgent::setAttributesAsText):
+ (WebCore::InspectorDOMAgent::performSearch):
+ (WebCore::InspectorDOMAgent::buildArrayForElementAttributes):
+ * page/PageSerializer.cpp:
+ (WebCore::isCharsetSpecifyingNode): Do not assume attributeMap will exist.
+ * svg/properties/SVGAnimatedPropertySynchronizer.h: Use ensureUpdatedAttributes()
+ since we will add new attributes.
+ * xml/XPathFunctions.cpp:
+ (WebCore::XPath::FunLang::evaluate): Do not create the attribute storage
+ unnecessarily.
+ * xml/XPathNodeSet.cpp:
+ (WebCore::XPath::NodeSet::traversalSort):
+ * xml/XPathStep.cpp:
+ (WebCore::XPath::Step::nodesInAxis): Use isElementNode() instead of comparing
+ nodeType() manually. Do not create the attribute storage unnecessarily.
+ * xml/parser/XMLDocumentParserLibxml2.cpp:
+ (WebCore::XMLDocumentParser::XMLDocumentParser): Do not create the attribute
+ storage unnecessarily.
+ * xml/parser/XMLDocumentParserQt.cpp:
+ (WebCore::XMLDocumentParser::XMLDocumentParser): Ditto.
+ * xml/parser/XMLTreeBuilder.cpp:
+ (WebCore::XMLTreeBuilder::XMLTreeBuilder): Ditto.
+
2012-02-01 Adam Barth <abarth@webkit.org>
contentDispositionType misparses the Content-Disposition header in some obscure corner cases
if (sel->isAttributeSelector()) {
const QualifiedName& attr = sel->attribute();
- NamedNodeMap* attributes = e->attributes(true);
+ NamedNodeMap* attributes = e->updatedAttributes();
if (!attributes)
return false;
void DatasetDOMStringMap::getNames(Vector<String>& names)
{
- NamedNodeMap* attributeMap = m_element->attributes(true);
+ NamedNodeMap* attributeMap = m_element->updatedAttributes();
if (attributeMap) {
unsigned length = attributeMap->length();
for (unsigned i = 0; i < length; i++) {
String DatasetDOMStringMap::item(const String& name)
{
- NamedNodeMap* attributeMap = m_element->attributes(true);
+ NamedNodeMap* attributeMap = m_element->updatedAttributes();
if (attributeMap) {
unsigned length = attributeMap->length();
for (unsigned i = 0; i < length; i++) {
bool DatasetDOMStringMap::contains(const String& name)
{
- NamedNodeMap* attributeMap = m_element->attributes(true);
+ NamedNodeMap* attributeMap = m_element->updatedAttributes();
if (attributeMap) {
unsigned length = attributeMap->length();
for (unsigned i = 0; i < length; i++) {
if (ec)
return 0;
- NamedNodeMap* attrs = oldElement->attributes(true);
+ NamedNodeMap* attrs = oldElement->updatedAttributes();
if (attrs) {
unsigned length = attrs->length();
for (unsigned i = 0; i < length; i++) {
const AtomicString& localName = shouldIgnoreAttributeCase(this) ? name.lower() : name;
- size_t index = attributes(false)->getAttributeItemIndex(localName, false);
+ size_t index = ensureUpdatedAttributes()->getAttributeItemIndex(localName, false);
const QualifiedName& qName = index != notFound ? m_attributeMap->attributeItem(index)->name() : QualifiedName(nullAtom, localName, nullAtom);
setAttributeInternal(index, qName, value);
}
void Element::setAttribute(const QualifiedName& name, const AtomicString& value)
{
- setAttributeInternal(attributes(false)->getAttributeItemIndex(name), name, value);
+ setAttributeInternal(ensureUpdatedAttributes()->getAttributeItemIndex(name), name, value);
}
inline void Element::setAttributeInternal(size_t index, const QualifiedName& name, const AtomicString& value)
bool Element::hasAttributes() const
{
- if (!isStyleAttributeValid())
- updateStyleAttribute();
-
-#if ENABLE(SVG)
- if (!areSVGAttributesValid())
- updateAnimatedSVGAttribute(anyQName());
-#endif
-
+ updateInvalidAttributes();
return m_attributeMap && m_attributeMap->length();
}
ec = TYPE_MISMATCH_ERR;
return 0;
}
- return static_pointer_cast<Attr>(attributes(false)->setNamedItem(attr, ec));
+ return static_pointer_cast<Attr>(ensureUpdatedAttributes()->setNamedItem(attr, ec));
}
PassRefPtr<Attr> Element::setAttributeNodeNS(Attr* attr, ExceptionCode& ec)
ec = TYPE_MISMATCH_ERR;
return 0;
}
- return static_pointer_cast<Attr>(attributes(false)->setNamedItem(attr, ec));
+ return static_pointer_cast<Attr>(ensureUpdatedAttributes()->setNamedItem(attr, ec));
}
PassRefPtr<Attr> Element::removeAttributeNode(Attr* attr, ExceptionCode& ec)
ASSERT(document() == attr->document());
- NamedNodeMap* attrs = attributes(true);
+ NamedNodeMap* attrs = updatedAttributes();
if (!attrs)
return 0;
PassRefPtr<Attr> Element::getAttributeNode(const String& name)
{
- NamedNodeMap* attrs = attributes(true);
+ NamedNodeMap* attrs = updatedAttributes();
if (!attrs)
return 0;
String localName = shouldIgnoreAttributeCase(this) ? name.lower() : name;
PassRefPtr<Attr> Element::getAttributeNodeNS(const String& namespaceURI, const String& localName)
{
- NamedNodeMap* attrs = attributes(true);
+ NamedNodeMap* attrs = updatedAttributes();
if (!attrs)
return 0;
return static_pointer_cast<Attr>(attrs->getNamedItem(QualifiedName(nullAtom, localName, namespaceURI)));
bool Element::hasAttribute(const String& name) const
{
- NamedNodeMap* attrs = attributes(true);
+ NamedNodeMap* attrs = updatedAttributes();
if (!attrs)
return false;
bool Element::hasAttributeNS(const String& namespaceURI, const String& localName) const
{
- NamedNodeMap* attrs = attributes(true);
+ NamedNodeMap* attrs = updatedAttributes();
if (!attrs)
return false;
return attrs->getAttributeItem(QualifiedName(nullAtom, localName, namespaceURI));
void Element::normalizeAttributes()
{
- // Normalize attributes.
- NamedNodeMap* attrs = attributes(true);
+ NamedNodeMap* attrs = updatedAttributes();
if (!attrs)
return;
void setBooleanAttribute(const QualifiedName& name, bool);
- NamedNodeMap* attributes(bool readonly = false) const;
+ // For exposing to DOM only.
+ NamedNodeMap* attributes() const { return ensureUpdatedAttributes(); }
+
+ NamedNodeMap* ensureUpdatedAttributes() const;
+ NamedNodeMap* updatedAttributes() const;
// This method is called whenever an attribute is added, changed or removed.
virtual void attributeChanged(Attribute*, bool preserveDecls = false);
void parserSetAttributeMap(PassOwnPtr<NamedNodeMap>, FragmentScriptingPermission);
NamedNodeMap* attributeMap() const { return m_attributeMap.get(); }
- NamedNodeMap* ensureAttributeMap();
+ NamedNodeMap* ensureAttributeMap() const;
ElementAttributeData* attributeData() const { return m_attributeMap ? m_attributeMap->attributeData() : 0; }
- ElementAttributeData* ensureAttributeData() const { return attributes()->attributeData(); }
+ ElementAttributeData* ensureAttributeData() const { return ensureUpdatedAttributes()->attributeData(); }
void setAttributesFromElement(const Element&);
HTMLCollection* ensureCachedHTMLCollection(CollectionType);
private:
+ void updateInvalidAttributes() const;
+
void scrollByUnits(int units, ScrollGranularity);
virtual void setPrefix(const AtomicString&, ExceptionCode&);
return parent && parent->isElementNode() ? toElement(parent) : 0;
}
-inline NamedNodeMap* Element::attributes(bool readonly) const
+inline NamedNodeMap* Element::ensureUpdatedAttributes() const
{
- if (!isStyleAttributeValid())
- updateStyleAttribute();
-
-#if ENABLE(SVG)
- if (!areSVGAttributesValid())
- updateAnimatedSVGAttribute(anyQName());
-#endif
+ updateInvalidAttributes();
+ return ensureAttributeMap();
+}
- if (!readonly && !m_attributeMap)
- createAttributeMap();
+inline NamedNodeMap* Element::updatedAttributes() const
+{
+ updateInvalidAttributes();
return m_attributeMap.get();
}
inline void Element::setAttributesFromElement(const Element& other)
{
- if (NamedNodeMap* attributeMap = other.attributes(true))
- attributes(false)->setAttributes(*attributeMap);
+ if (NamedNodeMap* attributeMap = other.updatedAttributes())
+ ensureUpdatedAttributes()->setAttributes(*attributeMap);
}
inline void Element::updateName(const AtomicString& oldName, const AtomicString& newName)
setAttribute(document()->idAttributeName(), value);
}
-inline NamedNodeMap* Element::ensureAttributeMap()
+inline NamedNodeMap* Element::ensureAttributeMap() const
{
if (!m_attributeMap)
createAttributeMap();
return m_attributeMap.get();
}
+inline void Element::updateInvalidAttributes() const
+{
+ if (!isStyleAttributeValid())
+ updateStyleAttribute();
+
+#if ENABLE(SVG)
+ if (!areSVGAttributesValid())
+ updateAnimatedSVGAttribute(anyQName());
+#endif
+}
+
inline Element* firstElementChild(const ContainerNode* container)
{
ASSERT_ARG(container, container);
bool NamedNodeMap::mapsEquivalent(const NamedNodeMap* otherMap) const
{
if (!otherMap)
- return false;
+ return isEmpty();
unsigned len = length();
if (len != otherMap->length())
if (nodeValue() != other->nodeValue())
return false;
- NamedNodeMap* attributes = this->attributes();
- NamedNodeMap* otherAttributes = other->attributes();
-
- if (!attributes && otherAttributes)
- return false;
-
- if (attributes && !attributes->mapsEquivalent(otherAttributes))
- return false;
+ if (isElementNode()) {
+ NamedNodeMap* attributes = toElement(this)->updatedAttributes();
+ NamedNodeMap* otherAttributes = toElement(other)->updatedAttributes();
+
+ if (attributes && !attributes->mapsEquivalent(otherAttributes))
+ return false;
+
+ if (otherAttributes && !otherAttributes->mapsEquivalent(attributes))
+ return false;
+ }
Node* child = firstChild();
Node* otherChild = other->firstChild();
if (elem->prefix().isNull())
return elem->namespaceURI() == namespaceURI;
- if (elem->hasAttributes()) {
- NamedNodeMap* attrs = elem->attributes();
-
+ if (NamedNodeMap* attrs = elem->updatedAttributes()) {
for (unsigned i = 0; i < attrs->length(); i++) {
Attribute* attr = attrs->attributeItem(i);
if (!elem->namespaceURI().isNull() && elem->prefix() == prefix)
return elem->namespaceURI();
- if (elem->hasAttributes()) {
- NamedNodeMap *attrs = elem->attributes();
-
+ if (NamedNodeMap* attrs = elem->updatedAttributes()) {
for (unsigned i = 0; i < attrs->length(); i++) {
Attribute *attr = attrs->attributeItem(i);
if (originalElement->lookupNamespaceURI(prefix()) == _namespaceURI)
return prefix();
- if (hasAttributes()) {
- NamedNodeMap *attrs = attributes();
-
+ if (NamedNodeMap* attrs = toElement(this)->updatedAttributes()) {
for (unsigned i = 0; i < attrs->length(); i++) {
- Attribute *attr = attrs->attributeItem(i);
+ Attribute* attr = attrs->attributeItem(i);
- if (attr->prefix() == xmlnsAtom &&
- attr->value() == _namespaceURI &&
- originalElement->lookupNamespaceURI(attr->localName()) == _namespaceURI)
+ if (attr->prefix() == xmlnsAtom && attr->value() == _namespaceURI
+ && originalElement->lookupNamespaceURI(attr->localName()) == _namespaceURI)
return attr->localName();
}
}
if (attr1 && attr2 && start1 == start2 && start1) {
// We are comparing two attributes on the same node. Crawl our attribute map
// and see which one we hit first.
- NamedNodeMap* map = attr1->ownerElement()->attributes(true);
+ NamedNodeMap* map = attr1->ownerElement()->updatedAttributes();
unsigned length = map->length();
for (unsigned i = 0; i < length; ++i) {
// If neither of the two determining nodes is a child node and nodeType is the same for both determining nodes, then an
enum ShouldStyleAttributeBeEmpty { AllowNonEmptyStyleAttribute, StyleAttributeShouldBeEmpty };
static bool hasNoAttributeOrOnlyStyleAttribute(const StyledElement* element, ShouldStyleAttributeBeEmpty shouldStyleAttributeBeEmpty)
{
- const bool readonly = true;
- NamedNodeMap* map = element->attributes(readonly);
+ NamedNodeMap* map = element->updatedAttributes();
if (!map || map->isEmpty())
return true;
return false;
const Element *elem = static_cast<const Element *>(node);
- NamedNodeMap *map = elem->attributes(true); // true for read-only
+ NamedNodeMap* map = elem->updatedAttributes();
if (!map)
return true;
return map->isEmpty() || (map->length() == 1 && elem->getAttribute(classAttr) == styleSpanClassString());
if ((parentNode && parentNode->firstChild() != parentNode->lastChild()) || !node->hasTagName(divTag))
return false;
- const NamedNodeMap* attributeMap = node->attributes();
- if (!attributeMap || attributeMap->isEmpty())
+ if (!node->isElementNode() || !toElement(node)->hasAttributes())
return true;
-
+
return false;
}
// We don't want to return a root node (if it happens to be a div, e.g., in a document fragment) because there are no
// siblings for us to append to.
while (!curBlock->nextSibling() && curBlock->parentElement()->hasTagName(divTag) && curBlock->parentElement()->parentElement()) {
- NamedNodeMap* attributes = curBlock->parentElement()->attributes(true);
+ NamedNodeMap* attributes = curBlock->parentElement()->updatedAttributes();
if (attributes && !attributes->isEmpty())
break;
curBlock = curBlock->parentElement();
{
appendOpenTag(out, element, namespaces);
- NamedNodeMap* attributes = element->attributes();
- unsigned length = attributes->length();
- for (unsigned int i = 0; i < length; i++)
- appendAttribute(out, element, *attributes->attributeItem(i), namespaces);
+ NamedNodeMap* attributes = element->updatedAttributes();
+ if (attributes) {
+ unsigned length = attributes->length();
+ for (unsigned int i = 0; i < length; i++)
+ appendAttribute(out, element, *attributes->attributeItem(i), namespaces);
+ }
// Give an opportunity to subclasses to add their own attributes.
appendCustomAttributes(out, element, namespaces);
if (!toElement(first)->tagQName().matches(toElement(second)->tagQName()))
return false;
- NamedNodeMap* firstMap = toElement(first)->attributes();
- NamedNodeMap* secondMap = toElement(second)->attributes();
- unsigned firstLength = firstMap->length();
-
- if (firstLength != secondMap->length())
- return false;
-
- for (unsigned i = 0; i < firstLength; i++) {
- Attribute* attribute = firstMap->attributeItem(i);
- Attribute* secondAttribute = secondMap->getAttributeItem(attribute->name());
- if (!secondAttribute || attribute->value() != secondAttribute->value())
- return false;
- }
+ NamedNodeMap* firstMap = toElement(first)->updatedAttributes();
+ NamedNodeMap* secondMap = toElement(second)->updatedAttributes();
+ if (firstMap)
+ return firstMap->mapsEquivalent(secondMap);
+ if (secondMap)
+ return secondMap->mapsEquivalent(firstMap);
return true;
}
for (Node* n = node; n != end; n = n->traverseNextNode()) {
if (n->isElementNode()) {
Element* e = static_cast<Element*>(n);
- NamedNodeMap* attributes = e->attributes();
+ NamedNodeMap* attributes = e->updatedAttributes();
+ if (!attributes)
+ continue;
unsigned length = attributes->length();
for (unsigned i = 0; i < length; i++) {
Attribute* attribute = attributes->attributeItem(i);
const bool documentIsHTML = element->document()->isHTMLDocument();
appendOpenTag(out, element, 0);
- NamedNodeMap* attributes = element->attributes();
- const unsigned length = attributes->length();
+ NamedNodeMap* attributes = element->updatedAttributes();
+ const unsigned length = attributes ? attributes->length() : 0;
const bool shouldAnnotateOrForceInline = element->isHTMLElement() && (shouldAnnotate() || addDisplayInline);
const bool shouldOverrideStyleAttr = shouldAnnotateOrForceInline || shouldApplyWrappingStyle(element);
for (unsigned int i = 0; i < length; i++) {
bool isPlainTextMarkup(Node *node)
{
- if (!node->isElementNode() || !node->hasTagName(divTag) || static_cast<Element*>(node)->attributes()->length())
+ if (!node->isElementNode() || !node->hasTagName(divTag) || static_cast<Element*>(node)->hasAttributes())
return false;
if (node->childNodeCount() == 1 && (node->firstChild()->isTextNode() || (node->firstChild()->firstChild())))
void HTMLEmbedElement::parametersForPlugin(Vector<String>& paramNames, Vector<String>& paramValues)
{
- NamedNodeMap* attributes = this->attributes(true);
+ NamedNodeMap* attributes = updatedAttributes();
if (!attributes)
return;
}
// Turn the attributes of the <object> element into arrays, but don't override <param> values.
- NamedNodeMap* attributes = this->attributes(true);
+ NamedNodeMap* attributes = updatedAttributes();
if (attributes) {
for (unsigned i = 0; i < attributes->length(); ++i) {
Attribute* it = attributes->attributeItem(i);
bool HTMLParamElement::isURLAttribute(Attribute* attr) const
{
- if (attr->name() == valueAttr) {
- Attribute* attr = attributes()->getAttributeItem(nameAttr);
- if (attr) {
- const AtomicString& value = attr->value();
+ if (attr->name() == valueAttr && hasAttributes()) {
+ Attribute* nameAttribute = attributeMap()->getAttributeItem(nameAttr);
+ if (nameAttribute) {
+ const AtomicString& value = nameAttribute->value();
if (isURLParameter(value))
return true;
}
if (!token.attributes())
return;
- NamedNodeMap* attributes = element->attributes(false);
+ NamedNodeMap* attributes = element->ensureUpdatedAttributes();
for (unsigned i = 0; i < token.attributes()->length(); ++i) {
Attribute* attribute = token.attributes()->attributeItem(i);
if (!attributes->getAttributeItem(attribute->name()))
// FIXME: Move this function to the top of the file.
inline PassOwnPtr<NamedNodeMap> cloneAttributes(Element* element)
{
- NamedNodeMap* attributes = element->attributes(true);
+ NamedNodeMap* attributes = element->updatedAttributes();
if (!attributes)
return nullptr;
PassRefPtr<InspectorArray> InspectorCSSAgent::buildArrayForAttributeStyles(Element* element)
{
RefPtr<InspectorArray> attrStyles = InspectorArray::create();
- NamedNodeMap* attributes = element->attributes();
+ NamedNodeMap* attributes = element->updatedAttributes();
+ if (!attributes)
+ return attrStyles.release();
+
for (unsigned i = 0; attributes && i < attributes->length(); ++i) {
Attribute* attribute = attributes->attributeItem(i);
if (!attribute->decl())
return;
}
- const NamedNodeMap* attrMap = toHTMLElement(child)->attributes(true);
+ const NamedNodeMap* attrMap = toHTMLElement(child)->updatedAttributes();
if (!attrMap && name) {
element->removeAttribute(*name);
return;
break;
}
// Go through all attributes and serialize them.
- const NamedNodeMap* attrMap = static_cast<Element*>(node)->attributes(true);
+ const NamedNodeMap* attrMap = static_cast<Element*>(node)->updatedAttributes();
if (!attrMap)
break;
{
RefPtr<InspectorArray> attributesValue = InspectorArray::create();
// Go through all attributes and serialize them.
- const NamedNodeMap* attrMap = element->attributes(true);
+ const NamedNodeMap* attrMap = element->updatedAttributes();
if (!attrMap)
return attributesValue.release();
unsigned numAttrs = attrMap->length();
if (!element->hasTagName(HTMLNames::metaTag))
return false;
HTMLMetaCharsetParser::AttributeList attributes;
- const NamedNodeMap* attributesMap = element->attributes(true);
- for (unsigned i = 0; i < attributesMap->length(); ++i) {
- Attribute* item = attributesMap->attributeItem(i);
- // FIXME: We should deal appropriately with the attribute if they have a namespace.
- attributes.append(make_pair(item->name().toString(), item->value().string()));
+ if (const NamedNodeMap* attributesMap = element->updatedAttributes()) {
+ for (unsigned i = 0; i < attributesMap->length(); ++i) {
+ Attribute* item = attributesMap->attributeItem(i);
+ // FIXME: We should deal appropriately with the attribute if they have a namespace.
+ attributes.append(make_pair(item->name().toString(), item->value().string()));
+ }
}
TextEncoding textEncoding = HTMLMetaCharsetParser::encodingFromMetaAttributes(attributes);
return textEncoding.isValid();
// Attribute directly to avoid a call to Element::attributeChanged
// that could cause the SVGElement to erroneously reset its properties.
// svg/dom/SVGStringList-basics.xhtml exercises this behavior.
- NamedNodeMap* namedAttrMap = ownerElement->attributes(false);
+ NamedNodeMap* namedAttrMap = ownerElement->ensureUpdatedAttributes();
Attribute* old = namedAttrMap->getAttributeItem(attrName);
if (old && value.isNull())
namedAttrMap->removeAttribute(old->name());
Attribute* languageAttribute = 0;
Node* node = evaluationContext().node.get();
while (node) {
- NamedNodeMap* attrs = node->attributes();
- if (attrs)
- languageAttribute = attrs->getAttributeItem(XMLNames::langAttr);
+ if (node->isElementNode()) {
+ if (NamedNodeMap* attributes = toElement(node)->updatedAttributes())
+ languageAttribute = attributes->getAttributeItem(XMLNames::langAttr);
+ }
if (languageAttribute)
break;
node = node->parentNode();
if (!containsAttributeNodes || !n->isElementNode())
continue;
- NamedNodeMap* attributes = toElement(n)->attributes(true /* read-only */);
+ NamedNodeMap* attributes = toElement(n)->updatedAttributes();
if (!attributes)
continue;
return;
}
case AttributeAxis: {
- if (context->nodeType() != Node::ELEMENT_NODE)
+ if (!context->isElementNode())
return;
+ Element* contextElement = toElement(context);
+
// Avoid lazily creating attribute nodes for attributes that we do not need anyway.
if (m_nodeTest.kind() == NodeTest::NameTest && m_nodeTest.data() != starAtom) {
- RefPtr<Node> n = static_cast<Element*>(context)->getAttributeNodeNS(m_nodeTest.namespaceURI(), m_nodeTest.data());
+ RefPtr<Node> n = contextElement->getAttributeNodeNS(m_nodeTest.namespaceURI(), m_nodeTest.data());
if (n && n->namespaceURI() != XMLNSNames::xmlnsNamespaceURI) { // In XPath land, namespace nodes are not accessible on the attribute axis.
if (nodeMatches(n.get(), AttributeAxis, m_nodeTest)) // Still need to check merged predicates.
nodes.append(n.release());
return;
}
- NamedNodeMap* attrs = context->attributes();
+ NamedNodeMap* attrs = contextElement->updatedAttributes();
if (!attrs)
return;
for (; !elemStack.isEmpty(); elemStack.removeLast()) {
Element* element = elemStack.last();
- if (NamedNodeMap* attrs = element->attributes()) {
+ if (NamedNodeMap* attrs = element->updatedAttributes()) {
for (unsigned i = 0; i < attrs->length(); i++) {
Attribute* attr = attrs->attributeItem(i);
if (attr->localName() == xmlnsAtom)
QXmlStreamNamespaceDeclarations namespaces;
for (Element* element = elemStack.last(); !elemStack.isEmpty(); elemStack.removeLast()) {
- if (NamedNodeMap* attrs = element->attributes()) {
+ if (NamedNodeMap* attrs = element->updatedAttributes()) {
for (unsigned i = 0; i < attrs->length(); i++) {
Attribute* attr = attrs->attributeItem(i);
if (attr->localName() == "xmlns")
for (Element* element; !nodeStack.isEmpty(); nodeStack.removeLast()) {
element = nodeStack.last();
- if (NamedNodeMap* attrs = element->attributes()) {
+ if (NamedNodeMap* attrs = element->updatedAttributes()) {
for (size_t i = 0; i < attrs->length(); ++i) {
Attribute* attr = attrs->attributeItem(i);
if (attr->localName() == xmlnsAtom)
+2012-02-01 Caio Marcelo de Oliveira Filho <caio.oliveira@openbossa.org>
+
+ Avoid creating NamedNodeMap unnecessarily
+ https://bugs.webkit.org/show_bug.cgi?id=77574
+
+ Reviewed by Ryosuke Niwa.
+
+ * src/WebPageSerializerImpl.cpp:
+ (WebKit::WebPageSerializerImpl::openTagToString): use updatedAttributes().
+
2012-02-01 Justin Novosad <junov@chromium.org>
[Chromium] Enable deferred canvas rendering in the skia port
// Add open tag
result += "<" + element->nodeName().lower();
// Go through all attributes and serialize them.
- const NamedNodeMap *attrMap = element->attributes(true);
+ const NamedNodeMap *attrMap = element->updatedAttributes();
if (attrMap) {
unsigned numAttrs = attrMap->length();
for (unsigned i = 0; i < numAttrs; i++) {
return QStringList();
QStringList attributeNameList;
- const NamedNodeMap* const attrs = m_element->attributes(/* read only = */ true);
+ const NamedNodeMap* const attrs = m_element->updatedAttributes();
if (attrs) {
const String namespaceUriString(namespaceUri); // convert QString -> String once
const unsigned attrsCount = attrs->length();
+2012-02-01 Caio Marcelo de Oliveira Filho <caio.oliveira@openbossa.org>
+
+ Avoid creating NamedNodeMap unnecessarily
+ https://bugs.webkit.org/show_bug.cgi?id=77574
+
+ Reviewed by Ryosuke Niwa.
+
+ * Api/qwebelement.cpp:
+ (QWebElement::attributeNames): use updateAttributes().
+
2012-02-01 Alexis Menard <alexis.menard@openbossa.org>
CSSStyleDeclaration.getPropertyPriority() fails for CSS shorthand properties with 'important' priority