Attr.cpp (8019B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 /* 8 * Implementation of DOM Core's Attr node. 9 */ 10 11 #include "mozilla/dom/Attr.h" 12 13 #include "NodeUbiReporting.h" 14 #include "mozAutoDocUpdate.h" 15 #include "mozilla/EventDispatcher.h" 16 #include "mozilla/StaticPrefs_dom.h" 17 #include "mozilla/dom/AttrBinding.h" 18 #include "mozilla/dom/Document.h" 19 #include "mozilla/dom/Element.h" 20 #include "mozilla/dom/TrustedTypeUtils.h" 21 #include "mozilla/dom/TrustedTypesConstants.h" 22 #include "nsCOMArray.h" 23 #include "nsContentCreatorFunctions.h" 24 #include "nsDOMString.h" 25 #include "nsError.h" 26 #include "nsGkAtoms.h" 27 #include "nsIContentInlines.h" 28 #include "nsNameSpaceManager.h" 29 #include "nsTextNode.h" 30 #include "nsUnicharUtils.h" 31 #include "nsWrapperCacheInlines.h" 32 33 namespace mozilla::dom { 34 35 //---------------------------------------------------------------------- 36 bool Attr::sInitialized; 37 38 Attr::Attr(nsDOMAttributeMap* aAttrMap, 39 already_AddRefed<dom::NodeInfo>&& aNodeInfo, const nsAString& aValue) 40 : nsINode(std::move(aNodeInfo)), mAttrMap(aAttrMap), mValue(aValue) { 41 MOZ_ASSERT(mNodeInfo, "We must get a nodeinfo here!"); 42 MOZ_ASSERT(mNodeInfo->NodeType() == ATTRIBUTE_NODE, "Wrong nodeType"); 43 44 // We don't add a reference to our content. It will tell us 45 // to drop our reference when it goes away. 46 } 47 48 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_CLASS(Attr) 49 50 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Attr) 51 if (!nsINode::Traverse(tmp, cb)) { 52 return NS_SUCCESS_INTERRUPTED_TRAVERSE; 53 } 54 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAttrMap) 55 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END 56 57 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Attr) 58 nsINode::Unlink(tmp); 59 NS_IMPL_CYCLE_COLLECTION_UNLINK(mAttrMap) 60 NS_IMPL_CYCLE_COLLECTION_UNLINK_END 61 62 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(Attr) 63 Element* ownerElement = tmp->GetElement(); 64 if (tmp->HasKnownLiveWrapper()) { 65 if (ownerElement) { 66 // The attribute owns the element via attribute map so we can 67 // mark it when the attribute is certainly alive. 68 mozilla::dom::FragmentOrElement::MarkNodeChildren(ownerElement); 69 } 70 return true; 71 } 72 if (ownerElement && 73 mozilla::dom::FragmentOrElement::CanSkip(ownerElement, true)) { 74 return true; 75 } 76 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END 77 78 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(Attr) 79 return tmp->HasKnownLiveWrapperAndDoesNotNeedTracing(tmp); 80 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_END 81 82 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN(Attr) 83 return tmp->HasKnownLiveWrapper(); 84 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END 85 86 // QueryInterface implementation for Attr 87 NS_INTERFACE_TABLE_HEAD(Attr) 88 NS_WRAPPERCACHE_INTERFACE_TABLE_ENTRY 89 NS_INTERFACE_TABLE(Attr, nsINode, EventTarget) 90 NS_INTERFACE_TABLE_TO_MAP_SEGUE_CYCLE_COLLECTION(Attr) 91 NS_INTERFACE_MAP_ENTRY_TEAROFF(nsISupportsWeakReference, 92 new nsNodeSupportsWeakRefTearoff(this)) 93 NS_INTERFACE_MAP_END 94 95 NS_IMPL_CYCLE_COLLECTING_ADDREF(Attr) 96 97 NS_IMPL_CYCLE_COLLECTING_RELEASE_WITH_LAST_RELEASE_AND_DESTROY(Attr, 98 LastRelease(), 99 Destroy()) 100 101 NS_IMPL_DOMARENA_DESTROY(Attr) 102 103 void Attr::SetMap(nsDOMAttributeMap* aMap) { 104 if (mAttrMap && !aMap && sInitialized) { 105 // We're breaking a relationship with content and not getting a new one, 106 // need to locally cache value. GetValue() does that. 107 GetValue(mValue); 108 } 109 110 mAttrMap = aMap; 111 } 112 113 Element* Attr::GetElement() const { 114 if (!mAttrMap) { 115 return nullptr; 116 } 117 nsIContent* content = mAttrMap->GetContent(); 118 return content ? content->AsElement() : nullptr; 119 } 120 121 nsresult Attr::SetOwnerDocument(Document* aDocument) { 122 NS_ASSERTION(aDocument, "Missing document"); 123 124 Document* doc = OwnerDoc(); 125 NS_ASSERTION(doc != aDocument, "bad call to Attr::SetOwnerDocument"); 126 doc->RemoveAllPropertiesFor(this); 127 128 RefPtr<dom::NodeInfo> newNodeInfo = aDocument->NodeInfoManager()->GetNodeInfo( 129 mNodeInfo->NameAtom(), mNodeInfo->GetPrefixAtom(), 130 mNodeInfo->NamespaceID(), ATTRIBUTE_NODE); 131 NS_ASSERTION(newNodeInfo, "GetNodeInfo lies"); 132 mNodeInfo.swap(newNodeInfo); 133 134 return NS_OK; 135 } 136 137 void Attr::GetName(nsAString& aName) { aName = NodeName(); } 138 139 void Attr::GetValue(nsAString& aValue) { 140 Element* element = GetElement(); 141 if (element) { 142 RefPtr<nsAtom> nameAtom = mNodeInfo->NameAtom(); 143 element->GetAttr(mNodeInfo->NamespaceID(), nameAtom, aValue); 144 } else { 145 aValue = mValue; 146 } 147 } 148 149 void Attr::SetValue(const nsAString& aValue, nsIPrincipal* aTriggeringPrincipal, 150 ErrorResult& aRv) { 151 nsCOMPtr<Element> element = GetElement(); 152 if (!element) { 153 mValue = aValue; 154 return; 155 } 156 157 RefPtr<nsAtom> nameAtom = mNodeInfo->NameAtom(); 158 159 Maybe<nsAutoString> compliantStringHolder; 160 const nsAString* compliantString = 161 TrustedTypeUtils::GetTrustedTypesCompliantAttributeValue( 162 *element, nameAtom, mNodeInfo->NamespaceID(), aValue, 163 aTriggeringPrincipal, compliantStringHolder, aRv); 164 if (aRv.Failed()) { 165 return; 166 } 167 168 // After the GetTrustedTypesCompliantAttributeValue() call, the attribute may 169 // have been detached or moved to another element so perform the check on 170 // GetElement() again. 171 SetValueInternal(*compliantString, aRv); 172 } 173 174 void Attr::SetValueInternal(const nsAString& aValue, ErrorResult& aRv) { 175 Element* element = GetElement(); 176 if (!element) { 177 mValue = aValue; 178 return; 179 } 180 181 RefPtr<nsAtom> nameAtom = mNodeInfo->NameAtom(); 182 aRv = element->SetAttr(mNodeInfo->NamespaceID(), nameAtom, 183 mNodeInfo->GetPrefixAtom(), aValue, nullptr, true); 184 } 185 186 bool Attr::Specified() const { return true; } 187 188 Element* Attr::GetOwnerElement() { return GetElement(); } 189 190 void Attr::SetNodeValue(const nsAString& aNodeValue, ErrorResult& aError) { 191 SetValue(aNodeValue, nullptr, aError); 192 } 193 194 void Attr::GetNodeValueInternal(nsAString& aNodeValue) { GetValue(aNodeValue); } 195 196 void Attr::SetNodeValueInternal(const nsAString& aNodeValue, 197 ErrorResult& aError, MutationEffectOnScript) { 198 SetValueInternal(aNodeValue, aError); 199 } 200 201 nsresult Attr::Clone(dom::NodeInfo* aNodeInfo, nsINode** aResult) const { 202 nsAutoString value; 203 const_cast<Attr*>(this)->GetValue(value); 204 *aResult = new (aNodeInfo->NodeInfoManager()) 205 Attr(nullptr, do_AddRef(aNodeInfo), value); 206 207 NS_ADDREF(*aResult); 208 209 return NS_OK; 210 } 211 212 nsIURI* Attr::GetBaseURI(bool aTryUseXHRDocBaseURI) const { 213 Element* parent = GetElement(); 214 215 return parent ? parent->GetBaseURI(aTryUseXHRDocBaseURI) 216 : OwnerDoc()->GetBaseURI(aTryUseXHRDocBaseURI); 217 } 218 219 void Attr::SetTextContent(const nsAString& aTextContent, 220 nsIPrincipal* aSubjectPrincipal, 221 ErrorResult& aError) { 222 SetValue(aTextContent, aSubjectPrincipal, aError); 223 } 224 225 void Attr::GetTextContentInternal(nsAString& aTextContent, 226 OOMReporter& aError) { 227 GetValue(aTextContent); 228 } 229 230 void Attr::SetTextContentInternal(const nsAString& aTextContent, 231 nsIPrincipal* aSubjectPrincipal, 232 ErrorResult& aError, MutationEffectOnScript) { 233 SetValueInternal(aTextContent, aError); 234 } 235 236 void Attr::GetEventTargetParent(EventChainPreVisitor& aVisitor) { 237 aVisitor.mCanHandle = true; 238 } 239 240 void Attr::Initialize() { sInitialized = true; } 241 242 void Attr::Shutdown() { sInitialized = false; } 243 244 JSObject* Attr::WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) { 245 return Attr_Binding::Wrap(aCx, this, aGivenProto); 246 } 247 248 void Attr::ConstructUbiNode(void* storage) { 249 JS::ubi::Concrete<Attr>::construct(storage, this); 250 } 251 252 } // namespace mozilla::dom