Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/dom/base/DocumentOrShadowRoot.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 "DocumentOrShadowRoot.h"
8
#include "mozilla/EventStateManager.h"
9
#include "mozilla/dom/HTMLInputElement.h"
10
#include "mozilla/dom/ShadowRoot.h"
11
#include "mozilla/dom/StyleSheetList.h"
12
#include "nsDocument.h"
13
#include "nsFocusManager.h"
14
#include "nsIRadioVisitor.h"
15
#include "nsIFormControl.h"
16
#include "nsLayoutUtils.h"
17
#include "nsSVGUtils.h"
18
#include "nsWindowSizes.h"
19
20
namespace mozilla {
21
namespace dom {
22
23
DocumentOrShadowRoot::DocumentOrShadowRoot(mozilla::dom::ShadowRoot& aShadowRoot)
24
  : mAsNode(aShadowRoot)
25
  , mKind(Kind::ShadowRoot)
26
0
{}
27
28
DocumentOrShadowRoot::DocumentOrShadowRoot(nsIDocument& aDoc)
29
  : mAsNode(aDoc)
30
  , mKind(Kind::Document)
31
0
{}
32
33
void
34
DocumentOrShadowRoot::AddSizeOfOwnedSheetArrayExcludingThis(
35
  nsWindowSizes& aSizes,
36
  const nsTArray<RefPtr<StyleSheet>>& aSheets) const
37
0
{
38
0
  size_t n = 0;
39
0
  n += aSheets.ShallowSizeOfExcludingThis(aSizes.mState.mMallocSizeOf);
40
0
  for (StyleSheet* sheet : aSheets) {
41
0
    if (!sheet->GetAssociatedDocumentOrShadowRoot()) {
42
0
      // Avoid over-reporting shared sheets.
43
0
      continue;
44
0
    }
45
0
    n += sheet->SizeOfIncludingThis(aSizes.mState.mMallocSizeOf);
46
0
  }
47
0
48
0
  if (mKind == Kind::ShadowRoot) {
49
0
    aSizes.mLayoutShadowDomStyleSheetsSize += n;
50
0
  } else {
51
0
    aSizes.mLayoutStyleSheetsSize += n;
52
0
  }
53
0
}
54
55
void
56
DocumentOrShadowRoot::AddSizeOfExcludingThis(nsWindowSizes& aSizes) const
57
0
{
58
0
  AddSizeOfOwnedSheetArrayExcludingThis(aSizes, mStyleSheets);
59
0
  aSizes.mDOMOtherSize +=
60
0
    mIdentifierMap.SizeOfExcludingThis(aSizes.mState.mMallocSizeOf);
61
0
}
62
63
DocumentOrShadowRoot::~DocumentOrShadowRoot()
64
0
{
65
0
  for (StyleSheet* sheet : mStyleSheets) {
66
0
    sheet->ClearAssociatedDocumentOrShadowRoot();
67
0
  }
68
0
}
69
70
StyleSheetList&
71
DocumentOrShadowRoot::EnsureDOMStyleSheets()
72
0
{
73
0
  if (!mDOMStyleSheets) {
74
0
    mDOMStyleSheets = new StyleSheetList(*this);
75
0
  }
76
0
  return *mDOMStyleSheets;
77
0
}
78
79
void
80
DocumentOrShadowRoot::InsertSheetAt(size_t aIndex, StyleSheet& aSheet)
81
0
{
82
0
  aSheet.SetAssociatedDocumentOrShadowRoot(
83
0
    this, StyleSheet::OwnedByDocumentOrShadowRoot);
84
0
  mStyleSheets.InsertElementAt(aIndex, &aSheet);
85
0
}
86
87
already_AddRefed<StyleSheet>
88
DocumentOrShadowRoot::RemoveSheet(StyleSheet& aSheet)
89
0
{
90
0
  auto index = mStyleSheets.IndexOf(&aSheet);
91
0
  if (index == mStyleSheets.NoIndex) {
92
0
    return nullptr;
93
0
  }
94
0
  RefPtr<StyleSheet> sheet = std::move(mStyleSheets[index]);
95
0
  mStyleSheets.RemoveElementAt(index);
96
0
  sheet->ClearAssociatedDocumentOrShadowRoot();
97
0
  return sheet.forget();
98
0
}
99
100
Element*
101
DocumentOrShadowRoot::GetElementById(const nsAString& aElementId)
102
0
{
103
0
  if (MOZ_UNLIKELY(aElementId.IsEmpty())) {
104
0
    nsContentUtils::ReportEmptyGetElementByIdArg(AsNode().OwnerDoc());
105
0
    return nullptr;
106
0
  }
107
0
108
0
  if (nsIdentifierMapEntry* entry = mIdentifierMap.GetEntry(aElementId)) {
109
0
    if (Element* el = entry->GetIdElement()) {
110
0
      return el;
111
0
    }
112
0
  }
113
0
114
0
  return nullptr;
115
0
}
116
117
already_AddRefed<nsContentList>
118
DocumentOrShadowRoot::GetElementsByTagNameNS(const nsAString& aNamespaceURI,
119
                                   const nsAString& aLocalName)
120
0
{
121
0
  ErrorResult rv;
122
0
  RefPtr<nsContentList> list =
123
0
    GetElementsByTagNameNS(aNamespaceURI, aLocalName, rv);
124
0
  if (rv.Failed()) {
125
0
    return nullptr;
126
0
  }
127
0
  return list.forget();
128
0
}
129
130
already_AddRefed<nsContentList>
131
DocumentOrShadowRoot::GetElementsByTagNameNS(const nsAString& aNamespaceURI,
132
                                   const nsAString& aLocalName,
133
                                   mozilla::ErrorResult& aResult)
134
0
{
135
0
  int32_t nameSpaceId = kNameSpaceID_Wildcard;
136
0
137
0
  if (!aNamespaceURI.EqualsLiteral("*")) {
138
0
    aResult =
139
0
      nsContentUtils::NameSpaceManager()->RegisterNameSpace(aNamespaceURI,
140
0
                                                            nameSpaceId);
141
0
    if (aResult.Failed()) {
142
0
      return nullptr;
143
0
    }
144
0
  }
145
0
146
0
  NS_ASSERTION(nameSpaceId != kNameSpaceID_Unknown, "Unexpected namespace ID!");
147
0
  return NS_GetContentList(&AsNode(), nameSpaceId, aLocalName);
148
0
}
149
150
already_AddRefed<nsContentList>
151
DocumentOrShadowRoot::GetElementsByClassName(const nsAString& aClasses)
152
0
{
153
0
  return nsContentUtils::GetElementsByClassName(&AsNode(), aClasses);
154
0
}
155
156
nsIContent*
157
DocumentOrShadowRoot::Retarget(nsIContent* aContent) const
158
0
{
159
0
  for (nsIContent* cur = aContent;
160
0
       cur;
161
0
       cur = cur->GetContainingShadowHost()) {
162
0
    if (cur->SubtreeRoot() == &AsNode()) {
163
0
      return cur;
164
0
    }
165
0
  }
166
0
  return nullptr;
167
0
}
168
169
Element*
170
DocumentOrShadowRoot::GetRetargetedFocusedElement()
171
0
{
172
0
  if (nsCOMPtr<nsPIDOMWindowOuter> window = AsNode().OwnerDoc()->GetWindow()) {
173
0
    nsCOMPtr<nsPIDOMWindowOuter> focusedWindow;
174
0
    nsIContent* focusedContent =
175
0
      nsFocusManager::GetFocusedDescendant(window,
176
0
                                           nsFocusManager::eOnlyCurrentWindow,
177
0
                                           getter_AddRefs(focusedWindow));
178
0
    // be safe and make sure the element is from this document
179
0
    if (focusedContent && focusedContent->OwnerDoc() == AsNode().OwnerDoc()) {
180
0
      if (focusedContent->ChromeOnlyAccess()) {
181
0
        focusedContent = focusedContent->FindFirstNonChromeOnlyAccessContent();
182
0
      }
183
0
184
0
      if (focusedContent) {
185
0
        if (!nsDocument::IsShadowDOMEnabled(focusedContent)) {
186
0
          return focusedContent->AsElement();
187
0
        }
188
0
189
0
        if (nsIContent* retarget = Retarget(focusedContent)) {
190
0
          return retarget->AsElement();
191
0
        }
192
0
      }
193
0
    }
194
0
  }
195
0
196
0
  return nullptr;
197
0
}
198
199
Element*
200
DocumentOrShadowRoot::GetPointerLockElement()
201
0
{
202
0
  nsCOMPtr<Element> pointerLockedElement =
203
0
    do_QueryReferent(EventStateManager::sPointerLockedElement);
204
0
  if (!pointerLockedElement) {
205
0
    return nullptr;
206
0
  }
207
0
208
0
  nsIContent* retargetedPointerLockedElement = Retarget(pointerLockedElement);
209
0
  return
210
0
    retargetedPointerLockedElement && retargetedPointerLockedElement->IsElement() ?
211
0
      retargetedPointerLockedElement->AsElement() : nullptr;
212
0
}
213
214
Element*
215
DocumentOrShadowRoot::GetFullscreenElement()
216
0
{
217
0
  if (!AsNode().IsInComposedDoc()) {
218
0
    return nullptr;
219
0
  }
220
0
221
0
  Element* element = AsNode().OwnerDoc()->FullscreenStackTop();
222
0
  NS_ASSERTION(!element ||
223
0
               element->State().HasState(NS_EVENT_STATE_FULLSCREEN),
224
0
    "Fullscreen element should have fullscreen styles applied");
225
0
226
0
  nsIContent* retargeted = Retarget(element);
227
0
  if (retargeted && retargeted->IsElement()) {
228
0
    return retargeted->AsElement();
229
0
  }
230
0
231
0
  return nullptr;
232
0
}
233
234
Element*
235
DocumentOrShadowRoot::ElementFromPoint(float aX, float aY)
236
0
{
237
0
  return ElementFromPointHelper(aX, aY, false, true);
238
0
}
239
240
void
241
DocumentOrShadowRoot::ElementsFromPoint(float aX, float aY,
242
                                        nsTArray<RefPtr<Element>>& aElements)
243
0
{
244
0
  ElementsFromPointHelper(aX, aY, nsIDocument::FLUSH_LAYOUT, aElements);
245
0
}
246
247
Element*
248
DocumentOrShadowRoot::ElementFromPointHelper(float aX, float aY,
249
                                             bool aIgnoreRootScrollFrame,
250
                                             bool aFlushLayout)
251
0
{
252
0
  AutoTArray<RefPtr<Element>, 1> elementArray;
253
0
  ElementsFromPointHelper(aX, aY,
254
0
                          ((aIgnoreRootScrollFrame ? nsIDocument::IGNORE_ROOT_SCROLL_FRAME : 0) |
255
0
                           (aFlushLayout ? nsIDocument::FLUSH_LAYOUT : 0) |
256
0
                           nsIDocument::IS_ELEMENT_FROM_POINT),
257
0
                          elementArray);
258
0
  if (elementArray.IsEmpty()) {
259
0
    return nullptr;
260
0
  }
261
0
  return elementArray[0];
262
0
}
263
264
void
265
DocumentOrShadowRoot::ElementsFromPointHelper(float aX, float aY,
266
                                              uint32_t aFlags,
267
                                              nsTArray<RefPtr<mozilla::dom::Element>>& aElements)
268
0
{
269
0
  // As per the the spec, we return null if either coord is negative
270
0
  if (!(aFlags & nsIDocument::IGNORE_ROOT_SCROLL_FRAME) && (aX < 0 || aY < 0)) {
271
0
    return;
272
0
  }
273
0
274
0
  nscoord x = nsPresContext::CSSPixelsToAppUnits(aX);
275
0
  nscoord y = nsPresContext::CSSPixelsToAppUnits(aY);
276
0
  nsPoint pt(x, y);
277
0
278
0
  nsCOMPtr<nsIDocument> doc = AsNode().OwnerDoc();
279
0
280
0
  // Make sure the layout information we get is up-to-date, and
281
0
  // ensure we get a root frame (for everything but XUL)
282
0
  if (aFlags & nsIDocument::FLUSH_LAYOUT) {
283
0
    doc->FlushPendingNotifications(FlushType::Layout);
284
0
  }
285
0
286
0
  nsIPresShell* ps = doc->GetShell();
287
0
  if (!ps) {
288
0
    return;
289
0
  }
290
0
  nsIFrame* rootFrame = ps->GetRootFrame();
291
0
292
0
  // XUL docs, unlike HTML, have no frame tree until everything's done loading
293
0
  if (!rootFrame) {
294
0
    return; // return null to premature XUL callers as a reminder to wait
295
0
  }
296
0
297
0
  nsTArray<nsIFrame*> outFrames;
298
0
  // Emulate what GetFrameAtPoint does, since we want all the frames under our
299
0
  // point.
300
0
  nsLayoutUtils::GetFramesForArea(rootFrame, nsRect(pt, nsSize(1, 1)), outFrames,
301
0
    nsLayoutUtils::IGNORE_PAINT_SUPPRESSION | nsLayoutUtils::IGNORE_CROSS_DOC |
302
0
    ((aFlags & nsIDocument::IGNORE_ROOT_SCROLL_FRAME) ? nsLayoutUtils::IGNORE_ROOT_SCROLL_FRAME : 0));
303
0
304
0
  // Dunno when this would ever happen, as we should at least have a root frame under us?
305
0
  if (outFrames.IsEmpty()) {
306
0
    return;
307
0
  }
308
0
309
0
  // Used to filter out repeated elements in sequence.
310
0
  nsIContent* lastAdded = nullptr;
311
0
312
0
  for (uint32_t i = 0; i < outFrames.Length(); i++) {
313
0
    nsIContent* node = doc->GetContentInThisDocument(outFrames[i]);
314
0
315
0
    if (!node || !node->IsElement()) {
316
0
      // If this helper is called via ElementsFromPoint, we need to make sure
317
0
      // our frame is an element. Otherwise return whatever the top frame is
318
0
      // even if it isn't the top-painted element.
319
0
      // SVG 'text' element's SVGTextFrame doesn't respond to hit-testing, so
320
0
      // if 'node' is a child of such an element then we need to manually defer
321
0
      // to the parent here.
322
0
      if (!(aFlags & nsIDocument::IS_ELEMENT_FROM_POINT) &&
323
0
          !nsSVGUtils::IsInSVGTextSubtree(outFrames[i])) {
324
0
        continue;
325
0
      }
326
0
      node = node->GetParent();
327
0
      if (ShadowRoot* shadow = ShadowRoot::FromNodeOrNull(node)) {
328
0
        node = shadow->Host();
329
0
      }
330
0
    }
331
0
332
0
    //XXXsmaug There is plenty of unspec'ed behavior here
333
0
    //         https://github.com/w3c/webcomponents/issues/735
334
0
    //         https://github.com/w3c/webcomponents/issues/736
335
0
    node = Retarget(node);
336
0
337
0
    if (node && node != lastAdded) {
338
0
      aElements.AppendElement(node->AsElement());
339
0
      lastAdded = node;
340
0
      // If this helper is called via ElementFromPoint, just return the first
341
0
      // element we find.
342
0
      if (aFlags & nsIDocument::IS_ELEMENT_FROM_POINT) {
343
0
        return;
344
0
      }
345
0
    }
346
0
  }
347
0
}
348
349
Element*
350
DocumentOrShadowRoot::AddIDTargetObserver(nsAtom* aID,
351
                                          IDTargetObserver aObserver,
352
                                          void* aData, bool aForImage)
353
0
{
354
0
  nsDependentAtomString id(aID);
355
0
356
0
  if (!CheckGetElementByIdArg(id)) {
357
0
    return nullptr;
358
0
  }
359
0
360
0
  nsIdentifierMapEntry* entry = mIdentifierMap.PutEntry(aID);
361
0
  NS_ENSURE_TRUE(entry, nullptr);
362
0
363
0
  entry->AddContentChangeCallback(aObserver, aData, aForImage);
364
0
  return aForImage ? entry->GetImageIdElement() : entry->GetIdElement();
365
0
}
366
367
void
368
DocumentOrShadowRoot::RemoveIDTargetObserver(nsAtom* aID,
369
                                             IDTargetObserver aObserver,
370
                                             void* aData, bool aForImage)
371
0
{
372
0
  nsDependentAtomString id(aID);
373
0
374
0
  if (!CheckGetElementByIdArg(id)) {
375
0
    return;
376
0
  }
377
0
378
0
  nsIdentifierMapEntry* entry = mIdentifierMap.GetEntry(aID);
379
0
  if (!entry) {
380
0
    return;
381
0
  }
382
0
383
0
  entry->RemoveContentChangeCallback(aObserver, aData, aForImage);
384
0
}
385
386
387
Element*
388
DocumentOrShadowRoot::LookupImageElement(const nsAString& aId)
389
0
{
390
0
  if (aId.IsEmpty()) {
391
0
    return nullptr;
392
0
  }
393
0
394
0
  nsIdentifierMapEntry* entry = mIdentifierMap.GetEntry(aId);
395
0
  return entry ? entry->GetImageIdElement() : nullptr;
396
0
}
397
398
void
399
DocumentOrShadowRoot::ReportEmptyGetElementByIdArg()
400
0
{
401
0
  nsContentUtils::ReportEmptyGetElementByIdArg(AsNode().OwnerDoc());
402
0
}
403
404
/**
405
 * A struct that holds all the information about a radio group.
406
 */
407
struct nsRadioGroupStruct
408
{
409
  nsRadioGroupStruct()
410
    : mRequiredRadioCount(0)
411
    , mGroupSuffersFromValueMissing(false)
412
0
  {}
413
414
  /**
415
   * A strong pointer to the currently selected radio button.
416
   */
417
  RefPtr<HTMLInputElement> mSelectedRadioButton;
418
  nsCOMArray<nsIFormControl> mRadioButtons;
419
  uint32_t mRequiredRadioCount;
420
  bool mGroupSuffersFromValueMissing;
421
};
422
423
nsresult
424
DocumentOrShadowRoot::WalkRadioGroup(const nsAString& aName,
425
                                     nsIRadioVisitor* aVisitor,
426
                                     bool aFlushContent)
427
0
{
428
0
  nsRadioGroupStruct* radioGroup = GetOrCreateRadioGroup(aName);
429
0
430
0
  for (int i = 0; i < radioGroup->mRadioButtons.Count(); i++) {
431
0
    if (!aVisitor->Visit(radioGroup->mRadioButtons[i])) {
432
0
      return NS_OK;
433
0
    }
434
0
  }
435
0
436
0
  return NS_OK;
437
0
}
438
439
void
440
DocumentOrShadowRoot::SetCurrentRadioButton(const nsAString& aName,
441
                                            HTMLInputElement* aRadio)
442
0
{
443
0
  nsRadioGroupStruct* radioGroup = GetOrCreateRadioGroup(aName);
444
0
  radioGroup->mSelectedRadioButton = aRadio;
445
0
}
446
447
HTMLInputElement*
448
DocumentOrShadowRoot::GetCurrentRadioButton(const nsAString& aName)
449
0
{
450
0
  return GetOrCreateRadioGroup(aName)->mSelectedRadioButton;
451
0
}
452
453
nsresult
454
DocumentOrShadowRoot::GetNextRadioButton(const nsAString& aName,
455
                                         const bool aPrevious,
456
                                         HTMLInputElement* aFocusedRadio,
457
                                         HTMLInputElement** aRadioOut)
458
0
{
459
0
  // XXX Can we combine the HTML radio button method impls of
460
0
  //     nsDocument and nsHTMLFormControl?
461
0
  // XXX Why is HTML radio button stuff in nsDocument, as
462
0
  //     opposed to nsHTMLDocument?
463
0
  *aRadioOut = nullptr;
464
0
465
0
  nsRadioGroupStruct* radioGroup = GetOrCreateRadioGroup(aName);
466
0
467
0
  // Return the radio button relative to the focused radio button.
468
0
  // If no radio is focused, get the radio relative to the selected one.
469
0
  RefPtr<HTMLInputElement> currentRadio;
470
0
  if (aFocusedRadio) {
471
0
    currentRadio = aFocusedRadio;
472
0
  } else {
473
0
    currentRadio = radioGroup->mSelectedRadioButton;
474
0
    if (!currentRadio) {
475
0
      return NS_ERROR_FAILURE;
476
0
    }
477
0
  }
478
0
  int32_t index = radioGroup->mRadioButtons.IndexOf(currentRadio);
479
0
  if (index < 0) {
480
0
    return NS_ERROR_FAILURE;
481
0
  }
482
0
483
0
  int32_t numRadios = radioGroup->mRadioButtons.Count();
484
0
  RefPtr<HTMLInputElement> radio;
485
0
  do {
486
0
    if (aPrevious) {
487
0
      if (--index < 0) {
488
0
        index = numRadios -1;
489
0
      }
490
0
    } else if (++index >= numRadios) {
491
0
      index = 0;
492
0
    }
493
0
    NS_ASSERTION(static_cast<nsGenericHTMLFormElement*>(radioGroup->mRadioButtons[index])->IsHTMLElement(nsGkAtoms::input),
494
0
                 "mRadioButtons holding a non-radio button");
495
0
    radio = static_cast<HTMLInputElement*>(radioGroup->mRadioButtons[index]);
496
0
  } while (radio->Disabled() && radio != currentRadio);
497
0
498
0
  radio.forget(aRadioOut);
499
0
  return NS_OK;
500
0
}
501
502
void
503
DocumentOrShadowRoot::AddToRadioGroup(const nsAString& aName,
504
                                      HTMLInputElement* aRadio)
505
0
{
506
0
  nsRadioGroupStruct* radioGroup = GetOrCreateRadioGroup(aName);
507
0
  radioGroup->mRadioButtons.AppendObject(aRadio);
508
0
509
0
  if (aRadio->IsRequired()) {
510
0
    radioGroup->mRequiredRadioCount++;
511
0
  }
512
0
}
513
514
void
515
DocumentOrShadowRoot::RemoveFromRadioGroup(const nsAString& aName,
516
                                           HTMLInputElement* aRadio)
517
0
{
518
0
  nsRadioGroupStruct* radioGroup = GetOrCreateRadioGroup(aName);
519
0
  radioGroup->mRadioButtons.RemoveObject(aRadio);
520
0
521
0
  if (aRadio->IsRequired()) {
522
0
    NS_ASSERTION(radioGroup->mRequiredRadioCount != 0,
523
0
                 "mRequiredRadioCount about to wrap below 0!");
524
0
    radioGroup->mRequiredRadioCount--;
525
0
  }
526
0
}
527
528
uint32_t
529
DocumentOrShadowRoot::GetRequiredRadioCount(const nsAString& aName) const
530
0
{
531
0
  nsRadioGroupStruct* radioGroup = GetRadioGroup(aName);
532
0
  return radioGroup ? radioGroup->mRequiredRadioCount : 0;
533
0
}
534
535
void
536
DocumentOrShadowRoot::RadioRequiredWillChange(const nsAString& aName,
537
                                              bool aRequiredAdded)
538
0
{
539
0
  nsRadioGroupStruct* radioGroup = GetOrCreateRadioGroup(aName);
540
0
541
0
  if (aRequiredAdded) {
542
0
    radioGroup->mRequiredRadioCount++;
543
0
  } else {
544
0
    NS_ASSERTION(radioGroup->mRequiredRadioCount != 0,
545
0
                 "mRequiredRadioCount about to wrap below 0!");
546
0
    radioGroup->mRequiredRadioCount--;
547
0
  }
548
0
}
549
550
bool
551
DocumentOrShadowRoot::GetValueMissingState(const nsAString& aName) const
552
0
{
553
0
  nsRadioGroupStruct* radioGroup = GetRadioGroup(aName);
554
0
  return radioGroup && radioGroup->mGroupSuffersFromValueMissing;
555
0
}
556
557
void
558
DocumentOrShadowRoot::SetValueMissingState(const nsAString& aName, bool aValue)
559
0
{
560
0
  nsRadioGroupStruct* radioGroup = GetOrCreateRadioGroup(aName);
561
0
  radioGroup->mGroupSuffersFromValueMissing = aValue;
562
0
}
563
564
nsRadioGroupStruct*
565
DocumentOrShadowRoot::GetRadioGroup(const nsAString& aName) const
566
0
{
567
0
  nsRadioGroupStruct* radioGroup = nullptr;
568
0
  mRadioGroups.Get(aName, &radioGroup);
569
0
  return radioGroup;
570
0
}
571
572
nsRadioGroupStruct*
573
DocumentOrShadowRoot::GetOrCreateRadioGroup(const nsAString& aName)
574
0
{
575
0
  return mRadioGroups.LookupForAdd(aName).OrInsert(
576
0
    [] () { return new nsRadioGroupStruct(); });
577
0
}
578
579
void
580
DocumentOrShadowRoot::Traverse(DocumentOrShadowRoot* tmp,
581
                               nsCycleCollectionTraversalCallback &cb)
582
0
{
583
0
  for (auto iter = tmp->mRadioGroups.Iter(); !iter.Done(); iter.Next()) {
584
0
    nsRadioGroupStruct* radioGroup = iter.UserData();
585
0
    NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(
586
0
      cb, "mRadioGroups entry->mSelectedRadioButton");
587
0
    cb.NoteXPCOMChild(ToSupports(radioGroup->mSelectedRadioButton));
588
0
589
0
    uint32_t i, count = radioGroup->mRadioButtons.Count();
590
0
    for (i = 0; i < count; ++i) {
591
0
      NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(
592
0
        cb, "mRadioGroups entry->mRadioButtons[i]");
593
0
      cb.NoteXPCOMChild(radioGroup->mRadioButtons[i]);
594
0
    }
595
0
  }
596
0
}
597
598
void
599
DocumentOrShadowRoot::Unlink(DocumentOrShadowRoot* tmp)
600
0
{
601
0
  tmp->mRadioGroups.Clear();
602
0
}
603
604
}
605
}