1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is Mozilla Communicator client code.
16 : *
17 : * The Initial Developer of the Original Code is
18 : * Netscape Communications Corporation.
19 : * Portions created by the Initial Developer are Copyright (C) 1998
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : *
24 : * Alternatively, the contents of this file may be used under the terms of
25 : * either of the GNU General Public License Version 2 or later (the "GPL"),
26 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 : * in which case the provisions of the GPL or the LGPL are applicable instead
28 : * of those above. If you wish to allow use of your version of this file only
29 : * under the terms of either the GPL or the LGPL, and not to allow others to
30 : * use your version of this file under the terms of the MPL, indicate your
31 : * decision by deleting the provisions above and replace them with the notice
32 : * and other provisions required by the GPL or the LGPL. If you do not delete
33 : * the provisions above, a recipient may use your version of this file under
34 : * the terms of any one of the MPL, the GPL or the LGPL.
35 : *
36 : * ***** END LICENSE BLOCK ***** */
37 :
38 : /*
39 : * Base class for DOM Core's nsIDOMComment, nsIDOMDocumentType, nsIDOMText,
40 : * nsIDOMCDATASection, and nsIDOMProcessingInstruction nodes.
41 : */
42 :
43 : #include "nsGenericDOMDataNode.h"
44 : #include "nsGenericElement.h"
45 : #include "nsIDocument.h"
46 : #include "nsEventListenerManager.h"
47 : #include "nsIDOMDocument.h"
48 : #include "nsReadableUtils.h"
49 : #include "nsMutationEvent.h"
50 : #include "nsINameSpaceManager.h"
51 : #include "nsIURI.h"
52 : #include "nsIPrivateDOMEvent.h"
53 : #include "nsIDOMEvent.h"
54 : #include "nsIDOMText.h"
55 : #include "nsCOMPtr.h"
56 : #include "nsDOMString.h"
57 : #include "nsIDOMUserDataHandler.h"
58 : #include "nsChangeHint.h"
59 : #include "nsEventDispatcher.h"
60 : #include "nsCOMArray.h"
61 : #include "nsNodeUtils.h"
62 : #include "nsBindingManager.h"
63 : #include "nsCCUncollectableMarker.h"
64 : #include "mozAutoDocUpdate.h"
65 : #include "nsAsyncDOMEvent.h"
66 :
67 : #include "pldhash.h"
68 : #include "prprf.h"
69 : #include "nsWrapperCacheInlines.h"
70 :
71 : using namespace mozilla;
72 :
73 74985 : nsGenericDOMDataNode::nsGenericDOMDataNode(already_AddRefed<nsINodeInfo> aNodeInfo)
74 74985 : : nsIContent(aNodeInfo)
75 : {
76 74985 : NS_ABORT_IF_FALSE(mNodeInfo->NodeType() == nsIDOMNode::TEXT_NODE ||
77 : mNodeInfo->NodeType() == nsIDOMNode::CDATA_SECTION_NODE ||
78 : mNodeInfo->NodeType() == nsIDOMNode::COMMENT_NODE ||
79 : mNodeInfo->NodeType() ==
80 : nsIDOMNode::PROCESSING_INSTRUCTION_NODE ||
81 : mNodeInfo->NodeType() == nsIDOMNode::DOCUMENT_TYPE_NODE,
82 : "Bad NodeType in aNodeInfo");
83 74985 : }
84 :
85 149966 : nsGenericDOMDataNode::~nsGenericDOMDataNode()
86 : {
87 74983 : NS_PRECONDITION(!IsInDoc(),
88 : "Please remove this from the document properly");
89 74983 : if (GetParent()) {
90 0 : NS_RELEASE(mParent);
91 : }
92 149966 : }
93 :
94 1464 : NS_IMPL_CYCLE_COLLECTION_CLASS(nsGenericDOMDataNode)
95 :
96 90491 : NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsGenericDOMDataNode)
97 90491 : nsINode::Trace(tmp, aCallback, aClosure);
98 90491 : NS_IMPL_CYCLE_COLLECTION_TRACE_END
99 :
100 195326 : NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(nsGenericDOMDataNode)
101 195326 : return nsGenericElement::CanSkip(tmp, aRemovingAllowed);
102 : NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END
103 :
104 61403 : NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(nsGenericDOMDataNode)
105 61403 : return nsGenericElement::CanSkipInCC(tmp);
106 : NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_END
107 :
108 75161 : NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN(nsGenericDOMDataNode)
109 75161 : return nsGenericElement::CanSkipThis(tmp);
110 : NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END
111 :
112 90491 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsGenericDOMDataNode)
113 : // Always need to traverse script objects, so do that before we check
114 : // if we're uncollectable.
115 90491 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
116 :
117 90491 : if (!nsINode::Traverse(tmp, cb)) {
118 0 : return NS_SUCCESS_INTERRUPTED_TRAVERSE;
119 : }
120 :
121 90491 : tmp->OwnerDoc()->BindingManager()->Traverse(tmp, cb);
122 90491 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
123 :
124 74786 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsGenericDOMDataNode)
125 74786 : nsINode::Unlink(tmp);
126 74786 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
127 :
128 200531 : NS_INTERFACE_MAP_BEGIN(nsGenericDOMDataNode)
129 200531 : NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
130 187702 : NS_INTERFACE_MAP_ENTRIES_CYCLE_COLLECTION(nsGenericDOMDataNode)
131 148134 : NS_INTERFACE_MAP_ENTRY(nsIContent)
132 180 : NS_INTERFACE_MAP_ENTRY(nsINode)
133 180 : NS_INTERFACE_MAP_ENTRY(nsIDOMEventTarget)
134 157 : NS_INTERFACE_MAP_ENTRY_TEAROFF(nsISupportsWeakReference,
135 : new nsNodeSupportsWeakRefTearoff(this))
136 73 : NS_INTERFACE_MAP_ENTRY_TEAROFF(nsIDOMXPathNSResolver,
137 : new nsNode3Tearoff(this))
138 : // nsNodeSH::PreCreate() depends on the identity pointer being the
139 : // same as nsINode (which nsIContent inherits), so if you change the
140 : // below line, make sure nsNodeSH::PreCreate() still does the right
141 : // thing!
142 73 : NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIContent)
143 73 : NS_INTERFACE_MAP_END
144 :
145 480817 : NS_IMPL_CYCLE_COLLECTING_ADDREF(nsGenericDOMDataNode)
146 480815 : NS_IMPL_CYCLE_COLLECTING_RELEASE_WITH_DESTROY(nsGenericDOMDataNode,
147 : nsNodeUtils::LastRelease(this))
148 :
149 :
150 : nsresult
151 764 : nsGenericDOMDataNode::GetNodeValue(nsAString& aNodeValue)
152 : {
153 764 : return GetData(aNodeValue);
154 : }
155 :
156 : nsresult
157 5 : nsGenericDOMDataNode::SetNodeValue(const nsAString& aNodeValue)
158 : {
159 : return SetTextInternal(0, mText.GetLength(), aNodeValue.BeginReading(),
160 5 : aNodeValue.Length(), true);
161 : }
162 :
163 : nsresult
164 0 : nsGenericDOMDataNode::GetNamespaceURI(nsAString& aNamespaceURI)
165 : {
166 0 : SetDOMStringToNull(aNamespaceURI);
167 :
168 0 : return NS_OK;
169 : }
170 :
171 : nsresult
172 0 : nsGenericDOMDataNode::GetPrefix(nsAString& aPrefix)
173 : {
174 0 : SetDOMStringToNull(aPrefix);
175 :
176 0 : return NS_OK;
177 : }
178 :
179 : nsresult
180 0 : nsGenericDOMDataNode::IsSupported(const nsAString& aFeature,
181 : const nsAString& aVersion,
182 : bool* aReturn)
183 : {
184 : return nsGenericElement::InternalIsSupported(static_cast<nsIContent*>(this),
185 0 : aFeature, aVersion, aReturn);
186 : }
187 :
188 : //----------------------------------------------------------------------
189 :
190 : // Implementation of nsIDOMCharacterData
191 :
192 : nsresult
193 837 : nsGenericDOMDataNode::GetData(nsAString& aData) const
194 : {
195 837 : if (mText.Is2b()) {
196 0 : aData.Assign(mText.Get2b(), mText.GetLength());
197 : } else {
198 : // Must use Substring() since nsDependentCString() requires null
199 : // terminated strings.
200 :
201 837 : const char *data = mText.Get1b();
202 :
203 837 : if (data) {
204 820 : CopyASCIItoUTF16(Substring(data, data + mText.GetLength()), aData);
205 : } else {
206 17 : aData.Truncate();
207 : }
208 : }
209 :
210 837 : return NS_OK;
211 : }
212 :
213 : nsresult
214 0 : nsGenericDOMDataNode::SetData(const nsAString& aData)
215 : {
216 : return SetTextInternal(0, mText.GetLength(), aData.BeginReading(),
217 0 : aData.Length(), true);
218 : }
219 :
220 : nsresult
221 35 : nsGenericDOMDataNode::GetLength(PRUint32* aLength)
222 : {
223 35 : *aLength = mText.GetLength();
224 35 : return NS_OK;
225 : }
226 :
227 : nsresult
228 9 : nsGenericDOMDataNode::SubstringData(PRUint32 aStart, PRUint32 aCount,
229 : nsAString& aReturn)
230 : {
231 9 : aReturn.Truncate();
232 :
233 9 : PRUint32 textLength = mText.GetLength();
234 9 : if (aStart > textLength) {
235 0 : return NS_ERROR_DOM_INDEX_SIZE_ERR;
236 : }
237 :
238 9 : PRUint32 amount = aCount;
239 9 : if (amount > textLength - aStart) {
240 0 : amount = textLength - aStart;
241 : }
242 :
243 9 : if (mText.Is2b()) {
244 0 : aReturn.Assign(mText.Get2b() + aStart, amount);
245 : } else {
246 : // Must use Substring() since nsDependentCString() requires null
247 : // terminated strings.
248 :
249 9 : const char *data = mText.Get1b() + aStart;
250 9 : CopyASCIItoUTF16(Substring(data, data + amount), aReturn);
251 : }
252 :
253 9 : return NS_OK;
254 : }
255 :
256 : //----------------------------------------------------------------------
257 :
258 : nsresult
259 0 : nsGenericDOMDataNode::AppendData(const nsAString& aData)
260 : {
261 : return SetTextInternal(mText.GetLength(), 0, aData.BeginReading(),
262 0 : aData.Length(), true);
263 : }
264 :
265 : nsresult
266 0 : nsGenericDOMDataNode::InsertData(PRUint32 aOffset,
267 : const nsAString& aData)
268 : {
269 : return SetTextInternal(aOffset, 0, aData.BeginReading(),
270 0 : aData.Length(), true);
271 : }
272 :
273 : nsresult
274 9 : nsGenericDOMDataNode::DeleteData(PRUint32 aOffset, PRUint32 aCount)
275 : {
276 9 : return SetTextInternal(aOffset, aCount, nsnull, 0, true);
277 : }
278 :
279 : nsresult
280 0 : nsGenericDOMDataNode::ReplaceData(PRUint32 aOffset, PRUint32 aCount,
281 : const nsAString& aData)
282 : {
283 : return SetTextInternal(aOffset, aCount, aData.BeginReading(),
284 0 : aData.Length(), true);
285 : }
286 :
287 : nsresult
288 74499 : nsGenericDOMDataNode::SetTextInternal(PRUint32 aOffset, PRUint32 aCount,
289 : const PRUnichar* aBuffer,
290 : PRUint32 aLength, bool aNotify,
291 : CharacterDataChangeInfo::Details* aDetails)
292 : {
293 74499 : NS_PRECONDITION(aBuffer || !aLength,
294 : "Null buffer passed to SetTextInternal!");
295 :
296 : // sanitize arguments
297 74499 : PRUint32 textLength = mText.GetLength();
298 74499 : if (aOffset > textLength) {
299 0 : return NS_ERROR_DOM_INDEX_SIZE_ERR;
300 : }
301 :
302 74499 : if (aCount > textLength - aOffset) {
303 0 : aCount = textLength - aOffset;
304 : }
305 :
306 74499 : PRUint32 endOffset = aOffset + aCount;
307 :
308 : // Make sure the text fragment can hold the new data.
309 74499 : if (aLength > aCount && !mText.CanGrowBy(aLength - aCount)) {
310 : // This exception isn't per spec, but the spec doesn't actually
311 : // say what to do here.
312 :
313 0 : return NS_ERROR_DOM_DOMSTRING_SIZE_ERR;
314 : }
315 :
316 74499 : nsIDocument *document = GetCurrentDoc();
317 148998 : mozAutoDocUpdate updateBatch(document, UPDATE_CONTENT_MODEL, aNotify);
318 :
319 : bool haveMutationListeners = aNotify &&
320 : nsContentUtils::HasMutationListeners(this,
321 : NS_EVENT_BITS_MUTATION_CHARACTERDATAMODIFIED,
322 74499 : this);
323 :
324 148998 : nsCOMPtr<nsIAtom> oldValue;
325 74499 : if (haveMutationListeners) {
326 0 : oldValue = GetCurrentValueAtom();
327 : }
328 :
329 74499 : if (aNotify) {
330 : CharacterDataChangeInfo info = {
331 : aOffset == textLength,
332 : aOffset,
333 : endOffset,
334 : aLength,
335 : aDetails
336 32 : };
337 32 : nsNodeUtils::CharacterDataWillChange(this, &info);
338 : }
339 :
340 74499 : if (aOffset == 0 && endOffset == textLength) {
341 : // Replacing whole text or old text was empty. Don't bother to check for
342 : // bidi in this string if the document already has bidi enabled.
343 74476 : mText.SetTo(aBuffer, aLength, !document || !document->GetBidiEnabled());
344 : }
345 23 : else if (aOffset == textLength) {
346 : // Appending to existing
347 10 : mText.Append(aBuffer, aLength, !document || !document->GetBidiEnabled());
348 : }
349 : else {
350 : // Merging old and new
351 :
352 : // Allocate new buffer
353 13 : PRInt32 newLength = textLength - aCount + aLength;
354 26 : PRUnichar* to = new PRUnichar[newLength];
355 13 : NS_ENSURE_TRUE(to, NS_ERROR_OUT_OF_MEMORY);
356 :
357 : // Copy over appropriate data
358 13 : if (aOffset) {
359 9 : mText.CopyTo(to, 0, aOffset);
360 : }
361 13 : if (aLength) {
362 0 : memcpy(to + aOffset, aBuffer, aLength * sizeof(PRUnichar));
363 : }
364 13 : if (endOffset != textLength) {
365 11 : mText.CopyTo(to + aOffset + aLength, endOffset, textLength - endOffset);
366 : }
367 :
368 : // XXX Add OOM checking to this
369 13 : mText.SetTo(to, newLength, !document || !document->GetBidiEnabled());
370 :
371 13 : delete [] to;
372 : }
373 :
374 74499 : if (document && mText.IsBidi()) {
375 : // If we found bidi characters in mText.SetTo() above, indicate that the
376 : // document contains bidi characters.
377 0 : document->SetBidiEnabled();
378 : }
379 :
380 : // Notify observers
381 74499 : if (aNotify) {
382 : CharacterDataChangeInfo info = {
383 : aOffset == textLength,
384 : aOffset,
385 : endOffset,
386 : aLength,
387 : aDetails
388 32 : };
389 32 : nsNodeUtils::CharacterDataChanged(this, &info);
390 :
391 32 : if (haveMutationListeners) {
392 0 : nsMutationEvent mutation(true, NS_MUTATION_CHARACTERDATAMODIFIED);
393 :
394 0 : mutation.mPrevAttrValue = oldValue;
395 0 : if (aLength > 0) {
396 0 : nsAutoString val;
397 0 : mText.AppendTo(val);
398 0 : mutation.mNewAttrValue = do_GetAtom(val);
399 : }
400 :
401 0 : mozAutoSubtreeModified subtree(OwnerDoc(), this);
402 0 : (new nsAsyncDOMEvent(this, mutation))->RunDOMEventWhenSafe();
403 : }
404 : }
405 :
406 74499 : return NS_OK;
407 : }
408 :
409 : //----------------------------------------------------------------------
410 :
411 : // Implementation of nsIContent
412 :
413 : #ifdef DEBUG
414 : void
415 0 : nsGenericDOMDataNode::ToCString(nsAString& aBuf, PRInt32 aOffset,
416 : PRInt32 aLen) const
417 : {
418 0 : if (mText.Is2b()) {
419 0 : const PRUnichar* cp = mText.Get2b() + aOffset;
420 0 : const PRUnichar* end = cp + aLen;
421 :
422 0 : while (cp < end) {
423 0 : PRUnichar ch = *cp++;
424 0 : if (ch == '&') {
425 0 : aBuf.AppendLiteral("&");
426 0 : } else if (ch == '<') {
427 0 : aBuf.AppendLiteral("<");
428 0 : } else if (ch == '>') {
429 0 : aBuf.AppendLiteral(">");
430 0 : } else if ((ch < ' ') || (ch >= 127)) {
431 : char buf[10];
432 0 : PR_snprintf(buf, sizeof(buf), "\\u%04x", ch);
433 0 : AppendASCIItoUTF16(buf, aBuf);
434 : } else {
435 0 : aBuf.Append(ch);
436 : }
437 : }
438 : } else {
439 0 : unsigned char* cp = (unsigned char*)mText.Get1b() + aOffset;
440 0 : const unsigned char* end = cp + aLen;
441 :
442 0 : while (cp < end) {
443 0 : PRUnichar ch = *cp++;
444 0 : if (ch == '&') {
445 0 : aBuf.AppendLiteral("&");
446 0 : } else if (ch == '<') {
447 0 : aBuf.AppendLiteral("<");
448 0 : } else if (ch == '>') {
449 0 : aBuf.AppendLiteral(">");
450 0 : } else if ((ch < ' ') || (ch >= 127)) {
451 : char buf[10];
452 0 : PR_snprintf(buf, sizeof(buf), "\\u%04x", ch);
453 0 : AppendASCIItoUTF16(buf, aBuf);
454 : } else {
455 0 : aBuf.Append(ch);
456 : }
457 : }
458 : }
459 0 : }
460 : #endif
461 :
462 :
463 : nsresult
464 74006 : nsGenericDOMDataNode::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
465 : nsIContent* aBindingParent,
466 : bool aCompileEventHandlers)
467 : {
468 74006 : NS_PRECONDITION(aParent || aDocument, "Must have document if no parent!");
469 74006 : NS_PRECONDITION(HasSameOwnerDoc(NODE_FROM(aParent, aDocument)),
470 : "Must have the same owner document");
471 74006 : NS_PRECONDITION(!aParent || aDocument == aParent->GetCurrentDoc(),
472 : "aDocument must be current doc of aParent");
473 74006 : NS_PRECONDITION(!GetCurrentDoc() && !IsInDoc(),
474 : "Already have a document. Unbind first!");
475 : // Note that as we recurse into the kids, they'll have a non-null parent. So
476 : // only assert if our parent is _changing_ while we have a parent.
477 74006 : NS_PRECONDITION(!GetParent() || aParent == GetParent(),
478 : "Already have a parent. Unbind first!");
479 74006 : NS_PRECONDITION(!GetBindingParent() ||
480 : aBindingParent == GetBindingParent() ||
481 : (!aBindingParent && aParent &&
482 : aParent->GetBindingParent() == GetBindingParent()),
483 : "Already have a binding parent. Unbind first!");
484 74006 : NS_PRECONDITION(aBindingParent != this,
485 : "Content must not be its own binding parent");
486 74006 : NS_PRECONDITION(!IsRootOfNativeAnonymousSubtree() ||
487 : aBindingParent == aParent,
488 : "Native anonymous content must have its parent as its "
489 : "own binding parent");
490 :
491 74006 : if (!aBindingParent && aParent) {
492 73904 : aBindingParent = aParent->GetBindingParent();
493 : }
494 :
495 : // First set the binding parent
496 74006 : if (aBindingParent) {
497 0 : nsDataSlots *slots = GetDataSlots();
498 0 : NS_ENSURE_TRUE(slots, NS_ERROR_OUT_OF_MEMORY);
499 :
500 0 : NS_ASSERTION(IsRootOfNativeAnonymousSubtree() ||
501 : !HasFlag(NODE_IS_IN_ANONYMOUS_SUBTREE) ||
502 : (aParent && aParent->IsInNativeAnonymousSubtree()),
503 : "Trying to re-bind content from native anonymous subtree to "
504 : "non-native anonymous parent!");
505 0 : slots->mBindingParent = aBindingParent; // Weak, so no addref happens.
506 0 : if (aParent->IsInNativeAnonymousSubtree()) {
507 0 : SetFlags(NODE_IS_IN_ANONYMOUS_SUBTREE);
508 : }
509 : }
510 :
511 : // Set parent
512 74006 : if (aParent) {
513 73904 : if (!GetParent()) {
514 73897 : NS_ADDREF(aParent);
515 : }
516 73904 : mParent = aParent;
517 : }
518 : else {
519 102 : mParent = aDocument;
520 : }
521 74006 : SetParentIsContent(aParent);
522 :
523 : // XXXbz sXBL/XBL2 issue!
524 :
525 : // Set document
526 74006 : if (aDocument) {
527 : // XXX See the comment in nsGenericElement::BindToTree
528 73458 : SetInDocument();
529 73458 : if (mText.IsBidi()) {
530 4 : aDocument->SetBidiEnabled();
531 : }
532 : // Clear the lazy frame construction bits.
533 73458 : UnsetFlags(NODE_NEEDS_FRAME | NODE_DESCENDANTS_NEED_FRAMES);
534 : }
535 :
536 74006 : nsNodeUtils::ParentChainChanged(this);
537 :
538 74006 : UpdateEditableState(false);
539 :
540 74006 : NS_POSTCONDITION(aDocument == GetCurrentDoc(), "Bound to wrong document");
541 74006 : NS_POSTCONDITION(aParent == GetParent(), "Bound to wrong parent");
542 74006 : NS_POSTCONDITION(aBindingParent == GetBindingParent(),
543 : "Bound to wrong binding parent");
544 :
545 74006 : return NS_OK;
546 : }
547 :
548 : void
549 250948 : nsGenericDOMDataNode::UnbindFromTree(bool aDeep, bool aNullParent)
550 : {
551 : // Unset frame flags; if we need them again later, they'll get set again.
552 : UnsetFlags(NS_CREATE_FRAME_IF_NON_WHITESPACE |
553 250948 : NS_REFRAME_IF_WHITESPACE);
554 :
555 250948 : nsIDocument *document = GetCurrentDoc();
556 250948 : if (document) {
557 : // Notify XBL- & nsIAnonymousContentCreator-generated
558 : // anonymous content that the document is changing.
559 : // This is needed to update the insertion point.
560 73456 : document->BindingManager()->RemovedFromDocument(this, document);
561 : }
562 :
563 250948 : if (aNullParent) {
564 73997 : if (GetParent()) {
565 73895 : NS_RELEASE(mParent);
566 : } else {
567 102 : mParent = nsnull;
568 : }
569 73997 : SetParentIsContent(false);
570 : }
571 250948 : ClearInDocument();
572 :
573 250948 : nsDataSlots *slots = GetExistingDataSlots();
574 250948 : if (slots) {
575 23 : slots->mBindingParent = nsnull;
576 : }
577 :
578 250948 : nsNodeUtils::ParentChainChanged(this);
579 250948 : }
580 :
581 : already_AddRefed<nsINodeList>
582 0 : nsGenericDOMDataNode::GetChildren(PRUint32 aFilter)
583 : {
584 0 : return nsnull;
585 : }
586 :
587 : nsIAtom *
588 0 : nsGenericDOMDataNode::GetIDAttributeName() const
589 : {
590 0 : return nsnull;
591 : }
592 :
593 : already_AddRefed<nsINodeInfo>
594 0 : nsGenericDOMDataNode::GetExistingAttrNameFromQName(const nsAString& aStr) const
595 : {
596 0 : return nsnull;
597 : }
598 :
599 : nsresult
600 0 : nsGenericDOMDataNode::SetAttr(PRInt32 aNameSpaceID, nsIAtom* aAttr,
601 : nsIAtom* aPrefix, const nsAString& aValue,
602 : bool aNotify)
603 : {
604 0 : return NS_OK;
605 : }
606 :
607 : nsresult
608 0 : nsGenericDOMDataNode::UnsetAttr(PRInt32 aNameSpaceID, nsIAtom* aAttr,
609 : bool aNotify)
610 : {
611 0 : return NS_OK;
612 : }
613 :
614 : bool
615 0 : nsGenericDOMDataNode::GetAttr(PRInt32 aNameSpaceID, nsIAtom *aAttr,
616 : nsAString& aResult) const
617 : {
618 0 : aResult.Truncate();
619 :
620 0 : return false;
621 : }
622 :
623 : bool
624 0 : nsGenericDOMDataNode::HasAttr(PRInt32 aNameSpaceID, nsIAtom *aAttribute) const
625 : {
626 0 : return false;
627 : }
628 :
629 : const nsAttrName*
630 0 : nsGenericDOMDataNode::GetAttrNameAt(PRUint32 aIndex) const
631 : {
632 0 : return nsnull;
633 : }
634 :
635 : PRUint32
636 0 : nsGenericDOMDataNode::GetAttrCount() const
637 : {
638 0 : return 0;
639 : }
640 :
641 : PRUint32
642 12 : nsGenericDOMDataNode::GetChildCount() const
643 : {
644 12 : return 0;
645 : }
646 :
647 : nsIContent *
648 0 : nsGenericDOMDataNode::GetChildAt(PRUint32 aIndex) const
649 : {
650 0 : return nsnull;
651 : }
652 :
653 : nsIContent * const *
654 0 : nsGenericDOMDataNode::GetChildArray(PRUint32* aChildCount) const
655 : {
656 0 : *aChildCount = 0;
657 0 : return nsnull;
658 : }
659 :
660 : PRInt32
661 0 : nsGenericDOMDataNode::IndexOf(nsINode* aPossibleChild) const
662 : {
663 0 : return -1;
664 : }
665 :
666 : nsresult
667 0 : nsGenericDOMDataNode::InsertChildAt(nsIContent* aKid, PRUint32 aIndex,
668 : bool aNotify)
669 : {
670 0 : return NS_OK;
671 : }
672 :
673 : nsresult
674 0 : nsGenericDOMDataNode::RemoveChildAt(PRUint32 aIndex, bool aNotify)
675 : {
676 0 : return NS_OK;
677 : }
678 :
679 : nsIContent *
680 154595 : nsGenericDOMDataNode::GetBindingParent() const
681 : {
682 154595 : nsDataSlots *slots = GetExistingDataSlots();
683 154595 : return slots ? slots->mBindingParent : nsnull;
684 : }
685 :
686 : bool
687 0 : nsGenericDOMDataNode::IsNodeOfType(PRUint32 aFlags) const
688 : {
689 0 : return !(aFlags & ~(eCONTENT | eDATA_NODE));
690 : }
691 :
692 : void
693 0 : nsGenericDOMDataNode::SaveSubtreeState()
694 : {
695 0 : }
696 :
697 : void
698 0 : nsGenericDOMDataNode::DestroyContent()
699 : {
700 : // XXX We really should let cycle collection do this, but that currently still
701 : // leaks (see https://bugzilla.mozilla.org/show_bug.cgi?id=406684).
702 0 : nsContentUtils::ReleaseWrapper(this, this);
703 0 : }
704 :
705 : #ifdef DEBUG
706 : void
707 0 : nsGenericDOMDataNode::List(FILE* out, PRInt32 aIndent) const
708 : {
709 0 : }
710 :
711 : void
712 0 : nsGenericDOMDataNode::DumpContent(FILE* out, PRInt32 aIndent,
713 : bool aDumpAll) const
714 : {
715 0 : }
716 : #endif
717 :
718 : bool
719 0 : nsGenericDOMDataNode::IsLink(nsIURI** aURI) const
720 : {
721 0 : *aURI = nsnull;
722 0 : return false;
723 : }
724 :
725 : nsINode::nsSlots*
726 23 : nsGenericDOMDataNode::CreateSlots()
727 : {
728 23 : return new nsDataSlots();
729 : }
730 :
731 : //----------------------------------------------------------------------
732 :
733 : // Implementation of the nsIDOMText interface
734 :
735 : nsresult
736 4 : nsGenericDOMDataNode::SplitData(PRUint32 aOffset, nsIContent** aReturn,
737 : bool aCloneAfterOriginal)
738 : {
739 4 : *aReturn = nsnull;
740 4 : nsresult rv = NS_OK;
741 8 : nsAutoString cutText;
742 4 : PRUint32 length = TextLength();
743 :
744 4 : if (aOffset > length) {
745 0 : return NS_ERROR_DOM_INDEX_SIZE_ERR;
746 : }
747 :
748 4 : PRUint32 cutStartOffset = aCloneAfterOriginal ? aOffset : 0;
749 4 : PRUint32 cutLength = aCloneAfterOriginal ? length - aOffset : aOffset;
750 4 : rv = SubstringData(cutStartOffset, cutLength, cutText);
751 4 : if (NS_FAILED(rv)) {
752 0 : return rv;
753 : }
754 :
755 4 : nsIDocument* document = GetCurrentDoc();
756 8 : mozAutoDocUpdate updateBatch(document, UPDATE_CONTENT_MODEL, true);
757 :
758 : // Use Clone for creating the new node so that the new node is of same class
759 : // as this node!
760 8 : nsCOMPtr<nsIContent> newContent = CloneDataNode(mNodeInfo, false);
761 4 : if (!newContent) {
762 0 : return NS_ERROR_OUT_OF_MEMORY;
763 : }
764 4 : newContent->SetText(cutText, true); // XXX should be false?
765 :
766 : CharacterDataChangeInfo::Details details = {
767 : CharacterDataChangeInfo::Details::eSplit, newContent
768 4 : };
769 : rv = SetTextInternal(cutStartOffset, cutLength, nsnull, 0, true,
770 4 : aCloneAfterOriginal ? &details : nsnull);
771 4 : if (NS_FAILED(rv)) {
772 0 : return rv;
773 : }
774 :
775 8 : nsCOMPtr<nsINode> parent = GetNodeParent();
776 4 : if (parent) {
777 4 : PRInt32 insertionIndex = parent->IndexOf(this);
778 4 : if (aCloneAfterOriginal) {
779 2 : ++insertionIndex;
780 : }
781 4 : parent->InsertChildAt(newContent, insertionIndex, true);
782 : }
783 :
784 4 : newContent.swap(*aReturn);
785 4 : return rv;
786 : }
787 :
788 : nsresult
789 0 : nsGenericDOMDataNode::SplitText(PRUint32 aOffset, nsIDOMText** aReturn)
790 : {
791 0 : nsCOMPtr<nsIContent> newChild;
792 0 : nsresult rv = SplitData(aOffset, getter_AddRefs(newChild));
793 0 : if (NS_SUCCEEDED(rv)) {
794 0 : rv = CallQueryInterface(newChild, aReturn);
795 : }
796 0 : return rv;
797 : }
798 :
799 : /* static */ PRInt32
800 0 : nsGenericDOMDataNode::FirstLogicallyAdjacentTextNode(nsIContent* aParent,
801 : PRInt32 aIndex)
802 : {
803 0 : while (aIndex-- > 0) {
804 0 : nsIContent* sibling = aParent->GetChildAt(aIndex);
805 0 : if (!sibling->IsNodeOfType(nsINode::eTEXT))
806 0 : return aIndex + 1;
807 : }
808 0 : return 0;
809 : }
810 :
811 : /* static */ PRInt32
812 0 : nsGenericDOMDataNode::LastLogicallyAdjacentTextNode(nsIContent* aParent,
813 : PRInt32 aIndex,
814 : PRUint32 aCount)
815 : {
816 0 : while (++aIndex < PRInt32(aCount)) {
817 0 : nsIContent* sibling = aParent->GetChildAt(aIndex);
818 0 : if (!sibling->IsNodeOfType(nsINode::eTEXT))
819 0 : return aIndex - 1;
820 : }
821 0 : return aCount - 1;
822 : }
823 :
824 : nsresult
825 0 : nsGenericDOMDataNode::GetWholeText(nsAString& aWholeText)
826 : {
827 0 : nsIContent* parent = GetParent();
828 :
829 : // Handle parent-less nodes
830 0 : if (!parent)
831 0 : return GetData(aWholeText);
832 :
833 0 : PRInt32 index = parent->IndexOf(this);
834 0 : NS_WARN_IF_FALSE(index >= 0,
835 : "Trying to use .wholeText with an anonymous"
836 : "text node child of a binding parent?");
837 0 : NS_ENSURE_TRUE(index >= 0, NS_ERROR_DOM_NOT_SUPPORTED_ERR);
838 : PRInt32 first =
839 0 : FirstLogicallyAdjacentTextNode(parent, index);
840 : PRInt32 last =
841 0 : LastLogicallyAdjacentTextNode(parent, index, parent->GetChildCount());
842 :
843 0 : aWholeText.Truncate();
844 :
845 0 : nsCOMPtr<nsIDOMText> node;
846 0 : nsAutoString tmp;
847 0 : do {
848 0 : node = do_QueryInterface(parent->GetChildAt(first));
849 0 : node->GetData(tmp);
850 0 : aWholeText.Append(tmp);
851 : } while (first++ < last);
852 :
853 0 : return NS_OK;
854 : }
855 :
856 : //----------------------------------------------------------------------
857 :
858 : // Implementation of the nsIContent interface text functions
859 :
860 : const nsTextFragment *
861 535 : nsGenericDOMDataNode::GetText()
862 : {
863 535 : return &mText;
864 : }
865 :
866 : PRUint32
867 102 : nsGenericDOMDataNode::TextLength()
868 : {
869 102 : return mText.GetLength();
870 : }
871 :
872 : nsresult
873 74323 : nsGenericDOMDataNode::SetText(const PRUnichar* aBuffer,
874 : PRUint32 aLength,
875 : bool aNotify)
876 : {
877 74323 : return SetTextInternal(0, mText.GetLength(), aBuffer, aLength, aNotify);
878 : }
879 :
880 : nsresult
881 1 : nsGenericDOMDataNode::AppendText(const PRUnichar* aBuffer,
882 : PRUint32 aLength,
883 : bool aNotify)
884 : {
885 1 : return SetTextInternal(mText.GetLength(), 0, aBuffer, aLength, aNotify);
886 : }
887 :
888 : bool
889 0 : nsGenericDOMDataNode::TextIsOnlyWhitespace()
890 : {
891 0 : if (mText.Is2b()) {
892 : // The fragment contains non-8bit characters and such characters
893 : // are never considered whitespace.
894 0 : return false;
895 : }
896 :
897 0 : const char* cp = mText.Get1b();
898 0 : const char* end = cp + mText.GetLength();
899 :
900 0 : while (cp < end) {
901 0 : char ch = *cp;
902 :
903 0 : if (!XP_IS_SPACE(ch)) {
904 0 : return false;
905 : }
906 :
907 0 : ++cp;
908 : }
909 :
910 0 : return true;
911 : }
912 :
913 : void
914 8436 : nsGenericDOMDataNode::AppendTextTo(nsAString& aResult)
915 : {
916 8436 : mText.AppendTo(aResult);
917 8436 : }
918 :
919 : already_AddRefed<nsIAtom>
920 0 : nsGenericDOMDataNode::GetCurrentValueAtom()
921 : {
922 0 : nsAutoString val;
923 0 : GetData(val);
924 0 : return NS_NewAtom(val);
925 : }
926 :
927 : nsIAtom*
928 0 : nsGenericDOMDataNode::DoGetID() const
929 : {
930 0 : return nsnull;
931 : }
932 :
933 : const nsAttrValue*
934 0 : nsGenericDOMDataNode::DoGetClasses() const
935 : {
936 0 : NS_NOTREACHED("Shouldn't ever be called");
937 0 : return nsnull;
938 : }
939 :
940 : NS_IMETHODIMP
941 0 : nsGenericDOMDataNode::WalkContentStyleRules(nsRuleWalker* aRuleWalker)
942 : {
943 0 : return NS_OK;
944 : }
945 :
946 : nsIDOMCSSStyleDeclaration*
947 0 : nsGenericDOMDataNode::GetSMILOverrideStyle()
948 : {
949 0 : return nsnull;
950 : }
951 :
952 : css::StyleRule*
953 0 : nsGenericDOMDataNode::GetSMILOverrideStyleRule()
954 : {
955 0 : return nsnull;
956 : }
957 :
958 : nsresult
959 0 : nsGenericDOMDataNode::SetSMILOverrideStyleRule(css::StyleRule* aStyleRule,
960 : bool aNotify)
961 : {
962 0 : NS_NOTREACHED("How come we're setting SMILOverrideStyle on a non-element?");
963 0 : return NS_ERROR_UNEXPECTED;
964 : }
965 :
966 : css::StyleRule*
967 0 : nsGenericDOMDataNode::GetInlineStyleRule()
968 : {
969 0 : return nsnull;
970 : }
971 :
972 : NS_IMETHODIMP
973 0 : nsGenericDOMDataNode::SetInlineStyleRule(css::StyleRule* aStyleRule,
974 : bool aNotify)
975 : {
976 0 : NS_NOTREACHED("How come we're setting inline style on a non-element?");
977 0 : return NS_ERROR_UNEXPECTED;
978 : }
979 :
980 : NS_IMETHODIMP_(bool)
981 0 : nsGenericDOMDataNode::IsAttributeMapped(const nsIAtom* aAttribute) const
982 : {
983 0 : return false;
984 : }
985 :
986 : nsChangeHint
987 0 : nsGenericDOMDataNode::GetAttributeChangeHint(const nsIAtom* aAttribute,
988 : PRInt32 aModType) const
989 : {
990 0 : NS_NOTREACHED("Shouldn't be calling this!");
991 0 : return nsChangeHint(0);
992 : }
993 :
994 : nsIAtom*
995 0 : nsGenericDOMDataNode::GetClassAttributeName() const
996 : {
997 0 : return nsnull;
998 : }
999 :
1000 : size_t
1001 0 : nsGenericDOMDataNode::SizeOfExcludingThis(nsMallocSizeOfFun aMallocSizeOf) const
1002 : {
1003 0 : size_t n = nsIContent::SizeOfExcludingThis(aMallocSizeOf);
1004 0 : n += mText.SizeOfExcludingThis(aMallocSizeOf);
1005 0 : return n;
1006 4392 : }
1007 :
|