Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
michael@0 | 1 | /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
michael@0 | 2 | /* This Source Code Form is subject to the terms of the Mozilla Public |
michael@0 | 3 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
michael@0 | 4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
michael@0 | 5 | |
michael@0 | 6 | /* |
michael@0 | 7 | * Implementation of the |attributes| property of DOM Core's Element object. |
michael@0 | 8 | */ |
michael@0 | 9 | |
michael@0 | 10 | #include "nsDOMAttributeMap.h" |
michael@0 | 11 | |
michael@0 | 12 | #include "mozilla/MemoryReporting.h" |
michael@0 | 13 | #include "mozilla/dom/Attr.h" |
michael@0 | 14 | #include "mozilla/dom/Element.h" |
michael@0 | 15 | #include "mozilla/dom/MozNamedAttrMapBinding.h" |
michael@0 | 16 | #include "nsAttrName.h" |
michael@0 | 17 | #include "nsContentUtils.h" |
michael@0 | 18 | #include "nsError.h" |
michael@0 | 19 | #include "nsIContentInlines.h" |
michael@0 | 20 | #include "nsIDocument.h" |
michael@0 | 21 | #include "nsNameSpaceManager.h" |
michael@0 | 22 | #include "nsNodeInfoManager.h" |
michael@0 | 23 | #include "nsUnicharUtils.h" |
michael@0 | 24 | #include "nsWrapperCacheInlines.h" |
michael@0 | 25 | |
michael@0 | 26 | using namespace mozilla; |
michael@0 | 27 | using namespace mozilla::dom; |
michael@0 | 28 | |
michael@0 | 29 | //---------------------------------------------------------------------- |
michael@0 | 30 | |
michael@0 | 31 | nsDOMAttributeMap::nsDOMAttributeMap(Element* aContent) |
michael@0 | 32 | : mContent(aContent) |
michael@0 | 33 | { |
michael@0 | 34 | // We don't add a reference to our content. If it goes away, |
michael@0 | 35 | // we'll be told to drop our reference |
michael@0 | 36 | SetIsDOMBinding(); |
michael@0 | 37 | } |
michael@0 | 38 | |
michael@0 | 39 | /** |
michael@0 | 40 | * Clear map pointer for attributes. |
michael@0 | 41 | */ |
michael@0 | 42 | PLDHashOperator |
michael@0 | 43 | RemoveMapRef(nsAttrHashKey::KeyType aKey, nsRefPtr<Attr>& aData, |
michael@0 | 44 | void* aUserArg) |
michael@0 | 45 | { |
michael@0 | 46 | aData->SetMap(nullptr); |
michael@0 | 47 | |
michael@0 | 48 | return PL_DHASH_REMOVE; |
michael@0 | 49 | } |
michael@0 | 50 | |
michael@0 | 51 | nsDOMAttributeMap::~nsDOMAttributeMap() |
michael@0 | 52 | { |
michael@0 | 53 | mAttributeCache.Enumerate(RemoveMapRef, nullptr); |
michael@0 | 54 | } |
michael@0 | 55 | |
michael@0 | 56 | void |
michael@0 | 57 | nsDOMAttributeMap::DropReference() |
michael@0 | 58 | { |
michael@0 | 59 | mAttributeCache.Enumerate(RemoveMapRef, nullptr); |
michael@0 | 60 | mContent = nullptr; |
michael@0 | 61 | } |
michael@0 | 62 | |
michael@0 | 63 | NS_IMPL_CYCLE_COLLECTION_CLASS(nsDOMAttributeMap) |
michael@0 | 64 | |
michael@0 | 65 | NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsDOMAttributeMap) |
michael@0 | 66 | tmp->DropReference(); |
michael@0 | 67 | NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER |
michael@0 | 68 | NS_IMPL_CYCLE_COLLECTION_UNLINK(mContent) |
michael@0 | 69 | NS_IMPL_CYCLE_COLLECTION_UNLINK_END |
michael@0 | 70 | |
michael@0 | 71 | |
michael@0 | 72 | PLDHashOperator |
michael@0 | 73 | TraverseMapEntry(nsAttrHashKey::KeyType aKey, nsRefPtr<Attr>& aData, |
michael@0 | 74 | void* aUserArg) |
michael@0 | 75 | { |
michael@0 | 76 | nsCycleCollectionTraversalCallback *cb = |
michael@0 | 77 | static_cast<nsCycleCollectionTraversalCallback*>(aUserArg); |
michael@0 | 78 | |
michael@0 | 79 | cb->NoteXPCOMChild(static_cast<nsINode*>(aData.get())); |
michael@0 | 80 | |
michael@0 | 81 | return PL_DHASH_NEXT; |
michael@0 | 82 | } |
michael@0 | 83 | |
michael@0 | 84 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsDOMAttributeMap) |
michael@0 | 85 | tmp->mAttributeCache.Enumerate(TraverseMapEntry, &cb); |
michael@0 | 86 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS |
michael@0 | 87 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mContent) |
michael@0 | 88 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END |
michael@0 | 89 | |
michael@0 | 90 | NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(nsDOMAttributeMap) |
michael@0 | 91 | |
michael@0 | 92 | NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(nsDOMAttributeMap) |
michael@0 | 93 | if (tmp->IsBlack()) { |
michael@0 | 94 | if (tmp->mContent) { |
michael@0 | 95 | // The map owns the element so we can mark it when the |
michael@0 | 96 | // map itself is certainly alive. |
michael@0 | 97 | mozilla::dom::FragmentOrElement::MarkNodeChildren(tmp->mContent); |
michael@0 | 98 | } |
michael@0 | 99 | return true; |
michael@0 | 100 | } |
michael@0 | 101 | if (tmp->mContent && |
michael@0 | 102 | mozilla::dom::FragmentOrElement::CanSkip(tmp->mContent, true)) { |
michael@0 | 103 | return true; |
michael@0 | 104 | } |
michael@0 | 105 | NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END |
michael@0 | 106 | |
michael@0 | 107 | NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(nsDOMAttributeMap) |
michael@0 | 108 | return tmp->IsBlackAndDoesNotNeedTracing(tmp); |
michael@0 | 109 | NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_END |
michael@0 | 110 | |
michael@0 | 111 | NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN(nsDOMAttributeMap) |
michael@0 | 112 | return tmp->IsBlack(); |
michael@0 | 113 | NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END |
michael@0 | 114 | |
michael@0 | 115 | // QueryInterface implementation for nsDOMAttributeMap |
michael@0 | 116 | NS_INTERFACE_TABLE_HEAD(nsDOMAttributeMap) |
michael@0 | 117 | NS_INTERFACE_TABLE(nsDOMAttributeMap, nsIDOMMozNamedAttrMap) |
michael@0 | 118 | NS_INTERFACE_TABLE_TO_MAP_SEGUE |
michael@0 | 119 | NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY |
michael@0 | 120 | NS_INTERFACE_MAP_ENTRIES_CYCLE_COLLECTION(nsDOMAttributeMap) |
michael@0 | 121 | NS_INTERFACE_MAP_END |
michael@0 | 122 | |
michael@0 | 123 | NS_IMPL_CYCLE_COLLECTING_ADDREF(nsDOMAttributeMap) |
michael@0 | 124 | NS_IMPL_CYCLE_COLLECTING_RELEASE(nsDOMAttributeMap) |
michael@0 | 125 | |
michael@0 | 126 | PLDHashOperator |
michael@0 | 127 | SetOwnerDocumentFunc(nsAttrHashKey::KeyType aKey, |
michael@0 | 128 | nsRefPtr<Attr>& aData, |
michael@0 | 129 | void* aUserArg) |
michael@0 | 130 | { |
michael@0 | 131 | nsresult rv = aData->SetOwnerDocument(static_cast<nsIDocument*>(aUserArg)); |
michael@0 | 132 | |
michael@0 | 133 | return NS_FAILED(rv) ? PL_DHASH_STOP : PL_DHASH_NEXT; |
michael@0 | 134 | } |
michael@0 | 135 | |
michael@0 | 136 | nsresult |
michael@0 | 137 | nsDOMAttributeMap::SetOwnerDocument(nsIDocument* aDocument) |
michael@0 | 138 | { |
michael@0 | 139 | uint32_t n = mAttributeCache.Enumerate(SetOwnerDocumentFunc, aDocument); |
michael@0 | 140 | NS_ENSURE_TRUE(n == mAttributeCache.Count(), NS_ERROR_FAILURE); |
michael@0 | 141 | |
michael@0 | 142 | return NS_OK; |
michael@0 | 143 | } |
michael@0 | 144 | |
michael@0 | 145 | void |
michael@0 | 146 | nsDOMAttributeMap::DropAttribute(int32_t aNamespaceID, nsIAtom* aLocalName) |
michael@0 | 147 | { |
michael@0 | 148 | nsAttrKey attr(aNamespaceID, aLocalName); |
michael@0 | 149 | Attr *node = mAttributeCache.GetWeak(attr); |
michael@0 | 150 | if (node) { |
michael@0 | 151 | // Break link to map |
michael@0 | 152 | node->SetMap(nullptr); |
michael@0 | 153 | |
michael@0 | 154 | // Remove from cache |
michael@0 | 155 | mAttributeCache.Remove(attr); |
michael@0 | 156 | } |
michael@0 | 157 | } |
michael@0 | 158 | |
michael@0 | 159 | already_AddRefed<Attr> |
michael@0 | 160 | nsDOMAttributeMap::RemoveAttribute(nsINodeInfo* aNodeInfo) |
michael@0 | 161 | { |
michael@0 | 162 | NS_ASSERTION(aNodeInfo, "RemoveAttribute() called with aNodeInfo == nullptr!"); |
michael@0 | 163 | |
michael@0 | 164 | nsAttrKey attr(aNodeInfo->NamespaceID(), aNodeInfo->NameAtom()); |
michael@0 | 165 | |
michael@0 | 166 | nsRefPtr<Attr> node; |
michael@0 | 167 | if (!mAttributeCache.Get(attr, getter_AddRefs(node))) { |
michael@0 | 168 | nsAutoString value; |
michael@0 | 169 | // As we are removing the attribute we need to set the current value in |
michael@0 | 170 | // the attribute node. |
michael@0 | 171 | mContent->GetAttr(aNodeInfo->NamespaceID(), aNodeInfo->NameAtom(), value); |
michael@0 | 172 | nsCOMPtr<nsINodeInfo> ni = aNodeInfo; |
michael@0 | 173 | node = new Attr(nullptr, ni.forget(), value, true); |
michael@0 | 174 | } |
michael@0 | 175 | else { |
michael@0 | 176 | // Break link to map |
michael@0 | 177 | node->SetMap(nullptr); |
michael@0 | 178 | |
michael@0 | 179 | // Remove from cache |
michael@0 | 180 | mAttributeCache.Remove(attr); |
michael@0 | 181 | } |
michael@0 | 182 | |
michael@0 | 183 | return node.forget(); |
michael@0 | 184 | } |
michael@0 | 185 | |
michael@0 | 186 | Attr* |
michael@0 | 187 | nsDOMAttributeMap::GetAttribute(nsINodeInfo* aNodeInfo, bool aNsAware) |
michael@0 | 188 | { |
michael@0 | 189 | NS_ASSERTION(aNodeInfo, "GetAttribute() called with aNodeInfo == nullptr!"); |
michael@0 | 190 | |
michael@0 | 191 | nsAttrKey attr(aNodeInfo->NamespaceID(), aNodeInfo->NameAtom()); |
michael@0 | 192 | |
michael@0 | 193 | Attr* node = mAttributeCache.GetWeak(attr); |
michael@0 | 194 | if (!node) { |
michael@0 | 195 | nsCOMPtr<nsINodeInfo> ni = aNodeInfo; |
michael@0 | 196 | nsRefPtr<Attr> newAttr = |
michael@0 | 197 | new Attr(this, ni.forget(), EmptyString(), aNsAware); |
michael@0 | 198 | mAttributeCache.Put(attr, newAttr); |
michael@0 | 199 | node = newAttr; |
michael@0 | 200 | } |
michael@0 | 201 | |
michael@0 | 202 | return node; |
michael@0 | 203 | } |
michael@0 | 204 | |
michael@0 | 205 | Attr* |
michael@0 | 206 | nsDOMAttributeMap::NamedGetter(const nsAString& aAttrName, bool& aFound) |
michael@0 | 207 | { |
michael@0 | 208 | aFound = false; |
michael@0 | 209 | NS_ENSURE_TRUE(mContent, nullptr); |
michael@0 | 210 | |
michael@0 | 211 | nsCOMPtr<nsINodeInfo> ni = mContent->GetExistingAttrNameFromQName(aAttrName); |
michael@0 | 212 | if (!ni) { |
michael@0 | 213 | return nullptr; |
michael@0 | 214 | } |
michael@0 | 215 | |
michael@0 | 216 | aFound = true; |
michael@0 | 217 | return GetAttribute(ni, false); |
michael@0 | 218 | } |
michael@0 | 219 | |
michael@0 | 220 | bool |
michael@0 | 221 | nsDOMAttributeMap::NameIsEnumerable(const nsAString& aName) |
michael@0 | 222 | { |
michael@0 | 223 | return true; |
michael@0 | 224 | } |
michael@0 | 225 | |
michael@0 | 226 | Attr* |
michael@0 | 227 | nsDOMAttributeMap::GetNamedItem(const nsAString& aAttrName) |
michael@0 | 228 | { |
michael@0 | 229 | bool dummy; |
michael@0 | 230 | return NamedGetter(aAttrName, dummy); |
michael@0 | 231 | } |
michael@0 | 232 | |
michael@0 | 233 | NS_IMETHODIMP |
michael@0 | 234 | nsDOMAttributeMap::GetNamedItem(const nsAString& aAttrName, |
michael@0 | 235 | nsIDOMAttr** aAttribute) |
michael@0 | 236 | { |
michael@0 | 237 | NS_ENSURE_ARG_POINTER(aAttribute); |
michael@0 | 238 | |
michael@0 | 239 | NS_IF_ADDREF(*aAttribute = GetNamedItem(aAttrName)); |
michael@0 | 240 | |
michael@0 | 241 | return NS_OK; |
michael@0 | 242 | } |
michael@0 | 243 | |
michael@0 | 244 | NS_IMETHODIMP |
michael@0 | 245 | nsDOMAttributeMap::SetNamedItem(nsIDOMAttr* aAttr, nsIDOMAttr** aReturn) |
michael@0 | 246 | { |
michael@0 | 247 | Attr* attribute = static_cast<Attr*>(aAttr); |
michael@0 | 248 | NS_ENSURE_ARG(attribute); |
michael@0 | 249 | |
michael@0 | 250 | ErrorResult rv; |
michael@0 | 251 | *aReturn = SetNamedItem(*attribute, rv).take(); |
michael@0 | 252 | return rv.ErrorCode(); |
michael@0 | 253 | } |
michael@0 | 254 | |
michael@0 | 255 | NS_IMETHODIMP |
michael@0 | 256 | nsDOMAttributeMap::SetNamedItemNS(nsIDOMAttr* aAttr, nsIDOMAttr** aReturn) |
michael@0 | 257 | { |
michael@0 | 258 | Attr* attribute = static_cast<Attr*>(aAttr); |
michael@0 | 259 | NS_ENSURE_ARG(attribute); |
michael@0 | 260 | |
michael@0 | 261 | ErrorResult rv; |
michael@0 | 262 | *aReturn = SetNamedItemNS(*attribute, rv).take(); |
michael@0 | 263 | return rv.ErrorCode(); |
michael@0 | 264 | } |
michael@0 | 265 | |
michael@0 | 266 | already_AddRefed<Attr> |
michael@0 | 267 | nsDOMAttributeMap::SetNamedItemInternal(Attr& aAttr, |
michael@0 | 268 | bool aWithNS, |
michael@0 | 269 | ErrorResult& aError) |
michael@0 | 270 | { |
michael@0 | 271 | NS_ENSURE_TRUE(mContent, nullptr); |
michael@0 | 272 | |
michael@0 | 273 | // XXX should check same-origin between mContent and aAttr however |
michael@0 | 274 | // nsContentUtils::CheckSameOrigin can't deal with attributenodes yet |
michael@0 | 275 | |
michael@0 | 276 | // Check that attribute is not owned by somebody else |
michael@0 | 277 | nsDOMAttributeMap* owner = aAttr.GetMap(); |
michael@0 | 278 | if (owner) { |
michael@0 | 279 | if (owner != this) { |
michael@0 | 280 | aError.Throw(NS_ERROR_DOM_INUSE_ATTRIBUTE_ERR); |
michael@0 | 281 | return nullptr; |
michael@0 | 282 | } |
michael@0 | 283 | |
michael@0 | 284 | // setting a preexisting attribute is a no-op, just return the same |
michael@0 | 285 | // node. |
michael@0 | 286 | nsRefPtr<Attr> attribute = &aAttr; |
michael@0 | 287 | return attribute.forget(); |
michael@0 | 288 | } |
michael@0 | 289 | |
michael@0 | 290 | nsresult rv; |
michael@0 | 291 | if (mContent->OwnerDoc() != aAttr.OwnerDoc()) { |
michael@0 | 292 | nsCOMPtr<nsINode> adoptedNode = |
michael@0 | 293 | mContent->OwnerDoc()->AdoptNode(aAttr, aError); |
michael@0 | 294 | if (aError.Failed()) { |
michael@0 | 295 | return nullptr; |
michael@0 | 296 | } |
michael@0 | 297 | |
michael@0 | 298 | NS_ASSERTION(adoptedNode == &aAttr, "Uh, adopt node changed nodes?"); |
michael@0 | 299 | } |
michael@0 | 300 | |
michael@0 | 301 | // Get nodeinfo and preexisting attribute (if it exists) |
michael@0 | 302 | nsAutoString name; |
michael@0 | 303 | nsCOMPtr<nsINodeInfo> ni; |
michael@0 | 304 | |
michael@0 | 305 | nsRefPtr<Attr> attr; |
michael@0 | 306 | // SetNamedItemNS() |
michael@0 | 307 | if (aWithNS) { |
michael@0 | 308 | // Return existing attribute, if present |
michael@0 | 309 | ni = aAttr.NodeInfo(); |
michael@0 | 310 | |
michael@0 | 311 | if (mContent->HasAttr(ni->NamespaceID(), ni->NameAtom())) { |
michael@0 | 312 | attr = RemoveAttribute(ni); |
michael@0 | 313 | } |
michael@0 | 314 | } else { // SetNamedItem() |
michael@0 | 315 | aAttr.GetName(name); |
michael@0 | 316 | |
michael@0 | 317 | // get node-info of old attribute |
michael@0 | 318 | ni = mContent->GetExistingAttrNameFromQName(name); |
michael@0 | 319 | if (ni) { |
michael@0 | 320 | attr = RemoveAttribute(ni); |
michael@0 | 321 | } |
michael@0 | 322 | else { |
michael@0 | 323 | if (mContent->IsInHTMLDocument() && |
michael@0 | 324 | mContent->IsHTML()) { |
michael@0 | 325 | nsContentUtils::ASCIIToLower(name); |
michael@0 | 326 | } |
michael@0 | 327 | |
michael@0 | 328 | rv = mContent->NodeInfo()->NodeInfoManager()-> |
michael@0 | 329 | GetNodeInfo(name, nullptr, kNameSpaceID_None, |
michael@0 | 330 | nsIDOMNode::ATTRIBUTE_NODE, getter_AddRefs(ni)); |
michael@0 | 331 | if (NS_FAILED(rv)) { |
michael@0 | 332 | aError.Throw(rv); |
michael@0 | 333 | return nullptr; |
michael@0 | 334 | } |
michael@0 | 335 | // value is already empty |
michael@0 | 336 | } |
michael@0 | 337 | } |
michael@0 | 338 | |
michael@0 | 339 | nsAutoString value; |
michael@0 | 340 | aAttr.GetValue(value); |
michael@0 | 341 | |
michael@0 | 342 | // Add the new attribute to the attribute map before updating |
michael@0 | 343 | // its value in the element. @see bug 364413. |
michael@0 | 344 | nsAttrKey attrkey(ni->NamespaceID(), ni->NameAtom()); |
michael@0 | 345 | mAttributeCache.Put(attrkey, &aAttr); |
michael@0 | 346 | aAttr.SetMap(this); |
michael@0 | 347 | |
michael@0 | 348 | rv = mContent->SetAttr(ni->NamespaceID(), ni->NameAtom(), |
michael@0 | 349 | ni->GetPrefixAtom(), value, true); |
michael@0 | 350 | if (NS_FAILED(rv)) { |
michael@0 | 351 | aError.Throw(rv); |
michael@0 | 352 | DropAttribute(ni->NamespaceID(), ni->NameAtom()); |
michael@0 | 353 | } |
michael@0 | 354 | |
michael@0 | 355 | return attr.forget(); |
michael@0 | 356 | } |
michael@0 | 357 | |
michael@0 | 358 | NS_IMETHODIMP |
michael@0 | 359 | nsDOMAttributeMap::RemoveNamedItem(const nsAString& aName, |
michael@0 | 360 | nsIDOMAttr** aReturn) |
michael@0 | 361 | { |
michael@0 | 362 | NS_ENSURE_ARG_POINTER(aReturn); |
michael@0 | 363 | |
michael@0 | 364 | ErrorResult rv; |
michael@0 | 365 | *aReturn = RemoveNamedItem(aName, rv).take(); |
michael@0 | 366 | return rv.ErrorCode(); |
michael@0 | 367 | } |
michael@0 | 368 | |
michael@0 | 369 | already_AddRefed<Attr> |
michael@0 | 370 | nsDOMAttributeMap::RemoveNamedItem(const nsAString& aName, ErrorResult& aError) |
michael@0 | 371 | { |
michael@0 | 372 | if (!mContent) { |
michael@0 | 373 | aError.Throw(NS_ERROR_DOM_NOT_FOUND_ERR); |
michael@0 | 374 | return nullptr; |
michael@0 | 375 | } |
michael@0 | 376 | |
michael@0 | 377 | nsCOMPtr<nsINodeInfo> ni = mContent->GetExistingAttrNameFromQName(aName); |
michael@0 | 378 | if (!ni) { |
michael@0 | 379 | aError.Throw(NS_ERROR_DOM_NOT_FOUND_ERR); |
michael@0 | 380 | return nullptr; |
michael@0 | 381 | } |
michael@0 | 382 | |
michael@0 | 383 | nsRefPtr<Attr> attribute = GetAttribute(ni, true); |
michael@0 | 384 | |
michael@0 | 385 | // This removes the attribute node from the attribute map. |
michael@0 | 386 | aError = mContent->UnsetAttr(ni->NamespaceID(), ni->NameAtom(), true); |
michael@0 | 387 | return attribute.forget(); |
michael@0 | 388 | } |
michael@0 | 389 | |
michael@0 | 390 | |
michael@0 | 391 | Attr* |
michael@0 | 392 | nsDOMAttributeMap::IndexedGetter(uint32_t aIndex, bool& aFound) |
michael@0 | 393 | { |
michael@0 | 394 | aFound = false; |
michael@0 | 395 | NS_ENSURE_TRUE(mContent, nullptr); |
michael@0 | 396 | |
michael@0 | 397 | const nsAttrName* name = mContent->GetAttrNameAt(aIndex); |
michael@0 | 398 | NS_ENSURE_TRUE(name, nullptr); |
michael@0 | 399 | |
michael@0 | 400 | aFound = true; |
michael@0 | 401 | // Don't use the nodeinfo even if one exists since it can have the wrong |
michael@0 | 402 | // owner document. |
michael@0 | 403 | nsCOMPtr<nsINodeInfo> ni = mContent->NodeInfo()->NodeInfoManager()-> |
michael@0 | 404 | GetNodeInfo(name->LocalName(), name->GetPrefix(), name->NamespaceID(), |
michael@0 | 405 | nsIDOMNode::ATTRIBUTE_NODE); |
michael@0 | 406 | return GetAttribute(ni, true); |
michael@0 | 407 | } |
michael@0 | 408 | |
michael@0 | 409 | Attr* |
michael@0 | 410 | nsDOMAttributeMap::Item(uint32_t aIndex) |
michael@0 | 411 | { |
michael@0 | 412 | bool dummy; |
michael@0 | 413 | return IndexedGetter(aIndex, dummy); |
michael@0 | 414 | } |
michael@0 | 415 | |
michael@0 | 416 | NS_IMETHODIMP |
michael@0 | 417 | nsDOMAttributeMap::Item(uint32_t aIndex, nsIDOMAttr** aReturn) |
michael@0 | 418 | { |
michael@0 | 419 | NS_IF_ADDREF(*aReturn = Item(aIndex)); |
michael@0 | 420 | return NS_OK; |
michael@0 | 421 | } |
michael@0 | 422 | |
michael@0 | 423 | uint32_t |
michael@0 | 424 | nsDOMAttributeMap::Length() const |
michael@0 | 425 | { |
michael@0 | 426 | NS_ENSURE_TRUE(mContent, 0); |
michael@0 | 427 | |
michael@0 | 428 | return mContent->GetAttrCount(); |
michael@0 | 429 | } |
michael@0 | 430 | |
michael@0 | 431 | nsresult |
michael@0 | 432 | nsDOMAttributeMap::GetLength(uint32_t *aLength) |
michael@0 | 433 | { |
michael@0 | 434 | NS_ENSURE_ARG_POINTER(aLength); |
michael@0 | 435 | *aLength = Length(); |
michael@0 | 436 | return NS_OK; |
michael@0 | 437 | } |
michael@0 | 438 | |
michael@0 | 439 | NS_IMETHODIMP |
michael@0 | 440 | nsDOMAttributeMap::GetNamedItemNS(const nsAString& aNamespaceURI, |
michael@0 | 441 | const nsAString& aLocalName, |
michael@0 | 442 | nsIDOMAttr** aReturn) |
michael@0 | 443 | { |
michael@0 | 444 | NS_IF_ADDREF(*aReturn = GetNamedItemNS(aNamespaceURI, aLocalName)); |
michael@0 | 445 | return NS_OK; |
michael@0 | 446 | } |
michael@0 | 447 | |
michael@0 | 448 | Attr* |
michael@0 | 449 | nsDOMAttributeMap::GetNamedItemNS(const nsAString& aNamespaceURI, |
michael@0 | 450 | const nsAString& aLocalName) |
michael@0 | 451 | { |
michael@0 | 452 | nsCOMPtr<nsINodeInfo> ni = GetAttrNodeInfo(aNamespaceURI, aLocalName); |
michael@0 | 453 | if (!ni) { |
michael@0 | 454 | return nullptr; |
michael@0 | 455 | } |
michael@0 | 456 | |
michael@0 | 457 | return GetAttribute(ni, true); |
michael@0 | 458 | } |
michael@0 | 459 | |
michael@0 | 460 | already_AddRefed<nsINodeInfo> |
michael@0 | 461 | nsDOMAttributeMap::GetAttrNodeInfo(const nsAString& aNamespaceURI, |
michael@0 | 462 | const nsAString& aLocalName) |
michael@0 | 463 | { |
michael@0 | 464 | if (!mContent) { |
michael@0 | 465 | return nullptr; |
michael@0 | 466 | } |
michael@0 | 467 | |
michael@0 | 468 | int32_t nameSpaceID = kNameSpaceID_None; |
michael@0 | 469 | |
michael@0 | 470 | if (!aNamespaceURI.IsEmpty()) { |
michael@0 | 471 | nameSpaceID = |
michael@0 | 472 | nsContentUtils::NameSpaceManager()->GetNameSpaceID(aNamespaceURI); |
michael@0 | 473 | |
michael@0 | 474 | if (nameSpaceID == kNameSpaceID_Unknown) { |
michael@0 | 475 | return nullptr; |
michael@0 | 476 | } |
michael@0 | 477 | } |
michael@0 | 478 | |
michael@0 | 479 | uint32_t i, count = mContent->GetAttrCount(); |
michael@0 | 480 | for (i = 0; i < count; ++i) { |
michael@0 | 481 | const nsAttrName* name = mContent->GetAttrNameAt(i); |
michael@0 | 482 | int32_t attrNS = name->NamespaceID(); |
michael@0 | 483 | nsIAtom* nameAtom = name->LocalName(); |
michael@0 | 484 | |
michael@0 | 485 | if (nameSpaceID == attrNS && |
michael@0 | 486 | nameAtom->Equals(aLocalName)) { |
michael@0 | 487 | nsCOMPtr<nsINodeInfo> ni; |
michael@0 | 488 | ni = mContent->NodeInfo()->NodeInfoManager()-> |
michael@0 | 489 | GetNodeInfo(nameAtom, name->GetPrefix(), nameSpaceID, |
michael@0 | 490 | nsIDOMNode::ATTRIBUTE_NODE); |
michael@0 | 491 | |
michael@0 | 492 | return ni.forget(); |
michael@0 | 493 | } |
michael@0 | 494 | } |
michael@0 | 495 | |
michael@0 | 496 | return nullptr; |
michael@0 | 497 | } |
michael@0 | 498 | |
michael@0 | 499 | NS_IMETHODIMP |
michael@0 | 500 | nsDOMAttributeMap::RemoveNamedItemNS(const nsAString& aNamespaceURI, |
michael@0 | 501 | const nsAString& aLocalName, |
michael@0 | 502 | nsIDOMAttr** aReturn) |
michael@0 | 503 | { |
michael@0 | 504 | NS_ENSURE_ARG_POINTER(aReturn); |
michael@0 | 505 | ErrorResult rv; |
michael@0 | 506 | *aReturn = RemoveNamedItemNS(aNamespaceURI, aLocalName, rv).take(); |
michael@0 | 507 | return rv.ErrorCode(); |
michael@0 | 508 | } |
michael@0 | 509 | |
michael@0 | 510 | already_AddRefed<Attr> |
michael@0 | 511 | nsDOMAttributeMap::RemoveNamedItemNS(const nsAString& aNamespaceURI, |
michael@0 | 512 | const nsAString& aLocalName, |
michael@0 | 513 | ErrorResult& aError) |
michael@0 | 514 | { |
michael@0 | 515 | nsCOMPtr<nsINodeInfo> ni = GetAttrNodeInfo(aNamespaceURI, aLocalName); |
michael@0 | 516 | if (!ni) { |
michael@0 | 517 | aError.Throw(NS_ERROR_DOM_NOT_FOUND_ERR); |
michael@0 | 518 | return nullptr; |
michael@0 | 519 | } |
michael@0 | 520 | |
michael@0 | 521 | nsRefPtr<Attr> attr = RemoveAttribute(ni); |
michael@0 | 522 | nsINodeInfo* attrNi = attr->NodeInfo(); |
michael@0 | 523 | mContent->UnsetAttr(attrNi->NamespaceID(), attrNi->NameAtom(), true); |
michael@0 | 524 | |
michael@0 | 525 | return attr.forget(); |
michael@0 | 526 | } |
michael@0 | 527 | |
michael@0 | 528 | uint32_t |
michael@0 | 529 | nsDOMAttributeMap::Count() const |
michael@0 | 530 | { |
michael@0 | 531 | return mAttributeCache.Count(); |
michael@0 | 532 | } |
michael@0 | 533 | |
michael@0 | 534 | uint32_t |
michael@0 | 535 | nsDOMAttributeMap::Enumerate(AttrCache::EnumReadFunction aFunc, |
michael@0 | 536 | void *aUserArg) const |
michael@0 | 537 | { |
michael@0 | 538 | return mAttributeCache.EnumerateRead(aFunc, aUserArg); |
michael@0 | 539 | } |
michael@0 | 540 | |
michael@0 | 541 | size_t |
michael@0 | 542 | AttrCacheSizeEnumerator(const nsAttrKey& aKey, |
michael@0 | 543 | const nsRefPtr<Attr>& aValue, |
michael@0 | 544 | MallocSizeOf aMallocSizeOf, |
michael@0 | 545 | void* aUserArg) |
michael@0 | 546 | { |
michael@0 | 547 | return aMallocSizeOf(aValue.get()); |
michael@0 | 548 | } |
michael@0 | 549 | |
michael@0 | 550 | size_t |
michael@0 | 551 | nsDOMAttributeMap::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const |
michael@0 | 552 | { |
michael@0 | 553 | size_t n = aMallocSizeOf(this); |
michael@0 | 554 | n += mAttributeCache.SizeOfExcludingThis(AttrCacheSizeEnumerator, |
michael@0 | 555 | aMallocSizeOf); |
michael@0 | 556 | |
michael@0 | 557 | // NB: mContent is non-owning and thus not counted. |
michael@0 | 558 | return n; |
michael@0 | 559 | } |
michael@0 | 560 | |
michael@0 | 561 | /* virtual */ JSObject* |
michael@0 | 562 | nsDOMAttributeMap::WrapObject(JSContext* aCx) |
michael@0 | 563 | { |
michael@0 | 564 | return MozNamedAttrMapBinding::Wrap(aCx, this); |
michael@0 | 565 | } |