Bug 1698238 return default dictionary from GetUserMediaRequest#getConstraints() if...
[gecko.git] / dom / base / ShadowRoot.cpp
blob4d4bcfad14cf3338a93db987102e0d9e47660923
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/. */
7 #include "mozilla/Preferences.h"
8 #include "mozilla/dom/BindContext.h"
9 #include "mozilla/dom/ShadowRoot.h"
10 #include "mozilla/dom/DocumentFragment.h"
11 #include "ChildIterator.h"
12 #include "nsContentUtils.h"
13 #include "nsWindowSizes.h"
14 #include "mozilla/dom/DirectionalityUtils.h"
15 #include "mozilla/dom/Element.h"
16 #include "mozilla/dom/HTMLSlotElement.h"
17 #include "mozilla/dom/TreeOrderedArrayInlines.h"
18 #include "mozilla/EventDispatcher.h"
19 #include "mozilla/IdentifierMapEntry.h"
20 #include "mozilla/PresShell.h"
21 #include "mozilla/PresShellInlines.h"
22 #include "mozilla/ScopeExit.h"
23 #include "mozilla/ServoStyleRuleMap.h"
24 #include "mozilla/StyleSheet.h"
25 #include "mozilla/StyleSheetInlines.h"
26 #include "mozilla/dom/StyleSheetList.h"
28 using namespace mozilla;
29 using namespace mozilla::dom;
31 NS_IMPL_CYCLE_COLLECTION_CLASS(ShadowRoot)
33 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(ShadowRoot, DocumentFragment)
34 DocumentOrShadowRoot::Traverse(tmp, cb);
35 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
37 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(ShadowRoot)
38 DocumentOrShadowRoot::Unlink(tmp);
39 NS_IMPL_CYCLE_COLLECTION_UNLINK_END_INHERITED(DocumentFragment)
41 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ShadowRoot)
42 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIContent)
43 NS_INTERFACE_MAP_ENTRY(nsIRadioGroupContainer)
44 NS_INTERFACE_MAP_END_INHERITING(DocumentFragment)
46 NS_IMPL_ADDREF_INHERITED(ShadowRoot, DocumentFragment)
47 NS_IMPL_RELEASE_INHERITED(ShadowRoot, DocumentFragment)
49 ShadowRoot::ShadowRoot(Element* aElement, ShadowRootMode aMode,
50 already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo)
51 : DocumentFragment(std::move(aNodeInfo)),
52 DocumentOrShadowRoot(this),
53 mMode(aMode),
54 mIsUAWidget(false) {
55 SetHost(aElement);
57 // Nodes in a shadow tree should never store a value
58 // in the subtree root pointer, nodes in the shadow tree
59 // track the subtree root using GetContainingShadow().
60 ClearSubtreeRootPointer();
62 SetFlags(NODE_IS_IN_SHADOW_TREE);
63 Bind();
65 ExtendedDOMSlots()->mContainingShadow = this;
68 ShadowRoot::~ShadowRoot() {
69 if (IsInComposedDoc()) {
70 OwnerDoc()->RemoveComposedDocShadowRoot(*this);
73 MOZ_DIAGNOSTIC_ASSERT(!OwnerDoc()->IsComposedDocShadowRoot(*this));
75 UnsetFlags(NODE_IS_IN_SHADOW_TREE);
77 // nsINode destructor expects mSubtreeRoot == this.
78 SetSubtreeRootPointer(this);
81 MOZ_DEFINE_MALLOC_SIZE_OF(ShadowRootAuthorStylesMallocSizeOf)
82 MOZ_DEFINE_MALLOC_ENCLOSING_SIZE_OF(ShadowRootAuthorStylesMallocEnclosingSizeOf)
84 void ShadowRoot::AddSizeOfExcludingThis(nsWindowSizes& aSizes,
85 size_t* aNodeSize) const {
86 DocumentFragment::AddSizeOfExcludingThis(aSizes, aNodeSize);
87 DocumentOrShadowRoot::AddSizeOfExcludingThis(aSizes);
88 aSizes.mLayoutShadowDomAuthorStyles += Servo_AuthorStyles_SizeOfIncludingThis(
89 ShadowRootAuthorStylesMallocSizeOf,
90 ShadowRootAuthorStylesMallocEnclosingSizeOf, mServoStyles.get());
93 JSObject* ShadowRoot::WrapNode(JSContext* aCx,
94 JS::Handle<JSObject*> aGivenProto) {
95 return mozilla::dom::ShadowRoot_Binding::Wrap(aCx, this, aGivenProto);
98 void ShadowRoot::CloneInternalDataFrom(ShadowRoot* aOther) {
99 if (aOther->IsUAWidget()) {
100 SetIsUAWidget();
103 size_t sheetCount = aOther->SheetCount();
104 for (size_t i = 0; i < sheetCount; ++i) {
105 StyleSheet* sheet = aOther->SheetAt(i);
106 if (sheet->IsApplicable()) {
107 RefPtr<StyleSheet> clonedSheet =
108 sheet->Clone(nullptr, nullptr, this, nullptr);
109 if (clonedSheet) {
110 AppendStyleSheet(*clonedSheet.get());
114 CloneAdoptedSheetsFrom(*aOther);
117 nsresult ShadowRoot::Bind() {
118 MOZ_ASSERT(!IsInComposedDoc(), "Forgot to unbind?");
119 if (Host()->IsInComposedDoc()) {
120 SetIsConnected(true);
121 Document* doc = OwnerDoc();
122 doc->AddComposedDocShadowRoot(*this);
123 // If our stylesheets somehow mutated when we were disconnected, we need to
124 // ensure that our style data gets flushed as appropriate.
125 if (mServoStyles && Servo_AuthorStyles_IsDirty(mServoStyles.get())) {
126 doc->RecordShadowStyleChange(*this);
130 BindContext context(*this);
131 for (nsIContent* child = GetFirstChild(); child;
132 child = child->GetNextSibling()) {
133 nsresult rv = child->BindToTree(context, *this);
134 NS_ENSURE_SUCCESS(rv, rv);
137 return NS_OK;
140 void ShadowRoot::Unbind() {
141 if (IsInComposedDoc()) {
142 SetIsConnected(false);
143 OwnerDoc()->RemoveComposedDocShadowRoot(*this);
146 for (nsIContent* child = GetFirstChild(); child;
147 child = child->GetNextSibling()) {
148 child->UnbindFromTree(false);
152 void ShadowRoot::Unattach() {
153 MOZ_ASSERT(!HasSlots(), "Won't work!");
154 if (!GetHost()) {
155 // It is possible that we've been unlinked already. In such case host
156 // should have called Unbind and ShadowRoot's own unlink.
157 return;
160 Unbind();
161 SetHost(nullptr);
164 void ShadowRoot::InvalidateStyleAndLayoutOnSubtree(Element* aElement) {
165 MOZ_ASSERT(aElement);
166 Document* doc = GetComposedDoc();
167 if (!doc) {
168 return;
171 PresShell* presShell = doc->GetPresShell();
172 if (!presShell) {
173 return;
176 presShell->DestroyFramesForAndRestyle(aElement);
179 void ShadowRoot::PartAdded(const Element& aPart) {
180 MOZ_ASSERT(aPart.HasPartAttribute());
181 MOZ_ASSERT(!mParts.Contains(&aPart));
182 mParts.AppendElement(&aPart);
185 void ShadowRoot::PartRemoved(const Element& aPart) {
186 MOZ_ASSERT(mParts.Contains(&aPart));
187 mParts.RemoveElement(&aPart);
188 MOZ_ASSERT(!mParts.Contains(&aPart));
191 void ShadowRoot::AddSlot(HTMLSlotElement* aSlot) {
192 MOZ_ASSERT(aSlot);
194 // Note that if name attribute missing, the slot is a default slot.
195 nsAutoString name;
196 aSlot->GetName(name);
198 SlotArray& currentSlots = *mSlotMap.GetOrInsertNew(name);
200 size_t index = currentSlots.Insert(*aSlot);
201 if (index != 0) {
202 return;
205 HTMLSlotElement* oldSlot = currentSlots->SafeElementAt(1);
206 if (oldSlot) {
207 MOZ_DIAGNOSTIC_ASSERT(oldSlot != aSlot);
209 // Move assigned nodes from old slot to new slot.
210 InvalidateStyleAndLayoutOnSubtree(oldSlot);
211 const nsTArray<RefPtr<nsINode>>& assignedNodes = oldSlot->AssignedNodes();
212 bool doEnqueueSlotChange = false;
213 while (assignedNodes.Length() > 0) {
214 nsINode* assignedNode = assignedNodes[0];
216 oldSlot->RemoveAssignedNode(*assignedNode->AsContent());
217 aSlot->AppendAssignedNode(*assignedNode->AsContent());
218 doEnqueueSlotChange = true;
221 if (doEnqueueSlotChange) {
222 oldSlot->EnqueueSlotChangeEvent();
223 aSlot->EnqueueSlotChangeEvent();
224 SlotStateChanged(oldSlot);
225 SlotStateChanged(aSlot);
227 } else {
228 bool doEnqueueSlotChange = false;
229 // Otherwise add appropriate nodes to this slot from the host.
230 for (nsIContent* child = GetHost()->GetFirstChild(); child;
231 child = child->GetNextSibling()) {
232 nsAutoString slotName;
233 if (auto* element = Element::FromNode(*child)) {
234 element->GetAttr(nsGkAtoms::slot, slotName);
236 if (!child->IsSlotable() || !slotName.Equals(name)) {
237 continue;
239 doEnqueueSlotChange = true;
240 aSlot->AppendAssignedNode(*child);
243 if (doEnqueueSlotChange) {
244 aSlot->EnqueueSlotChangeEvent();
245 SlotStateChanged(aSlot);
250 void ShadowRoot::RemoveSlot(HTMLSlotElement* aSlot) {
251 MOZ_ASSERT(aSlot);
253 nsAutoString name;
254 aSlot->GetName(name);
256 MOZ_ASSERT(mSlotMap.Get(name));
258 SlotArray& currentSlots = *mSlotMap.Get(name);
259 MOZ_DIAGNOSTIC_ASSERT(currentSlots->Contains(aSlot),
260 "Slot to de-register wasn't found?");
261 if (currentSlots->Length() == 1) {
262 MOZ_ASSERT(currentSlots->ElementAt(0) == aSlot);
264 InvalidateStyleAndLayoutOnSubtree(aSlot);
266 mSlotMap.Remove(name);
267 if (!aSlot->AssignedNodes().IsEmpty()) {
268 aSlot->ClearAssignedNodes();
269 aSlot->EnqueueSlotChangeEvent();
272 return;
275 const bool wasFirstSlot = currentSlots->ElementAt(0) == aSlot;
276 currentSlots.RemoveElement(*aSlot);
277 if (!wasFirstSlot) {
278 return;
281 // Move assigned nodes from removed slot to the next slot in
282 // tree order with the same name.
283 InvalidateStyleAndLayoutOnSubtree(aSlot);
284 HTMLSlotElement* replacementSlot = currentSlots->ElementAt(0);
285 const nsTArray<RefPtr<nsINode>>& assignedNodes = aSlot->AssignedNodes();
286 if (assignedNodes.IsEmpty()) {
287 return;
290 InvalidateStyleAndLayoutOnSubtree(replacementSlot);
291 while (!assignedNodes.IsEmpty()) {
292 nsINode* assignedNode = assignedNodes[0];
294 aSlot->RemoveAssignedNode(*assignedNode->AsContent());
295 replacementSlot->AppendAssignedNode(*assignedNode->AsContent());
298 aSlot->EnqueueSlotChangeEvent();
299 replacementSlot->EnqueueSlotChangeEvent();
302 // FIXME(emilio): There's a bit of code duplication between this and the
303 // equivalent ServoStyleSet methods, it'd be nice to not duplicate it...
304 void ShadowRoot::RuleAdded(StyleSheet& aSheet, css::Rule& aRule) {
305 if (!aSheet.IsApplicable()) {
306 return;
309 MOZ_ASSERT(mServoStyles);
310 if (mStyleRuleMap) {
311 mStyleRuleMap->RuleAdded(aSheet, aRule);
314 if (aRule.IsIncompleteImportRule()) {
315 return;
318 Servo_AuthorStyles_ForceDirty(mServoStyles.get());
319 ApplicableRulesChanged();
322 void ShadowRoot::RuleRemoved(StyleSheet& aSheet, css::Rule& aRule) {
323 if (!aSheet.IsApplicable()) {
324 return;
327 MOZ_ASSERT(mServoStyles);
328 if (mStyleRuleMap) {
329 mStyleRuleMap->RuleRemoved(aSheet, aRule);
331 Servo_AuthorStyles_ForceDirty(mServoStyles.get());
332 ApplicableRulesChanged();
335 void ShadowRoot::RuleChanged(StyleSheet& aSheet, css::Rule*,
336 StyleRuleChangeKind) {
337 if (!aSheet.IsApplicable()) {
338 return;
341 MOZ_ASSERT(mServoStyles);
342 Servo_AuthorStyles_ForceDirty(mServoStyles.get());
343 ApplicableRulesChanged();
346 void ShadowRoot::ImportRuleLoaded(CSSImportRule&, StyleSheet& aSheet) {
347 if (mStyleRuleMap) {
348 mStyleRuleMap->SheetAdded(aSheet);
351 if (!aSheet.IsApplicable()) {
352 return;
355 // TODO(emilio): Could handle it like a regular sheet insertion, I guess, to
356 // avoid throwing away the whole style data.
357 Servo_AuthorStyles_ForceDirty(mServoStyles.get());
358 ApplicableRulesChanged();
361 // We don't need to do anything else than forwarding to the document if
362 // necessary.
363 void ShadowRoot::SheetCloned(StyleSheet& aSheet) {
364 if (Document* doc = GetComposedDoc()) {
365 if (PresShell* shell = doc->GetPresShell()) {
366 shell->StyleSet()->SheetCloned(aSheet);
371 void ShadowRoot::ApplicableRulesChanged() {
372 if (Document* doc = GetComposedDoc()) {
373 doc->RecordShadowStyleChange(*this);
377 void ShadowRoot::InsertSheetAt(size_t aIndex, StyleSheet& aSheet) {
378 DocumentOrShadowRoot::InsertSheetAt(aIndex, aSheet);
379 if (aSheet.IsApplicable()) {
380 InsertSheetIntoAuthorData(aIndex, aSheet, mStyleSheets);
384 StyleSheet* FirstApplicableAdoptedStyleSheet(
385 const nsTArray<RefPtr<StyleSheet>>& aList) {
386 size_t i = 0;
387 for (StyleSheet* sheet : aList) {
388 // Deal with duplicate sheets by only considering the last one.
389 if (sheet->IsApplicable() && MOZ_LIKELY(aList.LastIndexOf(sheet) == i)) {
390 return sheet;
392 i++;
394 return nullptr;
397 void ShadowRoot::InsertSheetIntoAuthorData(
398 size_t aIndex, StyleSheet& aSheet,
399 const nsTArray<RefPtr<StyleSheet>>& aList) {
400 MOZ_ASSERT(aSheet.IsApplicable());
401 MOZ_ASSERT(aList[aIndex] == &aSheet);
402 MOZ_ASSERT(aList.LastIndexOf(&aSheet) == aIndex);
403 MOZ_ASSERT(&aList == &mAdoptedStyleSheets || &aList == &mStyleSheets);
405 if (!mServoStyles) {
406 mServoStyles = Servo_AuthorStyles_Create().Consume();
409 if (mStyleRuleMap) {
410 mStyleRuleMap->SheetAdded(aSheet);
413 auto changedOnExit =
414 mozilla::MakeScopeExit([&] { ApplicableRulesChanged(); });
416 for (size_t i = aIndex + 1; i < aList.Length(); ++i) {
417 StyleSheet* beforeSheet = aList.ElementAt(i);
418 if (!beforeSheet->IsApplicable()) {
419 continue;
422 // If this is a duplicate adopted stylesheet that is not in the right
423 // position (the last one) then we skip over it. Otherwise we're done.
424 if (&aList == &mAdoptedStyleSheets &&
425 MOZ_UNLIKELY(aList.LastIndexOf(beforeSheet) != i)) {
426 continue;
429 Servo_AuthorStyles_InsertStyleSheetBefore(mServoStyles.get(), &aSheet,
430 beforeSheet);
431 return;
434 if (mAdoptedStyleSheets.IsEmpty() || &aList == &mAdoptedStyleSheets) {
435 Servo_AuthorStyles_AppendStyleSheet(mServoStyles.get(), &aSheet);
436 return;
439 if (auto* before = FirstApplicableAdoptedStyleSheet(mAdoptedStyleSheets)) {
440 Servo_AuthorStyles_InsertStyleSheetBefore(mServoStyles.get(), &aSheet,
441 before);
442 } else {
443 Servo_AuthorStyles_AppendStyleSheet(mServoStyles.get(), &aSheet);
447 // FIXME(emilio): This needs to notify document observers and such,
448 // presumably.
449 void ShadowRoot::StyleSheetApplicableStateChanged(StyleSheet& aSheet) {
450 auto& sheetList = aSheet.IsConstructed() ? mAdoptedStyleSheets : mStyleSheets;
451 int32_t index = sheetList.LastIndexOf(&aSheet);
452 if (index < 0) {
453 // NOTE(emilio): @import sheets are handled in the relevant RuleAdded
454 // notification, which only notifies after the sheet is loaded.
456 // This setup causes weirdness in other places, we may want to fix this in
457 // bug 1465031.
458 MOZ_DIAGNOSTIC_ASSERT(aSheet.GetParentSheet(),
459 "It'd better be an @import sheet");
460 return;
462 if (aSheet.IsApplicable()) {
463 InsertSheetIntoAuthorData(size_t(index), aSheet, sheetList);
464 } else {
465 MOZ_ASSERT(mServoStyles);
466 if (mStyleRuleMap) {
467 mStyleRuleMap->SheetRemoved(aSheet);
469 Servo_AuthorStyles_RemoveStyleSheet(mServoStyles.get(), &aSheet);
470 ApplicableRulesChanged();
474 void ShadowRoot::RemoveSheetFromStyles(StyleSheet& aSheet) {
475 MOZ_ASSERT(aSheet.IsApplicable());
476 MOZ_ASSERT(mServoStyles);
477 if (mStyleRuleMap) {
478 mStyleRuleMap->SheetRemoved(aSheet);
480 Servo_AuthorStyles_RemoveStyleSheet(mServoStyles.get(), &aSheet);
481 ApplicableRulesChanged();
484 void ShadowRoot::AddToIdTable(Element* aElement, nsAtom* aId) {
485 IdentifierMapEntry* entry = mIdentifierMap.PutEntry(aId);
486 if (entry) {
487 entry->AddIdElement(aElement);
491 void ShadowRoot::RemoveFromIdTable(Element* aElement, nsAtom* aId) {
492 IdentifierMapEntry* entry = mIdentifierMap.GetEntry(aId);
493 if (entry) {
494 entry->RemoveIdElement(aElement);
495 if (entry->IsEmpty()) {
496 mIdentifierMap.RemoveEntry(entry);
501 void ShadowRoot::GetEventTargetParent(EventChainPreVisitor& aVisitor) {
502 aVisitor.mCanHandle = true;
503 aVisitor.mRootOfClosedTree = IsClosed();
504 // Inform that we're about to exit the current scope.
505 aVisitor.mRelatedTargetRetargetedInCurrentScope = false;
507 // https://dom.spec.whatwg.org/#ref-for-get-the-parent%E2%91%A6
508 if (!aVisitor.mEvent->mFlags.mComposed) {
509 nsCOMPtr<nsIContent> originalTarget =
510 do_QueryInterface(aVisitor.mEvent->mOriginalTarget);
511 if (originalTarget && originalTarget->GetContainingShadow() == this) {
512 // If we do stop propagation, we still want to propagate
513 // the event to chrome (nsPIDOMWindow::GetParentTarget()).
514 // The load event is special in that we don't ever propagate it
515 // to chrome.
516 nsCOMPtr<nsPIDOMWindowOuter> win = OwnerDoc()->GetWindow();
517 EventTarget* parentTarget = win && aVisitor.mEvent->mMessage != eLoad
518 ? win->GetParentTarget()
519 : nullptr;
521 aVisitor.SetParentTarget(parentTarget, true);
522 return;
526 nsIContent* shadowHost = GetHost();
527 aVisitor.SetParentTarget(shadowHost, false);
529 nsCOMPtr<nsIContent> content(do_QueryInterface(aVisitor.mEvent->mTarget));
530 if (content && content->GetContainingShadow() == this) {
531 aVisitor.mEventTargetAtParent = shadowHost;
535 ShadowRoot::SlotAssignment ShadowRoot::SlotAssignmentFor(nsIContent& aContent) {
536 nsAutoString slotName;
537 // Note that if slot attribute is missing, assign it to the first default
538 // slot, if exists.
539 if (Element* element = Element::FromNode(aContent)) {
540 element->GetAttr(nsGkAtoms::slot, slotName);
543 SlotArray* slots = mSlotMap.Get(slotName);
544 if (!slots) {
545 return {};
548 HTMLSlotElement* slot = (*slots)->ElementAt(0);
549 MOZ_ASSERT(slot);
551 if (!aContent.GetNextSibling()) {
552 // aContent is the last child, no need to loop through the assigned nodes,
553 // we're necessarily the last one.
555 // This prevents multiple appends into the host from getting quadratic.
556 return {slot, Nothing()};
559 // Find the appropriate position in the assigned node list for the newly
560 // assigned content.
561 const nsTArray<RefPtr<nsINode>>& assignedNodes = slot->AssignedNodes();
562 nsIContent* currentContent = GetHost()->GetFirstChild();
563 for (uint32_t i = 0; i < assignedNodes.Length(); i++) {
564 // Seek through the host's explicit children until the
565 // assigned content is found.
566 while (currentContent && currentContent != assignedNodes[i]) {
567 if (currentContent == &aContent) {
568 return {slot, Some(i)};
570 currentContent = currentContent->GetNextSibling();
574 return {slot, Nothing()};
577 void ShadowRoot::MaybeReassignElement(Element& aElement) {
578 MOZ_ASSERT(aElement.GetParent() == GetHost());
579 HTMLSlotElement* oldSlot = aElement.GetAssignedSlot();
580 SlotAssignment assignment = SlotAssignmentFor(aElement);
582 if (assignment.mSlot == oldSlot) {
583 // Nothing to do here.
584 return;
587 if (Document* doc = GetComposedDoc()) {
588 if (RefPtr<PresShell> presShell = doc->GetPresShell()) {
589 presShell->SlotAssignmentWillChange(aElement, oldSlot, assignment.mSlot);
593 if (oldSlot) {
594 oldSlot->RemoveAssignedNode(aElement);
595 oldSlot->EnqueueSlotChangeEvent();
598 if (assignment.mSlot) {
599 if (assignment.mIndex) {
600 assignment.mSlot->InsertAssignedNode(*assignment.mIndex, aElement);
601 } else {
602 assignment.mSlot->AppendAssignedNode(aElement);
604 assignment.mSlot->EnqueueSlotChangeEvent();
607 SlotAssignedNodeChanged(oldSlot, aElement);
608 SlotAssignedNodeChanged(assignment.mSlot, aElement);
611 Element* ShadowRoot::GetActiveElement() {
612 return GetRetargetedFocusedElement();
615 nsINode* ShadowRoot::ImportNodeAndAppendChildAt(nsINode& aParentNode,
616 nsINode& aNode, bool aDeep,
617 mozilla::ErrorResult& rv) {
618 MOZ_ASSERT(mIsUAWidget);
620 if (!aParentNode.IsInUAWidget()) {
621 rv.Throw(NS_ERROR_INVALID_ARG);
622 return nullptr;
625 RefPtr<nsINode> node = OwnerDoc()->ImportNode(aNode, aDeep, rv);
626 if (rv.Failed()) {
627 return nullptr;
630 return aParentNode.AppendChild(*node, rv);
633 nsINode* ShadowRoot::CreateElementAndAppendChildAt(nsINode& aParentNode,
634 const nsAString& aTagName,
635 mozilla::ErrorResult& rv) {
636 MOZ_ASSERT(mIsUAWidget);
638 if (!aParentNode.IsInUAWidget()) {
639 rv.Throw(NS_ERROR_INVALID_ARG);
640 return nullptr;
643 // This option is not exposed to UA Widgets
644 ElementCreationOptionsOrString options;
646 RefPtr<nsINode> node = OwnerDoc()->CreateElement(aTagName, options, rv);
647 if (rv.Failed()) {
648 return nullptr;
651 return aParentNode.AppendChild(*node, rv);
654 void ShadowRoot::MaybeUnslotHostChild(nsIContent& aChild) {
655 // Need to null-check the host because we may be unlinked already.
656 MOZ_ASSERT(!GetHost() || aChild.GetParent() == GetHost());
658 HTMLSlotElement* slot = aChild.GetAssignedSlot();
659 if (!slot) {
660 return;
663 MOZ_DIAGNOSTIC_ASSERT(!aChild.IsRootOfNativeAnonymousSubtree(),
664 "How did aChild end up assigned to a slot?");
665 // If the slot is going to start showing fallback content, we need to tell
666 // layout about it.
667 if (slot->AssignedNodes().Length() == 1 && slot->HasChildren()) {
668 InvalidateStyleAndLayoutOnSubtree(slot);
671 slot->RemoveAssignedNode(aChild);
672 slot->EnqueueSlotChangeEvent();
675 void ShadowRoot::MaybeSlotHostChild(nsIContent& aChild) {
676 MOZ_ASSERT(aChild.GetParent() == GetHost());
677 // Check to ensure that the child not an anonymous subtree root because even
678 // though its parent could be the host it may not be in the host's child list.
679 if (aChild.IsRootOfNativeAnonymousSubtree()) {
680 return;
683 if (!aChild.IsSlotable()) {
684 return;
687 SlotAssignment assignment = SlotAssignmentFor(aChild);
688 if (!assignment.mSlot) {
689 return;
692 // Fallback content will go away, let layout know.
693 if (assignment.mSlot->AssignedNodes().IsEmpty() &&
694 assignment.mSlot->HasChildren()) {
695 InvalidateStyleAndLayoutOnSubtree(assignment.mSlot);
698 if (assignment.mIndex) {
699 assignment.mSlot->InsertAssignedNode(*assignment.mIndex, aChild);
700 } else {
701 assignment.mSlot->AppendAssignedNode(aChild);
703 assignment.mSlot->EnqueueSlotChangeEvent();
704 SlotAssignedNodeChanged(assignment.mSlot, aChild);
707 ServoStyleRuleMap& ShadowRoot::ServoStyleRuleMap() {
708 if (!mStyleRuleMap) {
709 mStyleRuleMap = MakeUnique<mozilla::ServoStyleRuleMap>();
711 mStyleRuleMap->EnsureTable(*this);
712 return *mStyleRuleMap;
715 nsresult ShadowRoot::Clone(dom::NodeInfo* aNodeInfo, nsINode** aResult) const {
716 *aResult = nullptr;
717 return NS_ERROR_DOM_NOT_SUPPORTED_ERR;