Bug 1550519 - Show a translucent parent highlight when a subgrid is highlighted....
[gecko.git] / dom / base / CharacterData.cpp
blobe56b664fe696ef3a76bb2ea37255f566149f83f7
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/. */
7 /*
8 * Base class for DOM Core's Comment, DocumentType, Text,
9 * CDATASection and ProcessingInstruction nodes.
12 #include "mozilla/dom/CharacterData.h"
14 #include "mozilla/DebugOnly.h"
16 #include "mozilla/AsyncEventDispatcher.h"
17 #include "mozilla/MemoryReporting.h"
18 #include "mozilla/dom/BindContext.h"
19 #include "mozilla/dom/Element.h"
20 #include "mozilla/dom/HTMLSlotElement.h"
21 #include "mozilla/dom/ShadowRoot.h"
22 #include "mozilla/dom/Document.h"
23 #include "nsReadableUtils.h"
24 #include "mozilla/InternalMutationEvent.h"
25 #include "nsIURI.h"
26 #include "nsCOMPtr.h"
27 #include "nsDOMString.h"
28 #include "nsChangeHint.h"
29 #include "nsCOMArray.h"
30 #include "nsNodeUtils.h"
31 #include "mozilla/dom/DirectionalityUtils.h"
32 #include "nsBindingManager.h"
33 #include "nsCCUncollectableMarker.h"
34 #include "mozAutoDocUpdate.h"
35 #include "nsTextNode.h"
36 #include "nsBidiUtils.h"
37 #include "PLDHashTable.h"
38 #include "mozilla/Sprintf.h"
39 #include "nsWindowSizes.h"
40 #include "nsWrapperCacheInlines.h"
42 namespace mozilla {
43 namespace dom {
45 CharacterData::CharacterData(already_AddRefed<dom::NodeInfo>&& aNodeInfo)
46 : nsIContent(std::move(aNodeInfo)) {
47 MOZ_ASSERT(mNodeInfo->NodeType() == TEXT_NODE ||
48 mNodeInfo->NodeType() == CDATA_SECTION_NODE ||
49 mNodeInfo->NodeType() == COMMENT_NODE ||
50 mNodeInfo->NodeType() == PROCESSING_INSTRUCTION_NODE ||
51 mNodeInfo->NodeType() == DOCUMENT_TYPE_NODE,
52 "Bad NodeType in aNodeInfo");
55 CharacterData::~CharacterData() {
56 MOZ_ASSERT(!IsInUncomposedDoc(),
57 "Please remove this from the document properly");
58 if (GetParent()) {
59 NS_RELEASE(mParent);
63 NS_IMPL_CYCLE_COLLECTION_CLASS(CharacterData)
65 NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(CharacterData)
67 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(CharacterData)
68 return Element::CanSkip(tmp, aRemovingAllowed);
69 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END
71 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(CharacterData)
72 return Element::CanSkipInCC(tmp);
73 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_END
75 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN(CharacterData)
76 return Element::CanSkipThis(tmp);
77 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END
79 // We purposefully don't TRAVERSE_BEGIN_INHERITED here. All the bits
80 // we should traverse should be added here or in nsINode::Traverse.
81 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(CharacterData)
82 if (MOZ_UNLIKELY(cb.WantDebugInfo())) {
83 char name[40];
84 SprintfLiteral(name, "CharacterData (len=%d)", tmp->mText.GetLength());
85 cb.DescribeRefCountedNode(tmp->mRefCnt.get(), name);
86 } else {
87 NS_IMPL_CYCLE_COLLECTION_DESCRIBE(CharacterData, tmp->mRefCnt.get())
90 if (!nsIContent::Traverse(tmp, cb)) {
91 return NS_SUCCESS_INTERRUPTED_TRAVERSE;
93 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
95 // We purposefully don't UNLINK_BEGIN_INHERITED here.
96 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(CharacterData)
97 nsIContent::Unlink(tmp);
99 if (nsContentSlots* slots = tmp->GetExistingContentSlots()) {
100 slots->Unlink();
102 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
104 NS_INTERFACE_MAP_BEGIN(CharacterData)
105 NS_INTERFACE_MAP_ENTRIES_CYCLE_COLLECTION(CharacterData)
106 NS_INTERFACE_MAP_END_INHERITING(nsIContent)
108 void CharacterData::GetNodeValueInternal(nsAString& aNodeValue) {
109 GetData(aNodeValue);
112 void CharacterData::SetNodeValueInternal(const nsAString& aNodeValue,
113 ErrorResult& aError) {
114 aError = SetTextInternal(0, mText.GetLength(), aNodeValue.BeginReading(),
115 aNodeValue.Length(), true);
118 //----------------------------------------------------------------------
120 // Implementation of CharacterData
122 void CharacterData::GetData(nsAString& aData) const {
123 if (mText.Is2b()) {
124 aData.Truncate();
125 mText.AppendTo(aData);
126 } else {
127 // Must use Substring() since nsDependentCString() requires null
128 // terminated strings.
130 const char* data = mText.Get1b();
132 if (data) {
133 CopyASCIItoUTF16(Substring(data, data + mText.GetLength()), aData);
134 } else {
135 aData.Truncate();
140 void CharacterData::SetData(const nsAString& aData, ErrorResult& aRv) {
141 nsresult rv = SetTextInternal(0, mText.GetLength(), aData.BeginReading(),
142 aData.Length(), true);
143 if (NS_FAILED(rv)) {
144 aRv.Throw(rv);
148 void CharacterData::SubstringData(uint32_t aStart, uint32_t aCount,
149 nsAString& aReturn, ErrorResult& rv) {
150 aReturn.Truncate();
152 uint32_t textLength = mText.GetLength();
153 if (aStart > textLength) {
154 rv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
155 return;
158 uint32_t amount = aCount;
159 if (amount > textLength - aStart) {
160 amount = textLength - aStart;
163 if (mText.Is2b()) {
164 aReturn.Assign(mText.Get2b() + aStart, amount);
165 } else {
166 // Must use Substring() since nsDependentCString() requires null
167 // terminated strings.
169 const char* data = mText.Get1b() + aStart;
170 CopyASCIItoUTF16(Substring(data, data + amount), aReturn);
174 //----------------------------------------------------------------------
176 void CharacterData::AppendData(const nsAString& aData, ErrorResult& aRv) {
177 InsertData(mText.GetLength(), aData, aRv);
180 void CharacterData::InsertData(uint32_t aOffset, const nsAString& aData,
181 ErrorResult& aRv) {
182 nsresult rv =
183 SetTextInternal(aOffset, 0, aData.BeginReading(), aData.Length(), true);
184 if (NS_FAILED(rv)) {
185 aRv.Throw(rv);
189 void CharacterData::DeleteData(uint32_t aOffset, uint32_t aCount,
190 ErrorResult& aRv) {
191 nsresult rv = SetTextInternal(aOffset, aCount, nullptr, 0, true);
192 if (NS_FAILED(rv)) {
193 aRv.Throw(rv);
197 void CharacterData::ReplaceData(uint32_t aOffset, uint32_t aCount,
198 const nsAString& aData, ErrorResult& aRv) {
199 nsresult rv = SetTextInternal(aOffset, aCount, aData.BeginReading(),
200 aData.Length(), true);
201 if (NS_FAILED(rv)) {
202 aRv.Throw(rv);
206 nsresult CharacterData::SetTextInternal(
207 uint32_t aOffset, uint32_t aCount, const char16_t* aBuffer,
208 uint32_t aLength, bool aNotify,
209 CharacterDataChangeInfo::Details* aDetails) {
210 MOZ_ASSERT(aBuffer || !aLength, "Null buffer passed to SetTextInternal!");
212 // sanitize arguments
213 uint32_t textLength = mText.GetLength();
214 if (aOffset > textLength) {
215 return NS_ERROR_DOM_INDEX_SIZE_ERR;
218 if (aCount > textLength - aOffset) {
219 aCount = textLength - aOffset;
222 uint32_t endOffset = aOffset + aCount;
224 // Make sure the text fragment can hold the new data.
225 if (aLength > aCount && !mText.CanGrowBy(aLength - aCount)) {
226 return NS_ERROR_OUT_OF_MEMORY;
229 Document* document = GetComposedDoc();
230 mozAutoDocUpdate updateBatch(document, aNotify);
232 bool haveMutationListeners =
233 aNotify && nsContentUtils::HasMutationListeners(
234 this, NS_EVENT_BITS_MUTATION_CHARACTERDATAMODIFIED, this);
236 RefPtr<nsAtom> oldValue;
237 if (haveMutationListeners) {
238 oldValue = GetCurrentValueAtom();
241 if (aNotify) {
242 CharacterDataChangeInfo info = {aOffset == textLength, aOffset, endOffset,
243 aLength, aDetails};
244 nsNodeUtils::CharacterDataWillChange(this, info);
247 Directionality oldDir = eDir_NotSet;
248 bool dirAffectsAncestor =
249 (NodeType() == TEXT_NODE &&
250 TextNodeWillChangeDirection(static_cast<nsTextNode*>(this), &oldDir,
251 aOffset));
253 if (aOffset == 0 && endOffset == textLength) {
254 // Replacing whole text or old text was empty. Don't bother to check for
255 // bidi in this string if the document already has bidi enabled.
256 // If this is marked as "maybe modified frequently", the text should be
257 // stored as char16_t since converting char* to char16_t* is expensive.
258 bool ok =
259 mText.SetTo(aBuffer, aLength, !document || !document->GetBidiEnabled(),
260 HasFlag(NS_MAYBE_MODIFIED_FREQUENTLY));
261 NS_ENSURE_TRUE(ok, NS_ERROR_OUT_OF_MEMORY);
262 } else if (aOffset == textLength) {
263 // Appending to existing
264 bool ok =
265 mText.Append(aBuffer, aLength, !document || !document->GetBidiEnabled(),
266 HasFlag(NS_MAYBE_MODIFIED_FREQUENTLY));
267 NS_ENSURE_TRUE(ok, NS_ERROR_OUT_OF_MEMORY);
268 } else {
269 // Merging old and new
271 bool bidi = mText.IsBidi();
273 // Allocate new buffer
274 int32_t newLength = textLength - aCount + aLength;
275 // Use nsString and not nsAutoString so that we get a nsStringBuffer which
276 // can be just AddRefed in nsTextFragment.
277 nsString to;
278 to.SetCapacity(newLength);
280 // Copy over appropriate data
281 if (aOffset) {
282 mText.AppendTo(to, 0, aOffset);
284 if (aLength) {
285 to.Append(aBuffer, aLength);
286 if (!bidi && (!document || !document->GetBidiEnabled())) {
287 bidi = HasRTLChars(MakeSpan(aBuffer, aLength));
290 if (endOffset != textLength) {
291 mText.AppendTo(to, endOffset, textLength - endOffset);
294 // If this is marked as "maybe modified frequently", the text should be
295 // stored as char16_t since converting char* to char16_t* is expensive.
296 // Use char16_t also when we have bidi characters.
297 bool use2b = HasFlag(NS_MAYBE_MODIFIED_FREQUENTLY) || bidi;
298 bool ok = mText.SetTo(to, false, use2b);
299 mText.SetBidi(bidi);
301 NS_ENSURE_TRUE(ok, NS_ERROR_OUT_OF_MEMORY);
304 UnsetFlags(NS_CACHED_TEXT_IS_ONLY_WHITESPACE);
306 if (document && mText.IsBidi()) {
307 // If we found bidi characters in mText.SetTo() above, indicate that the
308 // document contains bidi characters.
309 document->SetBidiEnabled();
312 if (dirAffectsAncestor) {
313 // dirAffectsAncestor being true implies that we have a text node, see
314 // above.
315 MOZ_ASSERT(NodeType() == TEXT_NODE);
316 TextNodeChangedDirection(static_cast<nsTextNode*>(this), oldDir, aNotify);
319 // Notify observers
320 if (aNotify) {
321 CharacterDataChangeInfo info = {aOffset == textLength, aOffset, endOffset,
322 aLength, aDetails};
323 nsNodeUtils::CharacterDataChanged(this, info);
325 if (haveMutationListeners) {
326 InternalMutationEvent mutation(true, eLegacyCharacterDataModified);
328 mutation.mPrevAttrValue = oldValue;
329 if (aLength > 0) {
330 nsAutoString val;
331 mText.AppendTo(val);
332 mutation.mNewAttrValue = NS_Atomize(val);
335 mozAutoSubtreeModified subtree(OwnerDoc(), this);
336 (new AsyncEventDispatcher(this, mutation))->RunDOMEventWhenSafe();
340 return NS_OK;
343 //----------------------------------------------------------------------
345 // Implementation of nsIContent
347 #ifdef DEBUG
348 void CharacterData::ToCString(nsAString& aBuf, int32_t aOffset,
349 int32_t aLen) const {
350 if (mText.Is2b()) {
351 const char16_t* cp = mText.Get2b() + aOffset;
352 const char16_t* end = cp + aLen;
354 while (cp < end) {
355 char16_t ch = *cp++;
356 if (ch == '&') {
357 aBuf.AppendLiteral("&amp;");
358 } else if (ch == '<') {
359 aBuf.AppendLiteral("&lt;");
360 } else if (ch == '>') {
361 aBuf.AppendLiteral("&gt;");
362 } else if ((ch < ' ') || (ch >= 127)) {
363 aBuf.AppendPrintf("\\u%04x", ch);
364 } else {
365 aBuf.Append(ch);
368 } else {
369 unsigned char* cp = (unsigned char*)mText.Get1b() + aOffset;
370 const unsigned char* end = cp + aLen;
372 while (cp < end) {
373 char16_t ch = *cp++;
374 if (ch == '&') {
375 aBuf.AppendLiteral("&amp;");
376 } else if (ch == '<') {
377 aBuf.AppendLiteral("&lt;");
378 } else if (ch == '>') {
379 aBuf.AppendLiteral("&gt;");
380 } else if ((ch < ' ') || (ch >= 127)) {
381 aBuf.AppendPrintf("\\u%04x", ch);
382 } else {
383 aBuf.Append(ch);
388 #endif
390 nsresult CharacterData::BindToTree(BindContext& aContext, nsINode& aParent) {
391 MOZ_ASSERT(aParent.IsContent() || aParent.IsDocument(),
392 "Must have content or document parent!");
393 MOZ_ASSERT(aParent.OwnerDoc() == OwnerDoc(),
394 "Must have the same owner document");
395 MOZ_ASSERT(OwnerDoc() == &aContext.OwnerDoc(), "These should match too");
396 MOZ_ASSERT(!IsInUncomposedDoc(), "Already have a document. Unbind first!");
397 MOZ_ASSERT(!IsInComposedDoc(), "Already have a document. Unbind first!");
398 // Note that as we recurse into the kids, they'll have a non-null parent. So
399 // only assert if our parent is _changing_ while we have a parent.
400 MOZ_ASSERT(!GetParentNode() || &aParent == GetParentNode(),
401 "Already have a parent. Unbind first!");
402 MOZ_ASSERT(
403 !GetBindingParent() ||
404 aContext.GetBindingParent() == GetBindingParent() ||
405 (!aContext.GetBindingParent() && aParent.IsContent() &&
406 aParent.AsContent()->GetBindingParent() == GetBindingParent()),
407 "Already have a binding parent. Unbind first!");
408 MOZ_ASSERT(!IsRootOfNativeAnonymousSubtree() ||
409 aContext.GetBindingParent() == &aParent,
410 "Native anonymous content must have its parent as its "
411 "own binding parent");
412 MOZ_ASSERT(aContext.GetBindingParent() || !aParent.IsContent() ||
413 aContext.GetBindingParent() ==
414 aParent.AsContent()->GetBindingParent(),
415 "We should be passed the right binding parent");
417 // First set the binding parent
418 if (Element* bindingParent = aContext.GetBindingParent()) {
419 ExtendedContentSlots()->mBindingParent = bindingParent;
422 const bool hadParent = !!GetParentNode();
424 NS_ASSERTION(!aContext.GetBindingParent() ||
425 IsRootOfNativeAnonymousSubtree() ||
426 !HasFlag(NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE) ||
427 aParent.IsInNativeAnonymousSubtree(),
428 "Trying to re-bind content from native anonymous subtree to "
429 "non-native anonymous parent!");
430 if (aParent.IsInNativeAnonymousSubtree()) {
431 SetFlags(NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE);
433 if (aParent.HasFlag(NODE_HAS_BEEN_IN_UA_WIDGET)) {
434 SetFlags(NODE_HAS_BEEN_IN_UA_WIDGET);
436 if (HasFlag(NODE_IS_ANONYMOUS_ROOT)) {
437 aParent.SetMayHaveAnonymousChildren();
440 // Set parent
441 mParent = &aParent;
442 if (!hadParent && aParent.IsContent()) {
443 SetParentIsContent(true);
444 NS_ADDREF(mParent);
446 MOZ_ASSERT(!!GetParent() == aParent.IsContent());
448 if (aParent.IsInUncomposedDoc() || aParent.IsInShadowTree()) {
449 // We no longer need to track the subtree pointer (and in fact we'll assert
450 // if we do this any later).
451 ClearSubtreeRootPointer();
452 SetIsConnected(aParent.IsInComposedDoc());
454 if (aParent.IsInUncomposedDoc()) {
455 SetIsInDocument();
456 // FIXME(emilio): This should probably be dependent on composed doc, not
457 // uncomposed.
458 if (mText.IsBidi()) {
459 aContext.OwnerDoc().SetBidiEnabled();
461 } else {
462 SetFlags(NODE_IS_IN_SHADOW_TREE);
463 MOZ_ASSERT(aParent.IsContent() &&
464 aParent.AsContent()->GetContainingShadow());
465 ExtendedContentSlots()->mContainingShadow =
466 aParent.AsContent()->GetContainingShadow();
468 // Clear the lazy frame construction bits.
469 UnsetFlags(NODE_NEEDS_FRAME | NODE_DESCENDANTS_NEED_FRAMES);
470 } else {
471 // If we're not in the doc and not in a shadow tree,
472 // update our subtree pointer.
473 SetSubtreeRootPointer(aParent.SubtreeRoot());
476 nsNodeUtils::ParentChainChanged(this);
477 if (!hadParent && IsRootOfNativeAnonymousSubtree()) {
478 nsNodeUtils::NativeAnonymousChildListChange(this, false);
481 UpdateEditableState(false);
483 MOZ_ASSERT(OwnerDoc() == aParent.OwnerDoc(), "Bound to wrong document");
484 MOZ_ASSERT(IsInComposedDoc() == aContext.InComposedDoc());
485 MOZ_ASSERT(IsInUncomposedDoc() == aContext.InUncomposedDoc());
486 MOZ_ASSERT(&aParent == GetParentNode(), "Bound to wrong parent node");
487 MOZ_ASSERT(aContext.GetBindingParent() == GetBindingParent(),
488 "Bound to wrong binding parent");
489 MOZ_ASSERT(aParent.IsInUncomposedDoc() == IsInUncomposedDoc());
490 MOZ_ASSERT(aParent.IsInComposedDoc() == IsInComposedDoc());
491 MOZ_ASSERT(aParent.IsInShadowTree() == IsInShadowTree());
492 MOZ_ASSERT(aParent.SubtreeRoot() == SubtreeRoot());
493 return NS_OK;
496 void CharacterData::UnbindFromTree(bool aNullParent) {
497 // Unset frame flags; if we need them again later, they'll get set again.
498 UnsetFlags(NS_CREATE_FRAME_IF_NON_WHITESPACE | NS_REFRAME_IF_WHITESPACE);
500 Document* document = GetComposedDoc();
502 if (aNullParent) {
503 if (IsRootOfNativeAnonymousSubtree()) {
504 nsNodeUtils::NativeAnonymousChildListChange(this, true);
506 if (GetParent()) {
507 NS_RELEASE(mParent);
508 } else {
509 mParent = nullptr;
511 SetParentIsContent(false);
513 ClearInDocument();
514 SetIsConnected(false);
516 if (aNullParent || !mParent->IsInShadowTree()) {
517 UnsetFlags(NODE_IS_IN_SHADOW_TREE);
519 // Begin keeping track of our subtree root.
520 SetSubtreeRootPointer(aNullParent ? this : mParent->SubtreeRoot());
523 if (document && !GetContainingShadow()) {
524 // Notify XBL- & nsIAnonymousContentCreator-generated
525 // anonymous content that the document is changing.
526 // Unlike XBL, bindings for web components shadow DOM
527 // do not get uninstalled.
528 if (HasFlag(NODE_MAY_BE_IN_BINDING_MNGR)) {
529 nsContentUtils::AddScriptRunner(new RemoveFromBindingManagerRunnable(
530 document->BindingManager(), this, document));
534 nsExtendedContentSlots* slots = GetExistingExtendedContentSlots();
535 if (slots) {
536 slots->mBindingParent = nullptr;
537 if (aNullParent || !mParent->IsInShadowTree()) {
538 slots->mContainingShadow = nullptr;
542 nsNodeUtils::ParentChainChanged(this);
545 //----------------------------------------------------------------------
547 // Implementation of the nsIContent interface text functions
549 nsresult CharacterData::SetText(const char16_t* aBuffer, uint32_t aLength,
550 bool aNotify) {
551 return SetTextInternal(0, mText.GetLength(), aBuffer, aLength, aNotify);
554 nsresult CharacterData::AppendText(const char16_t* aBuffer, uint32_t aLength,
555 bool aNotify) {
556 return SetTextInternal(mText.GetLength(), 0, aBuffer, aLength, aNotify);
559 bool CharacterData::TextIsOnlyWhitespace() {
560 MOZ_ASSERT(NS_IsMainThread());
561 if (!ThreadSafeTextIsOnlyWhitespace()) {
562 UnsetFlags(NS_TEXT_IS_ONLY_WHITESPACE);
563 SetFlags(NS_CACHED_TEXT_IS_ONLY_WHITESPACE);
564 return false;
567 SetFlags(NS_CACHED_TEXT_IS_ONLY_WHITESPACE | NS_TEXT_IS_ONLY_WHITESPACE);
568 return true;
571 bool CharacterData::ThreadSafeTextIsOnlyWhitespace() const {
572 // FIXME: should this method take content language into account?
573 if (mText.Is2b()) {
574 // The fragment contains non-8bit characters and such characters
575 // are never considered whitespace.
577 // FIXME(emilio): This is not quite true in presence of the
578 // NS_MAYBE_MODIFIED_FREQUENTLY flag... But looks like we only set that on
579 // anonymous nodes, so should be fine...
580 return false;
583 if (HasFlag(NS_CACHED_TEXT_IS_ONLY_WHITESPACE)) {
584 return HasFlag(NS_TEXT_IS_ONLY_WHITESPACE);
587 const char* cp = mText.Get1b();
588 const char* end = cp + mText.GetLength();
590 while (cp < end) {
591 char ch = *cp;
593 // NOTE(emilio): If you ever change the definition of "whitespace" here, you
594 // need to change it too in RestyleManager::CharacterDataChanged.
595 if (!dom::IsSpaceCharacter(ch)) {
596 return false;
599 ++cp;
602 return true;
605 already_AddRefed<nsAtom> CharacterData::GetCurrentValueAtom() {
606 nsAutoString val;
607 GetData(val);
608 return NS_Atomize(val);
611 void CharacterData::AddSizeOfExcludingThis(nsWindowSizes& aSizes,
612 size_t* aNodeSize) const {
613 nsIContent::AddSizeOfExcludingThis(aSizes, aNodeSize);
614 *aNodeSize += mText.SizeOfExcludingThis(aSizes.mState.mMallocSizeOf);
617 } // namespace dom
618 } // namespace mozilla