content/base/src/FragmentOrElement.cpp

Thu, 15 Jan 2015 21:03:48 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 15 Jan 2015 21:03:48 +0100
branch
TOR_BUG_9701
changeset 11
deefc01c0e14
permissions
-rw-r--r--

Integrate friendly tips from Tor colleagues to make (or not) 4.5 alpha 3;
This includes removal of overloaded (but unused) methods, and addition of
a overlooked call to DataStruct::SetData(nsISupports, uint32_t, bool.)

     1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* vim: set ts=2 sw=2 et tw=79: */
     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 all element classes; this provides an implementation
     9  * of DOM Core's nsIDOMElement, implements nsIContent, provides
    10  * utility methods for subclasses, and so forth.
    11  */
    13 #include "mozilla/ArrayUtils.h"
    14 #include "mozilla/Likely.h"
    15 #include "mozilla/MemoryReporting.h"
    16 #include "mozilla/StaticPtr.h"
    18 #include "mozilla/dom/FragmentOrElement.h"
    20 #include "mozilla/AsyncEventDispatcher.h"
    21 #include "mozilla/EventDispatcher.h"
    22 #include "mozilla/EventListenerManager.h"
    23 #include "mozilla/EventStates.h"
    24 #include "mozilla/dom/Attr.h"
    25 #include "nsDOMAttributeMap.h"
    26 #include "nsIAtom.h"
    27 #include "nsINodeInfo.h"
    28 #include "nsIDocumentInlines.h"
    29 #include "nsIDocumentEncoder.h"
    30 #include "nsIDOMNodeList.h"
    31 #include "nsIContentIterator.h"
    32 #include "nsFocusManager.h"
    33 #include "nsILinkHandler.h"
    34 #include "nsIScriptGlobalObject.h"
    35 #include "nsIURL.h"
    36 #include "nsNetUtil.h"
    37 #include "nsIFrame.h"
    38 #include "nsIAnonymousContentCreator.h"
    39 #include "nsIPresShell.h"
    40 #include "nsPresContext.h"
    41 #include "nsStyleConsts.h"
    42 #include "nsString.h"
    43 #include "nsUnicharUtils.h"
    44 #include "nsIDOMEvent.h"
    45 #include "nsDOMCID.h"
    46 #include "nsIServiceManager.h"
    47 #include "nsIDOMCSSStyleDeclaration.h"
    48 #include "nsDOMCSSAttrDeclaration.h"
    49 #include "nsNameSpaceManager.h"
    50 #include "nsContentList.h"
    51 #include "nsDOMTokenList.h"
    52 #include "nsXBLPrototypeBinding.h"
    53 #include "nsError.h"
    54 #include "nsDOMString.h"
    55 #include "nsIScriptSecurityManager.h"
    56 #include "nsIDOMMutationEvent.h"
    57 #include "mozilla/InternalMutationEvent.h"
    58 #include "mozilla/MouseEvents.h"
    59 #include "nsNodeUtils.h"
    60 #include "nsDocument.h"
    61 #include "nsAttrValueOrString.h"
    62 #ifdef MOZ_XUL
    63 #include "nsXULElement.h"
    64 #endif /* MOZ_XUL */
    65 #include "nsFrameManager.h"
    66 #include "nsFrameSelection.h"
    67 #ifdef DEBUG
    68 #include "nsRange.h"
    69 #endif
    71 #include "nsBindingManager.h"
    72 #include "nsXBLBinding.h"
    73 #include "nsPIDOMWindow.h"
    74 #include "nsPIBoxObject.h"
    75 #include "nsSVGUtils.h"
    76 #include "nsLayoutUtils.h"
    77 #include "nsGkAtoms.h"
    78 #include "nsContentUtils.h"
    79 #include "nsTextFragment.h"
    80 #include "nsContentCID.h"
    82 #include "nsIDOMEventListener.h"
    83 #include "nsIWebNavigation.h"
    84 #include "nsIBaseWindow.h"
    85 #include "nsIWidget.h"
    87 #include "js/GCAPI.h"
    89 #include "nsNodeInfoManager.h"
    90 #include "nsICategoryManager.h"
    91 #include "nsIDOMUserDataHandler.h"
    92 #include "nsGenericHTMLElement.h"
    93 #include "nsIEditor.h"
    94 #include "nsIEditorIMESupport.h"
    95 #include "nsContentCreatorFunctions.h"
    96 #include "nsIControllers.h"
    97 #include "nsView.h"
    98 #include "nsViewManager.h"
    99 #include "nsIScrollableFrame.h"
   100 #include "ChildIterator.h"
   101 #include "mozilla/css/StyleRule.h" /* For nsCSSSelectorList */
   102 #include "nsRuleProcessorData.h"
   103 #include "nsTextNode.h"
   104 #include "mozilla/dom/NodeListBinding.h"
   105 #include "mozilla/dom/UndoManager.h"
   107 #ifdef MOZ_XUL
   108 #include "nsIXULDocument.h"
   109 #endif /* MOZ_XUL */
   111 #include "nsCCUncollectableMarker.h"
   113 #include "mozAutoDocUpdate.h"
   115 #include "prprf.h"
   116 #include "nsDOMMutationObserver.h"
   117 #include "nsWrapperCacheInlines.h"
   118 #include "nsCycleCollector.h"
   119 #include "xpcpublic.h"
   120 #include "nsIScriptError.h"
   121 #include "mozilla/Telemetry.h"
   123 #include "mozilla/CORSMode.h"
   125 #include "mozilla/dom/ShadowRoot.h"
   126 #include "mozilla/dom/HTMLTemplateElement.h"
   128 #include "nsStyledElement.h"
   129 #include "nsIContentInlines.h"
   131 using namespace mozilla;
   132 using namespace mozilla::dom;
   134 int32_t nsIContent::sTabFocusModel = eTabFocus_any;
   135 bool nsIContent::sTabFocusModelAppliesToXUL = false;
   136 uint32_t nsMutationGuard::sMutationCount = 0;
   138 nsIContent*
   139 nsIContent::FindFirstNonChromeOnlyAccessContent() const
   140 {
   141   // This handles also nested native anonymous content.
   142   for (const nsIContent *content = this; content;
   143        content = content->GetBindingParent()) {
   144     if (!content->ChromeOnlyAccess()) {
   145       // Oops, this function signature allows casting const to
   146       // non-const.  (Then again, so does GetChildAt(0)->GetParent().)
   147       return const_cast<nsIContent*>(content);
   148     }
   149   }
   150   return nullptr;
   151 }
   153 nsIContent*
   154 nsIContent::GetFlattenedTreeParent() const
   155 {
   156   if (HasFlag(NODE_MAY_BE_IN_BINDING_MNGR)) {
   157     nsIContent* parent = GetXBLInsertionParent();
   158     if (parent) {
   159       return parent;
   160     }
   161   }
   163   return GetParent();
   164 }
   166 nsIContent::IMEState
   167 nsIContent::GetDesiredIMEState()
   168 {
   169   if (!IsEditableInternal()) {
   170     // Check for the special case where we're dealing with elements which don't
   171     // have the editable flag set, but are readwrite (such as text controls).
   172     if (!IsElement() ||
   173         !AsElement()->State().HasState(NS_EVENT_STATE_MOZ_READWRITE)) {
   174       return IMEState(IMEState::DISABLED);
   175     }
   176   }
   177   // NOTE: The content for independent editors (e.g., input[type=text],
   178   // textarea) must override this method, so, we don't need to worry about
   179   // that here.
   180   nsIContent *editableAncestor = GetEditingHost();
   182   // This is in another editable content, use the result of it.
   183   if (editableAncestor && editableAncestor != this) {
   184     return editableAncestor->GetDesiredIMEState();
   185   }
   186   nsIDocument* doc = GetCurrentDoc();
   187   if (!doc) {
   188     return IMEState(IMEState::DISABLED);
   189   }
   190   nsIPresShell* ps = doc->GetShell();
   191   if (!ps) {
   192     return IMEState(IMEState::DISABLED);
   193   }
   194   nsPresContext* pc = ps->GetPresContext();
   195   if (!pc) {
   196     return IMEState(IMEState::DISABLED);
   197   }
   198   nsIEditor* editor = nsContentUtils::GetHTMLEditor(pc);
   199   nsCOMPtr<nsIEditorIMESupport> imeEditor = do_QueryInterface(editor);
   200   if (!imeEditor) {
   201     return IMEState(IMEState::DISABLED);
   202   }
   203   IMEState state;
   204   imeEditor->GetPreferredIMEState(&state);
   205   return state;
   206 }
   208 bool
   209 nsIContent::HasIndependentSelection()
   210 {
   211   nsIFrame* frame = GetPrimaryFrame();
   212   return (frame && frame->GetStateBits() & NS_FRAME_INDEPENDENT_SELECTION);
   213 }
   215 dom::Element*
   216 nsIContent::GetEditingHost()
   217 {
   218   // If this isn't editable, return nullptr.
   219   NS_ENSURE_TRUE(IsEditableInternal(), nullptr);
   221   nsIDocument* doc = GetCurrentDoc();
   222   NS_ENSURE_TRUE(doc, nullptr);
   223   // If this is in designMode, we should return <body>
   224   if (doc->HasFlag(NODE_IS_EDITABLE)) {
   225     return doc->GetBodyElement();
   226   }
   228   nsIContent* content = this;
   229   for (dom::Element* parent = GetParentElement();
   230        parent && parent->HasFlag(NODE_IS_EDITABLE);
   231        parent = content->GetParentElement()) {
   232     content = parent;
   233   }
   234   return content->AsElement();
   235 }
   237 nsresult
   238 nsIContent::LookupNamespaceURIInternal(const nsAString& aNamespacePrefix,
   239                                        nsAString& aNamespaceURI) const
   240 {
   241   if (aNamespacePrefix.EqualsLiteral("xml")) {
   242     // Special-case for xml prefix
   243     aNamespaceURI.AssignLiteral("http://www.w3.org/XML/1998/namespace");
   244     return NS_OK;
   245   }
   247   if (aNamespacePrefix.EqualsLiteral("xmlns")) {
   248     // Special-case for xmlns prefix
   249     aNamespaceURI.AssignLiteral("http://www.w3.org/2000/xmlns/");
   250     return NS_OK;
   251   }
   253   nsCOMPtr<nsIAtom> name;
   254   if (!aNamespacePrefix.IsEmpty()) {
   255     name = do_GetAtom(aNamespacePrefix);
   256     NS_ENSURE_TRUE(name, NS_ERROR_OUT_OF_MEMORY);
   257   }
   258   else {
   259     name = nsGkAtoms::xmlns;
   260   }
   261   // Trace up the content parent chain looking for the namespace
   262   // declaration that declares aNamespacePrefix.
   263   const nsIContent* content = this;
   264   do {
   265     if (content->GetAttr(kNameSpaceID_XMLNS, name, aNamespaceURI))
   266       return NS_OK;
   267   } while ((content = content->GetParent()));
   268   return NS_ERROR_FAILURE;
   269 }
   271 already_AddRefed<nsIURI>
   272 nsIContent::GetBaseURI(bool aTryUseXHRDocBaseURI) const
   273 {
   274   nsIDocument* doc = OwnerDoc();
   275   // Start with document base
   276   nsCOMPtr<nsIURI> base = doc->GetBaseURI(aTryUseXHRDocBaseURI);
   278   // Collect array of xml:base attribute values up the parent chain. This
   279   // is slightly slower for the case when there are xml:base attributes, but
   280   // faster for the far more common case of there not being any such
   281   // attributes.
   282   // Also check for SVG elements which require special handling
   283   nsAutoTArray<nsString, 5> baseAttrs;
   284   nsString attr;
   285   const nsIContent *elem = this;
   286   do {
   287     // First check for SVG specialness (why is this SVG specific?)
   288     if (elem->IsSVG()) {
   289       nsIContent* bindingParent = elem->GetBindingParent();
   290       if (bindingParent) {
   291         nsXBLBinding* binding = bindingParent->GetXBLBinding();
   292         if (binding) {
   293           // XXX sXBL/XBL2 issue
   294           // If this is an anonymous XBL element use the binding
   295           // document for the base URI. 
   296           // XXX Will fail with xml:base
   297           base = binding->PrototypeBinding()->DocURI();
   298           break;
   299         }
   300       }
   301     }
   303     nsIURI* explicitBaseURI = elem->GetExplicitBaseURI();
   304     if (explicitBaseURI) {
   305       base = explicitBaseURI;
   306       break;
   307     }
   309     // Otherwise check for xml:base attribute
   310     elem->GetAttr(kNameSpaceID_XML, nsGkAtoms::base, attr);
   311     if (!attr.IsEmpty()) {
   312       baseAttrs.AppendElement(attr);
   313     }
   314     elem = elem->GetParent();
   315   } while(elem);
   317   // Now resolve against all xml:base attrs
   318   for (uint32_t i = baseAttrs.Length() - 1; i != uint32_t(-1); --i) {
   319     nsCOMPtr<nsIURI> newBase;
   320     nsresult rv = NS_NewURI(getter_AddRefs(newBase), baseAttrs[i],
   321                             doc->GetDocumentCharacterSet().get(), base);
   322     // Do a security check, almost the same as nsDocument::SetBaseURL()
   323     // Only need to do this on the final uri
   324     if (NS_SUCCEEDED(rv) && i == 0) {
   325       rv = nsContentUtils::GetSecurityManager()->
   326         CheckLoadURIWithPrincipal(NodePrincipal(), newBase,
   327                                   nsIScriptSecurityManager::STANDARD);
   328     }
   329     if (NS_SUCCEEDED(rv)) {
   330       base.swap(newBase);
   331     }
   332   }
   334   return base.forget();
   335 }
   337 //----------------------------------------------------------------------
   339 static inline JSObject*
   340 GetJSObjectChild(nsWrapperCache* aCache)
   341 {
   342   return aCache->PreservingWrapper() ? aCache->GetWrapperPreserveColor() : nullptr;
   343 }
   345 static bool
   346 NeedsScriptTraverse(nsINode* aNode)
   347 {
   348   return aNode->PreservingWrapper() && aNode->GetWrapperPreserveColor() &&
   349          !aNode->IsBlackAndDoesNotNeedTracing(aNode);
   350 }
   352 //----------------------------------------------------------------------
   354 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsChildContentList)
   355 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsChildContentList)
   357 // If nsChildContentList is changed so that any additional fields are
   358 // traversed by the cycle collector, then CAN_SKIP must be updated to
   359 // check that the additional fields are null.
   360 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(nsChildContentList)
   362 // nsChildContentList only ever has a single child, its wrapper, so if
   363 // the wrapper is black, the list can't be part of a garbage cycle.
   364 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(nsChildContentList)
   365   return tmp->IsBlack();
   366 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END
   368 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(nsChildContentList)
   369   return tmp->IsBlackAndDoesNotNeedTracing(tmp);
   370 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_END
   372 // CanSkipThis returns false to avoid problems with incomplete unlinking.
   373 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN(nsChildContentList)
   374 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END
   376 NS_INTERFACE_TABLE_HEAD(nsChildContentList)
   377   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   378   NS_INTERFACE_TABLE(nsChildContentList, nsINodeList, nsIDOMNodeList)
   379   NS_INTERFACE_TABLE_TO_MAP_SEGUE_CYCLE_COLLECTION(nsChildContentList)
   380 NS_INTERFACE_MAP_END
   382 JSObject*
   383 nsChildContentList::WrapObject(JSContext *cx)
   384 {
   385   return NodeListBinding::Wrap(cx, this);
   386 }
   388 NS_IMETHODIMP
   389 nsChildContentList::GetLength(uint32_t* aLength)
   390 {
   391   *aLength = mNode ? mNode->GetChildCount() : 0;
   393   return NS_OK;
   394 }
   396 NS_IMETHODIMP
   397 nsChildContentList::Item(uint32_t aIndex, nsIDOMNode** aReturn)
   398 {
   399   nsINode* node = Item(aIndex);
   400   if (!node) {
   401     *aReturn = nullptr;
   403     return NS_OK;
   404   }
   406   return CallQueryInterface(node, aReturn);
   407 }
   409 nsIContent*
   410 nsChildContentList::Item(uint32_t aIndex)
   411 {
   412   if (mNode) {
   413     return mNode->GetChildAt(aIndex);
   414   }
   416   return nullptr;
   417 }
   419 int32_t
   420 nsChildContentList::IndexOf(nsIContent* aContent)
   421 {
   422   if (mNode) {
   423     return mNode->IndexOf(aContent);
   424   }
   426   return -1;
   427 }
   429 //----------------------------------------------------------------------
   431 NS_IMPL_CYCLE_COLLECTION(nsNode3Tearoff, mNode)
   433 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsNode3Tearoff)
   434   NS_INTERFACE_MAP_ENTRY(nsIDOMXPathNSResolver)
   435 NS_INTERFACE_MAP_END_AGGREGATED(mNode)
   437 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsNode3Tearoff)
   438 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsNode3Tearoff)
   440 NS_IMETHODIMP
   441 nsNode3Tearoff::LookupNamespaceURI(const nsAString& aNamespacePrefix,
   442                                    nsAString& aNamespaceURI)
   443 {
   444   mNode->LookupNamespaceURI(aNamespacePrefix, aNamespaceURI);
   445   return NS_OK;
   446 }
   448 nsIHTMLCollection*
   449 FragmentOrElement::Children()
   450 {
   451   FragmentOrElement::nsDOMSlots *slots = DOMSlots();
   453   if (!slots->mChildrenList) {
   454     slots->mChildrenList = new nsContentList(this, kNameSpaceID_Wildcard, 
   455                                              nsGkAtoms::_asterix, nsGkAtoms::_asterix,
   456                                              false);
   457   }
   459   return slots->mChildrenList;
   460 }
   463 //----------------------------------------------------------------------
   466 NS_IMPL_ISUPPORTS(nsNodeWeakReference,
   467                   nsIWeakReference)
   469 nsNodeWeakReference::~nsNodeWeakReference()
   470 {
   471   if (mNode) {
   472     NS_ASSERTION(mNode->Slots()->mWeakReference == this,
   473                  "Weak reference has wrong value");
   474     mNode->Slots()->mWeakReference = nullptr;
   475   }
   476 }
   478 NS_IMETHODIMP
   479 nsNodeWeakReference::QueryReferent(const nsIID& aIID, void** aInstancePtr)
   480 {
   481   return mNode ? mNode->QueryInterface(aIID, aInstancePtr) :
   482                  NS_ERROR_NULL_POINTER;
   483 }
   486 NS_IMPL_CYCLE_COLLECTION(nsNodeSupportsWeakRefTearoff, mNode)
   488 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsNodeSupportsWeakRefTearoff)
   489   NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
   490 NS_INTERFACE_MAP_END_AGGREGATED(mNode)
   492 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsNodeSupportsWeakRefTearoff)
   493 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsNodeSupportsWeakRefTearoff)
   495 NS_IMETHODIMP
   496 nsNodeSupportsWeakRefTearoff::GetWeakReference(nsIWeakReference** aInstancePtr)
   497 {
   498   nsINode::nsSlots* slots = mNode->Slots();
   499   if (!slots->mWeakReference) {
   500     slots->mWeakReference = new nsNodeWeakReference(mNode);
   501     NS_ENSURE_TRUE(slots->mWeakReference, NS_ERROR_OUT_OF_MEMORY);
   502   }
   504   NS_ADDREF(*aInstancePtr = slots->mWeakReference);
   506   return NS_OK;
   507 }
   509 //----------------------------------------------------------------------
   510 FragmentOrElement::nsDOMSlots::nsDOMSlots()
   511   : nsINode::nsSlots(),
   512     mDataset(nullptr),
   513     mUndoManager(nullptr),
   514     mBindingParent(nullptr)
   515 {
   516 }
   518 FragmentOrElement::nsDOMSlots::~nsDOMSlots()
   519 {
   520   if (mAttributeMap) {
   521     mAttributeMap->DropReference();
   522   }
   523 }
   525 void
   526 FragmentOrElement::nsDOMSlots::Traverse(nsCycleCollectionTraversalCallback &cb, bool aIsXUL)
   527 {
   528   NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mSlots->mStyle");
   529   cb.NoteXPCOMChild(mStyle.get());
   531   NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mSlots->mSMILOverrideStyle");
   532   cb.NoteXPCOMChild(mSMILOverrideStyle.get());
   534   NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mSlots->mAttributeMap");
   535   cb.NoteXPCOMChild(mAttributeMap.get());
   537   NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mSlots->mUndoManager");
   538   cb.NoteXPCOMChild(mUndoManager.get());
   540   if (aIsXUL) {
   541     NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mSlots->mControllers");
   542     cb.NoteXPCOMChild(mControllers);
   543   }
   545   NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mSlots->mXBLBinding");
   546   cb.NoteNativeChild(mXBLBinding, NS_CYCLE_COLLECTION_PARTICIPANT(nsXBLBinding));
   548   NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mSlots->mXBLInsertionParent");
   549   cb.NoteXPCOMChild(mXBLInsertionParent.get());
   551   NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mSlots->mShadowRoot");
   552   cb.NoteXPCOMChild(NS_ISUPPORTS_CAST(nsIContent*, mShadowRoot));
   554   NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mSlots->mContainingShadow");
   555   cb.NoteXPCOMChild(NS_ISUPPORTS_CAST(nsIContent*, mContainingShadow));
   557   NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mSlots->mChildrenList");
   558   cb.NoteXPCOMChild(NS_ISUPPORTS_CAST(nsIDOMNodeList*, mChildrenList));
   560   NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mSlots->mClassList");
   561   cb.NoteXPCOMChild(mClassList.get());
   563   if (mCustomElementData) {
   564     for (uint32_t i = 0; i < mCustomElementData->mCallbackQueue.Length(); i++) {
   565       mCustomElementData->mCallbackQueue[i]->Traverse(cb);
   566     }
   567   }
   568 }
   570 void
   571 FragmentOrElement::nsDOMSlots::Unlink(bool aIsXUL)
   572 {
   573   mStyle = nullptr;
   574   mSMILOverrideStyle = nullptr;
   575   if (mAttributeMap) {
   576     mAttributeMap->DropReference();
   577     mAttributeMap = nullptr;
   578   }
   579   if (aIsXUL)
   580     NS_IF_RELEASE(mControllers);
   581   mXBLBinding = nullptr;
   582   mXBLInsertionParent = nullptr;
   583   mShadowRoot = nullptr;
   584   mContainingShadow = nullptr;
   585   mChildrenList = nullptr;
   586   mUndoManager = nullptr;
   587   mCustomElementData = nullptr;
   588   mClassList = nullptr;
   589 }
   591 size_t
   592 FragmentOrElement::nsDOMSlots::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
   593 {
   594   size_t n = aMallocSizeOf(this);
   596   if (mAttributeMap) {
   597     n += mAttributeMap->SizeOfIncludingThis(aMallocSizeOf);
   598   }
   600   // Measurement of the following members may be added later if DMD finds it is
   601   // worthwhile:
   602   // - Superclass members (nsINode::nsSlots)
   603   // - mStyle
   604   // - mDataSet
   605   // - mSMILOverrideStyle
   606   // - mSMILOverrideStyleRule
   607   // - mChildrenList
   608   // - mClassList
   610   // The following members are not measured:
   611   // - mBindingParent / mControllers: because they're   non-owning
   612   return n;
   613 }
   615 FragmentOrElement::FragmentOrElement(already_AddRefed<nsINodeInfo>& aNodeInfo)
   616   : nsIContent(aNodeInfo)
   617 {
   618 }
   620 FragmentOrElement::FragmentOrElement(already_AddRefed<nsINodeInfo>&& aNodeInfo)
   621   : nsIContent(aNodeInfo)
   622 {
   623 }
   625 FragmentOrElement::~FragmentOrElement()
   626 {
   627   NS_PRECONDITION(!IsInDoc(),
   628                   "Please remove this from the document properly");
   629   if (GetParent()) {
   630     NS_RELEASE(mParent);
   631   }
   632 }
   634 already_AddRefed<nsINodeList>
   635 FragmentOrElement::GetChildren(uint32_t aFilter)
   636 {
   637   nsRefPtr<nsSimpleContentList> list = new nsSimpleContentList(this);
   638   if (!list) {
   639     return nullptr;
   640   }
   642   nsIFrame *frame = GetPrimaryFrame();
   644   // Append :before generated content.
   645   if (frame) {
   646     nsIFrame *beforeFrame = nsLayoutUtils::GetBeforeFrame(frame);
   647     if (beforeFrame) {
   648       list->AppendElement(beforeFrame->GetContent());
   649     }
   650   }
   652   // If XBL is bound to this node then append XBL anonymous content including
   653   // explict content altered by insertion point if we were requested for XBL
   654   // anonymous content, otherwise append explicit content with respect to
   655   // insertion point if any.
   656   if (!(aFilter & eAllButXBL)) {
   657     FlattenedChildIterator iter(this);
   658     for (nsIContent* child = iter.GetNextChild(); child; child = iter.GetNextChild()) {
   659       list->AppendElement(child);
   660     }
   661   } else {
   662     ExplicitChildIterator iter(this);
   663     for (nsIContent* child = iter.GetNextChild(); child; child = iter.GetNextChild()) {
   664       list->AppendElement(child);
   665     }
   666   }
   668   if (frame) {
   669     // Append native anonymous content to the end.
   670     nsIAnonymousContentCreator* creator = do_QueryFrame(frame);
   671     if (creator) {
   672       creator->AppendAnonymousContentTo(*list, aFilter);
   673     }
   675     // Append :after generated content.
   676     nsIFrame *afterFrame = nsLayoutUtils::GetAfterFrame(frame);
   677     if (afterFrame) {
   678       list->AppendElement(afterFrame->GetContent());
   679     }
   680   }
   682   return list.forget();
   683 }
   685 static nsIContent*
   686 FindChromeAccessOnlySubtreeOwner(nsIContent* aContent)
   687 {
   688   if (aContent->ChromeOnlyAccess()) {
   689     bool chromeAccessOnly = false;
   690     while (aContent && !chromeAccessOnly) {
   691       chromeAccessOnly = aContent->IsRootOfChromeAccessOnlySubtree();
   692       aContent = aContent->GetParent();
   693     }
   694   }
   695   return aContent;
   696 }
   698 nsresult
   699 nsIContent::PreHandleEvent(EventChainPreVisitor& aVisitor)
   700 {
   701   //FIXME! Document how this event retargeting works, Bug 329124.
   702   aVisitor.mCanHandle = true;
   703   aVisitor.mMayHaveListenerManager = HasListenerManager();
   705   // Don't propagate mouseover and mouseout events when mouse is moving
   706   // inside chrome access only content.
   707   bool isAnonForEvents = IsRootOfChromeAccessOnlySubtree();
   708   if ((aVisitor.mEvent->message == NS_MOUSE_ENTER_SYNTH ||
   709        aVisitor.mEvent->message == NS_MOUSE_EXIT_SYNTH ||
   710        aVisitor.mEvent->message == NS_POINTER_OVER ||
   711        aVisitor.mEvent->message == NS_POINTER_OUT) &&
   712       // Check if we should stop event propagation when event has just been
   713       // dispatched or when we're about to propagate from
   714       // chrome access only subtree.
   715       ((this == aVisitor.mEvent->originalTarget &&
   716         !ChromeOnlyAccess()) || isAnonForEvents)) {
   717      nsCOMPtr<nsIContent> relatedTarget =
   718        do_QueryInterface(aVisitor.mEvent->AsMouseEvent()->relatedTarget);
   719     if (relatedTarget &&
   720         relatedTarget->OwnerDoc() == OwnerDoc()) {
   722       // If current target is anonymous for events or we know that related
   723       // target is descendant of an element which is anonymous for events,
   724       // we may want to stop event propagation.
   725       // If this is the original target, aVisitor.mRelatedTargetIsInAnon
   726       // must be updated.
   727       if (isAnonForEvents || aVisitor.mRelatedTargetIsInAnon ||
   728           (aVisitor.mEvent->originalTarget == this &&
   729            (aVisitor.mRelatedTargetIsInAnon =
   730             relatedTarget->ChromeOnlyAccess()))) {
   731         nsIContent* anonOwner = FindChromeAccessOnlySubtreeOwner(this);
   732         if (anonOwner) {
   733           nsIContent* anonOwnerRelated =
   734             FindChromeAccessOnlySubtreeOwner(relatedTarget);
   735           if (anonOwnerRelated) {
   736             // Note, anonOwnerRelated may still be inside some other
   737             // native anonymous subtree. The case where anonOwner is still
   738             // inside native anonymous subtree will be handled when event
   739             // propagates up in the DOM tree.
   740             while (anonOwner != anonOwnerRelated &&
   741                    anonOwnerRelated->ChromeOnlyAccess()) {
   742               anonOwnerRelated = FindChromeAccessOnlySubtreeOwner(anonOwnerRelated);
   743             }
   744             if (anonOwner == anonOwnerRelated) {
   745 #ifdef DEBUG_smaug
   746               nsCOMPtr<nsIContent> originalTarget =
   747                 do_QueryInterface(aVisitor.mEvent->originalTarget);
   748               nsAutoString ot, ct, rt;
   749               if (originalTarget) {
   750                 originalTarget->Tag()->ToString(ot);
   751               }
   752               Tag()->ToString(ct);
   753               relatedTarget->Tag()->ToString(rt);
   754               printf("Stopping %s propagation:"
   755                      "\n\toriginalTarget=%s \n\tcurrentTarget=%s %s"
   756                      "\n\trelatedTarget=%s %s \n%s",
   757                      (aVisitor.mEvent->message == NS_MOUSE_ENTER_SYNTH)
   758                        ? "mouseover" : "mouseout",
   759                      NS_ConvertUTF16toUTF8(ot).get(),
   760                      NS_ConvertUTF16toUTF8(ct).get(),
   761                      isAnonForEvents
   762                        ? "(is native anonymous)"
   763                        : (ChromeOnlyAccess()
   764                            ? "(is in native anonymous subtree)" : ""),
   765                      NS_ConvertUTF16toUTF8(rt).get(),
   766                      relatedTarget->ChromeOnlyAccess()
   767                        ? "(is in native anonymous subtree)" : "",
   768                      (originalTarget &&
   769                       relatedTarget->FindFirstNonChromeOnlyAccessContent() ==
   770                         originalTarget->FindFirstNonChromeOnlyAccessContent())
   771                        ? "" : "Wrong event propagation!?!\n");
   772 #endif
   773               aVisitor.mParentTarget = nullptr;
   774               // Event should not propagate to non-anon content.
   775               aVisitor.mCanHandle = isAnonForEvents;
   776               return NS_OK;
   777             }
   778           }
   779         }
   780       }
   781     }
   782   }
   784   nsIContent* parent = GetParent();
   785   // Event may need to be retargeted if this is the root of a native
   786   // anonymous content subtree or event is dispatched somewhere inside XBL.
   787   if (isAnonForEvents) {
   788 #ifdef DEBUG
   789     // If a DOM event is explicitly dispatched using node.dispatchEvent(), then
   790     // all the events are allowed even in the native anonymous content..
   791     nsCOMPtr<nsIContent> t = do_QueryInterface(aVisitor.mEvent->originalTarget);
   792     NS_ASSERTION(!t || !t->ChromeOnlyAccess() ||
   793                  aVisitor.mEvent->eventStructType != NS_MUTATION_EVENT ||
   794                  aVisitor.mDOMEvent,
   795                  "Mutation event dispatched in native anonymous content!?!");
   796 #endif
   797     aVisitor.mEventTargetAtParent = parent;
   798   } else if (parent && aVisitor.mOriginalTargetIsInAnon) {
   799     nsCOMPtr<nsIContent> content(do_QueryInterface(aVisitor.mEvent->target));
   800     if (content && content->GetBindingParent() == parent) {
   801       aVisitor.mEventTargetAtParent = parent;
   802     }
   803   }
   805   // check for an anonymous parent
   806   // XXX XBL2/sXBL issue
   807   if (HasFlag(NODE_MAY_BE_IN_BINDING_MNGR)) {
   808     nsIContent* insertionParent = GetXBLInsertionParent();
   809     NS_ASSERTION(!(aVisitor.mEventTargetAtParent && insertionParent &&
   810                    aVisitor.mEventTargetAtParent != insertionParent),
   811                  "Retargeting and having insertion parent!");
   812     if (insertionParent) {
   813       parent = insertionParent;
   814     }
   815   }
   817   if (parent) {
   818     aVisitor.mParentTarget = parent;
   819   } else {
   820     aVisitor.mParentTarget = GetCurrentDoc();
   821   }
   822   return NS_OK;
   823 }
   825 bool
   826 nsIContent::GetAttr(int32_t aNameSpaceID, nsIAtom* aName,
   827                     nsAString& aResult) const
   828 {
   829   if (IsElement()) {
   830     return AsElement()->GetAttr(aNameSpaceID, aName, aResult);
   831   }
   832   aResult.Truncate();
   833   return false;
   834 }
   836 bool
   837 nsIContent::HasAttr(int32_t aNameSpaceID, nsIAtom* aName) const
   838 {
   839   return IsElement() && AsElement()->HasAttr(aNameSpaceID, aName);
   840 }
   842 bool
   843 nsIContent::AttrValueIs(int32_t aNameSpaceID,
   844                         nsIAtom* aName,
   845                         const nsAString& aValue,
   846                         nsCaseTreatment aCaseSensitive) const
   847 {
   848   return IsElement() &&
   849     AsElement()->AttrValueIs(aNameSpaceID, aName, aValue, aCaseSensitive);
   850 }
   852 bool
   853 nsIContent::AttrValueIs(int32_t aNameSpaceID,
   854                         nsIAtom* aName,
   855                         nsIAtom* aValue,
   856                         nsCaseTreatment aCaseSensitive) const
   857 {
   858   return IsElement() &&
   859     AsElement()->AttrValueIs(aNameSpaceID, aName, aValue, aCaseSensitive);
   860 }
   862 bool
   863 nsIContent::IsFocusable(int32_t* aTabIndex, bool aWithMouse)
   864 {
   865   bool focusable = IsFocusableInternal(aTabIndex, aWithMouse);
   866   // Ensure that the return value and aTabIndex are consistent in the case
   867   // we're in userfocusignored context.
   868   if (focusable || (aTabIndex && *aTabIndex != -1)) {
   869     if (nsContentUtils::IsUserFocusIgnored(this)) {
   870       if (aTabIndex) {
   871         *aTabIndex = -1;
   872       }
   873       return false;
   874     }
   875     return focusable;
   876   }
   877   return false;
   878 }
   880 bool
   881 nsIContent::IsFocusableInternal(int32_t* aTabIndex, bool aWithMouse)
   882 {
   883   if (aTabIndex) {
   884     *aTabIndex = -1; // Default, not tabbable
   885   }
   886   return false;
   887 }
   889 const nsAttrValue*
   890 FragmentOrElement::DoGetClasses() const
   891 {
   892   NS_NOTREACHED("Shouldn't ever be called");
   893   return nullptr;
   894 }
   896 NS_IMETHODIMP
   897 FragmentOrElement::WalkContentStyleRules(nsRuleWalker* aRuleWalker)
   898 {
   899   return NS_OK;
   900 }
   902 bool
   903 FragmentOrElement::IsLink(nsIURI** aURI) const
   904 {
   905   *aURI = nullptr;
   906   return false;
   907 }
   909 nsIContent*
   910 FragmentOrElement::GetBindingParent() const
   911 {
   912   nsDOMSlots *slots = GetExistingDOMSlots();
   914   if (slots) {
   915     return slots->mBindingParent;
   916   }
   917   return nullptr;
   918 }
   920 nsXBLBinding*
   921 FragmentOrElement::GetXBLBinding() const
   922 {
   923   if (HasFlag(NODE_MAY_BE_IN_BINDING_MNGR)) {
   924     nsDOMSlots *slots = GetExistingDOMSlots();
   925     if (slots) {
   926       return slots->mXBLBinding;
   927     }
   928   }
   930   return nullptr;
   931 }
   933 void
   934 FragmentOrElement::SetXBLBinding(nsXBLBinding* aBinding,
   935                                  nsBindingManager* aOldBindingManager)
   936 {
   937   nsBindingManager* bindingManager;
   938   if (aOldBindingManager) {
   939     MOZ_ASSERT(!aBinding, "aOldBindingManager should only be provided "
   940                           "when removing a binding.");
   941     bindingManager = aOldBindingManager;
   942   } else {
   943     bindingManager = OwnerDoc()->BindingManager();
   944   }
   946   // After this point, aBinding will be the most-derived binding for aContent.
   947   // If we already have a binding for aContent, make sure to
   948   // remove it from the attached stack.  Otherwise we might end up firing its
   949   // constructor twice (if aBinding inherits from it) or firing its constructor
   950   // after aContent has been deleted (if aBinding is null and the content node
   951   // dies before we process mAttachedStack).
   952   nsRefPtr<nsXBLBinding> oldBinding = GetXBLBinding();
   953   if (oldBinding) {
   954     bindingManager->RemoveFromAttachedQueue(oldBinding);
   955   }
   957   nsDOMSlots *slots = DOMSlots();
   958   if (aBinding) {
   959     SetFlags(NODE_MAY_BE_IN_BINDING_MNGR);
   960     slots->mXBLBinding = aBinding;
   961     bindingManager->AddBoundContent(this);
   962   } else {
   963     slots->mXBLBinding = nullptr;
   964     bindingManager->RemoveBoundContent(this);
   965     if (oldBinding) {
   966       oldBinding->SetBoundElement(nullptr);
   967     }
   968   }
   969 }
   971 nsIContent*
   972 FragmentOrElement::GetXBLInsertionParent() const
   973 {
   974   if (HasFlag(NODE_MAY_BE_IN_BINDING_MNGR)) {
   975     nsDOMSlots *slots = GetExistingDOMSlots();
   976     if (slots) {
   977       return slots->mXBLInsertionParent;
   978     }
   979   }
   981   return nullptr;
   982 }
   984 ShadowRoot*
   985 FragmentOrElement::GetShadowRoot() const
   986 {
   987   nsDOMSlots *slots = GetExistingDOMSlots();
   988   if (slots) {
   989     return slots->mShadowRoot;
   990   }
   991   return nullptr;
   992 }
   994 ShadowRoot*
   995 FragmentOrElement::GetContainingShadow() const
   996 {
   997   nsDOMSlots *slots = GetExistingDOMSlots();
   998   if (slots) {
   999     return slots->mContainingShadow;
  1001   return nullptr;
  1004 void
  1005 FragmentOrElement::SetShadowRoot(ShadowRoot* aShadowRoot)
  1007   nsDOMSlots *slots = DOMSlots();
  1008   slots->mShadowRoot = aShadowRoot;
  1011 void
  1012 FragmentOrElement::SetXBLInsertionParent(nsIContent* aContent)
  1014   nsDOMSlots *slots = DOMSlots();
  1015   if (aContent) {
  1016     SetFlags(NODE_MAY_BE_IN_BINDING_MNGR);
  1018   slots->mXBLInsertionParent = aContent;
  1021 CustomElementData*
  1022 FragmentOrElement::GetCustomElementData() const
  1024   nsDOMSlots *slots = GetExistingDOMSlots();
  1025   if (slots) {
  1026     return slots->mCustomElementData;
  1028   return nullptr;
  1031 void
  1032 FragmentOrElement::SetCustomElementData(CustomElementData* aData)
  1034   nsDOMSlots *slots = DOMSlots();
  1035   MOZ_ASSERT(!slots->mCustomElementData, "Custom element data may not be changed once set.");
  1036   slots->mCustomElementData = aData;
  1039 nsresult
  1040 FragmentOrElement::InsertChildAt(nsIContent* aKid,
  1041                                 uint32_t aIndex,
  1042                                 bool aNotify)
  1044   NS_PRECONDITION(aKid, "null ptr");
  1046   return doInsertChildAt(aKid, aIndex, aNotify, mAttrsAndChildren);
  1049 void
  1050 FragmentOrElement::RemoveChildAt(uint32_t aIndex, bool aNotify)
  1052   nsCOMPtr<nsIContent> oldKid = mAttrsAndChildren.GetSafeChildAt(aIndex);
  1053   NS_ASSERTION(oldKid == GetChildAt(aIndex), "Unexpected child in RemoveChildAt");
  1055   if (oldKid) {
  1056     doRemoveChildAt(aIndex, aNotify, oldKid, mAttrsAndChildren);
  1060 void
  1061 FragmentOrElement::GetTextContentInternal(nsAString& aTextContent)
  1063   if(!nsContentUtils::GetNodeTextContent(this, true, aTextContent))
  1064     NS_RUNTIMEABORT("OOM");
  1067 void
  1068 FragmentOrElement::SetTextContentInternal(const nsAString& aTextContent,
  1069                                           ErrorResult& aError)
  1071   aError = nsContentUtils::SetNodeTextContent(this, aTextContent, false);
  1074 void
  1075 FragmentOrElement::DestroyContent()
  1077   nsIDocument *document = OwnerDoc();
  1078   document->BindingManager()->RemovedFromDocument(this, document);
  1079   document->ClearBoxObjectFor(this);
  1081   // XXX We really should let cycle collection do this, but that currently still
  1082   //     leaks (see https://bugzilla.mozilla.org/show_bug.cgi?id=406684).
  1083   ReleaseWrapper(this);
  1085   uint32_t i, count = mAttrsAndChildren.ChildCount();
  1086   for (i = 0; i < count; ++i) {
  1087     // The child can remove itself from the parent in BindToTree.
  1088     mAttrsAndChildren.ChildAt(i)->DestroyContent();
  1092 void
  1093 FragmentOrElement::SaveSubtreeState()
  1095   uint32_t i, count = mAttrsAndChildren.ChildCount();
  1096   for (i = 0; i < count; ++i) {
  1097     mAttrsAndChildren.ChildAt(i)->SaveSubtreeState();
  1101 //----------------------------------------------------------------------
  1103 // Generic DOMNode implementations
  1105 void
  1106 FragmentOrElement::FireNodeInserted(nsIDocument* aDoc,
  1107                                    nsINode* aParent,
  1108                                    nsTArray<nsCOMPtr<nsIContent> >& aNodes)
  1110   uint32_t count = aNodes.Length();
  1111   for (uint32_t i = 0; i < count; ++i) {
  1112     nsIContent* childContent = aNodes[i];
  1114     if (nsContentUtils::HasMutationListeners(childContent,
  1115           NS_EVENT_BITS_MUTATION_NODEINSERTED, aParent)) {
  1116       InternalMutationEvent mutation(true, NS_MUTATION_NODEINSERTED);
  1117       mutation.mRelatedNode = do_QueryInterface(aParent);
  1119       mozAutoSubtreeModified subtree(aDoc, aParent);
  1120       (new AsyncEventDispatcher(childContent, mutation))->RunDOMEventWhenSafe();
  1125 //----------------------------------------------------------------------
  1127 // nsISupports implementation
  1129 #define SUBTREE_UNBINDINGS_PER_RUNNABLE 500
  1131 class ContentUnbinder : public nsRunnable
  1133 public:
  1134   ContentUnbinder()
  1136     mLast = this;
  1139   ~ContentUnbinder()
  1141     Run();
  1144   void UnbindSubtree(nsIContent* aNode)
  1146     if (aNode->NodeType() != nsIDOMNode::ELEMENT_NODE &&
  1147         aNode->NodeType() != nsIDOMNode::DOCUMENT_FRAGMENT_NODE) {
  1148       return;
  1150     FragmentOrElement* container = static_cast<FragmentOrElement*>(aNode);
  1151     uint32_t childCount = container->mAttrsAndChildren.ChildCount();
  1152     if (childCount) {
  1153       while (childCount-- > 0) {
  1154         // Hold a strong ref to the node when we remove it, because we may be
  1155         // the last reference to it.  We need to call TakeChildAt() and
  1156         // update mFirstChild before calling UnbindFromTree, since this last
  1157         // can notify various observers and they should really see consistent
  1158         // tree state.
  1159         nsCOMPtr<nsIContent> child =
  1160           container->mAttrsAndChildren.TakeChildAt(childCount);
  1161         if (childCount == 0) {
  1162           container->mFirstChild = nullptr;
  1164         UnbindSubtree(child);
  1165         child->UnbindFromTree();
  1170   NS_IMETHOD Run()
  1172     nsAutoScriptBlocker scriptBlocker;
  1173     uint32_t len = mSubtreeRoots.Length();
  1174     if (len) {
  1175       PRTime start = PR_Now();
  1176       for (uint32_t i = 0; i < len; ++i) {
  1177         UnbindSubtree(mSubtreeRoots[i]);
  1179       mSubtreeRoots.Clear();
  1180       Telemetry::Accumulate(Telemetry::CYCLE_COLLECTOR_CONTENT_UNBIND,
  1181                             uint32_t(PR_Now() - start) / PR_USEC_PER_MSEC);
  1183     nsCycleCollector_dispatchDeferredDeletion();
  1184     if (this == sContentUnbinder) {
  1185       sContentUnbinder = nullptr;
  1186       if (mNext) {
  1187         nsRefPtr<ContentUnbinder> next;
  1188         next.swap(mNext);
  1189         sContentUnbinder = next;
  1190         next->mLast = mLast;
  1191         mLast = nullptr;
  1192         NS_DispatchToMainThread(next);
  1195     return NS_OK;
  1198   static void UnbindAll()
  1200     nsRefPtr<ContentUnbinder> ub = sContentUnbinder;
  1201     sContentUnbinder = nullptr;
  1202     while (ub) {
  1203       ub->Run();
  1204       ub = ub->mNext;
  1208   static void Append(nsIContent* aSubtreeRoot)
  1210     if (!sContentUnbinder) {
  1211       sContentUnbinder = new ContentUnbinder();
  1212       nsCOMPtr<nsIRunnable> e = sContentUnbinder;
  1213       NS_DispatchToMainThread(e);
  1216     if (sContentUnbinder->mLast->mSubtreeRoots.Length() >=
  1217         SUBTREE_UNBINDINGS_PER_RUNNABLE) {
  1218       sContentUnbinder->mLast->mNext = new ContentUnbinder();
  1219       sContentUnbinder->mLast = sContentUnbinder->mLast->mNext;
  1221     sContentUnbinder->mLast->mSubtreeRoots.AppendElement(aSubtreeRoot);
  1224 private:
  1225   nsAutoTArray<nsCOMPtr<nsIContent>,
  1226                SUBTREE_UNBINDINGS_PER_RUNNABLE> mSubtreeRoots;
  1227   nsRefPtr<ContentUnbinder>                     mNext;
  1228   ContentUnbinder*                              mLast;
  1229   static ContentUnbinder*                       sContentUnbinder;
  1230 };
  1232 ContentUnbinder* ContentUnbinder::sContentUnbinder = nullptr;
  1234 void
  1235 FragmentOrElement::ClearContentUnbinder()
  1237   ContentUnbinder::UnbindAll();
  1240 NS_IMPL_CYCLE_COLLECTION_CLASS(FragmentOrElement)
  1242 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(FragmentOrElement)
  1243   nsINode::Unlink(tmp);
  1245   if (tmp->HasProperties()) {
  1246     if (tmp->IsHTML()) {
  1247       nsIAtom*** props = nsGenericHTMLElement::PropertiesToTraverseAndUnlink();
  1248       for (uint32_t i = 0; props[i]; ++i) {
  1249         tmp->DeleteProperty(*props[i]);
  1254   // Unlink child content (and unbind our subtree).
  1255   if (tmp->UnoptimizableCCNode() || !nsCCUncollectableMarker::sGeneration) {
  1256     uint32_t childCount = tmp->mAttrsAndChildren.ChildCount();
  1257     if (childCount) {
  1258       // Don't allow script to run while we're unbinding everything.
  1259       nsAutoScriptBlocker scriptBlocker;
  1260       while (childCount-- > 0) {
  1261         // Hold a strong ref to the node when we remove it, because we may be
  1262         // the last reference to it.  We need to call TakeChildAt() and
  1263         // update mFirstChild before calling UnbindFromTree, since this last
  1264         // can notify various observers and they should really see consistent
  1265         // tree state.
  1266         nsCOMPtr<nsIContent> child = tmp->mAttrsAndChildren.TakeChildAt(childCount);
  1267         if (childCount == 0) {
  1268           tmp->mFirstChild = nullptr;
  1270         child->UnbindFromTree();
  1273   } else if (!tmp->GetParent() && tmp->mAttrsAndChildren.ChildCount()) {
  1274     ContentUnbinder::Append(tmp);
  1275   } /* else {
  1276     The subtree root will end up to a ContentUnbinder, and that will
  1277     unbind the child nodes.
  1278   } */
  1280   // Unlink any DOM slots of interest.
  1282     nsDOMSlots *slots = tmp->GetExistingDOMSlots();
  1283     if (slots) {
  1284       slots->Unlink(tmp->IsXUL());
  1289     nsIDocument *doc;
  1290     if (!tmp->GetParentNode() && (doc = tmp->OwnerDoc())) {
  1291       doc->BindingManager()->RemovedFromDocument(tmp, doc);
  1294 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
  1296 NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(FragmentOrElement)
  1298 void
  1299 FragmentOrElement::MarkUserData(void* aObject, nsIAtom* aKey, void* aChild,
  1300                                void* aData)
  1302   uint32_t* gen = static_cast<uint32_t*>(aData);
  1303   xpc_MarkInCCGeneration(static_cast<nsISupports*>(aChild), *gen);
  1306 void
  1307 FragmentOrElement::MarkUserDataHandler(void* aObject, nsIAtom* aKey,
  1308                                       void* aChild, void* aData)
  1310   xpc_TryUnmarkWrappedGrayObject(static_cast<nsISupports*>(aChild));
  1313 void
  1314 FragmentOrElement::MarkNodeChildren(nsINode* aNode)
  1316   JSObject* o = GetJSObjectChild(aNode);
  1317   if (o) {
  1318     JS::ExposeObjectToActiveJS(o);
  1321   EventListenerManager* elm = aNode->GetExistingListenerManager();
  1322   if (elm) {
  1323     elm->MarkForCC();
  1326   if (aNode->HasProperties()) {
  1327     nsIDocument* ownerDoc = aNode->OwnerDoc();
  1328     ownerDoc->PropertyTable(DOM_USER_DATA)->
  1329       Enumerate(aNode, FragmentOrElement::MarkUserData,
  1330                 &nsCCUncollectableMarker::sGeneration);
  1331     ownerDoc->PropertyTable(DOM_USER_DATA_HANDLER)->
  1332       Enumerate(aNode, FragmentOrElement::MarkUserDataHandler,
  1333                 &nsCCUncollectableMarker::sGeneration);
  1337 nsINode*
  1338 FindOptimizableSubtreeRoot(nsINode* aNode)
  1340   nsINode* p;
  1341   while ((p = aNode->GetParentNode())) {
  1342     if (aNode->UnoptimizableCCNode()) {
  1343       return nullptr;
  1345     aNode = p;
  1348   if (aNode->UnoptimizableCCNode()) {
  1349     return nullptr;
  1351   return aNode;
  1354 StaticAutoPtr<nsTHashtable<nsPtrHashKey<nsINode>>> gCCBlackMarkedNodes;
  1356 static PLDHashOperator
  1357 VisitBlackMarkedNode(nsPtrHashKey<nsINode>* aEntry, void*)
  1359   nsINode* n = aEntry->GetKey();
  1360   n->SetCCMarkedRoot(false);
  1361   n->SetInCCBlackTree(false);
  1362   return PL_DHASH_NEXT;
  1365 static void
  1366 ClearBlackMarkedNodes()
  1368   if (!gCCBlackMarkedNodes) {
  1369     return;
  1371   gCCBlackMarkedNodes->EnumerateEntries(VisitBlackMarkedNode, nullptr);
  1372   gCCBlackMarkedNodes = nullptr;
  1375 // static
  1376 void
  1377 FragmentOrElement::RemoveBlackMarkedNode(nsINode* aNode)
  1379   if (!gCCBlackMarkedNodes) {
  1380     return;
  1382   gCCBlackMarkedNodes->RemoveEntry(aNode);
  1385 // static
  1386 bool
  1387 FragmentOrElement::CanSkipInCC(nsINode* aNode)
  1389   // Don't try to optimize anything during shutdown.
  1390   if (nsCCUncollectableMarker::sGeneration == 0) {
  1391     return false;
  1394   nsIDocument* currentDoc = aNode->GetCurrentDoc();
  1395   if (currentDoc &&
  1396       nsCCUncollectableMarker::InGeneration(currentDoc->GetMarkedCCGeneration())) {
  1397     return !NeedsScriptTraverse(aNode);
  1400   // Bail out early if aNode is somewhere in anonymous content,
  1401   // or otherwise unusual.
  1402   if (aNode->UnoptimizableCCNode()) {
  1403     return false;
  1406   nsINode* root =
  1407     currentDoc ? static_cast<nsINode*>(currentDoc) :
  1408                  FindOptimizableSubtreeRoot(aNode);
  1409   if (!root) {
  1410     return false;
  1413   // Subtree has been traversed already.
  1414   if (root->CCMarkedRoot()) {
  1415     return root->InCCBlackTree() && !NeedsScriptTraverse(aNode);
  1418   if (!gCCBlackMarkedNodes) {
  1419     gCCBlackMarkedNodes = new nsTHashtable<nsPtrHashKey<nsINode> >(1020);
  1422   // nodesToUnpurple contains nodes which will be removed
  1423   // from the purple buffer if the DOM tree is black.
  1424   nsAutoTArray<nsIContent*, 1020> nodesToUnpurple;
  1425   // grayNodes need script traverse, so they aren't removed from
  1426   // the purple buffer, but are marked to be in black subtree so that
  1427   // traverse is faster.
  1428   nsAutoTArray<nsINode*, 1020> grayNodes;
  1430   bool foundBlack = root->IsBlack();
  1431   if (root != currentDoc) {
  1432     currentDoc = nullptr;
  1433     if (NeedsScriptTraverse(root)) {
  1434       grayNodes.AppendElement(root);
  1435     } else if (static_cast<nsIContent*>(root)->IsPurple()) {
  1436       nodesToUnpurple.AppendElement(static_cast<nsIContent*>(root));
  1440   // Traverse the subtree and check if we could know without CC
  1441   // that it is black.
  1442   // Note, this traverse is non-virtual and inline, so it should be a lot faster
  1443   // than CC's generic traverse.
  1444   for (nsIContent* node = root->GetFirstChild(); node;
  1445        node = node->GetNextNode(root)) {
  1446     foundBlack = foundBlack || node->IsBlack();
  1447     if (foundBlack && currentDoc) {
  1448       // If we can mark the whole document black, no need to optimize
  1449       // so much, since when the next purple node in the document will be
  1450       // handled, it is fast to check that currentDoc is in CCGeneration.
  1451       break;
  1453     if (NeedsScriptTraverse(node)) {
  1454       // Gray nodes need real CC traverse.
  1455       grayNodes.AppendElement(node);
  1456     } else if (node->IsPurple()) {
  1457       nodesToUnpurple.AppendElement(node);
  1461   root->SetCCMarkedRoot(true);
  1462   root->SetInCCBlackTree(foundBlack);
  1463   gCCBlackMarkedNodes->PutEntry(root);
  1465   if (!foundBlack) {
  1466     return false;
  1469   if (currentDoc) {
  1470     // Special case documents. If we know the document is black,
  1471     // we can mark the document to be in CCGeneration.
  1472     currentDoc->
  1473       MarkUncollectableForCCGeneration(nsCCUncollectableMarker::sGeneration);
  1474   } else {
  1475     for (uint32_t i = 0; i < grayNodes.Length(); ++i) {
  1476       nsINode* node = grayNodes[i];
  1477       node->SetInCCBlackTree(true);
  1478       gCCBlackMarkedNodes->PutEntry(node);
  1482   // Subtree is black, we can remove non-gray purple nodes from
  1483   // purple buffer.
  1484   for (uint32_t i = 0; i < nodesToUnpurple.Length(); ++i) {
  1485     nsIContent* purple = nodesToUnpurple[i];
  1486     // Can't remove currently handled purple node.
  1487     if (purple != aNode) {
  1488       purple->RemovePurple();
  1491   return !NeedsScriptTraverse(aNode);
  1494 nsAutoTArray<nsINode*, 1020>* gPurpleRoots = nullptr;
  1495 nsAutoTArray<nsIContent*, 1020>* gNodesToUnbind = nullptr;
  1497 void ClearCycleCollectorCleanupData()
  1499   if (gPurpleRoots) {
  1500     uint32_t len = gPurpleRoots->Length();
  1501     for (uint32_t i = 0; i < len; ++i) {
  1502       nsINode* n = gPurpleRoots->ElementAt(i);
  1503       n->SetIsPurpleRoot(false);
  1505     delete gPurpleRoots;
  1506     gPurpleRoots = nullptr;
  1508   if (gNodesToUnbind) {
  1509     uint32_t len = gNodesToUnbind->Length();
  1510     for (uint32_t i = 0; i < len; ++i) {
  1511       nsIContent* c = gNodesToUnbind->ElementAt(i);
  1512       c->SetIsPurpleRoot(false);
  1513       ContentUnbinder::Append(c);
  1515     delete gNodesToUnbind;
  1516     gNodesToUnbind = nullptr;
  1520 static bool
  1521 ShouldClearPurple(nsIContent* aContent)
  1523   if (aContent && aContent->IsPurple()) {
  1524     return true;
  1527   JSObject* o = GetJSObjectChild(aContent);
  1528   if (o && xpc_IsGrayGCThing(o)) {
  1529     return true;
  1532   if (aContent->HasListenerManager()) {
  1533     return true;
  1536   return aContent->HasProperties();
  1539 // If aNode is not optimizable, but is an element
  1540 // with a frame in a document which has currently active presshell,
  1541 // we can act as if it was optimizable. When the primary frame dies, aNode
  1542 // will end up to the purple buffer because of the refcount change.
  1543 bool
  1544 NodeHasActiveFrame(nsIDocument* aCurrentDoc, nsINode* aNode)
  1546   return aCurrentDoc->GetShell() && aNode->IsElement() &&
  1547          aNode->AsElement()->GetPrimaryFrame();
  1550 bool
  1551 OwnedByBindingManager(nsIDocument* aCurrentDoc, nsINode* aNode)
  1553   return aNode->IsElement() && aNode->AsElement()->GetXBLBinding();
  1556 // CanSkip checks if aNode is black, and if it is, returns
  1557 // true. If aNode is in a black DOM tree, CanSkip may also remove other objects
  1558 // from purple buffer and unmark event listeners and user data.
  1559 // If the root of the DOM tree is a document, less optimizations are done
  1560 // since checking the blackness of the current document is usually fast and we
  1561 // don't want slow down such common cases.
  1562 bool
  1563 FragmentOrElement::CanSkip(nsINode* aNode, bool aRemovingAllowed)
  1565   // Don't try to optimize anything during shutdown.
  1566   if (nsCCUncollectableMarker::sGeneration == 0) {
  1567     return false;
  1570   bool unoptimizable = aNode->UnoptimizableCCNode();
  1571   nsIDocument* currentDoc = aNode->GetCurrentDoc();
  1572   if (currentDoc &&
  1573       nsCCUncollectableMarker::InGeneration(currentDoc->GetMarkedCCGeneration()) &&
  1574       (!unoptimizable || NodeHasActiveFrame(currentDoc, aNode) ||
  1575        OwnedByBindingManager(currentDoc, aNode))) {
  1576     MarkNodeChildren(aNode);
  1577     return true;
  1580   if (unoptimizable) {
  1581     return false;
  1584   nsINode* root = currentDoc ? static_cast<nsINode*>(currentDoc) :
  1585                                FindOptimizableSubtreeRoot(aNode);
  1586   if (!root) {
  1587     return false;
  1590   // Subtree has been traversed already, and aNode has
  1591   // been handled in a way that doesn't require revisiting it.
  1592   if (root->IsPurpleRoot()) {
  1593     return false;
  1596   // nodesToClear contains nodes which are either purple or
  1597   // gray.
  1598   nsAutoTArray<nsIContent*, 1020> nodesToClear;
  1600   bool foundBlack = root->IsBlack();
  1601   bool domOnlyCycle = false;
  1602   if (root != currentDoc) {
  1603     currentDoc = nullptr;
  1604     if (!foundBlack) {
  1605       domOnlyCycle = static_cast<nsIContent*>(root)->OwnedOnlyByTheDOMTree();
  1607     if (ShouldClearPurple(static_cast<nsIContent*>(root))) {
  1608       nodesToClear.AppendElement(static_cast<nsIContent*>(root));
  1612   // Traverse the subtree and check if we could know without CC
  1613   // that it is black.
  1614   // Note, this traverse is non-virtual and inline, so it should be a lot faster
  1615   // than CC's generic traverse.
  1616   for (nsIContent* node = root->GetFirstChild(); node;
  1617        node = node->GetNextNode(root)) {
  1618     foundBlack = foundBlack || node->IsBlack();
  1619     if (foundBlack) {
  1620       domOnlyCycle = false;
  1621       if (currentDoc) {
  1622         // If we can mark the whole document black, no need to optimize
  1623         // so much, since when the next purple node in the document will be
  1624         // handled, it is fast to check that the currentDoc is in CCGeneration.
  1625         break;
  1627       // No need to put stuff to the nodesToClear array, if we can clear it
  1628       // already here.
  1629       if (node->IsPurple() && (node != aNode || aRemovingAllowed)) {
  1630         node->RemovePurple();
  1632       MarkNodeChildren(node);
  1633     } else {
  1634       domOnlyCycle = domOnlyCycle && node->OwnedOnlyByTheDOMTree();
  1635       if (ShouldClearPurple(node)) {
  1636         // Collect interesting nodes which we can clear if we find that
  1637         // they are kept alive in a black tree or are in a DOM-only cycle.
  1638         nodesToClear.AppendElement(node);
  1643   if (!currentDoc || !foundBlack) { 
  1644     root->SetIsPurpleRoot(true);
  1645     if (domOnlyCycle) {
  1646       if (!gNodesToUnbind) {
  1647         gNodesToUnbind = new nsAutoTArray<nsIContent*, 1020>();
  1649       gNodesToUnbind->AppendElement(static_cast<nsIContent*>(root));
  1650       for (uint32_t i = 0; i < nodesToClear.Length(); ++i) {
  1651         nsIContent* n = nodesToClear[i];
  1652         if ((n != aNode || aRemovingAllowed) && n->IsPurple()) {
  1653           n->RemovePurple();
  1656       return true;
  1657     } else {
  1658       if (!gPurpleRoots) {
  1659         gPurpleRoots = new nsAutoTArray<nsINode*, 1020>();
  1661       gPurpleRoots->AppendElement(root);
  1665   if (!foundBlack) {
  1666     return false;
  1669   if (currentDoc) {
  1670     // Special case documents. If we know the document is black,
  1671     // we can mark the document to be in CCGeneration.
  1672     currentDoc->
  1673       MarkUncollectableForCCGeneration(nsCCUncollectableMarker::sGeneration);
  1674     MarkNodeChildren(currentDoc);
  1677   // Subtree is black, so we can remove purple nodes from
  1678   // purple buffer and mark stuff that to be certainly alive.
  1679   for (uint32_t i = 0; i < nodesToClear.Length(); ++i) {
  1680     nsIContent* n = nodesToClear[i];
  1681     MarkNodeChildren(n);
  1682     // Can't remove currently handled purple node,
  1683     // unless aRemovingAllowed is true. 
  1684     if ((n != aNode || aRemovingAllowed) && n->IsPurple()) {
  1685       n->RemovePurple();
  1688   return true;
  1691 bool
  1692 FragmentOrElement::CanSkipThis(nsINode* aNode)
  1694   if (nsCCUncollectableMarker::sGeneration == 0) {
  1695     return false;
  1697   if (aNode->IsBlack()) {
  1698     return true;
  1700   nsIDocument* c = aNode->GetCurrentDoc();
  1701   return 
  1702     ((c && nsCCUncollectableMarker::InGeneration(c->GetMarkedCCGeneration())) ||
  1703      aNode->InCCBlackTree()) && !NeedsScriptTraverse(aNode);
  1706 void
  1707 FragmentOrElement::InitCCCallbacks()
  1709   nsCycleCollector_setForgetSkippableCallback(ClearCycleCollectorCleanupData);
  1710   nsCycleCollector_setBeforeUnlinkCallback(ClearBlackMarkedNodes);
  1713 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(FragmentOrElement)
  1714   return FragmentOrElement::CanSkip(tmp, aRemovingAllowed);
  1715 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END
  1717 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(FragmentOrElement)
  1718   return FragmentOrElement::CanSkipInCC(tmp);
  1719 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_END
  1721 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN(FragmentOrElement)
  1722   return FragmentOrElement::CanSkipThis(tmp);
  1723 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END
  1725 static const char* kNSURIs[] = {
  1726   " ([none])",
  1727   " (xmlns)",
  1728   " (xml)",
  1729   " (xhtml)",
  1730   " (XLink)",
  1731   " (XSLT)",
  1732   " (XBL)",
  1733   " (MathML)",
  1734   " (RDF)",
  1735   " (XUL)",
  1736   " (SVG)",
  1737   " (XML Events)"
  1738 };
  1740 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(FragmentOrElement)
  1741   if (MOZ_UNLIKELY(cb.WantDebugInfo())) {
  1742     char name[512];
  1743     uint32_t nsid = tmp->GetNameSpaceID();
  1744     nsAtomCString localName(tmp->NodeInfo()->NameAtom());
  1745     nsAutoCString uri;
  1746     if (tmp->OwnerDoc()->GetDocumentURI()) {
  1747       tmp->OwnerDoc()->GetDocumentURI()->GetSpec(uri);
  1750     nsAutoString id;
  1751     nsIAtom* idAtom = tmp->GetID();
  1752     if (idAtom) {
  1753       id.AppendLiteral(" id='");
  1754       id.Append(nsDependentAtomString(idAtom));
  1755       id.AppendLiteral("'");
  1758     nsAutoString classes;
  1759     const nsAttrValue* classAttrValue = tmp->GetClasses();
  1760     if (classAttrValue) {
  1761       classes.AppendLiteral(" class='");
  1762       nsAutoString classString;
  1763       classAttrValue->ToString(classString);
  1764       classString.ReplaceChar(char16_t('\n'), char16_t(' '));
  1765       classes.Append(classString);
  1766       classes.AppendLiteral("'");
  1769     nsAutoCString orphan;
  1770     if (!tmp->IsInDoc() &&
  1771         // Ignore xbl:content, which is never in the document and hence always
  1772         // appears to be orphaned.
  1773         !tmp->NodeInfo()->Equals(nsGkAtoms::content, kNameSpaceID_XBL)) {
  1774       orphan.AppendLiteral(" (orphan)");
  1777     const char* nsuri = nsid < ArrayLength(kNSURIs) ? kNSURIs[nsid] : "";
  1778     PR_snprintf(name, sizeof(name), "FragmentOrElement%s %s%s%s%s %s",
  1779                 nsuri,
  1780                 localName.get(),
  1781                 NS_ConvertUTF16toUTF8(id).get(),
  1782                 NS_ConvertUTF16toUTF8(classes).get(),
  1783                 orphan.get(),
  1784                 uri.get());
  1785     cb.DescribeRefCountedNode(tmp->mRefCnt.get(), name);
  1787   else {
  1788     NS_IMPL_CYCLE_COLLECTION_DESCRIBE(FragmentOrElement, tmp->mRefCnt.get())
  1791   // Always need to traverse script objects, so do that before we check
  1792   // if we're uncollectable.
  1793   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
  1795   if (!nsINode::Traverse(tmp, cb)) {
  1796     return NS_SUCCESS_INTERRUPTED_TRAVERSE;
  1799   tmp->OwnerDoc()->BindingManager()->Traverse(tmp, cb);
  1801   if (tmp->HasProperties()) {
  1802     if (tmp->IsHTML()) {
  1803       nsIAtom*** props = nsGenericHTMLElement::PropertiesToTraverseAndUnlink();
  1804       for (uint32_t i = 0; props[i]; ++i) {
  1805         nsISupports* property =
  1806           static_cast<nsISupports*>(tmp->GetProperty(*props[i]));
  1807         cb.NoteXPCOMChild(property);
  1812   // Traverse attribute names and child content.
  1814     uint32_t i;
  1815     uint32_t attrs = tmp->mAttrsAndChildren.AttrCount();
  1816     for (i = 0; i < attrs; i++) {
  1817       const nsAttrName* name = tmp->mAttrsAndChildren.AttrNameAt(i);
  1818       if (!name->IsAtom()) {
  1819         NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb,
  1820                                            "mAttrsAndChildren[i]->NodeInfo()");
  1821         cb.NoteXPCOMChild(name->NodeInfo());
  1825     uint32_t kids = tmp->mAttrsAndChildren.ChildCount();
  1826     for (i = 0; i < kids; i++) {
  1827       NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mAttrsAndChildren[i]");
  1828       cb.NoteXPCOMChild(tmp->mAttrsAndChildren.GetSafeChildAt(i));
  1832   // Traverse any DOM slots of interest.
  1834     nsDOMSlots *slots = tmp->GetExistingDOMSlots();
  1835     if (slots) {
  1836       slots->Traverse(cb, tmp->IsXUL());
  1839 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
  1842 NS_INTERFACE_MAP_BEGIN(FragmentOrElement)
  1843   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
  1844   NS_INTERFACE_MAP_ENTRIES_CYCLE_COLLECTION(FragmentOrElement)
  1845   NS_INTERFACE_MAP_ENTRY(Element)
  1846   NS_INTERFACE_MAP_ENTRY(nsIContent)
  1847   NS_INTERFACE_MAP_ENTRY(nsINode)
  1848   NS_INTERFACE_MAP_ENTRY(nsIDOMEventTarget)
  1849   NS_INTERFACE_MAP_ENTRY(mozilla::dom::EventTarget)
  1850   NS_INTERFACE_MAP_ENTRY_TEAROFF(nsISupportsWeakReference,
  1851                                  new nsNodeSupportsWeakRefTearoff(this))
  1852   NS_INTERFACE_MAP_ENTRY_TEAROFF(nsIDOMXPathNSResolver,
  1853                                  new nsNode3Tearoff(this))
  1854   // DOM bindings depend on the identity pointer being the
  1855   // same as nsINode (which nsIContent inherits).
  1856   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIContent)
  1857 NS_INTERFACE_MAP_END
  1859 NS_IMPL_CYCLE_COLLECTING_ADDREF(FragmentOrElement)
  1860 NS_IMPL_CYCLE_COLLECTING_RELEASE_WITH_LAST_RELEASE(FragmentOrElement,
  1861                                                    nsNodeUtils::LastRelease(this))
  1863 //----------------------------------------------------------------------
  1865 nsresult
  1866 FragmentOrElement::CopyInnerTo(FragmentOrElement* aDst)
  1868   uint32_t i, count = mAttrsAndChildren.AttrCount();
  1869   for (i = 0; i < count; ++i) {
  1870     const nsAttrName* name = mAttrsAndChildren.AttrNameAt(i);
  1871     const nsAttrValue* value = mAttrsAndChildren.AttrAt(i);
  1872     nsAutoString valStr;
  1873     value->ToString(valStr);
  1874     nsresult rv = aDst->SetAttr(name->NamespaceID(), name->LocalName(),
  1875                                 name->GetPrefix(), valStr, false);
  1876     NS_ENSURE_SUCCESS(rv, rv);
  1879   return NS_OK;
  1882 const nsTextFragment*
  1883 FragmentOrElement::GetText()
  1885   return nullptr;
  1888 uint32_t
  1889 FragmentOrElement::TextLength() const
  1891   // We can remove this assertion if it turns out to be useful to be able
  1892   // to depend on this returning 0
  1893   NS_NOTREACHED("called FragmentOrElement::TextLength");
  1895   return 0;
  1898 nsresult
  1899 FragmentOrElement::SetText(const char16_t* aBuffer, uint32_t aLength,
  1900                           bool aNotify)
  1902   NS_ERROR("called FragmentOrElement::SetText");
  1904   return NS_ERROR_FAILURE;
  1907 nsresult
  1908 FragmentOrElement::AppendText(const char16_t* aBuffer, uint32_t aLength,
  1909                              bool aNotify)
  1911   NS_ERROR("called FragmentOrElement::AppendText");
  1913   return NS_ERROR_FAILURE;
  1916 bool
  1917 FragmentOrElement::TextIsOnlyWhitespace()
  1919   return false;
  1922 bool
  1923 FragmentOrElement::HasTextForTranslation()
  1925   return false;
  1928 void
  1929 FragmentOrElement::AppendTextTo(nsAString& aResult)
  1931   // We can remove this assertion if it turns out to be useful to be able
  1932   // to depend on this appending nothing.
  1933   NS_NOTREACHED("called FragmentOrElement::TextLength");
  1936 bool
  1937 FragmentOrElement::AppendTextTo(nsAString& aResult, const mozilla::fallible_t&)
  1939   // We can remove this assertion if it turns out to be useful to be able
  1940   // to depend on this appending nothing.
  1941   NS_NOTREACHED("called FragmentOrElement::TextLength");
  1943   return false;
  1946 uint32_t
  1947 FragmentOrElement::GetChildCount() const
  1949   return mAttrsAndChildren.ChildCount();
  1952 nsIContent *
  1953 FragmentOrElement::GetChildAt(uint32_t aIndex) const
  1955   return mAttrsAndChildren.GetSafeChildAt(aIndex);
  1958 nsIContent * const *
  1959 FragmentOrElement::GetChildArray(uint32_t* aChildCount) const
  1961   return mAttrsAndChildren.GetChildArray(aChildCount);
  1964 int32_t
  1965 FragmentOrElement::IndexOf(const nsINode* aPossibleChild) const
  1967   return mAttrsAndChildren.IndexOfChild(aPossibleChild);
  1970 // Try to keep the size of StringBuilder close to a jemalloc bucket size.
  1971 #define STRING_BUFFER_UNITS 1020
  1973 namespace {
  1975 // We put StringBuilder in the anonymous namespace to prevent anything outside
  1976 // this file from accidentally being linked against it.
  1978 class StringBuilder
  1980 private:
  1981   class Unit
  1983   public:
  1984     Unit() : mAtom(nullptr), mType(eUnknown), mLength(0)
  1986       MOZ_COUNT_CTOR(StringBuilder::Unit);
  1988     ~Unit()
  1990       if (mType == eString || mType == eStringWithEncode) {
  1991         delete mString;
  1993       MOZ_COUNT_DTOR(StringBuilder::Unit);
  1996     enum Type
  1998       eUnknown,
  1999       eAtom,
  2000       eString,
  2001       eStringWithEncode,
  2002       eLiteral,
  2003       eTextFragment,
  2004       eTextFragmentWithEncode,
  2005     };
  2007     union
  2009       nsIAtom*              mAtom;
  2010       const char*           mLiteral;
  2011       nsAutoString*         mString;
  2012       const nsTextFragment* mTextFragment;
  2013     };
  2014     Type     mType;
  2015     uint32_t mLength;
  2016   };
  2017 public:
  2018   StringBuilder() : mLast(MOZ_THIS_IN_INITIALIZER_LIST()), mLength(0)
  2020     MOZ_COUNT_CTOR(StringBuilder);
  2023   ~StringBuilder()
  2025     MOZ_COUNT_DTOR(StringBuilder);
  2028   void Append(nsIAtom* aAtom)
  2030     Unit* u = AddUnit();
  2031     u->mAtom = aAtom;
  2032     u->mType = Unit::eAtom;
  2033     uint32_t len = aAtom->GetLength();
  2034     u->mLength = len;
  2035     mLength += len;
  2038   template<int N>
  2039   void Append(const char (&aLiteral)[N])
  2041     Unit* u = AddUnit();
  2042     u->mLiteral = aLiteral;
  2043     u->mType = Unit::eLiteral;
  2044     uint32_t len = N - 1;
  2045     u->mLength = len;
  2046     mLength += len;
  2049   template<int N>
  2050   void Append(char (&aLiteral)[N])
  2052     Unit* u = AddUnit();
  2053     u->mLiteral = aLiteral;
  2054     u->mType = Unit::eLiteral;
  2055     uint32_t len = N - 1;
  2056     u->mLength = len;
  2057     mLength += len;
  2060   void Append(const nsAString& aString)
  2062     Unit* u = AddUnit();
  2063     u->mString = new nsAutoString(aString);
  2064     u->mType = Unit::eString;
  2065     uint32_t len = aString.Length();
  2066     u->mLength = len;
  2067     mLength += len;
  2070   void Append(nsAutoString* aString)
  2072     Unit* u = AddUnit();
  2073     u->mString = aString;
  2074     u->mType = Unit::eString;
  2075     uint32_t len = aString->Length();
  2076     u->mLength = len;
  2077     mLength += len;
  2080   void AppendWithAttrEncode(nsAutoString* aString, uint32_t aLen)
  2082     Unit* u = AddUnit();
  2083     u->mString = aString;
  2084     u->mType = Unit::eStringWithEncode;
  2085     u->mLength = aLen;
  2086     mLength += aLen;
  2089   void Append(const nsTextFragment* aTextFragment)
  2091     Unit* u = AddUnit();
  2092     u->mTextFragment = aTextFragment;
  2093     u->mType = Unit::eTextFragment;
  2094     uint32_t len = aTextFragment->GetLength();
  2095     u->mLength = len;
  2096     mLength += len;
  2099   void AppendWithEncode(const nsTextFragment* aTextFragment, uint32_t aLen)
  2101     Unit* u = AddUnit();
  2102     u->mTextFragment = aTextFragment;
  2103     u->mType = Unit::eTextFragmentWithEncode;
  2104     u->mLength = aLen;
  2105     mLength += aLen;
  2108   bool ToString(nsAString& aOut)
  2110     if (!aOut.SetCapacity(mLength, fallible_t())) {
  2111       return false;
  2114     for (StringBuilder* current = this; current; current = current->mNext) {
  2115       uint32_t len = current->mUnits.Length();
  2116       for (uint32_t i = 0; i < len; ++i) {
  2117         Unit& u = current->mUnits[i];
  2118         switch (u.mType) {
  2119           case Unit::eAtom:
  2120             aOut.Append(nsDependentAtomString(u.mAtom));
  2121             break;
  2122           case Unit::eString:
  2123             aOut.Append(*(u.mString));
  2124             break;
  2125           case Unit::eStringWithEncode:
  2126             EncodeAttrString(*(u.mString), aOut);
  2127             break;
  2128           case Unit::eLiteral:
  2129             aOut.AppendASCII(u.mLiteral, u.mLength);
  2130             break;
  2131           case Unit::eTextFragment:
  2132             u.mTextFragment->AppendTo(aOut);
  2133             break;
  2134           case Unit::eTextFragmentWithEncode:
  2135             EncodeTextFragment(u.mTextFragment, aOut);
  2136             break;
  2137           default:
  2138             MOZ_CRASH("Unknown unit type?");
  2142     return true;
  2144 private:
  2145   Unit* AddUnit()
  2147     if (mLast->mUnits.Length() == STRING_BUFFER_UNITS) {
  2148       new StringBuilder(this);
  2150     return mLast->mUnits.AppendElement();
  2153   StringBuilder(StringBuilder* aFirst)
  2154   : mLast(nullptr), mLength(0)
  2156     MOZ_COUNT_CTOR(StringBuilder);
  2157     aFirst->mLast->mNext = this;
  2158     aFirst->mLast = this;
  2161   void EncodeAttrString(const nsAutoString& aValue, nsAString& aOut)
  2163     const char16_t* c = aValue.BeginReading();
  2164     const char16_t* end = aValue.EndReading();
  2165     while (c < end) {
  2166       switch (*c) {
  2167       case '"':
  2168         aOut.AppendLiteral("&quot;");
  2169         break;
  2170       case '&':
  2171         aOut.AppendLiteral("&amp;");
  2172         break;
  2173       case 0x00A0:
  2174         aOut.AppendLiteral("&nbsp;");
  2175         break;
  2176       default:
  2177         aOut.Append(*c);
  2178         break;
  2180       ++c;
  2184   void EncodeTextFragment(const nsTextFragment* aValue, nsAString& aOut)
  2186     uint32_t len = aValue->GetLength();
  2187     if (aValue->Is2b()) {
  2188       const char16_t* data = aValue->Get2b();
  2189       for (uint32_t i = 0; i < len; ++i) {
  2190         const char16_t c = data[i];
  2191         switch (c) {
  2192           case '<':
  2193             aOut.AppendLiteral("&lt;");
  2194             break;
  2195           case '>':
  2196             aOut.AppendLiteral("&gt;");
  2197             break;
  2198           case '&':
  2199             aOut.AppendLiteral("&amp;");
  2200             break;
  2201           case 0x00A0:
  2202             aOut.AppendLiteral("&nbsp;");
  2203             break;
  2204           default:
  2205             aOut.Append(c);
  2206             break;
  2209     } else {
  2210       const char* data = aValue->Get1b();
  2211       for (uint32_t i = 0; i < len; ++i) {
  2212         const unsigned char c = data[i];
  2213         switch (c) {
  2214           case '<':
  2215             aOut.AppendLiteral("&lt;");
  2216             break;
  2217           case '>':
  2218             aOut.AppendLiteral("&gt;");
  2219             break;
  2220           case '&':
  2221             aOut.AppendLiteral("&amp;");
  2222             break;
  2223           case 0x00A0:
  2224             aOut.AppendLiteral("&nbsp;");
  2225             break;
  2226           default:
  2227             aOut.Append(c);
  2228             break;
  2234   nsAutoTArray<Unit, STRING_BUFFER_UNITS> mUnits;
  2235   nsAutoPtr<StringBuilder>                mNext;
  2236   StringBuilder*                          mLast;
  2237   // mLength is used only in the first StringBuilder object in the linked list.
  2238   uint32_t                                mLength;
  2239 };
  2241 } // anonymous namespace
  2243 static void
  2244 AppendEncodedCharacters(const nsTextFragment* aText, StringBuilder& aBuilder)
  2246   uint32_t extraSpaceNeeded = 0;
  2247   uint32_t len = aText->GetLength();
  2248   if (aText->Is2b()) {
  2249     const char16_t* data = aText->Get2b();
  2250     for (uint32_t i = 0; i < len; ++i) {
  2251       const char16_t c = data[i];
  2252       switch (c) {
  2253         case '<':
  2254           extraSpaceNeeded += ArrayLength("&lt;") - 2;
  2255           break;
  2256         case '>':
  2257           extraSpaceNeeded += ArrayLength("&gt;") - 2;
  2258           break;
  2259         case '&':
  2260           extraSpaceNeeded += ArrayLength("&amp;") - 2;
  2261           break;
  2262         case 0x00A0:
  2263           extraSpaceNeeded += ArrayLength("&nbsp;") - 2;
  2264           break;
  2265         default:
  2266           break;
  2269   } else {
  2270     const char* data = aText->Get1b();
  2271     for (uint32_t i = 0; i < len; ++i) {
  2272       const unsigned char c = data[i];
  2273       switch (c) {
  2274         case '<':
  2275           extraSpaceNeeded += ArrayLength("&lt;") - 2;
  2276           break;
  2277         case '>':
  2278           extraSpaceNeeded += ArrayLength("&gt;") - 2;
  2279           break;
  2280         case '&':
  2281           extraSpaceNeeded += ArrayLength("&amp;") - 2;
  2282           break;
  2283         case 0x00A0:
  2284           extraSpaceNeeded += ArrayLength("&nbsp;") - 2;
  2285           break;
  2286         default:
  2287           break;
  2292   if (extraSpaceNeeded) {
  2293     aBuilder.AppendWithEncode(aText, len + extraSpaceNeeded);
  2294   } else {
  2295     aBuilder.Append(aText);
  2299 static void
  2300 AppendEncodedAttributeValue(nsAutoString* aValue, StringBuilder& aBuilder)
  2302   const char16_t* c = aValue->BeginReading();
  2303   const char16_t* end = aValue->EndReading();
  2305   uint32_t extraSpaceNeeded = 0;
  2306   while (c < end) {
  2307     switch (*c) {
  2308       case '"':
  2309         extraSpaceNeeded += ArrayLength("&quot;") - 2;
  2310         break;
  2311       case '&':
  2312         extraSpaceNeeded += ArrayLength("&amp;") - 2;
  2313         break;
  2314       case 0x00A0:
  2315         extraSpaceNeeded += ArrayLength("&nbsp;") - 2;
  2316         break;
  2317       default:
  2318         break;
  2320     ++c;
  2323   if (extraSpaceNeeded) {
  2324     aBuilder.AppendWithAttrEncode(aValue, aValue->Length() + extraSpaceNeeded);
  2325   } else {
  2326     aBuilder.Append(aValue);
  2330 static void
  2331 StartElement(Element* aContent, StringBuilder& aBuilder)
  2333   nsIAtom* localName = aContent->Tag();
  2334   int32_t tagNS = aContent->GetNameSpaceID();
  2336   aBuilder.Append("<");
  2337   if (aContent->IsHTML() || aContent->IsSVG() || aContent->IsMathML()) {
  2338     aBuilder.Append(localName);
  2339   } else {
  2340     aBuilder.Append(aContent->NodeName());
  2343   int32_t count = aContent->GetAttrCount();
  2344   for (int32_t i = count; i > 0;) {
  2345     --i;
  2346     const nsAttrName* name = aContent->GetAttrNameAt(i);
  2347     int32_t attNs = name->NamespaceID();
  2348     nsIAtom* attName = name->LocalName();
  2350     // Filter out any attribute starting with [-|_]moz
  2351     nsDependentAtomString attrNameStr(attName);
  2352     if (StringBeginsWith(attrNameStr, NS_LITERAL_STRING("_moz")) ||
  2353         StringBeginsWith(attrNameStr, NS_LITERAL_STRING("-moz"))) {
  2354       continue;
  2357     nsAutoString* attValue = new nsAutoString();
  2358     aContent->GetAttr(attNs, attName, *attValue);
  2360     // Filter out special case of <br type="_moz*"> used by the editor.
  2361     // Bug 16988.  Yuck.
  2362     if (localName == nsGkAtoms::br && tagNS == kNameSpaceID_XHTML &&
  2363         attName == nsGkAtoms::type && attNs == kNameSpaceID_None &&
  2364         StringBeginsWith(*attValue, NS_LITERAL_STRING("_moz"))) {
  2365       delete attValue;
  2366       continue;
  2369     aBuilder.Append(" ");
  2371     if (MOZ_LIKELY(attNs == kNameSpaceID_None) ||
  2372         (attNs == kNameSpaceID_XMLNS &&
  2373          attName == nsGkAtoms::xmlns)) {
  2374       // Nothing else required
  2375     } else if (attNs == kNameSpaceID_XML) {
  2376       aBuilder.Append("xml:");
  2377     } else if (attNs == kNameSpaceID_XMLNS) {
  2378       aBuilder.Append("xmlns:");
  2379     } else if (attNs == kNameSpaceID_XLink) {
  2380       aBuilder.Append("xlink:");
  2381     } else {
  2382       nsIAtom* prefix = name->GetPrefix();
  2383       if (prefix) {
  2384         aBuilder.Append(prefix);
  2385         aBuilder.Append(":");
  2389     aBuilder.Append(attName);
  2390     aBuilder.Append("=\"");
  2391     AppendEncodedAttributeValue(attValue, aBuilder);
  2392     aBuilder.Append("\"");
  2395   aBuilder.Append(">");
  2397   /*
  2398   // Per HTML spec we should append one \n if the first child of
  2399   // pre/textarea/listing is a textnode and starts with a \n.
  2400   // But because browsers haven't traditionally had that behavior,
  2401   // we're not changing our behavior either - yet.
  2402   if (aContent->IsHTML()) {
  2403     if (localName == nsGkAtoms::pre || localName == nsGkAtoms::textarea ||
  2404         localName == nsGkAtoms::listing) {
  2405       nsIContent* fc = aContent->GetFirstChild();
  2406       if (fc &&
  2407           (fc->NodeType() == nsIDOMNode::TEXT_NODE ||
  2408            fc->NodeType() == nsIDOMNode::CDATA_SECTION_NODE)) {
  2409         const nsTextFragment* text = fc->GetText();
  2410         if (text && text->GetLength() && text->CharAt(0) == char16_t('\n')) {
  2411           aBuilder.Append("\n");
  2415   }*/
  2418 static inline bool
  2419 ShouldEscape(nsIContent* aParent)
  2421   if (!aParent || !aParent->IsHTML()) {
  2422     return true;
  2425   static const nsIAtom* nonEscapingElements[] = {
  2426     nsGkAtoms::style, nsGkAtoms::script, nsGkAtoms::xmp,
  2427     nsGkAtoms::iframe, nsGkAtoms::noembed, nsGkAtoms::noframes,
  2428     nsGkAtoms::plaintext, 
  2429     // Per the current spec noscript should be escaped in case
  2430     // scripts are disabled or if document doesn't have
  2431     // browsing context. However the latter seems to be a spec bug
  2432     // and Gecko hasn't traditionally done the former.
  2433     nsGkAtoms::noscript    
  2434   };
  2435   static mozilla::BloomFilter<12, nsIAtom> sFilter;
  2436   static bool sInitialized = false;
  2437   if (!sInitialized) {
  2438     sInitialized = true;
  2439     for (uint32_t i = 0; i < ArrayLength(nonEscapingElements); ++i) {
  2440       sFilter.add(nonEscapingElements[i]);
  2444   nsIAtom* tag = aParent->Tag();
  2445   if (sFilter.mightContain(tag)) {
  2446     for (uint32_t i = 0; i < ArrayLength(nonEscapingElements); ++i) {
  2447       if (tag == nonEscapingElements[i]) {
  2448         return false;
  2452   return true;
  2455 static inline bool
  2456 IsVoidTag(Element* aElement)
  2458   if (!aElement->IsHTML()) {
  2459     return false;
  2462   static const nsIAtom* voidElements[] = {
  2463     nsGkAtoms::area, nsGkAtoms::base, nsGkAtoms::basefont,
  2464     nsGkAtoms::bgsound, nsGkAtoms::br, nsGkAtoms::col,
  2465     nsGkAtoms::command, nsGkAtoms::embed, nsGkAtoms::frame,
  2466     nsGkAtoms::hr, nsGkAtoms::img, nsGkAtoms::input,
  2467     nsGkAtoms::keygen, nsGkAtoms::link, nsGkAtoms::meta,
  2468     nsGkAtoms::param, nsGkAtoms::source, nsGkAtoms::track,
  2469     nsGkAtoms::wbr
  2470   };
  2472   static mozilla::BloomFilter<12, nsIAtom> sFilter;
  2473   static bool sInitialized = false;
  2474   if (!sInitialized) {
  2475     sInitialized = true;
  2476     for (uint32_t i = 0; i < ArrayLength(voidElements); ++i) {
  2477       sFilter.add(voidElements[i]);
  2481   nsIAtom* tag = aElement->Tag();
  2482   if (sFilter.mightContain(tag)) {
  2483     for (uint32_t i = 0; i < ArrayLength(voidElements); ++i) {
  2484       if (tag == voidElements[i]) {
  2485         return true;
  2489   return false;
  2492 static bool
  2493 Serialize(FragmentOrElement* aRoot, bool aDescendentsOnly, nsAString& aOut)
  2495   nsINode* current = aDescendentsOnly ?
  2496     nsNodeUtils::GetFirstChildOfTemplateOrNode(aRoot) : aRoot;
  2498   if (!current) {
  2499     return true;
  2502   StringBuilder builder;
  2503   nsIContent* next;
  2504   while (true) {
  2505     bool isVoid = false;
  2506     switch (current->NodeType()) {
  2507       case nsIDOMNode::ELEMENT_NODE: {
  2508         Element* elem = current->AsElement();
  2509         StartElement(elem, builder);
  2510         isVoid = IsVoidTag(elem);
  2511         if (!isVoid &&
  2512             (next = nsNodeUtils::GetFirstChildOfTemplateOrNode(current))) {
  2513           current = next;
  2514           continue;
  2516         break;
  2519       case nsIDOMNode::TEXT_NODE:
  2520       case nsIDOMNode::CDATA_SECTION_NODE: {
  2521         const nsTextFragment* text = static_cast<nsIContent*>(current)->GetText();
  2522         nsIContent* parent = current->GetParent();
  2523         if (ShouldEscape(parent)) {
  2524           AppendEncodedCharacters(text, builder);
  2525         } else {
  2526           builder.Append(text);
  2528         break;
  2531       case nsIDOMNode::COMMENT_NODE: {
  2532         builder.Append("<!--");
  2533         builder.Append(static_cast<nsIContent*>(current)->GetText());
  2534         builder.Append("-->");
  2535         break;
  2538       case nsIDOMNode::DOCUMENT_TYPE_NODE: {
  2539         builder.Append("<!DOCTYPE ");
  2540         builder.Append(current->NodeName());
  2541         builder.Append(">");
  2542         break;
  2545       case nsIDOMNode::PROCESSING_INSTRUCTION_NODE: {
  2546         builder.Append("<?");
  2547         builder.Append(current->NodeName());
  2548         builder.Append(" ");
  2549         builder.Append(static_cast<nsIContent*>(current)->GetText());
  2550         builder.Append(">");
  2551         break;
  2555     while (true) {
  2556       if (!isVoid && current->NodeType() == nsIDOMNode::ELEMENT_NODE) {
  2557         builder.Append("</");
  2558         nsIContent* elem = static_cast<nsIContent*>(current);
  2559         if (elem->IsHTML() || elem->IsSVG() || elem->IsMathML()) {
  2560           builder.Append(elem->Tag());
  2561         } else {
  2562           builder.Append(current->NodeName());
  2564         builder.Append(">");
  2566       isVoid = false;
  2568       if (current == aRoot) {
  2569         return builder.ToString(aOut);
  2572       if ((next = current->GetNextSibling())) {
  2573         current = next;
  2574         break;
  2577       current = current->GetParentNode();
  2579       // Template case, if we are in a template's content, then the parent
  2580       // should be the host template element.
  2581       if (current->NodeType() == nsIDOMNode::DOCUMENT_FRAGMENT_NODE) {
  2582         DocumentFragment* frag = static_cast<DocumentFragment*>(current);
  2583         nsIContent* fragHost = frag->GetHost();
  2584         if (fragHost && nsNodeUtils::IsTemplateElement(fragHost)) {
  2585           current = fragHost;
  2589       if (aDescendentsOnly && current == aRoot) {
  2590         return builder.ToString(aOut);
  2596 void
  2597 FragmentOrElement::GetMarkup(bool aIncludeSelf, nsAString& aMarkup)
  2599   aMarkup.Truncate();
  2601   nsIDocument* doc = OwnerDoc();
  2602   if (IsInHTMLDocument()) {
  2603     Serialize(this, !aIncludeSelf, aMarkup);
  2604     return;
  2607   nsAutoString contentType;
  2608   doc->GetContentType(contentType);
  2609   bool tryToCacheEncoder = !aIncludeSelf;
  2611   nsCOMPtr<nsIDocumentEncoder> docEncoder = doc->GetCachedEncoder();
  2612   if (!docEncoder) {
  2613     docEncoder =
  2614       do_CreateInstance(PromiseFlatCString(
  2615         nsDependentCString(NS_DOC_ENCODER_CONTRACTID_BASE) +
  2616         NS_ConvertUTF16toUTF8(contentType)
  2617       ).get());
  2619   if (!docEncoder) {
  2620     // This could be some type for which we create a synthetic document.  Try
  2621     // again as XML
  2622     contentType.AssignLiteral("application/xml");
  2623     docEncoder = do_CreateInstance(NS_DOC_ENCODER_CONTRACTID_BASE "application/xml");
  2624     // Don't try to cache the encoder since it would point to a different
  2625     // contentType once it has been reinitialized.
  2626     tryToCacheEncoder = false;
  2629   NS_ENSURE_TRUE_VOID(docEncoder);
  2631   uint32_t flags = nsIDocumentEncoder::OutputEncodeBasicEntities |
  2632                    // Output DOM-standard newlines
  2633                    nsIDocumentEncoder::OutputLFLineBreak |
  2634                    // Don't do linebreaking that's not present in
  2635                    // the source
  2636                    nsIDocumentEncoder::OutputRaw |
  2637                    // Only check for mozdirty when necessary (bug 599983)
  2638                    nsIDocumentEncoder::OutputIgnoreMozDirty;
  2640   if (IsEditable()) {
  2641     nsCOMPtr<Element> elem = do_QueryInterface(this);
  2642     nsIEditor* editor = elem ? elem->GetEditorInternal() : nullptr;
  2643     if (editor && editor->OutputsMozDirty()) {
  2644       flags &= ~nsIDocumentEncoder::OutputIgnoreMozDirty;
  2648   DebugOnly<nsresult> rv = docEncoder->NativeInit(doc, contentType, flags);
  2649   MOZ_ASSERT(NS_SUCCEEDED(rv));
  2651   if (aIncludeSelf) {
  2652     docEncoder->SetNativeNode(this);
  2653   } else {
  2654     docEncoder->SetNativeContainerNode(this);
  2656   rv = docEncoder->EncodeToString(aMarkup);
  2657   MOZ_ASSERT(NS_SUCCEEDED(rv));
  2658   if (tryToCacheEncoder) {
  2659     doc->SetCachedEncoder(docEncoder.forget());
  2663 static bool
  2664 ContainsMarkup(const nsAString& aStr)
  2666   // Note: we can't use FindCharInSet because null is one of the characters we
  2667   // want to search for.
  2668   const char16_t* start = aStr.BeginReading();
  2669   const char16_t* end = aStr.EndReading();
  2671   while (start != end) {
  2672     char16_t c = *start;
  2673     if (c == char16_t('<') ||
  2674         c == char16_t('&') ||
  2675         c == char16_t('\r') ||
  2676         c == char16_t('\0')) {
  2677       return true;
  2679     ++start;
  2682   return false;
  2685 void
  2686 FragmentOrElement::SetInnerHTMLInternal(const nsAString& aInnerHTML, ErrorResult& aError)
  2688   FragmentOrElement* target = this;
  2689   // Handle template case.
  2690   if (nsNodeUtils::IsTemplateElement(target)) {
  2691     DocumentFragment* frag =
  2692       static_cast<HTMLTemplateElement*>(target)->Content();
  2693     MOZ_ASSERT(frag);
  2694     target = frag;
  2697   // Fast-path for strings with no markup. Limit this to short strings, to
  2698   // avoid ContainsMarkup taking too long. The choice for 100 is based on
  2699   // gut feeling.
  2700   //
  2701   // Don't do this for elements with a weird parser insertion mode, for
  2702   // instance setting innerHTML = "" on a <html> element should add the
  2703   // optional <head> and <body> elements.
  2704   if (!target->HasWeirdParserInsertionMode() &&
  2705       aInnerHTML.Length() < 100 && !ContainsMarkup(aInnerHTML)) {
  2706     aError = nsContentUtils::SetNodeTextContent(target, aInnerHTML, false);
  2707     return;
  2710   nsIDocument* doc = target->OwnerDoc();
  2712   // Batch possible DOMSubtreeModified events.
  2713   mozAutoSubtreeModified subtree(doc, nullptr);
  2715   target->FireNodeRemovedForChildren();
  2717   // Needed when innerHTML is used in combination with contenteditable
  2718   mozAutoDocUpdate updateBatch(doc, UPDATE_CONTENT_MODEL, true);
  2720   // Remove childnodes.
  2721   uint32_t childCount = target->GetChildCount();
  2722   nsAutoMutationBatch mb(target, true, false);
  2723   for (uint32_t i = 0; i < childCount; ++i) {
  2724     target->RemoveChildAt(0, true);
  2726   mb.RemovalDone();
  2728   nsAutoScriptLoaderDisabler sld(doc);
  2730   nsIAtom* contextLocalName = Tag();
  2731   int32_t contextNameSpaceID = GetNameSpaceID();
  2733   ShadowRoot* shadowRoot = ShadowRoot::FromNode(this);
  2734   if (shadowRoot) {
  2735     // Fix up the context to be the host of the ShadowRoot.
  2736     contextLocalName = shadowRoot->GetHost()->Tag();
  2737     contextNameSpaceID = shadowRoot->GetHost()->GetNameSpaceID();
  2740   if (doc->IsHTML()) {
  2741     int32_t oldChildCount = target->GetChildCount();
  2742     aError = nsContentUtils::ParseFragmentHTML(aInnerHTML,
  2743                                                target,
  2744                                                contextLocalName,
  2745                                                contextNameSpaceID,
  2746                                                doc->GetCompatibilityMode() ==
  2747                                                  eCompatibility_NavQuirks,
  2748                                                true);
  2749     mb.NodesAdded();
  2750     // HTML5 parser has notified, but not fired mutation events.
  2751     nsContentUtils::FireMutationEventsForDirectParsing(doc, target,
  2752                                                        oldChildCount);
  2753   } else {
  2754     nsRefPtr<DocumentFragment> df =
  2755       nsContentUtils::CreateContextualFragment(target, aInnerHTML, true, aError);
  2756     if (!aError.Failed()) {
  2757       // Suppress assertion about node removal mutation events that can't have
  2758       // listeners anyway, because no one has had the chance to register mutation
  2759       // listeners on the fragment that comes from the parser.
  2760       nsAutoScriptBlockerSuppressNodeRemoved scriptBlocker;
  2762       static_cast<nsINode*>(target)->AppendChild(*df, aError);
  2763       mb.NodesAdded();
  2768 nsINode::nsSlots*
  2769 FragmentOrElement::CreateSlots()
  2771   return new nsDOMSlots();
  2774 void
  2775 FragmentOrElement::FireNodeRemovedForChildren()
  2777   nsIDocument* doc = OwnerDoc();
  2778   // Optimize the common case
  2779   if (!nsContentUtils::
  2780         HasMutationListeners(doc, NS_EVENT_BITS_MUTATION_NODEREMOVED)) {
  2781     return;
  2784   nsCOMPtr<nsIDocument> owningDoc = doc;
  2786   nsCOMPtr<nsINode> child;
  2787   for (child = GetFirstChild();
  2788        child && child->GetParentNode() == this;
  2789        child = child->GetNextSibling()) {
  2790     nsContentUtils::MaybeFireNodeRemoved(child, this, doc);
  2794 size_t
  2795 FragmentOrElement::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
  2797   size_t n = 0;
  2798   n += nsIContent::SizeOfExcludingThis(aMallocSizeOf);
  2799   n += mAttrsAndChildren.SizeOfExcludingThis(aMallocSizeOf);
  2801   nsDOMSlots* slots = GetExistingDOMSlots();
  2802   if (slots) {
  2803     n += slots->SizeOfIncludingThis(aMallocSizeOf);
  2806   return n;

mercurial