content/base/src/nsGenericDOMDataNode.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     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  * Base class for DOM Core's nsIDOMComment, nsIDOMDocumentType, nsIDOMText,
     8  * nsIDOMCDATASection, and nsIDOMProcessingInstruction nodes.
     9  */
    11 #include "mozilla/DebugOnly.h"
    13 #include "nsGenericDOMDataNode.h"
    14 #include "mozilla/AsyncEventDispatcher.h"
    15 #include "mozilla/MemoryReporting.h"
    16 #include "mozilla/dom/Element.h"
    17 #include "mozilla/dom/ShadowRoot.h"
    18 #include "nsIDocument.h"
    19 #include "nsIDOMDocument.h"
    20 #include "nsReadableUtils.h"
    21 #include "mozilla/InternalMutationEvent.h"
    22 #include "nsIURI.h"
    23 #include "nsIDOMEvent.h"
    24 #include "nsIDOMText.h"
    25 #include "nsCOMPtr.h"
    26 #include "nsDOMString.h"
    27 #include "nsIDOMUserDataHandler.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"
    36 #include "pldhash.h"
    37 #include "prprf.h"
    38 #include "nsWrapperCacheInlines.h"
    40 using namespace mozilla;
    41 using namespace mozilla::dom;
    43 nsGenericDOMDataNode::nsGenericDOMDataNode(already_AddRefed<nsINodeInfo>& aNodeInfo)
    44   : nsIContent(aNodeInfo)
    45 {
    46   NS_ABORT_IF_FALSE(mNodeInfo->NodeType() == nsIDOMNode::TEXT_NODE ||
    47                     mNodeInfo->NodeType() == nsIDOMNode::CDATA_SECTION_NODE ||
    48                     mNodeInfo->NodeType() == nsIDOMNode::COMMENT_NODE ||
    49                     mNodeInfo->NodeType() ==
    50                       nsIDOMNode::PROCESSING_INSTRUCTION_NODE ||
    51                     mNodeInfo->NodeType() == nsIDOMNode::DOCUMENT_TYPE_NODE,
    52                     "Bad NodeType in aNodeInfo");
    53 }
    55 nsGenericDOMDataNode::nsGenericDOMDataNode(already_AddRefed<nsINodeInfo>&& aNodeInfo)
    56   : nsIContent(aNodeInfo)
    57 {
    58   NS_ABORT_IF_FALSE(mNodeInfo->NodeType() == nsIDOMNode::TEXT_NODE ||
    59                     mNodeInfo->NodeType() == nsIDOMNode::CDATA_SECTION_NODE ||
    60                     mNodeInfo->NodeType() == nsIDOMNode::COMMENT_NODE ||
    61                     mNodeInfo->NodeType() ==
    62                       nsIDOMNode::PROCESSING_INSTRUCTION_NODE ||
    63                     mNodeInfo->NodeType() == nsIDOMNode::DOCUMENT_TYPE_NODE,
    64                     "Bad NodeType in aNodeInfo");
    65 }
    67 nsGenericDOMDataNode::~nsGenericDOMDataNode()
    68 {
    69   NS_PRECONDITION(!IsInDoc(),
    70                   "Please remove this from the document properly");
    71   if (GetParent()) {
    72     NS_RELEASE(mParent);
    73   }
    74 }
    76 NS_IMPL_CYCLE_COLLECTION_CLASS(nsGenericDOMDataNode)
    78 NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(nsGenericDOMDataNode)
    80 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(nsGenericDOMDataNode)
    81   return Element::CanSkip(tmp, aRemovingAllowed);
    82 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END
    84 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(nsGenericDOMDataNode)
    85   return Element::CanSkipInCC(tmp);
    86 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_END
    88 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN(nsGenericDOMDataNode)
    89   return Element::CanSkipThis(tmp);
    90 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END
    92 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsGenericDOMDataNode)
    93   // Always need to traverse script objects, so do that before we check
    94   // if we're uncollectable.
    95   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
    97   if (!nsINode::Traverse(tmp, cb)) {
    98     return NS_SUCCESS_INTERRUPTED_TRAVERSE;
    99   }
   101   nsDataSlots *slots = tmp->GetExistingDataSlots();
   102   if (slots) {
   103     slots->Traverse(cb);
   104   }
   106   tmp->OwnerDoc()->BindingManager()->Traverse(tmp, cb);
   107 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
   109 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsGenericDOMDataNode)
   110   nsINode::Unlink(tmp);
   112   nsDataSlots *slots = tmp->GetExistingDataSlots();
   113   if (slots) {
   114     slots->Unlink();
   115   }
   116 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
   118 NS_INTERFACE_MAP_BEGIN(nsGenericDOMDataNode)
   119   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   120   NS_INTERFACE_MAP_ENTRIES_CYCLE_COLLECTION(nsGenericDOMDataNode)
   121   NS_INTERFACE_MAP_ENTRY(nsIContent)
   122   NS_INTERFACE_MAP_ENTRY(nsINode)
   123   NS_INTERFACE_MAP_ENTRY(nsIDOMEventTarget)
   124   NS_INTERFACE_MAP_ENTRY(mozilla::dom::EventTarget)
   125   NS_INTERFACE_MAP_ENTRY_TEAROFF(nsISupportsWeakReference,
   126                                  new nsNodeSupportsWeakRefTearoff(this))
   127   NS_INTERFACE_MAP_ENTRY_TEAROFF(nsIDOMXPathNSResolver,
   128                                  new nsNode3Tearoff(this))
   129   // DOM bindings depend on the identity pointer being the
   130   // same as nsINode (which nsIContent inherits).
   131   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIContent)
   132 NS_INTERFACE_MAP_END
   134 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsGenericDOMDataNode)
   135 NS_IMPL_CYCLE_COLLECTING_RELEASE_WITH_LAST_RELEASE(nsGenericDOMDataNode,
   136                                                    nsNodeUtils::LastRelease(this))
   139 void
   140 nsGenericDOMDataNode::GetNodeValueInternal(nsAString& aNodeValue)
   141 {
   142   DebugOnly<nsresult> rv = GetData(aNodeValue);
   143   NS_ASSERTION(NS_SUCCEEDED(rv), "GetData() failed!");
   144 }
   146 void
   147 nsGenericDOMDataNode::SetNodeValueInternal(const nsAString& aNodeValue,
   148                                            ErrorResult& aError)
   149 {
   150   aError = SetTextInternal(0, mText.GetLength(), aNodeValue.BeginReading(),
   151                            aNodeValue.Length(), true);
   152 }
   154 //----------------------------------------------------------------------
   156 // Implementation of nsIDOMCharacterData
   158 nsresult
   159 nsGenericDOMDataNode::GetData(nsAString& aData) const
   160 {
   161   if (mText.Is2b()) {
   162     aData.Assign(mText.Get2b(), mText.GetLength());
   163   } else {
   164     // Must use Substring() since nsDependentCString() requires null
   165     // terminated strings.
   167     const char *data = mText.Get1b();
   169     if (data) {
   170       CopyASCIItoUTF16(Substring(data, data + mText.GetLength()), aData);
   171     } else {
   172       aData.Truncate();
   173     }
   174   }
   176   return NS_OK;
   177 }
   179 nsresult
   180 nsGenericDOMDataNode::SetData(const nsAString& aData)
   181 {
   182   return SetTextInternal(0, mText.GetLength(), aData.BeginReading(),
   183                          aData.Length(), true);
   184 }
   186 nsresult
   187 nsGenericDOMDataNode::GetLength(uint32_t* aLength)
   188 {
   189   *aLength = mText.GetLength();
   190   return NS_OK;
   191 }
   193 nsresult
   194 nsGenericDOMDataNode::SubstringData(uint32_t aStart, uint32_t aCount,
   195                                     nsAString& aReturn)
   196 {
   197   ErrorResult rv;
   198   SubstringData(aStart, aCount, aReturn, rv);
   199   return rv.ErrorCode();
   200 }
   202 void
   203 nsGenericDOMDataNode::SubstringData(uint32_t aStart, uint32_t aCount,
   204                                     nsAString& aReturn, ErrorResult& rv)
   205 {
   206   aReturn.Truncate();
   208   uint32_t textLength = mText.GetLength();
   209   if (aStart > textLength) {
   210     rv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
   211     return;
   212   }
   214   uint32_t amount = aCount;
   215   if (amount > textLength - aStart) {
   216     amount = textLength - aStart;
   217   }
   219   if (mText.Is2b()) {
   220     aReturn.Assign(mText.Get2b() + aStart, amount);
   221   } else {
   222     // Must use Substring() since nsDependentCString() requires null
   223     // terminated strings.
   225     const char *data = mText.Get1b() + aStart;
   226     CopyASCIItoUTF16(Substring(data, data + amount), aReturn);
   227   }
   228 }
   230 NS_IMETHODIMP
   231 nsGenericDOMDataNode::MozRemove()
   232 {
   233   Remove();
   234   return NS_OK;
   235 }
   237 //----------------------------------------------------------------------
   239 nsresult
   240 nsGenericDOMDataNode::AppendData(const nsAString& aData)
   241 {
   242   return SetTextInternal(mText.GetLength(), 0, aData.BeginReading(),
   243                          aData.Length(), true);
   244 }
   246 nsresult
   247 nsGenericDOMDataNode::InsertData(uint32_t aOffset,
   248                                  const nsAString& aData)
   249 {
   250   return SetTextInternal(aOffset, 0, aData.BeginReading(),
   251                          aData.Length(), true);
   252 }
   254 nsresult
   255 nsGenericDOMDataNode::DeleteData(uint32_t aOffset, uint32_t aCount)
   256 {
   257   return SetTextInternal(aOffset, aCount, nullptr, 0, true);
   258 }
   260 nsresult
   261 nsGenericDOMDataNode::ReplaceData(uint32_t aOffset, uint32_t aCount,
   262                                   const nsAString& aData)
   263 {
   264   return SetTextInternal(aOffset, aCount, aData.BeginReading(),
   265                          aData.Length(), true);
   266 }
   268 nsresult
   269 nsGenericDOMDataNode::SetTextInternal(uint32_t aOffset, uint32_t aCount,
   270                                       const char16_t* aBuffer,
   271                                       uint32_t aLength, bool aNotify,
   272                                       CharacterDataChangeInfo::Details* aDetails)
   273 {
   274   NS_PRECONDITION(aBuffer || !aLength,
   275                   "Null buffer passed to SetTextInternal!");
   277   // sanitize arguments
   278   uint32_t textLength = mText.GetLength();
   279   if (aOffset > textLength) {
   280     return NS_ERROR_DOM_INDEX_SIZE_ERR;
   281   }
   283   if (aCount > textLength - aOffset) {
   284     aCount = textLength - aOffset;
   285   }
   287   uint32_t endOffset = aOffset + aCount;
   289   // Make sure the text fragment can hold the new data.
   290   if (aLength > aCount && !mText.CanGrowBy(aLength - aCount)) {
   291     return NS_ERROR_OUT_OF_MEMORY;
   292   }
   294   nsIDocument *document = GetCurrentDoc();
   295   mozAutoDocUpdate updateBatch(document, UPDATE_CONTENT_MODEL, aNotify);
   297   bool haveMutationListeners = aNotify &&
   298     nsContentUtils::HasMutationListeners(this,
   299       NS_EVENT_BITS_MUTATION_CHARACTERDATAMODIFIED,
   300       this);
   302   nsCOMPtr<nsIAtom> oldValue;
   303   if (haveMutationListeners) {
   304     oldValue = GetCurrentValueAtom();
   305   }
   307   if (aNotify) {
   308     CharacterDataChangeInfo info = {
   309       aOffset == textLength,
   310       aOffset,
   311       endOffset,
   312       aLength,
   313       aDetails
   314     };
   315     nsNodeUtils::CharacterDataWillChange(this, &info);
   316   }
   318   Directionality oldDir = eDir_NotSet;
   319   bool dirAffectsAncestor = (NodeType() == nsIDOMNode::TEXT_NODE &&
   320                              TextNodeWillChangeDirection(this, &oldDir, aOffset));
   322   if (aOffset == 0 && endOffset == textLength) {
   323     // Replacing whole text or old text was empty.  Don't bother to check for
   324     // bidi in this string if the document already has bidi enabled.
   325     bool ok = mText.SetTo(aBuffer, aLength, !document || !document->GetBidiEnabled());
   326     NS_ENSURE_TRUE(ok, NS_ERROR_OUT_OF_MEMORY);
   327   }
   328   else if (aOffset == textLength) {
   329     // Appending to existing
   330     bool ok = mText.Append(aBuffer, aLength, !document || !document->GetBidiEnabled());
   331     NS_ENSURE_TRUE(ok, NS_ERROR_OUT_OF_MEMORY);
   332   }
   333   else {
   334     // Merging old and new
   336     // Allocate new buffer
   337     int32_t newLength = textLength - aCount + aLength;
   338     char16_t* to = new char16_t[newLength];
   339     NS_ENSURE_TRUE(to, NS_ERROR_OUT_OF_MEMORY);
   341     // Copy over appropriate data
   342     if (aOffset) {
   343       mText.CopyTo(to, 0, aOffset);
   344     }
   345     if (aLength) {
   346       memcpy(to + aOffset, aBuffer, aLength * sizeof(char16_t));
   347     }
   348     if (endOffset != textLength) {
   349       mText.CopyTo(to + aOffset + aLength, endOffset, textLength - endOffset);
   350     }
   352     bool ok = mText.SetTo(to, newLength, !document || !document->GetBidiEnabled());
   354     delete [] to;
   356     NS_ENSURE_TRUE(ok, NS_ERROR_OUT_OF_MEMORY);
   357   }
   359   UnsetFlags(NS_CACHED_TEXT_IS_ONLY_WHITESPACE);
   361   if (document && mText.IsBidi()) {
   362     // If we found bidi characters in mText.SetTo() above, indicate that the
   363     // document contains bidi characters.
   364     document->SetBidiEnabled();
   365   }
   367   if (dirAffectsAncestor) {
   368     TextNodeChangedDirection(this, oldDir, aNotify);
   369   }
   371   // Notify observers
   372   if (aNotify) {
   373     CharacterDataChangeInfo info = {
   374       aOffset == textLength,
   375       aOffset,
   376       endOffset,
   377       aLength,
   378       aDetails
   379     };
   380     nsNodeUtils::CharacterDataChanged(this, &info);
   382     if (haveMutationListeners) {
   383       InternalMutationEvent mutation(true, NS_MUTATION_CHARACTERDATAMODIFIED);
   385       mutation.mPrevAttrValue = oldValue;
   386       if (aLength > 0) {
   387         nsAutoString val;
   388         mText.AppendTo(val);
   389         mutation.mNewAttrValue = do_GetAtom(val);
   390       }
   392       mozAutoSubtreeModified subtree(OwnerDoc(), this);
   393       (new AsyncEventDispatcher(this, mutation))->RunDOMEventWhenSafe();
   394     }
   395   }
   397   return NS_OK;
   398 }
   400 //----------------------------------------------------------------------
   402 // Implementation of nsIContent
   404 #ifdef DEBUG
   405 void
   406 nsGenericDOMDataNode::ToCString(nsAString& aBuf, int32_t aOffset,
   407                                 int32_t aLen) const
   408 {
   409   if (mText.Is2b()) {
   410     const char16_t* cp = mText.Get2b() + aOffset;
   411     const char16_t* end = cp + aLen;
   413     while (cp < end) {
   414       char16_t ch = *cp++;
   415       if (ch == '&') {
   416         aBuf.AppendLiteral("&amp;");
   417       } else if (ch == '<') {
   418         aBuf.AppendLiteral("&lt;");
   419       } else if (ch == '>') {
   420         aBuf.AppendLiteral("&gt;");
   421       } else if ((ch < ' ') || (ch >= 127)) {
   422         char buf[10];
   423         PR_snprintf(buf, sizeof(buf), "\\u%04x", ch);
   424         AppendASCIItoUTF16(buf, aBuf);
   425       } else {
   426         aBuf.Append(ch);
   427       }
   428     }
   429   } else {
   430     unsigned char* cp = (unsigned char*)mText.Get1b() + aOffset;
   431     const unsigned char* end = cp + aLen;
   433     while (cp < end) {
   434       char16_t ch = *cp++;
   435       if (ch == '&') {
   436         aBuf.AppendLiteral("&amp;");
   437       } else if (ch == '<') {
   438         aBuf.AppendLiteral("&lt;");
   439       } else if (ch == '>') {
   440         aBuf.AppendLiteral("&gt;");
   441       } else if ((ch < ' ') || (ch >= 127)) {
   442         char buf[10];
   443         PR_snprintf(buf, sizeof(buf), "\\u%04x", ch);
   444         AppendASCIItoUTF16(buf, aBuf);
   445       } else {
   446         aBuf.Append(ch);
   447       }
   448     }
   449   }
   450 }
   451 #endif
   454 nsresult
   455 nsGenericDOMDataNode::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
   456                                  nsIContent* aBindingParent,
   457                                  bool aCompileEventHandlers)
   458 {
   459   NS_PRECONDITION(aParent || aDocument, "Must have document if no parent!");
   460   NS_PRECONDITION(NODE_FROM(aParent, aDocument)->OwnerDoc() == OwnerDoc(),
   461                   "Must have the same owner document");
   462   NS_PRECONDITION(!aParent || aDocument == aParent->GetCurrentDoc(),
   463                   "aDocument must be current doc of aParent");
   464   NS_PRECONDITION(!GetCurrentDoc() && !IsInDoc(),
   465                   "Already have a document.  Unbind first!");
   466   // Note that as we recurse into the kids, they'll have a non-null parent.  So
   467   // only assert if our parent is _changing_ while we have a parent.
   468   NS_PRECONDITION(!GetParent() || aParent == GetParent(),
   469                   "Already have a parent.  Unbind first!");
   470   NS_PRECONDITION(!GetBindingParent() ||
   471                   aBindingParent == GetBindingParent() ||
   472                   (!aBindingParent && aParent &&
   473                    aParent->GetBindingParent() == GetBindingParent()),
   474                   "Already have a binding parent.  Unbind first!");
   475   NS_PRECONDITION(aBindingParent != this,
   476                   "Content must not be its own binding parent");
   477   NS_PRECONDITION(!IsRootOfNativeAnonymousSubtree() || 
   478                   aBindingParent == aParent,
   479                   "Native anonymous content must have its parent as its "
   480                   "own binding parent");
   482   if (!aBindingParent && aParent) {
   483     aBindingParent = aParent->GetBindingParent();
   484   }
   486   // First set the binding parent
   487   if (aBindingParent) {
   488     NS_ASSERTION(IsRootOfNativeAnonymousSubtree() ||
   489                  !HasFlag(NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE) ||
   490                  (aParent && aParent->IsInNativeAnonymousSubtree()),
   491                  "Trying to re-bind content from native anonymous subtree to "
   492                  "non-native anonymous parent!");
   493     DataSlots()->mBindingParent = aBindingParent; // Weak, so no addref happens.
   494     if (aParent->IsInNativeAnonymousSubtree()) {
   495       SetFlags(NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE);
   496     }
   497     if (aParent->HasFlag(NODE_CHROME_ONLY_ACCESS)) {
   498       SetFlags(NODE_CHROME_ONLY_ACCESS);
   499     }
   500     if (aParent->HasFlag(NODE_IS_IN_SHADOW_TREE)) {
   501       SetFlags(NODE_IS_IN_SHADOW_TREE);
   502     }
   503     ShadowRoot* parentContainingShadow = aParent->GetContainingShadow();
   504     if (parentContainingShadow) {
   505       DataSlots()->mContainingShadow = parentContainingShadow;
   506     }
   507   }
   509   // Set parent
   510   if (aParent) {
   511     if (!GetParent()) {
   512       NS_ADDREF(aParent);
   513     }
   514     mParent = aParent;
   515   }
   516   else {
   517     mParent = aDocument;
   518   }
   519   SetParentIsContent(aParent);
   521   // XXXbz sXBL/XBL2 issue!
   523   // Set document
   524   if (aDocument) {
   525     // We no longer need to track the subtree pointer (and in fact we'll assert
   526     // if we do this any later).
   527     ClearSubtreeRootPointer();
   529     // XXX See the comment in Element::BindToTree
   530     SetInDocument();
   531     if (mText.IsBidi()) {
   532       aDocument->SetBidiEnabled();
   533     }
   534     // Clear the lazy frame construction bits.
   535     UnsetFlags(NODE_NEEDS_FRAME | NODE_DESCENDANTS_NEED_FRAMES);
   536   } else {
   537     // If we're not in the doc, update our subtree pointer.
   538     SetSubtreeRootPointer(aParent->SubtreeRoot());
   539   }
   541   nsNodeUtils::ParentChainChanged(this);
   543   UpdateEditableState(false);
   545   NS_POSTCONDITION(aDocument == GetCurrentDoc(), "Bound to wrong document");
   546   NS_POSTCONDITION(aParent == GetParent(), "Bound to wrong parent");
   547   NS_POSTCONDITION(aBindingParent == GetBindingParent(),
   548                    "Bound to wrong binding parent");
   550   return NS_OK;
   551 }
   553 void
   554 nsGenericDOMDataNode::UnbindFromTree(bool aDeep, bool aNullParent)
   555 {
   556   // Unset frame flags; if we need them again later, they'll get set again.
   557   UnsetFlags(NS_CREATE_FRAME_IF_NON_WHITESPACE |
   558              NS_REFRAME_IF_WHITESPACE |
   559              // Also unset the shadow tree flag because it can
   560              // no longer be a descendant of a ShadowRoot.
   561              NODE_IS_IN_SHADOW_TREE);
   563   nsIDocument *document = GetCurrentDoc();
   564   if (document) {
   565     // Notify XBL- & nsIAnonymousContentCreator-generated
   566     // anonymous content that the document is changing.
   567     // This is needed to update the insertion point.
   568     document->BindingManager()->RemovedFromDocument(this, document);
   569   }
   571   if (aNullParent) {
   572     if (GetParent()) {
   573       NS_RELEASE(mParent);
   574     } else {
   575       mParent = nullptr;
   576     }
   577     SetParentIsContent(false);
   578   }
   579   ClearInDocument();
   581   // Begin keeping track of our subtree root.
   582   SetSubtreeRootPointer(aNullParent ? this : mParent->SubtreeRoot());
   584   nsDataSlots *slots = GetExistingDataSlots();
   585   if (slots) {
   586     slots->mBindingParent = nullptr;
   587     slots->mContainingShadow = nullptr;
   588   }
   590   nsNodeUtils::ParentChainChanged(this);
   591 }
   593 already_AddRefed<nsINodeList>
   594 nsGenericDOMDataNode::GetChildren(uint32_t aFilter)
   595 {
   596   return nullptr;
   597 }
   599 nsIAtom *
   600 nsGenericDOMDataNode::GetIDAttributeName() const
   601 {
   602   return nullptr;
   603 }
   605 nsresult
   606 nsGenericDOMDataNode::SetAttr(int32_t aNameSpaceID, nsIAtom* aAttr,
   607                               nsIAtom* aPrefix, const nsAString& aValue,
   608                               bool aNotify)
   609 {
   610   return NS_OK;
   611 }
   613 nsresult
   614 nsGenericDOMDataNode::UnsetAttr(int32_t aNameSpaceID, nsIAtom* aAttr,
   615                                 bool aNotify)
   616 {
   617   return NS_OK;
   618 }
   620 const nsAttrName*
   621 nsGenericDOMDataNode::GetAttrNameAt(uint32_t aIndex) const
   622 {
   623   return nullptr;
   624 }
   626 uint32_t
   627 nsGenericDOMDataNode::GetAttrCount() const
   628 {
   629   return 0;
   630 }
   632 uint32_t
   633 nsGenericDOMDataNode::GetChildCount() const
   634 {
   635   return 0;
   636 }
   638 nsIContent *
   639 nsGenericDOMDataNode::GetChildAt(uint32_t aIndex) const
   640 {
   641   return nullptr;
   642 }
   644 nsIContent * const *
   645 nsGenericDOMDataNode::GetChildArray(uint32_t* aChildCount) const
   646 {
   647   *aChildCount = 0;
   648   return nullptr;
   649 }
   651 int32_t
   652 nsGenericDOMDataNode::IndexOf(const nsINode* aPossibleChild) const
   653 {
   654   return -1;
   655 }
   657 nsresult
   658 nsGenericDOMDataNode::InsertChildAt(nsIContent* aKid, uint32_t aIndex,
   659                                     bool aNotify)
   660 {
   661   return NS_OK;
   662 }
   664 void
   665 nsGenericDOMDataNode::RemoveChildAt(uint32_t aIndex, bool aNotify)
   666 {
   667 }
   669 nsIContent *
   670 nsGenericDOMDataNode::GetBindingParent() const
   671 {
   672   nsDataSlots *slots = GetExistingDataSlots();
   673   return slots ? slots->mBindingParent : nullptr;
   674 }
   676 ShadowRoot *
   677 nsGenericDOMDataNode::GetShadowRoot() const
   678 {
   679   return nullptr;
   680 }
   682 ShadowRoot *
   683 nsGenericDOMDataNode::GetContainingShadow() const
   684 {
   685   nsDataSlots *slots = GetExistingDataSlots();
   686   return slots ? slots->mContainingShadow : nullptr;
   687 }
   689 void
   690 nsGenericDOMDataNode::SetShadowRoot(ShadowRoot* aShadowRoot)
   691 {
   692 }
   694 nsXBLBinding *
   695 nsGenericDOMDataNode::GetXBLBinding() const
   696 {
   697   return nullptr;
   698 }
   700 void
   701 nsGenericDOMDataNode::SetXBLBinding(nsXBLBinding* aBinding,
   702                                     nsBindingManager* aOldBindingManager)
   703 {
   704 }
   706 nsIContent *
   707 nsGenericDOMDataNode::GetXBLInsertionParent() const
   708 {
   709   if (HasFlag(NODE_MAY_BE_IN_BINDING_MNGR)) {
   710     nsDataSlots *slots = GetExistingDataSlots();
   711     if (slots) {
   712       return slots->mXBLInsertionParent;
   713     }
   714   }
   716   return nullptr;
   717 }
   719 void
   720 nsGenericDOMDataNode::SetXBLInsertionParent(nsIContent* aContent)
   721 {
   722   nsDataSlots *slots = DataSlots();
   723   if (aContent) {
   724     SetFlags(NODE_MAY_BE_IN_BINDING_MNGR);
   725   }
   726   slots->mXBLInsertionParent = aContent;
   727 }
   729 CustomElementData *
   730 nsGenericDOMDataNode::GetCustomElementData() const
   731 {
   732   return nullptr;
   733 }
   735 void
   736 nsGenericDOMDataNode::SetCustomElementData(CustomElementData* aData)
   737 {
   738 }
   740 bool
   741 nsGenericDOMDataNode::IsNodeOfType(uint32_t aFlags) const
   742 {
   743   return !(aFlags & ~(eCONTENT | eDATA_NODE));
   744 }
   746 void
   747 nsGenericDOMDataNode::SaveSubtreeState()
   748 {
   749 }
   751 void
   752 nsGenericDOMDataNode::DestroyContent()
   753 {
   754   // XXX We really should let cycle collection do this, but that currently still
   755   //     leaks (see https://bugzilla.mozilla.org/show_bug.cgi?id=406684).
   756   ReleaseWrapper(this);
   757 }
   759 #ifdef DEBUG
   760 void
   761 nsGenericDOMDataNode::List(FILE* out, int32_t aIndent) const
   762 {
   763 }
   765 void
   766 nsGenericDOMDataNode::DumpContent(FILE* out, int32_t aIndent,
   767                                   bool aDumpAll) const 
   768 {
   769 }
   770 #endif
   772 bool
   773 nsGenericDOMDataNode::IsLink(nsIURI** aURI) const
   774 {
   775   *aURI = nullptr;
   776   return false;
   777 }
   779 nsINode::nsSlots*
   780 nsGenericDOMDataNode::CreateSlots()
   781 {
   782   return new nsDataSlots();
   783 }
   785 nsGenericDOMDataNode::nsDataSlots::nsDataSlots()
   786   : nsINode::nsSlots(), mBindingParent(nullptr)
   787 {
   788 }
   790 void
   791 nsGenericDOMDataNode::nsDataSlots::Traverse(nsCycleCollectionTraversalCallback &cb)
   792 {
   793   NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mSlots->mXBLInsertionParent");
   794   cb.NoteXPCOMChild(mXBLInsertionParent.get());
   796   NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mSlots->mContainingShadow");
   797   cb.NoteXPCOMChild(NS_ISUPPORTS_CAST(nsIContent*, mContainingShadow));
   798 }
   800 void
   801 nsGenericDOMDataNode::nsDataSlots::Unlink()
   802 {
   803   mXBLInsertionParent = nullptr;
   804   mContainingShadow = nullptr;
   805 }
   807 //----------------------------------------------------------------------
   809 // Implementation of the nsIDOMText interface
   811 nsresult
   812 nsGenericDOMDataNode::SplitData(uint32_t aOffset, nsIContent** aReturn,
   813                                 bool aCloneAfterOriginal)
   814 {
   815   *aReturn = nullptr;
   816   nsresult rv = NS_OK;
   817   nsAutoString cutText;
   818   uint32_t length = TextLength();
   820   if (aOffset > length) {
   821     return NS_ERROR_DOM_INDEX_SIZE_ERR;
   822   }
   824   uint32_t cutStartOffset = aCloneAfterOriginal ? aOffset : 0;
   825   uint32_t cutLength = aCloneAfterOriginal ? length - aOffset : aOffset;
   826   rv = SubstringData(cutStartOffset, cutLength, cutText);
   827   if (NS_FAILED(rv)) {
   828     return rv;
   829   }
   831   nsIDocument* document = GetCurrentDoc();
   832   mozAutoDocUpdate updateBatch(document, UPDATE_CONTENT_MODEL, true);
   834   // Use Clone for creating the new node so that the new node is of same class
   835   // as this node!
   836   nsCOMPtr<nsIContent> newContent = CloneDataNode(mNodeInfo, false);
   837   if (!newContent) {
   838     return NS_ERROR_OUT_OF_MEMORY;
   839   }
   840   newContent->SetText(cutText, true); // XXX should be false?
   842   CharacterDataChangeInfo::Details details = {
   843     CharacterDataChangeInfo::Details::eSplit, newContent
   844   };
   845   rv = SetTextInternal(cutStartOffset, cutLength, nullptr, 0, true,
   846                        aCloneAfterOriginal ? &details : nullptr);
   847   if (NS_FAILED(rv)) {
   848     return rv;
   849   }
   851   nsCOMPtr<nsINode> parent = GetParentNode();
   852   if (parent) {
   853     int32_t insertionIndex = parent->IndexOf(this);
   854     if (aCloneAfterOriginal) {
   855       ++insertionIndex;
   856     }
   857     parent->InsertChildAt(newContent, insertionIndex, true);
   858   }
   860   newContent.swap(*aReturn);
   861   return rv;
   862 }
   864 nsresult
   865 nsGenericDOMDataNode::SplitText(uint32_t aOffset, nsIDOMText** aReturn)
   866 {
   867   nsCOMPtr<nsIContent> newChild;
   868   nsresult rv = SplitData(aOffset, getter_AddRefs(newChild));
   869   if (NS_SUCCEEDED(rv)) {
   870     rv = CallQueryInterface(newChild, aReturn);
   871   }
   872   return rv;
   873 }
   875 /* static */ int32_t
   876 nsGenericDOMDataNode::FirstLogicallyAdjacentTextNode(nsIContent* aParent,
   877                                                      int32_t aIndex)
   878 {
   879   while (aIndex-- > 0) {
   880     nsIContent* sibling = aParent->GetChildAt(aIndex);
   881     if (!sibling->IsNodeOfType(nsINode::eTEXT))
   882       return aIndex + 1;
   883   }
   884   return 0;
   885 }
   887 /* static */ int32_t
   888 nsGenericDOMDataNode::LastLogicallyAdjacentTextNode(nsIContent* aParent,
   889                                                     int32_t aIndex,
   890                                                     uint32_t aCount)
   891 {
   892   while (++aIndex < int32_t(aCount)) {
   893     nsIContent* sibling = aParent->GetChildAt(aIndex);
   894     if (!sibling->IsNodeOfType(nsINode::eTEXT))
   895       return aIndex - 1;
   896   }
   897   return aCount - 1;
   898 }
   900 nsresult
   901 nsGenericDOMDataNode::GetWholeText(nsAString& aWholeText)
   902 {
   903   nsIContent* parent = GetParent();
   905   // Handle parent-less nodes
   906   if (!parent)
   907     return GetData(aWholeText);
   909   int32_t index = parent->IndexOf(this);
   910   NS_WARN_IF_FALSE(index >= 0,
   911                    "Trying to use .wholeText with an anonymous"
   912                     "text node child of a binding parent?");
   913   NS_ENSURE_TRUE(index >= 0, NS_ERROR_DOM_NOT_SUPPORTED_ERR);
   914   int32_t first =
   915     FirstLogicallyAdjacentTextNode(parent, index);
   916   int32_t last =
   917     LastLogicallyAdjacentTextNode(parent, index, parent->GetChildCount());
   919   aWholeText.Truncate();
   921   nsCOMPtr<nsIDOMText> node;
   922   nsAutoString tmp;
   923   do {
   924     node = do_QueryInterface(parent->GetChildAt(first));
   925     node->GetData(tmp);
   926     aWholeText.Append(tmp);
   927   } while (first++ < last);
   929   return NS_OK;
   930 }
   932 //----------------------------------------------------------------------
   934 // Implementation of the nsIContent interface text functions
   936 const nsTextFragment *
   937 nsGenericDOMDataNode::GetText()
   938 {
   939   return &mText;
   940 }
   942 uint32_t
   943 nsGenericDOMDataNode::TextLength() const
   944 {
   945   return mText.GetLength();
   946 }
   948 nsresult
   949 nsGenericDOMDataNode::SetText(const char16_t* aBuffer,
   950                               uint32_t aLength,
   951                               bool aNotify)
   952 {
   953   return SetTextInternal(0, mText.GetLength(), aBuffer, aLength, aNotify);
   954 }
   956 nsresult
   957 nsGenericDOMDataNode::AppendText(const char16_t* aBuffer,
   958                                  uint32_t aLength,
   959                                  bool aNotify)
   960 {
   961   return SetTextInternal(mText.GetLength(), 0, aBuffer, aLength, aNotify);
   962 }
   964 bool
   965 nsGenericDOMDataNode::TextIsOnlyWhitespace()
   966 {
   967   // FIXME: should this method take content language into account?
   968   if (mText.Is2b()) {
   969     // The fragment contains non-8bit characters and such characters
   970     // are never considered whitespace.
   971     return false;
   972   }
   974   if (HasFlag(NS_CACHED_TEXT_IS_ONLY_WHITESPACE)) {
   975     return HasFlag(NS_TEXT_IS_ONLY_WHITESPACE);
   976   }
   978   const char* cp = mText.Get1b();
   979   const char* end = cp + mText.GetLength();
   981   while (cp < end) {
   982     char ch = *cp;
   984     if (!dom::IsSpaceCharacter(ch)) {
   985       UnsetFlags(NS_TEXT_IS_ONLY_WHITESPACE);
   986       SetFlags(NS_CACHED_TEXT_IS_ONLY_WHITESPACE);
   987       return false;
   988     }
   990     ++cp;
   991   }
   993   SetFlags(NS_CACHED_TEXT_IS_ONLY_WHITESPACE | NS_TEXT_IS_ONLY_WHITESPACE);
   994   return true;
   995 }
   997 bool
   998 nsGenericDOMDataNode::HasTextForTranslation()
   999 {
  1000   if (mText.Is2b()) {
  1001     // The fragment contains non-8bit characters which means there
  1002     // was at least one "interesting" character to trigger non-8bit.
  1003     return true;
  1006   if (HasFlag(NS_CACHED_TEXT_IS_ONLY_WHITESPACE) &&
  1007       HasFlag(NS_TEXT_IS_ONLY_WHITESPACE)) {
  1008     return false;
  1011   const char* cp = mText.Get1b();
  1012   const char* end = cp + mText.GetLength();
  1014   unsigned char ch;
  1015   for (; cp < end; cp++) {
  1016     ch = *cp;
  1018     // These are the characters that are letters
  1019     // in the first 256 UTF-8 codepoints.
  1020     if ((ch >= 'a' && ch <= 'z') ||
  1021        (ch >= 'A' && ch <= 'Z') ||
  1022        (ch >= 192 && ch <= 214) ||
  1023        (ch >= 216 && ch <= 246) ||
  1024        (ch >= 248)) {
  1025       return true;
  1029   return false;
  1032 void
  1033 nsGenericDOMDataNode::AppendTextTo(nsAString& aResult)
  1035   mText.AppendTo(aResult);
  1038 bool
  1039 nsGenericDOMDataNode::AppendTextTo(nsAString& aResult, const mozilla::fallible_t&)
  1041   return mText.AppendTo(aResult, mozilla::fallible_t());
  1044 already_AddRefed<nsIAtom>
  1045 nsGenericDOMDataNode::GetCurrentValueAtom()
  1047   nsAutoString val;
  1048   GetData(val);
  1049   return NS_NewAtom(val);
  1052 nsIAtom*
  1053 nsGenericDOMDataNode::DoGetID() const
  1055   return nullptr;
  1058 const nsAttrValue*
  1059 nsGenericDOMDataNode::DoGetClasses() const
  1061   NS_NOTREACHED("Shouldn't ever be called");
  1062   return nullptr;
  1065 NS_IMETHODIMP
  1066 nsGenericDOMDataNode::WalkContentStyleRules(nsRuleWalker* aRuleWalker)
  1068   return NS_OK;
  1071 NS_IMETHODIMP_(bool)
  1072 nsGenericDOMDataNode::IsAttributeMapped(const nsIAtom* aAttribute) const
  1074   return false;
  1077 nsChangeHint
  1078 nsGenericDOMDataNode::GetAttributeChangeHint(const nsIAtom* aAttribute,
  1079                                              int32_t aModType) const
  1081   NS_NOTREACHED("Shouldn't be calling this!");
  1082   return nsChangeHint(0);
  1085 nsIAtom*
  1086 nsGenericDOMDataNode::GetClassAttributeName() const
  1088   return nullptr;
  1091 size_t
  1092 nsGenericDOMDataNode::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
  1094   size_t n = nsIContent::SizeOfExcludingThis(aMallocSizeOf);
  1095   n += mText.SizeOfExcludingThis(aMallocSizeOf);
  1096   return n;

mercurial