/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "mozilla/Preferences.h" #include "mozilla/dom/ShadowRoot.h" #include "mozilla/dom/ShadowRootBinding.h" #include "mozilla/dom/DocumentFragment.h" #include "ChildIterator.h" #include "nsContentUtils.h" #include "nsDOMClassInfoID.h" #include "nsIDOMHTMLElement.h" #include "nsIStyleSheetLinkingElement.h" #include "mozilla/dom/Element.h" #include "mozilla/dom/HTMLContentElement.h" #include "nsXBLPrototypeBinding.h" #include "mozilla/StyleSheet.h" #include "mozilla/StyleSheetInlines.h" using namespace mozilla; using namespace mozilla::dom; NS_IMPL_CYCLE_COLLECTION_CLASS(ShadowRoot) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(ShadowRoot, DocumentFragment) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mStyleSheetList) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAssociatedBinding) for (auto iter = tmp->mIdentifierMap.ConstIter(); !iter.Done(); iter.Next()) { iter.Get()->Traverse(&cb); } NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(ShadowRoot) if (tmp->GetHost()) { tmp->GetHost()->RemoveMutationObserver(tmp); } NS_IMPL_CYCLE_COLLECTION_UNLINK(mStyleSheetList) NS_IMPL_CYCLE_COLLECTION_UNLINK(mAssociatedBinding) tmp->mIdentifierMap.Clear(); NS_IMPL_CYCLE_COLLECTION_UNLINK_END_INHERITED(DocumentFragment) NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(ShadowRoot) NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIContent) NS_INTERFACE_MAP_ENTRY(nsIMutationObserver) NS_INTERFACE_MAP_END_INHERITING(DocumentFragment) NS_IMPL_ADDREF_INHERITED(ShadowRoot, DocumentFragment) NS_IMPL_RELEASE_INHERITED(ShadowRoot, DocumentFragment) ShadowRoot::ShadowRoot(Element* aElement, bool aClosed, already_AddRefed&& aNodeInfo, nsXBLPrototypeBinding* aProtoBinding) : DocumentFragment(aNodeInfo) , mProtoBinding(aProtoBinding) , mInsertionPointChanged(false) , mIsComposedDocParticipant(false) { SetHost(aElement); mMode = aClosed ? ShadowRootMode::Closed : ShadowRootMode::Open; // Nodes in a shadow tree should never store a value // in the subtree root pointer, nodes in the shadow tree // track the subtree root using GetContainingShadow(). ClearSubtreeRootPointer(); SetFlags(NODE_IS_IN_SHADOW_TREE); ExtendedDOMSlots()->mBindingParent = aElement; ExtendedDOMSlots()->mContainingShadow = this; // Add the ShadowRoot as a mutation observer on the host to watch // for mutations because the insertion points in this ShadowRoot // may need to be updated when the host children are modified. GetHost()->AddMutationObserver(this); } ShadowRoot::~ShadowRoot() { if (auto* host = GetHost()) { // mHost may have been unlinked or a new ShadowRoot may have been // created, making this one obsolete. host->RemoveMutationObserver(this); } UnsetFlags(NODE_IS_IN_SHADOW_TREE); // nsINode destructor expects mSubtreeRoot == this. SetSubtreeRootPointer(this); } JSObject* ShadowRoot::WrapObject(JSContext* aCx, JS::Handle aGivenProto) { return mozilla::dom::ShadowRootBinding::Wrap(aCx, this, aGivenProto); } ShadowRoot* ShadowRoot::FromNode(nsINode* aNode) { if (aNode->IsInShadowTree() && !aNode->GetParentNode()) { MOZ_ASSERT(aNode->NodeType() == nsIDOMNode::DOCUMENT_FRAGMENT_NODE, "ShadowRoot is a document fragment."); return static_cast(aNode); } return nullptr; } void ShadowRoot::StyleSheetChanged() { mProtoBinding->FlushSkinSheets(); if (nsIPresShell* shell = OwnerDoc()->GetShell()) { OwnerDoc()->BeginUpdate(UPDATE_STYLE); shell->RecordShadowStyleChange(this); OwnerDoc()->EndUpdate(UPDATE_STYLE); } } void ShadowRoot::InsertSheet(StyleSheet* aSheet, nsIContent* aLinkingContent) { nsCOMPtr linkingElement = do_QueryInterface(aLinkingContent); MOZ_ASSERT(linkingElement, "The only styles in a ShadowRoot should come " "from