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/. */
7 * Implementation of DOM Core's nsIDOMText node.
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"
24 using namespace mozilla
;
25 using namespace mozilla::dom
;
28 * class used to implement attr() generated content
30 class nsAttributeTextNode MOZ_FINAL
: public nsTextNode
,
31 public nsStubMutationObserver
34 NS_DECL_ISUPPORTS_INHERITED
36 nsAttributeTextNode(already_AddRefed
<mozilla::dom::NodeInfo
>& aNodeInfo
,
39 nsTextNode(aNodeInfo
),
40 mGrandparent(nullptr),
41 mNameSpaceID(aNameSpaceID
),
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
,
65 if (it
&& aCloneText
) {
72 // Public method for the event to run
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
92 nsCOMPtr
<nsIAtom
> mAttrName
;
95 nsTextNode::~nsTextNode()
99 NS_IMPL_ISUPPORTS_INHERITED(nsTextNode
, nsGenericDOMDataNode
, nsIDOMNode
,
100 nsIDOMText
, nsIDOMCharacterData
)
103 nsTextNode::WrapNode(JSContext
*aCx
)
105 return TextBinding::Wrap(aCx
, this);
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
);
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
);
137 nsTextNode::BindToTree(nsIDocument
* aDocument
, nsIContent
* aParent
,
138 nsIContent
* aBindingParent
, bool aCompileEventHandlers
)
140 nsresult rv
= nsGenericDOMDataNode::BindToTree(aDocument
, aParent
,
142 aCompileEventHandlers
);
143 NS_ENSURE_SUCCESS(rv
, rv
);
145 SetDirectionFromNewTextNode(this);
150 void nsTextNode::UnbindFromTree(bool aDeep
, bool aNullParent
)
152 ResetDirectionSetByTextNode(this);
154 nsGenericDOMDataNode::UnbindFromTree(aDeep
, aNullParent
);
159 nsTextNode::List(FILE* out
, int32_t aIndent
) const
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());
176 ToCString(tmp
, 0, mText
.GetLength());
177 fputs(NS_LossyConvertUTF16toASCII(tmp
).get(), out
);
183 nsTextNode::DumpContent(FILE* out
, int32_t aIndent
, bool aDumpAll
) const
187 for (index
= aIndent
; --index
>= 0; ) fputs(" ", out
);
190 ToCString(tmp
, 0, mText
.GetLength());
192 if(!tmp
.EqualsLiteral("\\n")) {
193 fputs(NS_LossyConvertUTF16toASCII(tmp
).get(), out
);
194 if(aIndent
) fputs("\n", out
);
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");
211 already_AddRefed
<mozilla::dom::NodeInfo
> ni
= aNodeInfoManager
->GetTextNodeInfo();
213 nsAttributeTextNode
* textNode
= new nsAttributeTextNode(ni
,
217 return NS_ERROR_OUT_OF_MEMORY
;
220 NS_ADDREF(*aResult
= textNode
);
225 NS_IMPL_ISUPPORTS_INHERITED(nsAttributeTextNode
, nsTextNode
,
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.
252 nsAttributeTextNode::UnbindFromTree(bool aDeep
, bool aNullParent
)
254 // UnbindFromTree can be called anytime so we have to be safe.
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
259 mGrandparent
->RemoveMutationObserver(this);
260 mGrandparent
= nullptr;
262 nsTextNode::UnbindFromTree(aDeep
, aNullParent
);
266 nsAttributeTextNode::AttributeChanged(nsIDocument
* aDocument
,
268 int32_t aNameSpaceID
,
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
);
284 nsAttributeTextNode::NodeWillBeDestroyed(const nsINode
* aNode
)
286 NS_ASSERTION(aNode
== static_cast<nsINode
*>(mGrandparent
), "Wrong node!");
287 mGrandparent
= nullptr;
291 nsAttributeTextNode::UpdateText(bool aNotify
)
294 nsAutoString attrValue
;
295 mGrandparent
->GetAttr(mNameSpaceID
, mAttrName
, attrValue
);
296 SetText(attrValue
, aNotify
);