Bumping manifests a=b2g-bump
[gecko.git] / dom / base / nsTextNode.cpp
blob45a1461aadcc68df36b1df3ac77dfa7b5cb2f793
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 /*
7 * Implementation of DOM Core's nsIDOMText node.
8 */
10 #include "nsTextNode.h"
11 #include "mozilla/dom/TextBinding.h"
12 #include "nsContentUtils.h"
13 #include "mozilla/dom/DirectionalityUtils.h"
14 #include "nsIDOMEventListener.h"
15 #include "nsIDOMMutationEvent.h"
16 #include "nsIDocument.h"
17 #include "nsThreadUtils.h"
18 #include "nsStubMutationObserver.h"
19 #include "mozilla/IntegerPrintfMacros.h"
20 #ifdef DEBUG
21 #include "nsRange.h"
22 #endif
24 using namespace mozilla;
25 using namespace mozilla::dom;
27 /**
28 * class used to implement attr() generated content
30 class nsAttributeTextNode MOZ_FINAL : public nsTextNode,
31 public nsStubMutationObserver
33 public:
34 NS_DECL_ISUPPORTS_INHERITED
36 nsAttributeTextNode(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo,
37 int32_t aNameSpaceID,
38 nsIAtom* aAttrName) :
39 nsTextNode(aNodeInfo),
40 mGrandparent(nullptr),
41 mNameSpaceID(aNameSpaceID),
42 mAttrName(aAttrName)
44 NS_ASSERTION(mNameSpaceID != kNameSpaceID_Unknown, "Must know namespace");
45 NS_ASSERTION(mAttrName, "Must have attr name");
48 virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
49 nsIContent* aBindingParent,
50 bool aCompileEventHandlers) MOZ_OVERRIDE;
51 virtual void UnbindFromTree(bool aDeep = true,
52 bool aNullParent = true) MOZ_OVERRIDE;
54 NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTECHANGED
55 NS_DECL_NSIMUTATIONOBSERVER_NODEWILLBEDESTROYED
57 virtual nsGenericDOMDataNode *CloneDataNode(mozilla::dom::NodeInfo *aNodeInfo,
58 bool aCloneText) const MOZ_OVERRIDE
60 already_AddRefed<mozilla::dom::NodeInfo> ni =
61 nsRefPtr<mozilla::dom::NodeInfo>(aNodeInfo).forget();
62 nsAttributeTextNode *it = new nsAttributeTextNode(ni,
63 mNameSpaceID,
64 mAttrName);
65 if (it && aCloneText) {
66 it->mText = mText;
69 return it;
72 // Public method for the event to run
73 void UpdateText() {
74 UpdateText(true);
77 private:
78 virtual ~nsAttributeTextNode() {
79 NS_ASSERTION(!mGrandparent, "We were not unbound!");
82 // Update our text to our parent's current attr value
83 void UpdateText(bool aNotify);
85 // This doesn't need to be a strong pointer because it's only non-null
86 // while we're bound to the document tree, and it points to an ancestor
87 // so the ancestor must be bound to the document tree the whole time
88 // and can't be deleted.
89 nsIContent* mGrandparent;
90 // What attribute we're showing
91 int32_t mNameSpaceID;
92 nsCOMPtr<nsIAtom> mAttrName;
95 nsTextNode::~nsTextNode()
99 NS_IMPL_ISUPPORTS_INHERITED(nsTextNode, nsGenericDOMDataNode, nsIDOMNode,
100 nsIDOMText, nsIDOMCharacterData)
102 JSObject*
103 nsTextNode::WrapNode(JSContext *aCx)
105 return TextBinding::Wrap(aCx, this);
108 bool
109 nsTextNode::IsNodeOfType(uint32_t aFlags) const
111 return !(aFlags & ~(eCONTENT | eTEXT | eDATA_NODE));
114 nsGenericDOMDataNode*
115 nsTextNode::CloneDataNode(mozilla::dom::NodeInfo *aNodeInfo, bool aCloneText) const
117 already_AddRefed<mozilla::dom::NodeInfo> ni = nsRefPtr<mozilla::dom::NodeInfo>(aNodeInfo).forget();
118 nsTextNode *it = new nsTextNode(ni);
119 if (aCloneText) {
120 it->mText = mText;
123 return it;
126 nsresult
127 nsTextNode::AppendTextForNormalize(const char16_t* aBuffer, uint32_t aLength,
128 bool aNotify, nsIContent* aNextSibling)
130 CharacterDataChangeInfo::Details details = {
131 CharacterDataChangeInfo::Details::eMerge, aNextSibling
133 return SetTextInternal(mText.GetLength(), 0, aBuffer, aLength, aNotify, &details);
136 nsresult
137 nsTextNode::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
138 nsIContent* aBindingParent, bool aCompileEventHandlers)
140 nsresult rv = nsGenericDOMDataNode::BindToTree(aDocument, aParent,
141 aBindingParent,
142 aCompileEventHandlers);
143 NS_ENSURE_SUCCESS(rv, rv);
145 SetDirectionFromNewTextNode(this);
147 return NS_OK;
150 void nsTextNode::UnbindFromTree(bool aDeep, bool aNullParent)
152 ResetDirectionSetByTextNode(this);
154 nsGenericDOMDataNode::UnbindFromTree(aDeep, aNullParent);
157 #ifdef DEBUG
158 void
159 nsTextNode::List(FILE* out, int32_t aIndent) const
161 int32_t index;
162 for (index = aIndent; --index >= 0; ) fputs(" ", out);
164 fprintf(out, "Text@%p", static_cast<const void*>(this));
165 fprintf(out, " flags=[%08x]", static_cast<unsigned int>(GetFlags()));
166 if (IsCommonAncestorForRangeInSelection()) {
167 typedef nsTHashtable<nsPtrHashKey<nsRange> > RangeHashTable;
168 RangeHashTable* ranges =
169 static_cast<RangeHashTable*>(GetProperty(nsGkAtoms::range));
170 fprintf(out, " ranges:%d", ranges ? ranges->Count() : 0);
172 fprintf(out, " primaryframe=%p", static_cast<void*>(GetPrimaryFrame()));
173 fprintf(out, " refcount=%" PRIuPTR "<", mRefCnt.get());
175 nsAutoString tmp;
176 ToCString(tmp, 0, mText.GetLength());
177 fputs(NS_LossyConvertUTF16toASCII(tmp).get(), out);
179 fputs(">\n", out);
182 void
183 nsTextNode::DumpContent(FILE* out, int32_t aIndent, bool aDumpAll) const
185 if(aDumpAll) {
186 int32_t index;
187 for (index = aIndent; --index >= 0; ) fputs(" ", out);
189 nsAutoString tmp;
190 ToCString(tmp, 0, mText.GetLength());
192 if(!tmp.EqualsLiteral("\\n")) {
193 fputs(NS_LossyConvertUTF16toASCII(tmp).get(), out);
194 if(aIndent) fputs("\n", out);
198 #endif
200 nsresult
201 NS_NewAttributeContent(nsNodeInfoManager *aNodeInfoManager,
202 int32_t aNameSpaceID, nsIAtom* aAttrName,
203 nsIContent** aResult)
205 NS_PRECONDITION(aNodeInfoManager, "Missing nodeInfoManager");
206 NS_PRECONDITION(aAttrName, "Must have an attr name");
207 NS_PRECONDITION(aNameSpaceID != kNameSpaceID_Unknown, "Must know namespace");
209 *aResult = nullptr;
211 already_AddRefed<mozilla::dom::NodeInfo> ni = aNodeInfoManager->GetTextNodeInfo();
213 nsAttributeTextNode* textNode = new nsAttributeTextNode(ni,
214 aNameSpaceID,
215 aAttrName);
216 if (!textNode) {
217 return NS_ERROR_OUT_OF_MEMORY;
220 NS_ADDREF(*aResult = textNode);
222 return NS_OK;
225 NS_IMPL_ISUPPORTS_INHERITED(nsAttributeTextNode, nsTextNode,
226 nsIMutationObserver)
228 nsresult
229 nsAttributeTextNode::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
230 nsIContent* aBindingParent,
231 bool aCompileEventHandlers)
233 NS_PRECONDITION(aParent && aParent->GetParent(),
234 "This node can't be a child of the document or of the document root");
236 nsresult rv = nsTextNode::BindToTree(aDocument, aParent,
237 aBindingParent, aCompileEventHandlers);
238 NS_ENSURE_SUCCESS(rv, rv);
240 NS_ASSERTION(!mGrandparent, "We were already bound!");
241 mGrandparent = aParent->GetParent();
242 mGrandparent->AddMutationObserver(this);
244 // Note that there is no need to notify here, since we have no
245 // frame yet at this point.
246 UpdateText(false);
248 return NS_OK;
251 void
252 nsAttributeTextNode::UnbindFromTree(bool aDeep, bool aNullParent)
254 // UnbindFromTree can be called anytime so we have to be safe.
255 if (mGrandparent) {
256 // aNullParent might not be true here, but we want to remove the
257 // mutation observer anyway since we only need it while we're
258 // in the document.
259 mGrandparent->RemoveMutationObserver(this);
260 mGrandparent = nullptr;
262 nsTextNode::UnbindFromTree(aDeep, aNullParent);
265 void
266 nsAttributeTextNode::AttributeChanged(nsIDocument* aDocument,
267 Element* aElement,
268 int32_t aNameSpaceID,
269 nsIAtom* aAttribute,
270 int32_t aModType)
272 if (aNameSpaceID == mNameSpaceID && aAttribute == mAttrName &&
273 aElement == mGrandparent) {
274 // Since UpdateText notifies, do it when it's safe to run script. Note
275 // that if we get unbound while the event is up that's ok -- we'll just
276 // have no grandparent when it fires, and will do nothing.
277 void (nsAttributeTextNode::*update)() = &nsAttributeTextNode::UpdateText;
278 nsCOMPtr<nsIRunnable> ev = NS_NewRunnableMethod(this, update);
279 nsContentUtils::AddScriptRunner(ev);
283 void
284 nsAttributeTextNode::NodeWillBeDestroyed(const nsINode* aNode)
286 NS_ASSERTION(aNode == static_cast<nsINode*>(mGrandparent), "Wrong node!");
287 mGrandparent = nullptr;
290 void
291 nsAttributeTextNode::UpdateText(bool aNotify)
293 if (mGrandparent) {
294 nsAutoString attrValue;
295 mGrandparent->GetAttr(mNameSpaceID, mAttrName, attrValue);
296 SetText(attrValue, aNotify);