Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/dom/base/nsNodeUtils.cpp
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
3
/* This Source Code Form is subject to the terms of the Mozilla Public
4
 * License, v. 2.0. If a copy of the MPL was not distributed with this
5
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7
#include "nsNodeUtils.h"
8
#include "nsContentUtils.h"
9
#include "nsCSSPseudoElements.h"
10
#include "nsINode.h"
11
#include "nsIContent.h"
12
#include "nsIContentInlines.h"
13
#include "mozilla/dom/Element.h"
14
#include "nsIMutationObserver.h"
15
#include "nsIDocument.h"
16
#include "mozilla/EventListenerManager.h"
17
#include "nsIXPConnect.h"
18
#include "PLDHashTable.h"
19
#include "nsCOMArray.h"
20
#include "nsPIDOMWindow.h"
21
#include "nsDocument.h"
22
#ifdef MOZ_XUL
23
#include "nsXULElement.h"
24
#endif
25
#include "nsBindingManager.h"
26
#include "nsGenericHTMLElement.h"
27
#include "mozilla/AnimationTarget.h"
28
#include "mozilla/Assertions.h"
29
#include "mozilla/ErrorResult.h"
30
#include "mozilla/dom/Animation.h"
31
#include "mozilla/dom/HTMLImageElement.h"
32
#include "mozilla/dom/HTMLMediaElement.h"
33
#include "mozilla/dom/KeyframeEffect.h"
34
#include "nsWrapperCacheInlines.h"
35
#include "nsObjectLoadingContent.h"
36
#include "nsDOMMutationObserver.h"
37
#include "mozilla/dom/BindingUtils.h"
38
#include "mozilla/dom/HTMLTemplateElement.h"
39
#include "mozilla/dom/ShadowRoot.h"
40
41
using namespace mozilla;
42
using namespace mozilla::dom;
43
using mozilla::AutoJSContext;
44
45
enum class IsRemoveNotification
46
{
47
  Yes,
48
  No,
49
};
50
51
#ifdef DEBUG
52
#define COMPOSED_DOC_DECL \
53
  const bool wasInComposedDoc = !!node->GetComposedDoc();
54
#else
55
#define COMPOSED_DOC_DECL
56
#endif
57
58
// This macro expects the ownerDocument of content_ to be in scope as
59
// |nsIDocument* doc|
60
#define IMPL_MUTATION_NOTIFICATION(func_, content_, params_, remove_)       \
61
0
  PR_BEGIN_MACRO                                                            \
62
0
  bool needsEnterLeave = doc->MayHaveDOMMutationObservers();                \
63
0
  if (needsEnterLeave) {                                                    \
64
0
    nsDOMMutationObserver::EnterMutationHandling();                         \
65
0
  }                                                                         \
66
0
  nsINode* node = content_;                                                 \
67
0
  COMPOSED_DOC_DECL                                                         \
68
0
  NS_ASSERTION(node->OwnerDoc() == doc, "Bogus document");                  \
69
0
  if (remove_ == IsRemoveNotification::Yes && node->GetComposedDoc()) {     \
70
0
    if (nsIPresShell* shell = doc->GetObservingShell()) {                   \
71
0
      shell->func_ params_;                                                 \
72
0
    }                                                                       \
73
0
  }                                                                         \
74
0
  doc->BindingManager()->func_ params_;                                     \
75
0
  nsINode* last;                                                            \
76
0
  do {                                                                      \
77
0
    nsINode::nsSlots* slots = node->GetExistingSlots();                     \
78
0
    if (slots && !slots->mMutationObservers.IsEmpty()) {                    \
79
0
      NS_OBSERVER_AUTO_ARRAY_NOTIFY_OBSERVERS(                              \
80
0
        slots->mMutationObservers, nsIMutationObserver, 1,                  \
81
0
        func_, params_);                                                    \
82
0
    }                                                                       \
83
0
    last = node;                                                            \
84
0
    if (ShadowRoot* shadow = ShadowRoot::FromNode(node)) {                  \
85
0
      node = shadow->GetHost();                                             \
86
0
    } else {                                                                \
87
0
      node = node->GetParentNode();                                         \
88
0
    }                                                                       \
89
0
  } while (node);                                                           \
90
0
  /* Whitelist NativeAnonymousChildListChange removal notifications from    \
91
0
   * the assertion since it runs from UnbindFromTree, and thus we don't     \
92
0
   * reach the document, but doesn't matter. */                             \
93
0
  MOZ_ASSERT((last == doc) == wasInComposedDoc ||                           \
94
0
             (remove_ == IsRemoveNotification::Yes &&                       \
95
0
              !strcmp(#func_, "NativeAnonymousChildListChange")));          \
96
0
  if (remove_ == IsRemoveNotification::No && last == doc) {                 \
97
0
    if (nsIPresShell* shell = doc->GetObservingShell()) {                   \
98
0
      shell->func_ params_;                                                 \
99
0
    }                                                                       \
100
0
  }                                                                         \
101
0
  if (needsEnterLeave) {                                                    \
102
0
    nsDOMMutationObserver::LeaveMutationHandling();                         \
103
0
  }                                                                         \
104
0
  PR_END_MACRO
105
106
#define IMPL_ANIMATION_NOTIFICATION(func_, content_, params_)     \
107
0
  PR_BEGIN_MACRO                                                  \
108
0
  bool needsEnterLeave = doc->MayHaveDOMMutationObservers();      \
109
0
  if (needsEnterLeave) {                                          \
110
0
    nsDOMMutationObserver::EnterMutationHandling();               \
111
0
  }                                                               \
112
0
  nsINode* node = content_;                                       \
113
0
  do {                                                            \
114
0
    nsINode::nsSlots* slots = node->GetExistingSlots();           \
115
0
    if (slots && !slots->mMutationObservers.IsEmpty()) {          \
116
0
      NS_OBSERVER_AUTO_ARRAY_NOTIFY_OBSERVERS_WITH_QI(            \
117
0
        slots->mMutationObservers, nsIMutationObserver, 1,        \
118
0
        nsIAnimationObserver, func_, params_);                    \
119
0
    }                                                             \
120
0
    if (ShadowRoot* shadow = ShadowRoot::FromNode(node)) {        \
121
0
      node = shadow->GetHost();                                   \
122
0
    } else {                                                      \
123
0
      node = node->GetParentNode();                               \
124
0
    }                                                             \
125
0
  } while (node);                                                 \
126
0
  if (needsEnterLeave) {                                          \
127
0
    nsDOMMutationObserver::LeaveMutationHandling();               \
128
0
  }                                                               \
129
0
  PR_END_MACRO
130
131
void
132
nsNodeUtils::CharacterDataWillChange(nsIContent* aContent,
133
                                     const CharacterDataChangeInfo& aInfo)
134
0
{
135
0
  nsIDocument* doc = aContent->OwnerDoc();
136
0
  IMPL_MUTATION_NOTIFICATION(CharacterDataWillChange, aContent,
137
0
                             (aContent, aInfo), IsRemoveNotification::No);
138
0
}
139
140
void
141
nsNodeUtils::CharacterDataChanged(nsIContent* aContent,
142
                                  const CharacterDataChangeInfo& aInfo)
143
0
{
144
0
  nsIDocument* doc = aContent->OwnerDoc();
145
0
  IMPL_MUTATION_NOTIFICATION(CharacterDataChanged, aContent,
146
0
                             (aContent, aInfo), IsRemoveNotification::No);
147
0
}
148
149
void
150
nsNodeUtils::AttributeWillChange(Element* aElement,
151
                                 int32_t aNameSpaceID,
152
                                 nsAtom* aAttribute,
153
                                 int32_t aModType,
154
                                 const nsAttrValue* aNewValue)
155
0
{
156
0
  nsIDocument* doc = aElement->OwnerDoc();
157
0
  IMPL_MUTATION_NOTIFICATION(AttributeWillChange, aElement,
158
0
                             (aElement, aNameSpaceID, aAttribute,
159
0
                              aModType, aNewValue), IsRemoveNotification::No);
160
0
}
161
162
void
163
nsNodeUtils::AttributeChanged(Element* aElement,
164
                              int32_t aNameSpaceID,
165
                              nsAtom* aAttribute,
166
                              int32_t aModType,
167
                              const nsAttrValue* aOldValue)
168
0
{
169
0
  nsIDocument* doc = aElement->OwnerDoc();
170
0
  IMPL_MUTATION_NOTIFICATION(AttributeChanged, aElement,
171
0
                             (aElement, aNameSpaceID, aAttribute,
172
0
                              aModType, aOldValue), IsRemoveNotification::No);
173
0
}
174
175
void
176
nsNodeUtils::AttributeSetToCurrentValue(Element* aElement,
177
                                        int32_t aNameSpaceID,
178
                                        nsAtom* aAttribute)
179
0
{
180
0
  nsIDocument* doc = aElement->OwnerDoc();
181
0
  IMPL_MUTATION_NOTIFICATION(AttributeSetToCurrentValue, aElement,
182
0
                             (aElement, aNameSpaceID, aAttribute),
183
0
                             IsRemoveNotification::No);
184
0
}
185
186
void
187
nsNodeUtils::ContentAppended(nsIContent* aContainer,
188
                             nsIContent* aFirstNewContent)
189
0
{
190
0
  nsIDocument* doc = aContainer->OwnerDoc();
191
0
192
0
  IMPL_MUTATION_NOTIFICATION(ContentAppended, aContainer,
193
0
                             (aFirstNewContent),
194
0
                             IsRemoveNotification::No);
195
0
}
196
197
void
198
nsNodeUtils::NativeAnonymousChildListChange(nsIContent* aContent,
199
                                            bool aIsRemove)
200
0
{
201
0
  nsIDocument* doc = aContent->OwnerDoc();
202
0
  auto isRemove = aIsRemove
203
0
    ? IsRemoveNotification::Yes : IsRemoveNotification::No;
204
0
  IMPL_MUTATION_NOTIFICATION(NativeAnonymousChildListChange, aContent,
205
0
                            (aContent, aIsRemove),
206
0
                            isRemove);
207
0
}
208
209
void
210
nsNodeUtils::ContentInserted(nsINode* aContainer,
211
                             nsIContent* aChild)
212
0
{
213
0
  MOZ_ASSERT(aContainer->IsContent() || aContainer->IsDocument(),
214
0
             "container must be an nsIContent or an nsIDocument");
215
0
  nsIDocument* doc = aContainer->OwnerDoc();
216
0
  IMPL_MUTATION_NOTIFICATION(ContentInserted, aContainer, (aChild),
217
0
                             IsRemoveNotification::No);
218
0
}
219
220
void
221
nsNodeUtils::ContentRemoved(nsINode* aContainer,
222
                            nsIContent* aChild,
223
                            nsIContent* aPreviousSibling)
224
0
{
225
0
  MOZ_ASSERT(aContainer->IsContent() || aContainer->IsDocument(),
226
0
             "container must be an nsIContent or an nsIDocument");
227
0
  nsIDocument* doc = aContainer->OwnerDoc();
228
0
  MOZ_ASSERT(aChild->GetParentNode() == aContainer,
229
0
             "We expect the parent link to be still around at this point");
230
0
  IMPL_MUTATION_NOTIFICATION(ContentRemoved, aContainer,
231
0
                             (aChild, aPreviousSibling),
232
0
                             IsRemoveNotification::Yes);
233
0
}
234
235
Maybe<NonOwningAnimationTarget>
236
nsNodeUtils::GetTargetForAnimation(const Animation* aAnimation)
237
0
{
238
0
  AnimationEffect* effect = aAnimation->GetEffect();
239
0
  if (!effect || !effect->AsKeyframeEffect()) {
240
0
    return Nothing();
241
0
  }
242
0
  return effect->AsKeyframeEffect()->GetTarget();
243
0
}
244
245
void
246
nsNodeUtils::AnimationMutated(Animation* aAnimation,
247
                              AnimationMutationType aMutatedType)
248
0
{
249
0
  Maybe<NonOwningAnimationTarget> target = GetTargetForAnimation(aAnimation);
250
0
  if (!target) {
251
0
    return;
252
0
  }
253
0
254
0
  // A pseudo element and its parent element use the same owner doc.
255
0
  nsIDocument* doc = target->mElement->OwnerDoc();
256
0
  if (doc->MayHaveAnimationObservers()) {
257
0
    // we use the its parent element as the subject in DOM Mutation Observer.
258
0
    Element* elem = target->mElement;
259
0
    switch (aMutatedType) {
260
0
      case AnimationMutationType::Added:
261
0
        IMPL_ANIMATION_NOTIFICATION(AnimationAdded, elem, (aAnimation));
262
0
        break;
263
0
      case AnimationMutationType::Changed:
264
0
        IMPL_ANIMATION_NOTIFICATION(AnimationChanged, elem, (aAnimation));
265
0
        break;
266
0
      case AnimationMutationType::Removed:
267
0
        IMPL_ANIMATION_NOTIFICATION(AnimationRemoved, elem, (aAnimation));
268
0
        break;
269
0
      default:
270
0
        MOZ_ASSERT_UNREACHABLE("unexpected mutation type");
271
0
    }
272
0
  }
273
0
}
274
275
void
276
nsNodeUtils::AnimationAdded(Animation* aAnimation)
277
0
{
278
0
  AnimationMutated(aAnimation, AnimationMutationType::Added);
279
0
}
280
281
void
282
nsNodeUtils::AnimationChanged(Animation* aAnimation)
283
0
{
284
0
  AnimationMutated(aAnimation, AnimationMutationType::Changed);
285
0
}
286
287
void
288
nsNodeUtils::AnimationRemoved(Animation* aAnimation)
289
0
{
290
0
  AnimationMutated(aAnimation, AnimationMutationType::Removed);
291
0
}
292
293
void
294
nsNodeUtils::LastRelease(nsINode* aNode)
295
0
{
296
0
  nsINode::nsSlots* slots = aNode->GetExistingSlots();
297
0
  if (slots) {
298
0
    if (!slots->mMutationObservers.IsEmpty()) {
299
0
      NS_OBSERVER_AUTO_ARRAY_NOTIFY_OBSERVERS(slots->mMutationObservers,
300
0
                                              nsIMutationObserver, 1,
301
0
                                              NodeWillBeDestroyed, (aNode));
302
0
    }
303
0
304
0
    delete slots;
305
0
    aNode->mSlots = nullptr;
306
0
  }
307
0
308
0
  // Kill properties first since that may run external code, so we want to
309
0
  // be in as complete state as possible at that time.
310
0
  if (aNode->IsDocument()) {
311
0
    // Delete all properties before tearing down the document. Some of the
312
0
    // properties are bound to nsINode objects and the destructor functions of
313
0
    // the properties may want to use the owner document of the nsINode.
314
0
    aNode->AsDocument()->DeleteAllProperties();
315
0
  }
316
0
  else {
317
0
    if (aNode->HasProperties()) {
318
0
      // Strong reference to the document so that deleting properties can't
319
0
      // delete the document.
320
0
      nsCOMPtr<nsIDocument> document = aNode->OwnerDoc();
321
0
      document->DeleteAllPropertiesFor(aNode);
322
0
    }
323
0
324
0
    // I wonder whether it's faster to do the HasFlag check first....
325
0
    if (aNode->IsNodeOfType(nsINode::eHTML_FORM_CONTROL) &&
326
0
        aNode->HasFlag(ADDED_TO_FORM)) {
327
0
      // Tell the form (if any) this node is going away.  Don't
328
0
      // notify, since we're being destroyed in any case.
329
0
      static_cast<nsGenericHTMLFormElement*>(aNode)->ClearForm(true, true);
330
0
    }
331
0
332
0
    if (aNode->IsHTMLElement(nsGkAtoms::img) &&
333
0
        aNode->HasFlag(ADDED_TO_FORM)) {
334
0
      HTMLImageElement* imageElem = static_cast<HTMLImageElement*>(aNode);
335
0
      imageElem->ClearForm(true);
336
0
    }
337
0
  }
338
0
  aNode->UnsetFlags(NODE_HAS_PROPERTIES);
339
0
340
0
  if (aNode->NodeType() != nsINode::DOCUMENT_NODE &&
341
0
      aNode->HasFlag(NODE_HAS_LISTENERMANAGER)) {
342
#ifdef DEBUG
343
    if (nsContentUtils::IsInitialized()) {
344
      EventListenerManager* manager =
345
        nsContentUtils::GetExistingListenerManagerForNode(aNode);
346
      if (!manager) {
347
        NS_ERROR("Huh, our bit says we have a listener manager list, "
348
                 "but there's nothing in the hash!?!!");
349
      }
350
    }
351
#endif
352
353
0
    nsContentUtils::RemoveListenerManager(aNode);
354
0
    aNode->UnsetFlags(NODE_HAS_LISTENERMANAGER);
355
0
  }
356
0
357
0
  if (Element* element = Element::FromNode(aNode)) {
358
0
    element->OwnerDoc()->ClearBoxObjectFor(element);
359
0
    NS_ASSERTION(!element->GetXBLBinding(), "Node has binding on destruction");
360
0
  }
361
0
362
0
  aNode->ReleaseWrapper(aNode);
363
0
364
0
  FragmentOrElement::RemoveBlackMarkedNode(aNode);
365
0
}
366
367
/* static */
368
already_AddRefed<nsINode>
369
nsNodeUtils::CloneNodeImpl(nsINode *aNode, bool aDeep, ErrorResult& aError)
370
0
{
371
0
  return Clone(aNode, aDeep, nullptr, nullptr, aError);
372
0
}
373
374
/* static */
375
already_AddRefed<nsINode>
376
nsNodeUtils::CloneAndAdopt(nsINode *aNode, bool aClone, bool aDeep,
377
                           nsNodeInfoManager *aNewNodeInfoManager,
378
                           JS::Handle<JSObject*> aReparentScope,
379
                           nsCOMArray<nsINode> *aNodesWithProperties,
380
                           nsINode* aParent, ErrorResult& aError)
381
0
{
382
0
  MOZ_ASSERT((!aClone && aNewNodeInfoManager) || !aReparentScope,
383
0
              "If cloning or not getting a new nodeinfo we shouldn't rewrap");
384
0
  MOZ_ASSERT(!aParent || aNode->IsContent(),
385
0
             "Can't insert document or attribute nodes into a parent");
386
0
387
0
  // First deal with aNode and walk its attributes (and their children). Then,
388
0
  // if aDeep is true, deal with aNode's children (and recurse into their
389
0
  // attributes and children).
390
0
391
0
  nsAutoScriptBlocker scriptBlocker;
392
0
393
0
  nsNodeInfoManager *nodeInfoManager = aNewNodeInfoManager;
394
0
395
0
  // aNode.
396
0
  NodeInfo *nodeInfo = aNode->mNodeInfo;
397
0
  RefPtr<NodeInfo> newNodeInfo;
398
0
  if (nodeInfoManager) {
399
0
400
0
    // Don't allow importing/adopting nodes from non-privileged "scriptable"
401
0
    // documents to "non-scriptable" documents.
402
0
    nsIDocument* newDoc = nodeInfoManager->GetDocument();
403
0
    if (NS_WARN_IF(!newDoc)) {
404
0
      aError.Throw(NS_ERROR_UNEXPECTED);
405
0
      return nullptr;
406
0
    }
407
0
    bool hasHadScriptHandlingObject = false;
408
0
    if (!newDoc->GetScriptHandlingObject(hasHadScriptHandlingObject) &&
409
0
        !hasHadScriptHandlingObject) {
410
0
      nsIDocument* currentDoc = aNode->OwnerDoc();
411
0
      if (NS_WARN_IF(!nsContentUtils::IsChromeDoc(currentDoc) &&
412
0
                     (currentDoc->GetScriptHandlingObject(hasHadScriptHandlingObject) ||
413
0
                      hasHadScriptHandlingObject))) {
414
0
        aError.Throw(NS_ERROR_UNEXPECTED);
415
0
        return nullptr;
416
0
      }
417
0
    }
418
0
419
0
    newNodeInfo = nodeInfoManager->GetNodeInfo(nodeInfo->NameAtom(),
420
0
                                               nodeInfo->GetPrefixAtom(),
421
0
                                               nodeInfo->NamespaceID(),
422
0
                                               nodeInfo->NodeType(),
423
0
                                               nodeInfo->GetExtraName());
424
0
425
0
    nodeInfo = newNodeInfo;
426
0
  }
427
0
428
0
  Element* elem = Element::FromNode(aNode);
429
0
430
0
  nsCOMPtr<nsINode> clone;
431
0
  if (aClone) {
432
0
    nsresult rv = aNode->Clone(nodeInfo, getter_AddRefs(clone));
433
0
    if (NS_WARN_IF(NS_FAILED(rv))) {
434
0
      aError.Throw(rv);
435
0
      return nullptr;
436
0
    }
437
0
438
0
    if (CustomElementRegistry::IsCustomElementEnabled(nodeInfo->GetDocument()) &&
439
0
        (clone->IsHTMLElement() || clone->IsXULElement())) {
440
0
      // The cloned node may be a custom element that may require
441
0
      // enqueing upgrade reaction.
442
0
      Element* cloneElem = clone->AsElement();
443
0
      CustomElementData* data = elem->GetCustomElementData();
444
0
      RefPtr<nsAtom> typeAtom = data ? data->GetCustomElementType() : nullptr;
445
0
446
0
      if (typeAtom) {
447
0
        cloneElem->SetCustomElementData(new CustomElementData(typeAtom));
448
0
449
0
        MOZ_ASSERT(nodeInfo->NameAtom()->Equals(nodeInfo->LocalName()));
450
0
        CustomElementDefinition* definition =
451
0
          nsContentUtils::LookupCustomElementDefinition(nodeInfo->GetDocument(),
452
0
                                                        nodeInfo->NameAtom(),
453
0
                                                        nodeInfo->NamespaceID(),
454
0
                                                        typeAtom);
455
0
        if (definition) {
456
0
          nsContentUtils::EnqueueUpgradeReaction(cloneElem, definition);
457
0
        }
458
0
      }
459
0
    }
460
0
461
0
    if (aParent) {
462
0
      // If we're cloning we need to insert the cloned children into the cloned
463
0
      // parent.
464
0
      rv = aParent->AppendChildTo(static_cast<nsIContent*>(clone.get()),
465
0
                                  false);
466
0
      if (NS_WARN_IF(NS_FAILED(rv))) {
467
0
        aError.Throw(rv);
468
0
        return nullptr;
469
0
      }
470
0
    }
471
0
    else if (aDeep && clone->IsDocument()) {
472
0
      // After cloning the document itself, we want to clone the children into
473
0
      // the cloned document (somewhat like cloning and importing them into the
474
0
      // cloned document).
475
0
      nodeInfoManager = clone->mNodeInfo->NodeInfoManager();
476
0
    }
477
0
  }
478
0
  else if (nodeInfoManager) {
479
0
    nsIDocument* oldDoc = aNode->OwnerDoc();
480
0
    bool wasRegistered = false;
481
0
    if (elem) {
482
0
      oldDoc->ClearBoxObjectFor(elem);
483
0
      wasRegistered = oldDoc->UnregisterActivityObserver(elem);
484
0
    }
485
0
486
0
    aNode->mNodeInfo.swap(newNodeInfo);
487
0
    if (elem) {
488
0
      elem->NodeInfoChanged(oldDoc);
489
0
    }
490
0
491
0
    nsIDocument* newDoc = aNode->OwnerDoc();
492
0
    if (newDoc) {
493
0
      if (elem && CustomElementRegistry::IsCustomElementEnabled(newDoc)) {
494
0
        // Adopted callback must be enqueued whenever a node’s
495
0
        // shadow-including inclusive descendants that is custom.
496
0
        CustomElementData* data = elem->GetCustomElementData();
497
0
        if (data && data->mState == CustomElementData::State::eCustom) {
498
0
          LifecycleAdoptedCallbackArgs args = {
499
0
            oldDoc,
500
0
            newDoc
501
0
          };
502
0
          nsContentUtils::EnqueueLifecycleCallback(nsIDocument::eAdopted,
503
0
                                                   elem, nullptr, &args);
504
0
        }
505
0
      }
506
0
507
0
      // XXX what if oldDoc is null, we don't know if this should be
508
0
      // registered or not! Can that really happen?
509
0
      if (wasRegistered) {
510
0
        newDoc->RegisterActivityObserver(aNode->AsElement());
511
0
      }
512
0
513
0
      if (nsPIDOMWindowInner* window = newDoc->GetInnerWindow()) {
514
0
        EventListenerManager* elm = aNode->GetExistingListenerManager();
515
0
        if (elm) {
516
0
          window->SetMutationListeners(elm->MutationListenerBits());
517
0
          if (elm->MayHavePaintEventListener()) {
518
0
            window->SetHasPaintEventListeners();
519
0
          }
520
0
          if (elm->MayHaveTouchEventListener()) {
521
0
            window->SetHasTouchEventListeners();
522
0
          }
523
0
          if (elm->MayHaveMouseEnterLeaveEventListener()) {
524
0
            window->SetHasMouseEnterLeaveEventListeners();
525
0
          }
526
0
          if (elm->MayHavePointerEnterLeaveEventListener()) {
527
0
            window->SetHasPointerEnterLeaveEventListeners();
528
0
          }
529
0
          if (elm->MayHaveSelectionChangeEventListener()) {
530
0
            window->SetHasSelectionChangeEventListeners();
531
0
          }
532
0
        }
533
0
      }
534
0
    }
535
0
536
0
    if (wasRegistered && oldDoc != newDoc) {
537
0
      nsIContent* content = aNode->AsContent();
538
0
      if (auto mediaElem = HTMLMediaElement::FromNodeOrNull(content)) {
539
0
        mediaElem->NotifyOwnerDocumentActivityChanged();
540
0
      }
541
0
      nsCOMPtr<nsIObjectLoadingContent> objectLoadingContent(do_QueryInterface(aNode));
542
0
      if (objectLoadingContent) {
543
0
        nsObjectLoadingContent* olc = static_cast<nsObjectLoadingContent*>(objectLoadingContent.get());
544
0
        olc->NotifyOwnerDocumentActivityChanged();
545
0
      }
546
0
    }
547
0
548
0
    if (oldDoc != newDoc && oldDoc->MayHaveDOMMutationObservers()) {
549
0
      newDoc->SetMayHaveDOMMutationObservers();
550
0
    }
551
0
552
0
    if (oldDoc != newDoc && oldDoc->MayHaveAnimationObservers()) {
553
0
      newDoc->SetMayHaveAnimationObservers();
554
0
    }
555
0
556
0
    if (elem) {
557
0
      elem->RecompileScriptEventListeners();
558
0
    }
559
0
560
0
    if (aReparentScope) {
561
0
      AutoJSContext cx;
562
0
      JS::Rooted<JSObject*> wrapper(cx);
563
0
      if ((wrapper = aNode->GetWrapper())) {
564
0
        MOZ_ASSERT(IsDOMObject(wrapper));
565
0
        JSAutoRealm ar(cx, wrapper);
566
0
        ReparentWrapper(cx, wrapper, aError);
567
0
        if (aError.Failed()) {
568
0
          if (wasRegistered) {
569
0
            aNode->OwnerDoc()->UnregisterActivityObserver(aNode->AsElement());
570
0
          }
571
0
          aNode->mNodeInfo.swap(newNodeInfo);
572
0
          if (elem) {
573
0
            elem->NodeInfoChanged(newDoc);
574
0
          }
575
0
          if (wasRegistered) {
576
0
            aNode->OwnerDoc()->RegisterActivityObserver(aNode->AsElement());
577
0
          }
578
0
          return nullptr;
579
0
        }
580
0
      }
581
0
    }
582
0
  }
583
0
584
0
  if (aNodesWithProperties && aNode->HasProperties()) {
585
0
    bool ok = aNodesWithProperties->AppendObject(aNode);
586
0
    MOZ_RELEASE_ASSERT(ok, "Out of memory");
587
0
    if (aClone) {
588
0
      ok = aNodesWithProperties->AppendObject(clone);
589
0
      MOZ_RELEASE_ASSERT(ok, "Out of memory");
590
0
    }
591
0
  }
592
0
593
0
  if (aDeep && (!aClone || !aNode->IsAttr())) {
594
0
    // aNode's children.
595
0
    for (nsIContent* cloneChild = aNode->GetFirstChild();
596
0
         cloneChild;
597
0
         cloneChild = cloneChild->GetNextSibling()) {
598
0
      nsCOMPtr<nsINode> child =
599
0
        CloneAndAdopt(cloneChild, aClone, true, nodeInfoManager,
600
0
                      aReparentScope, aNodesWithProperties, clone,
601
0
                      aError);
602
0
      if (NS_WARN_IF(aError.Failed())) {
603
0
        return nullptr;
604
0
      }
605
0
    }
606
0
  }
607
0
608
0
  if (aDeep && aNode->IsElement()) {
609
0
    if (aClone) {
610
0
      if (clone->OwnerDoc()->IsStaticDocument()) {
611
0
        ShadowRoot* originalShadowRoot = aNode->AsElement()->GetShadowRoot();
612
0
        if (originalShadowRoot) {
613
0
          RefPtr<ShadowRoot> newShadowRoot =
614
0
            clone->AsElement()->AttachShadowWithoutNameChecks(originalShadowRoot->Mode());
615
0
616
0
          newShadowRoot->CloneInternalDataFrom(originalShadowRoot);
617
0
          for (nsIContent* origChild = originalShadowRoot->GetFirstChild();
618
0
               origChild;
619
0
               origChild = origChild->GetNextSibling()) {
620
0
            nsCOMPtr<nsINode> child =
621
0
              CloneAndAdopt(origChild, aClone, aDeep, nodeInfoManager,
622
0
                            aReparentScope, aNodesWithProperties, newShadowRoot,
623
0
                            aError);
624
0
            if (NS_WARN_IF(aError.Failed())) {
625
0
              return nullptr;
626
0
            }
627
0
          }
628
0
        }
629
0
      }
630
0
    } else {
631
0
      if (ShadowRoot* shadowRoot = aNode->AsElement()->GetShadowRoot()) {
632
0
        nsCOMPtr<nsINode> child =
633
0
          CloneAndAdopt(shadowRoot, aClone, aDeep, nodeInfoManager,
634
0
                        aReparentScope, aNodesWithProperties, clone,
635
0
                        aError);
636
0
        if (NS_WARN_IF(aError.Failed())) {
637
0
          return nullptr;
638
0
        }
639
0
      }
640
0
    }
641
0
  }
642
0
643
0
  // Cloning template element.
644
0
  if (aDeep && aClone && IsTemplateElement(aNode)) {
645
0
    DocumentFragment* origContent =
646
0
      static_cast<HTMLTemplateElement*>(aNode)->Content();
647
0
    DocumentFragment* cloneContent =
648
0
      static_cast<HTMLTemplateElement*>(clone.get())->Content();
649
0
650
0
    // Clone the children into the clone's template content owner
651
0
    // document's nodeinfo manager.
652
0
    nsNodeInfoManager* ownerNodeInfoManager =
653
0
      cloneContent->mNodeInfo->NodeInfoManager();
654
0
655
0
    for (nsIContent* cloneChild = origContent->GetFirstChild();
656
0
         cloneChild;
657
0
         cloneChild = cloneChild->GetNextSibling()) {
658
0
      nsCOMPtr<nsINode> child =
659
0
        CloneAndAdopt(cloneChild, aClone, aDeep, ownerNodeInfoManager,
660
0
                      aReparentScope, aNodesWithProperties, cloneContent,
661
0
                      aError);
662
0
      if (NS_WARN_IF(aError.Failed())) {
663
0
        return nullptr;
664
0
      }
665
0
    }
666
0
  }
667
0
668
0
  return clone.forget();
669
0
}
670
671
bool
672
nsNodeUtils::IsTemplateElement(const nsINode *aNode)
673
0
{
674
0
  return aNode->IsHTMLElement(nsGkAtoms::_template);
675
0
}
676
677
nsIContent*
678
nsNodeUtils::GetFirstChildOfTemplateOrNode(nsINode* aNode)
679
0
{
680
0
  if (nsNodeUtils::IsTemplateElement(aNode)) {
681
0
    DocumentFragment* frag =
682
0
      static_cast<HTMLTemplateElement*>(aNode)->Content();
683
0
    return frag->GetFirstChild();
684
0
  }
685
0
686
0
  return aNode->GetFirstChild();
687
0
}