void nsDOMAttributeMap::DropAttribute(int32_t aNamespaceID, nsIAtom* aLocalName) { nsAttrKey attr(aNamespaceID, aLocalName); Attr *node = mAttributeCache.GetWeak(attr); if (node) { // Break link to map node->SetMap(nullptr); // Remove from cache mAttributeCache.Remove(attr); } }
already_AddRefed<Attr> nsDOMAttributeMap::SetNamedItemInternal(Attr& aAttr, bool aWithNS, ErrorResult& aError) { NS_ENSURE_TRUE(mContent, nullptr); // XXX should check same-origin between mContent and aAttr however // nsContentUtils::CheckSameOrigin can't deal with attributenodes yet // Check that attribute is not owned by somebody else nsDOMAttributeMap* owner = aAttr.GetMap(); if (owner) { if (owner != this) { aError.Throw(NS_ERROR_DOM_INUSE_ATTRIBUTE_ERR); return nullptr; } // setting a preexisting attribute is a no-op, just return the same // node. nsRefPtr<Attr> attribute = &aAttr; return attribute.forget(); } nsresult rv; if (!mContent->HasSameOwnerDoc(&aAttr)) { nsCOMPtr<nsINode> adoptedNode = mContent->OwnerDoc()->AdoptNode(aAttr, aError); if (aError.Failed()) { return nullptr; } NS_ASSERTION(adoptedNode == &aAttr, "Uh, adopt node changed nodes?"); } // Get nodeinfo and preexisting attribute (if it exists) nsAutoString name; nsCOMPtr<nsINodeInfo> ni; nsRefPtr<Attr> attr; // SetNamedItemNS() if (aWithNS) { // Return existing attribute, if present ni = aAttr.NodeInfo(); if (mContent->HasAttr(ni->NamespaceID(), ni->NameAtom())) { attr = RemoveAttribute(ni); } } else { // SetNamedItem() aAttr.GetName(name); // get node-info of old attribute ni = mContent->GetExistingAttrNameFromQName(name); if (ni) { attr = RemoveAttribute(ni); } else { if (mContent->IsInHTMLDocument() && mContent->IsHTML()) { nsContentUtils::ASCIIToLower(name); } rv = mContent->NodeInfo()->NodeInfoManager()-> GetNodeInfo(name, nullptr, kNameSpaceID_None, nsIDOMNode::ATTRIBUTE_NODE, getter_AddRefs(ni)); if (NS_FAILED(rv)) { aError.Throw(rv); return nullptr; } // value is already empty } } nsAutoString value; aAttr.GetValue(value); // Add the new attribute to the attribute map before updating // its value in the element. @see bug 364413. nsAttrKey attrkey(ni->NamespaceID(), ni->NameAtom()); mAttributeCache.Put(attrkey, &aAttr); aAttr.SetMap(this); rv = mContent->SetAttr(ni->NamespaceID(), ni->NameAtom(), ni->GetPrefixAtom(), value, true); if (NS_FAILED(rv)) { aError.Throw(rv); DropAttribute(ni->NamespaceID(), ni->NameAtom()); } return attr.forget(); }