Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/dom/html/HTMLSlotElement.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 "mozilla/dom/DocGroup.h"
8
#include "mozilla/dom/HTMLSlotElement.h"
9
#include "mozilla/dom/HTMLSlotElementBinding.h"
10
#include "mozilla/dom/HTMLUnknownElement.h"
11
#include "mozilla/dom/ShadowRoot.h"
12
#include "nsGkAtoms.h"
13
#include "nsDocument.h"
14
15
nsGenericHTMLElement*
16
NS_NewHTMLSlotElement(already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
17
                      mozilla::dom::FromParser aFromParser)
18
0
{
19
0
  RefPtr<mozilla::dom::NodeInfo> nodeInfo(std::move(aNodeInfo));
20
0
  if (nsDocument::IsShadowDOMEnabled(nodeInfo->GetDocument())) {
21
0
    return new mozilla::dom::HTMLSlotElement(nodeInfo.forget());
22
0
  }
23
0
24
0
  return new mozilla::dom::HTMLUnknownElement(nodeInfo.forget());
25
0
}
26
27
namespace mozilla {
28
namespace dom {
29
30
HTMLSlotElement::HTMLSlotElement(already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo)
31
  : nsGenericHTMLElement(std::move(aNodeInfo))
32
0
{
33
0
}
34
35
0
HTMLSlotElement::~HTMLSlotElement() = default;
36
37
NS_IMPL_ADDREF_INHERITED(HTMLSlotElement, nsGenericHTMLElement)
38
NS_IMPL_RELEASE_INHERITED(HTMLSlotElement, nsGenericHTMLElement)
39
40
NS_IMPL_CYCLE_COLLECTION_INHERITED(HTMLSlotElement,
41
                                   nsGenericHTMLElement,
42
                                   mAssignedNodes)
43
44
0
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(HTMLSlotElement)
45
0
NS_INTERFACE_MAP_END_INHERITING(nsGenericHTMLElement)
46
47
NS_IMPL_ELEMENT_CLONE(HTMLSlotElement)
48
49
nsresult
50
HTMLSlotElement::BindToTree(nsIDocument* aDocument,
51
                            nsIContent* aParent,
52
                            nsIContent* aBindingParent)
53
0
{
54
0
  RefPtr<ShadowRoot> oldContainingShadow = GetContainingShadow();
55
0
56
0
  nsresult rv = nsGenericHTMLElement::BindToTree(aDocument, aParent,
57
0
                                                 aBindingParent);
58
0
  NS_ENSURE_SUCCESS(rv, rv);
59
0
60
0
  ShadowRoot* containingShadow = GetContainingShadow();
61
0
  if (containingShadow && !oldContainingShadow) {
62
0
    containingShadow->AddSlot(this);
63
0
  }
64
0
65
0
  return NS_OK;
66
0
}
67
68
void
69
HTMLSlotElement::UnbindFromTree(bool aDeep, bool aNullParent)
70
0
{
71
0
  RefPtr<ShadowRoot> oldContainingShadow = GetContainingShadow();
72
0
73
0
  nsGenericHTMLElement::UnbindFromTree(aDeep, aNullParent);
74
0
75
0
  if (oldContainingShadow && !GetContainingShadow()) {
76
0
    oldContainingShadow->RemoveSlot(this);
77
0
  }
78
0
}
79
80
nsresult
81
HTMLSlotElement::BeforeSetAttr(int32_t aNameSpaceID, nsAtom* aName,
82
                               const nsAttrValueOrString* aValue,
83
                               bool aNotify)
84
0
{
85
0
  if (aNameSpaceID == kNameSpaceID_None && aName == nsGkAtoms::name) {
86
0
    if (ShadowRoot* containingShadow = GetContainingShadow()) {
87
0
      containingShadow->RemoveSlot(this);
88
0
    }
89
0
  }
90
0
91
0
  return nsGenericHTMLElement::BeforeSetAttr(aNameSpaceID, aName, aValue,
92
0
                                             aNotify);
93
0
}
94
95
nsresult
96
HTMLSlotElement::AfterSetAttr(int32_t aNameSpaceID, nsAtom* aName,
97
                              const nsAttrValue* aValue,
98
                              const nsAttrValue* aOldValue,
99
                              nsIPrincipal* aSubjectPrincipal,
100
                              bool aNotify)
101
0
{
102
0
103
0
  if (aNameSpaceID == kNameSpaceID_None && aName == nsGkAtoms::name) {
104
0
    if (ShadowRoot* containingShadow = GetContainingShadow()) {
105
0
      containingShadow->AddSlot(this);
106
0
    }
107
0
  }
108
0
109
0
  return nsGenericHTMLElement::AfterSetAttr(aNameSpaceID, aName, aValue,
110
0
                                            aOldValue, aSubjectPrincipal,
111
0
                                            aNotify);
112
0
}
113
114
/**
115
 * Flatten assigned nodes given a slot, as in:
116
 * https://dom.spec.whatwg.org/#find-flattened-slotables
117
 */
118
static void
119
FlattenAssignedNodes(HTMLSlotElement* aSlot, nsTArray<RefPtr<nsINode>>& aNodes)
120
0
{
121
0
  if (!aSlot->GetContainingShadow()) {
122
0
    return;
123
0
  }
124
0
125
0
  const nsTArray<RefPtr<nsINode>>& assignedNodes = aSlot->AssignedNodes();
126
0
127
0
  // If assignedNodes is empty, use children of slot as fallback content.
128
0
  if (assignedNodes.IsEmpty()) {
129
0
    for (nsIContent* child = aSlot->GetFirstChild();
130
0
         child;
131
0
         child = child->GetNextSibling()) {
132
0
      if (!child->IsSlotable()) {
133
0
        continue;
134
0
      }
135
0
136
0
      if (auto* slot = HTMLSlotElement::FromNode(child)) {
137
0
        FlattenAssignedNodes(slot, aNodes);
138
0
      } else {
139
0
        aNodes.AppendElement(child);
140
0
      }
141
0
    }
142
0
    return;
143
0
  }
144
0
145
0
  for (const RefPtr<nsINode>& assignedNode : assignedNodes) {
146
0
    if (auto* slot = HTMLSlotElement::FromNode(assignedNode)) {
147
0
      FlattenAssignedNodes(slot, aNodes);
148
0
    } else {
149
0
      aNodes.AppendElement(assignedNode);
150
0
    }
151
0
  }
152
0
}
153
154
void
155
HTMLSlotElement::AssignedNodes(const AssignedNodesOptions& aOptions,
156
                               nsTArray<RefPtr<nsINode>>& aNodes)
157
0
{
158
0
  if (aOptions.mFlatten) {
159
0
    return FlattenAssignedNodes(this, aNodes);
160
0
  }
161
0
162
0
  aNodes = mAssignedNodes;
163
0
}
164
165
const nsTArray<RefPtr<nsINode>>&
166
HTMLSlotElement::AssignedNodes() const
167
0
{
168
0
  return mAssignedNodes;
169
0
}
170
171
void
172
HTMLSlotElement::InsertAssignedNode(uint32_t aIndex, nsINode* aNode)
173
0
{
174
0
  MOZ_ASSERT(!aNode->AsContent()->GetAssignedSlot(), "Losing track of a slot");
175
0
  mAssignedNodes.InsertElementAt(aIndex, aNode);
176
0
  aNode->AsContent()->SetAssignedSlot(this);
177
0
}
178
179
void
180
HTMLSlotElement::AppendAssignedNode(nsINode* aNode)
181
0
{
182
0
  MOZ_ASSERT(!aNode->AsContent()->GetAssignedSlot(), "Losing track of a slot");
183
0
  mAssignedNodes.AppendElement(aNode);
184
0
  aNode->AsContent()->SetAssignedSlot(this);
185
0
}
186
187
void
188
HTMLSlotElement::RemoveAssignedNode(nsINode* aNode)
189
0
{
190
0
  // This one runs from unlinking, so we can't guarantee that the slot pointer
191
0
  // hasn't been cleared.
192
0
  MOZ_ASSERT(!aNode->AsContent()->GetAssignedSlot() ||
193
0
             aNode->AsContent()->GetAssignedSlot() == this, "How exactly?");
194
0
  mAssignedNodes.RemoveElement(aNode);
195
0
  aNode->AsContent()->SetAssignedSlot(nullptr);
196
0
}
197
198
void
199
HTMLSlotElement::ClearAssignedNodes()
200
0
{
201
0
  for (RefPtr<nsINode>& node : mAssignedNodes) {
202
0
    MOZ_ASSERT(!node->AsContent()->GetAssignedSlot() ||
203
0
               node->AsContent()->GetAssignedSlot() == this, "How exactly?");
204
0
    node->AsContent()->SetAssignedSlot(nullptr);
205
0
  }
206
0
207
0
  mAssignedNodes.Clear();
208
0
}
209
210
void
211
HTMLSlotElement::EnqueueSlotChangeEvent()
212
0
{
213
0
  if (mInSignalSlotList) {
214
0
    return;
215
0
  }
216
0
217
0
  // FIXME(bug 1459704): Need to figure out how to deal with microtasks posted
218
0
  // during shutdown.
219
0
  if (gXPCOMThreadsShutDown) {
220
0
    return;
221
0
  }
222
0
223
0
  DocGroup* docGroup = OwnerDoc()->GetDocGroup();
224
0
  if (!docGroup) {
225
0
    return;
226
0
  }
227
0
228
0
  mInSignalSlotList = true;
229
0
  docGroup->SignalSlotChange(*this);
230
0
}
231
232
void
233
HTMLSlotElement::FireSlotChangeEvent()
234
0
{
235
0
  nsContentUtils::DispatchTrustedEvent(OwnerDoc(),
236
0
                                       static_cast<nsIContent*>(this),
237
0
                                       NS_LITERAL_STRING("slotchange"),
238
0
                                       CanBubble::eYes,
239
0
                                       Cancelable::eNo);
240
0
}
241
242
JSObject*
243
HTMLSlotElement::WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
244
0
{
245
0
  return HTMLSlotElement_Binding::Wrap(aCx, this, aGivenProto);
246
0
}
247
248
} // namespace dom
249
} // namespace mozilla