michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "mozilla/Preferences.h" michael@0: #include "mozilla/dom/ShadowRoot.h" michael@0: #include "mozilla/dom/ShadowRootBinding.h" michael@0: #include "mozilla/dom/DocumentFragment.h" michael@0: #include "ChildIterator.h" michael@0: #include "nsContentUtils.h" michael@0: #include "nsDOMClassInfoID.h" michael@0: #include "nsIDOMHTMLElement.h" michael@0: #include "nsIStyleSheetLinkingElement.h" michael@0: #include "mozilla/dom/Element.h" michael@0: #include "mozilla/dom/HTMLContentElement.h" michael@0: #include "mozilla/dom/HTMLShadowElement.h" michael@0: #include "nsXBLPrototypeBinding.h" michael@0: michael@0: using namespace mozilla; michael@0: using namespace mozilla::dom; michael@0: michael@0: static PLDHashOperator michael@0: IdentifierMapEntryTraverse(nsIdentifierMapEntry *aEntry, void *aArg) michael@0: { michael@0: nsCycleCollectionTraversalCallback *cb = michael@0: static_cast(aArg); michael@0: aEntry->Traverse(cb); michael@0: return PL_DHASH_NEXT; michael@0: } michael@0: michael@0: NS_IMPL_CYCLE_COLLECTION_CLASS(ShadowRoot) michael@0: michael@0: NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(ShadowRoot, michael@0: DocumentFragment) michael@0: NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPoolHost) michael@0: NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mStyleSheetList) michael@0: NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOlderShadow) michael@0: NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mYoungerShadow) michael@0: NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAssociatedBinding) michael@0: tmp->mIdentifierMap.EnumerateEntries(IdentifierMapEntryTraverse, &cb); michael@0: NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END michael@0: michael@0: NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(ShadowRoot, michael@0: DocumentFragment) michael@0: if (tmp->mPoolHost) { michael@0: tmp->mPoolHost->RemoveMutationObserver(tmp); michael@0: } michael@0: NS_IMPL_CYCLE_COLLECTION_UNLINK(mPoolHost) michael@0: NS_IMPL_CYCLE_COLLECTION_UNLINK(mStyleSheetList) michael@0: NS_IMPL_CYCLE_COLLECTION_UNLINK(mOlderShadow) michael@0: NS_IMPL_CYCLE_COLLECTION_UNLINK(mYoungerShadow) michael@0: NS_IMPL_CYCLE_COLLECTION_UNLINK(mAssociatedBinding) michael@0: tmp->mIdentifierMap.Clear(); michael@0: NS_IMPL_CYCLE_COLLECTION_UNLINK_END michael@0: michael@0: DOMCI_DATA(ShadowRoot, ShadowRoot) michael@0: michael@0: NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(ShadowRoot) michael@0: NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIContent) michael@0: NS_INTERFACE_MAP_ENTRY(nsIMutationObserver) michael@0: NS_INTERFACE_MAP_END_INHERITING(DocumentFragment) michael@0: michael@0: NS_IMPL_ADDREF_INHERITED(ShadowRoot, DocumentFragment) michael@0: NS_IMPL_RELEASE_INHERITED(ShadowRoot, DocumentFragment) michael@0: michael@0: ShadowRoot::ShadowRoot(nsIContent* aContent, michael@0: already_AddRefed&& aNodeInfo, michael@0: nsXBLPrototypeBinding* aProtoBinding) michael@0: : DocumentFragment(aNodeInfo), mPoolHost(aContent), michael@0: mProtoBinding(aProtoBinding), mShadowElement(nullptr), michael@0: mInsertionPointChanged(false) michael@0: { michael@0: SetHost(aContent); michael@0: SetFlags(NODE_IS_IN_SHADOW_TREE); michael@0: // ShadowRoot isn't really in the document but it behaves like it is. michael@0: SetInDocument(); michael@0: DOMSlots()->mBindingParent = aContent; michael@0: DOMSlots()->mContainingShadow = this; michael@0: michael@0: // Add the ShadowRoot as a mutation observer on the host to watch michael@0: // for mutations because the insertion points in this ShadowRoot michael@0: // may need to be updated when the host children are modified. michael@0: mPoolHost->AddMutationObserver(this); michael@0: } michael@0: michael@0: ShadowRoot::~ShadowRoot() michael@0: { michael@0: if (mPoolHost) { michael@0: // mPoolHost may have been unlinked or a new ShadowRoot may have been michael@0: // creating, making this one obsolete. michael@0: mPoolHost->RemoveMutationObserver(this); michael@0: } michael@0: michael@0: ClearInDocument(); michael@0: SetHost(nullptr); michael@0: } michael@0: michael@0: JSObject* michael@0: ShadowRoot::WrapObject(JSContext* aCx) michael@0: { michael@0: return mozilla::dom::ShadowRootBinding::Wrap(aCx, this); michael@0: } michael@0: michael@0: ShadowRoot* michael@0: ShadowRoot::FromNode(nsINode* aNode) michael@0: { michael@0: if (aNode->HasFlag(NODE_IS_IN_SHADOW_TREE) && !aNode->GetParentNode()) { michael@0: MOZ_ASSERT(aNode->NodeType() == nsIDOMNode::DOCUMENT_FRAGMENT_NODE, michael@0: "ShadowRoot is a document fragment."); michael@0: return static_cast(aNode); michael@0: } michael@0: michael@0: return nullptr; michael@0: } michael@0: michael@0: void michael@0: ShadowRoot::Restyle() michael@0: { michael@0: mProtoBinding->FlushSkinSheets(); michael@0: michael@0: nsIPresShell* shell = OwnerDoc()->GetShell(); michael@0: if (shell) { michael@0: OwnerDoc()->BeginUpdate(UPDATE_STYLE); michael@0: shell->RestyleShadowRoot(this); michael@0: OwnerDoc()->EndUpdate(UPDATE_STYLE); michael@0: } michael@0: } michael@0: michael@0: void michael@0: ShadowRoot::InsertSheet(nsCSSStyleSheet* aSheet, michael@0: nsIContent* aLinkingContent) michael@0: { michael@0: nsCOMPtr michael@0: linkingElement = do_QueryInterface(aLinkingContent); michael@0: MOZ_ASSERT(linkingElement, "The only styles in a ShadowRoot should come " michael@0: "from