1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/content/base/src/nsTextNode.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,299 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +/* 1.10 + * Implementation of DOM Core's nsIDOMText node. 1.11 + */ 1.12 + 1.13 +#include "nsTextNode.h" 1.14 +#include "mozilla/dom/TextBinding.h" 1.15 +#include "nsContentUtils.h" 1.16 +#include "mozilla/dom/DirectionalityUtils.h" 1.17 +#include "nsIDOMEventListener.h" 1.18 +#include "nsIDOMMutationEvent.h" 1.19 +#include "nsIDocument.h" 1.20 +#include "nsThreadUtils.h" 1.21 +#include "nsStubMutationObserver.h" 1.22 +#include "mozilla/IntegerPrintfMacros.h" 1.23 +#ifdef DEBUG 1.24 +#include "nsRange.h" 1.25 +#endif 1.26 + 1.27 +using namespace mozilla; 1.28 +using namespace mozilla::dom; 1.29 + 1.30 +/** 1.31 + * class used to implement attr() generated content 1.32 + */ 1.33 +class nsAttributeTextNode MOZ_FINAL : public nsTextNode, 1.34 + public nsStubMutationObserver 1.35 +{ 1.36 +public: 1.37 + NS_DECL_ISUPPORTS_INHERITED 1.38 + 1.39 + nsAttributeTextNode(already_AddRefed<nsINodeInfo>& aNodeInfo, 1.40 + int32_t aNameSpaceID, 1.41 + nsIAtom* aAttrName) : 1.42 + nsTextNode(aNodeInfo), 1.43 + mGrandparent(nullptr), 1.44 + mNameSpaceID(aNameSpaceID), 1.45 + mAttrName(aAttrName) 1.46 + { 1.47 + NS_ASSERTION(mNameSpaceID != kNameSpaceID_Unknown, "Must know namespace"); 1.48 + NS_ASSERTION(mAttrName, "Must have attr name"); 1.49 + } 1.50 + 1.51 + virtual ~nsAttributeTextNode() { 1.52 + NS_ASSERTION(!mGrandparent, "We were not unbound!"); 1.53 + } 1.54 + 1.55 + virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent, 1.56 + nsIContent* aBindingParent, 1.57 + bool aCompileEventHandlers); 1.58 + virtual void UnbindFromTree(bool aDeep = true, 1.59 + bool aNullParent = true); 1.60 + 1.61 + NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTECHANGED 1.62 + NS_DECL_NSIMUTATIONOBSERVER_NODEWILLBEDESTROYED 1.63 + 1.64 + virtual nsGenericDOMDataNode *CloneDataNode(nsINodeInfo *aNodeInfo, 1.65 + bool aCloneText) const 1.66 + { 1.67 + already_AddRefed<nsINodeInfo> ni = 1.68 + nsCOMPtr<nsINodeInfo>(aNodeInfo).forget(); 1.69 + nsAttributeTextNode *it = new nsAttributeTextNode(ni, 1.70 + mNameSpaceID, 1.71 + mAttrName); 1.72 + if (it && aCloneText) { 1.73 + it->mText = mText; 1.74 + } 1.75 + 1.76 + return it; 1.77 + } 1.78 + 1.79 + // Public method for the event to run 1.80 + void UpdateText() { 1.81 + UpdateText(true); 1.82 + } 1.83 + 1.84 +private: 1.85 + // Update our text to our parent's current attr value 1.86 + void UpdateText(bool aNotify); 1.87 + 1.88 + // This doesn't need to be a strong pointer because it's only non-null 1.89 + // while we're bound to the document tree, and it points to an ancestor 1.90 + // so the ancestor must be bound to the document tree the whole time 1.91 + // and can't be deleted. 1.92 + nsIContent* mGrandparent; 1.93 + // What attribute we're showing 1.94 + int32_t mNameSpaceID; 1.95 + nsCOMPtr<nsIAtom> mAttrName; 1.96 +}; 1.97 + 1.98 +nsTextNode::~nsTextNode() 1.99 +{ 1.100 +} 1.101 + 1.102 +NS_IMPL_ISUPPORTS_INHERITED(nsTextNode, nsGenericDOMDataNode, nsIDOMNode, 1.103 + nsIDOMText, nsIDOMCharacterData) 1.104 + 1.105 +JSObject* 1.106 +nsTextNode::WrapNode(JSContext *aCx) 1.107 +{ 1.108 + return TextBinding::Wrap(aCx, this); 1.109 +} 1.110 + 1.111 +bool 1.112 +nsTextNode::IsNodeOfType(uint32_t aFlags) const 1.113 +{ 1.114 + return !(aFlags & ~(eCONTENT | eTEXT | eDATA_NODE)); 1.115 +} 1.116 + 1.117 +nsGenericDOMDataNode* 1.118 +nsTextNode::CloneDataNode(nsINodeInfo *aNodeInfo, bool aCloneText) const 1.119 +{ 1.120 + already_AddRefed<nsINodeInfo> ni = nsCOMPtr<nsINodeInfo>(aNodeInfo).forget(); 1.121 + nsTextNode *it = new nsTextNode(ni); 1.122 + if (aCloneText) { 1.123 + it->mText = mText; 1.124 + } 1.125 + 1.126 + return it; 1.127 +} 1.128 + 1.129 +nsresult 1.130 +nsTextNode::AppendTextForNormalize(const char16_t* aBuffer, uint32_t aLength, 1.131 + bool aNotify, nsIContent* aNextSibling) 1.132 +{ 1.133 + CharacterDataChangeInfo::Details details = { 1.134 + CharacterDataChangeInfo::Details::eMerge, aNextSibling 1.135 + }; 1.136 + return SetTextInternal(mText.GetLength(), 0, aBuffer, aLength, aNotify, &details); 1.137 +} 1.138 + 1.139 +nsresult 1.140 +nsTextNode::BindToTree(nsIDocument* aDocument, nsIContent* aParent, 1.141 + nsIContent* aBindingParent, bool aCompileEventHandlers) 1.142 +{ 1.143 + nsresult rv = nsGenericDOMDataNode::BindToTree(aDocument, aParent, 1.144 + aBindingParent, 1.145 + aCompileEventHandlers); 1.146 + NS_ENSURE_SUCCESS(rv, rv); 1.147 + 1.148 + SetDirectionFromNewTextNode(this); 1.149 + 1.150 + return NS_OK; 1.151 +} 1.152 + 1.153 +void nsTextNode::UnbindFromTree(bool aDeep, bool aNullParent) 1.154 +{ 1.155 + ResetDirectionSetByTextNode(this, aNullParent); 1.156 + 1.157 + nsGenericDOMDataNode::UnbindFromTree(aDeep, aNullParent); 1.158 +} 1.159 + 1.160 +#ifdef DEBUG 1.161 +void 1.162 +nsTextNode::List(FILE* out, int32_t aIndent) const 1.163 +{ 1.164 + int32_t index; 1.165 + for (index = aIndent; --index >= 0; ) fputs(" ", out); 1.166 + 1.167 + fprintf(out, "Text@%p", static_cast<const void*>(this)); 1.168 + fprintf(out, " flags=[%08x]", static_cast<unsigned int>(GetFlags())); 1.169 + if (IsCommonAncestorForRangeInSelection()) { 1.170 + typedef nsTHashtable<nsPtrHashKey<nsRange> > RangeHashTable; 1.171 + RangeHashTable* ranges = 1.172 + static_cast<RangeHashTable*>(GetProperty(nsGkAtoms::range)); 1.173 + fprintf(out, " ranges:%d", ranges ? ranges->Count() : 0); 1.174 + } 1.175 + fprintf(out, " primaryframe=%p", static_cast<void*>(GetPrimaryFrame())); 1.176 + fprintf(out, " refcount=%" PRIuPTR "<", mRefCnt.get()); 1.177 + 1.178 + nsAutoString tmp; 1.179 + ToCString(tmp, 0, mText.GetLength()); 1.180 + fputs(NS_LossyConvertUTF16toASCII(tmp).get(), out); 1.181 + 1.182 + fputs(">\n", out); 1.183 +} 1.184 + 1.185 +void 1.186 +nsTextNode::DumpContent(FILE* out, int32_t aIndent, bool aDumpAll) const 1.187 +{ 1.188 + if(aDumpAll) { 1.189 + int32_t index; 1.190 + for (index = aIndent; --index >= 0; ) fputs(" ", out); 1.191 + 1.192 + nsAutoString tmp; 1.193 + ToCString(tmp, 0, mText.GetLength()); 1.194 + 1.195 + if(!tmp.EqualsLiteral("\\n")) { 1.196 + fputs(NS_LossyConvertUTF16toASCII(tmp).get(), out); 1.197 + if(aIndent) fputs("\n", out); 1.198 + } 1.199 + } 1.200 +} 1.201 +#endif 1.202 + 1.203 +nsresult 1.204 +NS_NewAttributeContent(nsNodeInfoManager *aNodeInfoManager, 1.205 + int32_t aNameSpaceID, nsIAtom* aAttrName, 1.206 + nsIContent** aResult) 1.207 +{ 1.208 + NS_PRECONDITION(aNodeInfoManager, "Missing nodeInfoManager"); 1.209 + NS_PRECONDITION(aAttrName, "Must have an attr name"); 1.210 + NS_PRECONDITION(aNameSpaceID != kNameSpaceID_Unknown, "Must know namespace"); 1.211 + 1.212 + *aResult = nullptr; 1.213 + 1.214 + already_AddRefed<nsINodeInfo> ni = aNodeInfoManager->GetTextNodeInfo(); 1.215 + 1.216 + nsAttributeTextNode* textNode = new nsAttributeTextNode(ni, 1.217 + aNameSpaceID, 1.218 + aAttrName); 1.219 + if (!textNode) { 1.220 + return NS_ERROR_OUT_OF_MEMORY; 1.221 + } 1.222 + 1.223 + NS_ADDREF(*aResult = textNode); 1.224 + 1.225 + return NS_OK; 1.226 +} 1.227 + 1.228 +NS_IMPL_ISUPPORTS_INHERITED(nsAttributeTextNode, nsTextNode, 1.229 + nsIMutationObserver) 1.230 + 1.231 +nsresult 1.232 +nsAttributeTextNode::BindToTree(nsIDocument* aDocument, nsIContent* aParent, 1.233 + nsIContent* aBindingParent, 1.234 + bool aCompileEventHandlers) 1.235 +{ 1.236 + NS_PRECONDITION(aParent && aParent->GetParent(), 1.237 + "This node can't be a child of the document or of the document root"); 1.238 + 1.239 + nsresult rv = nsTextNode::BindToTree(aDocument, aParent, 1.240 + aBindingParent, aCompileEventHandlers); 1.241 + NS_ENSURE_SUCCESS(rv, rv); 1.242 + 1.243 + NS_ASSERTION(!mGrandparent, "We were already bound!"); 1.244 + mGrandparent = aParent->GetParent(); 1.245 + mGrandparent->AddMutationObserver(this); 1.246 + 1.247 + // Note that there is no need to notify here, since we have no 1.248 + // frame yet at this point. 1.249 + UpdateText(false); 1.250 + 1.251 + return NS_OK; 1.252 +} 1.253 + 1.254 +void 1.255 +nsAttributeTextNode::UnbindFromTree(bool aDeep, bool aNullParent) 1.256 +{ 1.257 + // UnbindFromTree can be called anytime so we have to be safe. 1.258 + if (mGrandparent) { 1.259 + // aNullParent might not be true here, but we want to remove the 1.260 + // mutation observer anyway since we only need it while we're 1.261 + // in the document. 1.262 + mGrandparent->RemoveMutationObserver(this); 1.263 + mGrandparent = nullptr; 1.264 + } 1.265 + nsTextNode::UnbindFromTree(aDeep, aNullParent); 1.266 +} 1.267 + 1.268 +void 1.269 +nsAttributeTextNode::AttributeChanged(nsIDocument* aDocument, 1.270 + Element* aElement, 1.271 + int32_t aNameSpaceID, 1.272 + nsIAtom* aAttribute, 1.273 + int32_t aModType) 1.274 +{ 1.275 + if (aNameSpaceID == mNameSpaceID && aAttribute == mAttrName && 1.276 + aElement == mGrandparent) { 1.277 + // Since UpdateText notifies, do it when it's safe to run script. Note 1.278 + // that if we get unbound while the event is up that's ok -- we'll just 1.279 + // have no grandparent when it fires, and will do nothing. 1.280 + void (nsAttributeTextNode::*update)() = &nsAttributeTextNode::UpdateText; 1.281 + nsCOMPtr<nsIRunnable> ev = NS_NewRunnableMethod(this, update); 1.282 + nsContentUtils::AddScriptRunner(ev); 1.283 + } 1.284 +} 1.285 + 1.286 +void 1.287 +nsAttributeTextNode::NodeWillBeDestroyed(const nsINode* aNode) 1.288 +{ 1.289 + NS_ASSERTION(aNode == static_cast<nsINode*>(mGrandparent), "Wrong node!"); 1.290 + mGrandparent = nullptr; 1.291 +} 1.292 + 1.293 +void 1.294 +nsAttributeTextNode::UpdateText(bool aNotify) 1.295 +{ 1.296 + if (mGrandparent) { 1.297 + nsAutoString attrValue; 1.298 + mGrandparent->GetAttr(mNameSpaceID, mAttrName, attrValue); 1.299 + SetText(attrValue, aNotify); 1.300 + } 1.301 +} 1.302 +