Bug 1660051 [wpt PR 25111] - Origin isolation: expand getter test coverage, a=testonly
[gecko.git] / dom / base / ShadowRoot.cpp
blob5f602a22a4135c5be1a48045b6ff5ca4e8b9c8ed
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/ServoStyleRuleMap.h"
23 #include "mozilla/StyleSheet.h"
24 #include "mozilla/StyleSheetInlines.h"
25 #include "mozilla/dom/StyleSheetList.h"
27 using namespace mozilla;
28 using namespace mozilla::dom;
30 NS_IMPL_CYCLE_COLLECTION_CLASS(ShadowRoot)
32 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(ShadowRoot, DocumentFragment)
33 DocumentOrShadowRoot::Traverse(tmp, cb);
34 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
36 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(ShadowRoot)
37 DocumentOrShadowRoot::Unlink(tmp);
38 NS_IMPL_CYCLE_COLLECTION_UNLINK_END_INHERITED(DocumentFragment)
40 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ShadowRoot)
41 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIContent)
42 NS_INTERFACE_MAP_ENTRY(nsIRadioGroupContainer)
43 NS_INTERFACE_MAP_END_INHERITING(DocumentFragment)
45 NS_IMPL_ADDREF_INHERITED(ShadowRoot, DocumentFragment)
46 NS_IMPL_RELEASE_INHERITED(ShadowRoot, DocumentFragment)
48 ShadowRoot::ShadowRoot(Element* aElement, ShadowRootMode aMode,
49 already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo)
50 : DocumentFragment(std::move(aNodeInfo)),
51 DocumentOrShadowRoot(this),
52 mMode(aMode),
53 mIsUAWidget(false),
54 mIsStaticUAWidget(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 MOZ_ASSERT(aOther->ShouldStaticClone());
101 if (aOther->IsUAWidget()) {
102 SetIsUAWidget();
104 if (aOther->IsStaticUAWidget()) {
105 SetIsStaticUAWidget();
108 size_t sheetCount = aOther->SheetCount();
109 for (size_t i = 0; i < sheetCount; ++i) {
110 StyleSheet* sheet = aOther->SheetAt(i);
111 if (sheet->IsApplicable()) {
112 RefPtr<StyleSheet> clonedSheet =
113 sheet->Clone(nullptr, nullptr, this, nullptr);
114 if (clonedSheet) {
115 AppendStyleSheet(*clonedSheet.get());
119 CloneAdoptedSheetsFrom(*aOther);
122 nsresult ShadowRoot::Bind() {
123 MOZ_ASSERT(!IsInComposedDoc(), "Forgot to unbind?");
124 if (Host()->IsInComposedDoc()) {
125 SetIsConnected(true);
126 Document* doc = OwnerDoc();
127 doc->AddComposedDocShadowRoot(*this);
128 // If our stylesheets somehow mutated when we were disconnected, we need to
129 // ensure that our style data gets flushed as appropriate.
130 if (mServoStyles && Servo_AuthorStyles_IsDirty(mServoStyles.get())) {
131 doc->RecordShadowStyleChange(*this);
135 BindContext context(*this);
136 for (nsIContent* child = GetFirstChild(); child;
137 child = child->GetNextSibling()) {
138 nsresult rv = child->BindToTree(context, *this);
139 NS_ENSURE_SUCCESS(rv, rv);
142 return NS_OK;
145 void ShadowRoot::Unbind() {
146 if (IsInComposedDoc()) {
147 SetIsConnected(false);
148 OwnerDoc()->RemoveComposedDocShadowRoot(*this);
151 for (nsIContent* child = GetFirstChild(); child;
152 child = child->GetNextSibling()) {
153 child->UnbindFromTree(false);
157 void ShadowRoot::Unattach() {
158 MOZ_ASSERT(!HasSlots(), "Won't work!");
159 if (!GetHost()) {
160 // It is possible that we've been unlinked already. In such case host
161 // should have called Unbind and ShadowRoot's own unlink.
162 return;
165 Unbind();
166 SetHost(nullptr);
169 void ShadowRoot::InvalidateStyleAndLayoutOnSubtree(Element* aElement) {
170 MOZ_ASSERT(aElement);
171 Document* doc = GetComposedDoc();
172 if (!doc) {
173 return;
176 PresShell* presShell = doc->GetPresShell();
177 if (!presShell) {
178 return;
181 presShell->DestroyFramesForAndRestyle(aElement);
184 void ShadowRoot::PartAdded(const Element& aPart) {
185 MOZ_ASSERT(aPart.HasPartAttribute());
186 MOZ_ASSERT(!mParts.Contains(&aPart));
187 mParts.AppendElement(&aPart);
190 void ShadowRoot::PartRemoved(const Element& aPart) {
191 MOZ_ASSERT(mParts.Contains(&aPart));
192 mParts.RemoveElement(&aPart);
193 MOZ_ASSERT(!mParts.Contains(&aPart));
196 void ShadowRoot::AddSlot(HTMLSlotElement* aSlot) {
197 MOZ_ASSERT(aSlot);
199 // Note that if name attribute missing, the slot is a default slot.
200 nsAutoString name;
201 aSlot->GetName(name);
203 SlotArray& currentSlots = *mSlotMap.LookupOrAdd(name);
205 size_t index = currentSlots.Insert(*aSlot);
206 if (index != 0) {
207 return;
210 HTMLSlotElement* oldSlot = currentSlots->SafeElementAt(1);
211 if (oldSlot) {
212 MOZ_DIAGNOSTIC_ASSERT(oldSlot != aSlot);
214 // Move assigned nodes from old slot to new slot.
215 InvalidateStyleAndLayoutOnSubtree(oldSlot);
216 const nsTArray<RefPtr<nsINode>>& assignedNodes = oldSlot->AssignedNodes();
217 bool doEnqueueSlotChange = false;
218 while (assignedNodes.Length() > 0) {
219 nsINode* assignedNode = assignedNodes[0];
221 oldSlot->RemoveAssignedNode(*assignedNode->AsContent());
222 aSlot->AppendAssignedNode(*assignedNode->AsContent());
223 doEnqueueSlotChange = true;
226 if (doEnqueueSlotChange) {
227 oldSlot->EnqueueSlotChangeEvent();
228 aSlot->EnqueueSlotChangeEvent();
229 SlotStateChanged(oldSlot);
230 SlotStateChanged(aSlot);
232 } else {
233 bool doEnqueueSlotChange = false;
234 // Otherwise add appropriate nodes to this slot from the host.
235 for (nsIContent* child = GetHost()->GetFirstChild(); child;
236 child = child->GetNextSibling()) {
237 nsAutoString slotName;
238 if (child->IsElement()) {
239 child->AsElement()->GetAttr(kNameSpaceID_None, nsGkAtoms::slot,
240 slotName);
242 if (!child->IsSlotable() || !slotName.Equals(name)) {
243 continue;
245 doEnqueueSlotChange = true;
246 aSlot->AppendAssignedNode(*child);
249 if (doEnqueueSlotChange) {
250 aSlot->EnqueueSlotChangeEvent();
251 SlotStateChanged(aSlot);
256 void ShadowRoot::RemoveSlot(HTMLSlotElement* aSlot) {
257 MOZ_ASSERT(aSlot);
259 nsAutoString name;
260 aSlot->GetName(name);
262 MOZ_ASSERT(mSlotMap.Get(name));
264 SlotArray& currentSlots = *mSlotMap.Get(name);
265 MOZ_DIAGNOSTIC_ASSERT(currentSlots->Contains(aSlot),
266 "Slot to de-register wasn't found?");
267 if (currentSlots->Length() == 1) {
268 MOZ_ASSERT(currentSlots->ElementAt(0) == aSlot);
270 InvalidateStyleAndLayoutOnSubtree(aSlot);
272 mSlotMap.Remove(name);
273 if (!aSlot->AssignedNodes().IsEmpty()) {
274 aSlot->ClearAssignedNodes();
275 aSlot->EnqueueSlotChangeEvent();
278 return;
281 const bool wasFirstSlot = currentSlots->ElementAt(0) == aSlot;
282 currentSlots.RemoveElement(*aSlot);
283 if (!wasFirstSlot) {
284 return;
287 // Move assigned nodes from removed slot to the next slot in
288 // tree order with the same name.
289 InvalidateStyleAndLayoutOnSubtree(aSlot);
290 HTMLSlotElement* replacementSlot = currentSlots->ElementAt(0);
291 const nsTArray<RefPtr<nsINode>>& assignedNodes = aSlot->AssignedNodes();
292 if (assignedNodes.IsEmpty()) {
293 return;
296 InvalidateStyleAndLayoutOnSubtree(replacementSlot);
297 while (!assignedNodes.IsEmpty()) {
298 nsINode* assignedNode = assignedNodes[0];
300 aSlot->RemoveAssignedNode(*assignedNode->AsContent());
301 replacementSlot->AppendAssignedNode(*assignedNode->AsContent());
304 aSlot->EnqueueSlotChangeEvent();
305 replacementSlot->EnqueueSlotChangeEvent();
308 // FIXME(emilio): There's a bit of code duplication between this and the
309 // equivalent ServoStyleSet methods, it'd be nice to not duplicate it...
310 void ShadowRoot::RuleAdded(StyleSheet& aSheet, css::Rule& aRule) {
311 if (!aSheet.IsApplicable()) {
312 return;
315 MOZ_ASSERT(mServoStyles);
316 if (mStyleRuleMap) {
317 mStyleRuleMap->RuleAdded(aSheet, aRule);
320 if (aRule.IsIncompleteImportRule()) {
321 return;
324 Servo_AuthorStyles_ForceDirty(mServoStyles.get());
325 ApplicableRulesChanged();
328 void ShadowRoot::RuleRemoved(StyleSheet& aSheet, css::Rule& aRule) {
329 if (!aSheet.IsApplicable()) {
330 return;
333 MOZ_ASSERT(mServoStyles);
334 if (mStyleRuleMap) {
335 mStyleRuleMap->RuleRemoved(aSheet, aRule);
337 Servo_AuthorStyles_ForceDirty(mServoStyles.get());
338 ApplicableRulesChanged();
341 void ShadowRoot::RuleChanged(StyleSheet& aSheet, css::Rule*,
342 StyleRuleChangeKind) {
343 if (!aSheet.IsApplicable()) {
344 return;
347 MOZ_ASSERT(mServoStyles);
348 Servo_AuthorStyles_ForceDirty(mServoStyles.get());
349 ApplicableRulesChanged();
352 void ShadowRoot::ImportRuleLoaded(CSSImportRule&, StyleSheet& aSheet) {
353 if (mStyleRuleMap) {
354 mStyleRuleMap->SheetAdded(aSheet);
357 if (!aSheet.IsApplicable()) {
358 return;
361 // TODO(emilio): Could handle it like a regular sheet insertion, I guess, to
362 // avoid throwing away the whole style data.
363 Servo_AuthorStyles_ForceDirty(mServoStyles.get());
364 ApplicableRulesChanged();
367 // We don't need to do anything else than forwarding to the document if
368 // necessary.
369 void ShadowRoot::SheetCloned(StyleSheet& aSheet) {
370 if (Document* doc = GetComposedDoc()) {
371 if (PresShell* shell = doc->GetPresShell()) {
372 shell->StyleSet()->SheetCloned(aSheet);
377 void ShadowRoot::ApplicableRulesChanged() {
378 if (Document* doc = GetComposedDoc()) {
379 doc->RecordShadowStyleChange(*this);
383 void ShadowRoot::InsertSheetAt(size_t aIndex, StyleSheet& aSheet) {
384 DocumentOrShadowRoot::InsertSheetAt(aIndex, aSheet);
385 if (aSheet.IsApplicable()) {
386 InsertSheetIntoAuthorData(aIndex, aSheet, mStyleSheets);
390 StyleSheet* FirstApplicableAdoptedStyleSheet(
391 const nsTArray<RefPtr<StyleSheet>>& aList) {
392 size_t i = 0;
393 for (StyleSheet* sheet : aList) {
394 // Deal with duplicate sheets by only considering the last one.
395 if (sheet->IsApplicable() && MOZ_LIKELY(aList.LastIndexOf(sheet) == i)) {
396 return sheet;
398 i++;
400 return nullptr;
403 void ShadowRoot::InsertSheetIntoAuthorData(
404 size_t aIndex, StyleSheet& aSheet,
405 const nsTArray<RefPtr<StyleSheet>>& aList) {
406 MOZ_ASSERT(aSheet.IsApplicable());
407 MOZ_ASSERT(aList[aIndex] == &aSheet);
408 MOZ_ASSERT(aList.LastIndexOf(&aSheet) == aIndex);
409 MOZ_ASSERT(&aList == &mAdoptedStyleSheets || &aList == &mStyleSheets);
411 if (!mServoStyles) {
412 mServoStyles = Servo_AuthorStyles_Create().Consume();
415 if (mStyleRuleMap) {
416 mStyleRuleMap->SheetAdded(aSheet);
419 auto changedOnExit =
420 mozilla::MakeScopeExit([&] { ApplicableRulesChanged(); });
422 for (size_t i = aIndex + 1; i < aList.Length(); ++i) {
423 StyleSheet* beforeSheet = aList.ElementAt(i);
424 if (!beforeSheet->IsApplicable()) {
425 continue;
428 // If this is a duplicate adopted stylesheet that is not in the right
429 // position (the last one) then we skip over it. Otherwise we're done.
430 if (&aList == &mAdoptedStyleSheets &&
431 MOZ_UNLIKELY(aList.LastIndexOf(beforeSheet) != i)) {
432 continue;
435 Servo_AuthorStyles_InsertStyleSheetBefore(mServoStyles.get(), &aSheet,
436 beforeSheet);
437 return;
440 if (mAdoptedStyleSheets.IsEmpty() || &aList == &mAdoptedStyleSheets) {
441 Servo_AuthorStyles_AppendStyleSheet(mServoStyles.get(), &aSheet);
442 return;
445 if (auto* before = FirstApplicableAdoptedStyleSheet(mAdoptedStyleSheets)) {
446 Servo_AuthorStyles_InsertStyleSheetBefore(mServoStyles.get(), &aSheet,
447 before);
448 } else {
449 Servo_AuthorStyles_AppendStyleSheet(mServoStyles.get(), &aSheet);
453 // FIXME(emilio): This needs to notify document observers and such,
454 // presumably.
455 void ShadowRoot::StyleSheetApplicableStateChanged(StyleSheet& aSheet) {
456 auto& sheetList = aSheet.IsConstructed() ? mAdoptedStyleSheets : mStyleSheets;
457 int32_t index = sheetList.LastIndexOf(&aSheet);
458 if (index < 0) {
459 // NOTE(emilio): @import sheets are handled in the relevant RuleAdded
460 // notification, which only notifies after the sheet is loaded.
462 // This setup causes weirdness in other places, we may want to fix this in
463 // bug 1465031.
464 MOZ_DIAGNOSTIC_ASSERT(aSheet.GetParentSheet(),
465 "It'd better be an @import sheet");
466 return;
468 if (aSheet.IsApplicable()) {
469 InsertSheetIntoAuthorData(size_t(index), aSheet, sheetList);
470 } else {
471 MOZ_ASSERT(mServoStyles);
472 if (mStyleRuleMap) {
473 mStyleRuleMap->SheetRemoved(aSheet);
475 Servo_AuthorStyles_RemoveStyleSheet(mServoStyles.get(), &aSheet);
476 ApplicableRulesChanged();
480 void ShadowRoot::RemoveSheetFromStyles(StyleSheet& aSheet) {
481 MOZ_ASSERT(aSheet.IsApplicable());
482 MOZ_ASSERT(mServoStyles);
483 if (mStyleRuleMap) {
484 mStyleRuleMap->SheetRemoved(aSheet);
486 Servo_AuthorStyles_RemoveStyleSheet(mServoStyles.get(), &aSheet);
487 ApplicableRulesChanged();
490 void ShadowRoot::AddToIdTable(Element* aElement, nsAtom* aId) {
491 IdentifierMapEntry* entry = mIdentifierMap.PutEntry(aId);
492 if (entry) {
493 entry->AddIdElement(aElement);
497 void ShadowRoot::RemoveFromIdTable(Element* aElement, nsAtom* aId) {
498 IdentifierMapEntry* entry = mIdentifierMap.GetEntry(aId);
499 if (entry) {
500 entry->RemoveIdElement(aElement);
501 if (entry->IsEmpty()) {
502 mIdentifierMap.RemoveEntry(entry);
507 void ShadowRoot::GetEventTargetParent(EventChainPreVisitor& aVisitor) {
508 aVisitor.mCanHandle = true;
509 aVisitor.mRootOfClosedTree = IsClosed();
510 // Inform that we're about to exit the current scope.
511 aVisitor.mRelatedTargetRetargetedInCurrentScope = false;
513 // https://dom.spec.whatwg.org/#ref-for-get-the-parent%E2%91%A6
514 if (!aVisitor.mEvent->mFlags.mComposed) {
515 nsCOMPtr<nsIContent> originalTarget =
516 do_QueryInterface(aVisitor.mEvent->mOriginalTarget);
517 if (originalTarget && originalTarget->GetContainingShadow() == this) {
518 // If we do stop propagation, we still want to propagate
519 // the event to chrome (nsPIDOMWindow::GetParentTarget()).
520 // The load event is special in that we don't ever propagate it
521 // to chrome.
522 nsCOMPtr<nsPIDOMWindowOuter> win = OwnerDoc()->GetWindow();
523 EventTarget* parentTarget = win && aVisitor.mEvent->mMessage != eLoad
524 ? win->GetParentTarget()
525 : nullptr;
527 aVisitor.SetParentTarget(parentTarget, true);
528 return;
532 nsIContent* shadowHost = GetHost();
533 aVisitor.SetParentTarget(shadowHost, false);
535 nsCOMPtr<nsIContent> content(do_QueryInterface(aVisitor.mEvent->mTarget));
536 if (content && content->GetContainingShadow() == this) {
537 aVisitor.mEventTargetAtParent = shadowHost;
541 ShadowRoot::SlotAssignment ShadowRoot::SlotAssignmentFor(nsIContent& aContent) {
542 nsAutoString slotName;
543 // Note that if slot attribute is missing, assign it to the first default
544 // slot, if exists.
545 if (Element* element = Element::FromNode(aContent)) {
546 element->GetAttr(kNameSpaceID_None, nsGkAtoms::slot, slotName);
549 SlotArray* slots = mSlotMap.Get(slotName);
550 if (!slots) {
551 return {};
554 HTMLSlotElement* slot = (*slots)->ElementAt(0);
555 MOZ_ASSERT(slot);
557 // Find the appropriate position in the assigned node list for the
558 // newly assigned content.
559 const nsTArray<RefPtr<nsINode>>& assignedNodes = slot->AssignedNodes();
560 nsIContent* currentContent = GetHost()->GetFirstChild();
561 Maybe<uint32_t> insertionIndex;
562 for (uint32_t i = 0; i < assignedNodes.Length(); i++) {
563 // Seek through the host's explicit children until the
564 // assigned content is found.
565 while (currentContent && currentContent != assignedNodes[i]) {
566 if (currentContent == &aContent) {
567 insertionIndex.emplace(i);
568 break;
571 currentContent = currentContent->GetNextSibling();
574 if (insertionIndex) {
575 break;
579 return {slot, insertionIndex};
582 void ShadowRoot::MaybeReassignElement(Element& aElement) {
583 MOZ_ASSERT(aElement.GetParent() == GetHost());
584 HTMLSlotElement* oldSlot = aElement.GetAssignedSlot();
585 SlotAssignment assignment = SlotAssignmentFor(aElement);
587 if (assignment.mSlot == oldSlot) {
588 // Nothing to do here.
589 return;
592 if (Document* doc = GetComposedDoc()) {
593 if (RefPtr<PresShell> presShell = doc->GetPresShell()) {
594 presShell->SlotAssignmentWillChange(aElement, oldSlot, assignment.mSlot);
598 if (oldSlot) {
599 oldSlot->RemoveAssignedNode(aElement);
600 oldSlot->EnqueueSlotChangeEvent();
603 if (assignment.mSlot) {
604 if (assignment.mIndex) {
605 assignment.mSlot->InsertAssignedNode(*assignment.mIndex, aElement);
606 } else {
607 assignment.mSlot->AppendAssignedNode(aElement);
609 assignment.mSlot->EnqueueSlotChangeEvent();
612 SlotStateChanged(oldSlot);
613 SlotStateChanged(assignment.mSlot);
616 Element* ShadowRoot::GetActiveElement() {
617 return GetRetargetedFocusedElement();
620 nsINode* ShadowRoot::ImportNodeAndAppendChildAt(nsINode& aParentNode,
621 nsINode& aNode, bool aDeep,
622 mozilla::ErrorResult& rv) {
623 MOZ_ASSERT(mIsUAWidget);
625 if (!aParentNode.IsInUAWidget()) {
626 rv.Throw(NS_ERROR_INVALID_ARG);
627 return nullptr;
630 RefPtr<nsINode> node = OwnerDoc()->ImportNode(aNode, aDeep, rv);
631 if (rv.Failed()) {
632 return nullptr;
635 return aParentNode.AppendChild(*node, rv);
638 nsINode* ShadowRoot::CreateElementAndAppendChildAt(nsINode& aParentNode,
639 const nsAString& aTagName,
640 mozilla::ErrorResult& rv) {
641 MOZ_ASSERT(mIsUAWidget);
643 if (!aParentNode.IsInUAWidget()) {
644 rv.Throw(NS_ERROR_INVALID_ARG);
645 return nullptr;
648 // This option is not exposed to UA Widgets
649 ElementCreationOptionsOrString options;
651 RefPtr<nsINode> node = OwnerDoc()->CreateElement(aTagName, options, rv);
652 if (rv.Failed()) {
653 return nullptr;
656 return aParentNode.AppendChild(*node, rv);
659 void ShadowRoot::MaybeUnslotHostChild(nsIContent& aChild) {
660 // Need to null-check the host because we may be unlinked already.
661 MOZ_ASSERT(!GetHost() || aChild.GetParent() == GetHost());
663 HTMLSlotElement* slot = aChild.GetAssignedSlot();
664 if (!slot) {
665 return;
668 MOZ_DIAGNOSTIC_ASSERT(!aChild.IsRootOfNativeAnonymousSubtree(),
669 "How did aChild end up assigned to a slot?");
670 // If the slot is going to start showing fallback content, we need to tell
671 // layout about it.
672 if (slot->AssignedNodes().Length() == 1 && slot->HasChildren()) {
673 InvalidateStyleAndLayoutOnSubtree(slot);
676 slot->RemoveAssignedNode(aChild);
677 slot->EnqueueSlotChangeEvent();
680 void ShadowRoot::MaybeSlotHostChild(nsIContent& aChild) {
681 MOZ_ASSERT(aChild.GetParent() == GetHost());
682 // Check to ensure that the child not an anonymous subtree root because even
683 // though its parent could be the host it may not be in the host's child list.
684 if (aChild.IsRootOfNativeAnonymousSubtree()) {
685 return;
688 if (!aChild.IsSlotable()) {
689 return;
692 SlotAssignment assignment = SlotAssignmentFor(aChild);
693 if (!assignment.mSlot) {
694 return;
697 // Fallback content will go away, let layout know.
698 if (assignment.mSlot->AssignedNodes().IsEmpty() &&
699 assignment.mSlot->HasChildren()) {
700 InvalidateStyleAndLayoutOnSubtree(assignment.mSlot);
703 if (assignment.mIndex) {
704 assignment.mSlot->InsertAssignedNode(*assignment.mIndex, aChild);
705 } else {
706 assignment.mSlot->AppendAssignedNode(aChild);
708 assignment.mSlot->EnqueueSlotChangeEvent();
709 SlotStateChanged(assignment.mSlot);
712 ServoStyleRuleMap& ShadowRoot::ServoStyleRuleMap() {
713 if (!mStyleRuleMap) {
714 mStyleRuleMap = MakeUnique<mozilla::ServoStyleRuleMap>();
716 mStyleRuleMap->EnsureTable(*this);
717 return *mStyleRuleMap;
720 nsresult ShadowRoot::Clone(dom::NodeInfo* aNodeInfo, nsINode** aResult) const {
721 *aResult = nullptr;
722 return NS_ERROR_DOM_NOT_SUPPORTED_ERR;