ShadowRoot.h (11849B)
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 #ifndef mozilla_dom_shadowroot_h__ 8 #define mozilla_dom_shadowroot_h__ 9 10 #include "mozilla/BindgenUniquePtr.h" 11 #include "mozilla/DOMEventTargetHelper.h" 12 #include "mozilla/ServoBindingTypes.h" 13 #include "mozilla/dom/DocumentBinding.h" 14 #include "mozilla/dom/DocumentFragment.h" 15 #include "mozilla/dom/DocumentOrShadowRoot.h" 16 #include "mozilla/dom/NameSpaceConstants.h" 17 #include "mozilla/dom/ShadowRootBinding.h" 18 #include "nsCOMPtr.h" 19 #include "nsCycleCollectionParticipant.h" 20 #include "nsStubMutationObserver.h" 21 #include "nsTHashtable.h" 22 23 class nsAtom; 24 class nsIContent; 25 class nsIPrincipal; 26 27 namespace mozilla { 28 29 struct StyleAuthorStyles; 30 struct StyleRuleChange; 31 32 class EventChainPreVisitor; 33 class ServoStyleRuleMap; 34 35 enum class StyleRuleChangeKind : uint32_t; 36 enum class BuiltInStyleSheet : uint8_t; 37 38 namespace css { 39 class Rule; 40 } 41 42 namespace dom { 43 44 class CSSImportRule; 45 class Element; 46 class HTMLInputElement; 47 class OwningTrustedHTMLOrNullIsEmptyString; 48 class TrustedHTMLOrString; 49 class TrustedHTMLOrNullIsEmptyString; 50 51 class ShadowRoot final : public DocumentFragment, public DocumentOrShadowRoot { 52 friend class DocumentOrShadowRoot; 53 54 using Declarative = Element::ShadowRootDeclarative; 55 using IsClonable = Element::ShadowRootClonable; 56 using IsSerializable = Element::ShadowRootSerializable; 57 58 public: 59 NS_IMPL_FROMNODE_HELPER(ShadowRoot, IsShadowRoot()); 60 61 NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(ShadowRoot, DocumentFragment) 62 NS_DECL_ISUPPORTS_INHERITED 63 64 ShadowRoot(Element* aElement, ShadowRootMode aMode, 65 Element::DelegatesFocus aDelegatesFocus, 66 SlotAssignmentMode aSlotAssignment, IsClonable aClonable, 67 IsSerializable aIsSerializable, Declarative aDeclarative, 68 already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo); 69 70 void AddSizeOfExcludingThis(nsWindowSizes&, size_t* aNodeSize) const final; 71 72 // Try to reassign an element or text to a slot. 73 void MaybeReassignContent(nsIContent& aElementOrText); 74 // Called when an element is inserted as a direct child of our host. Tries to 75 // slot the child in one of our slots. 76 void MaybeSlotHostChild(nsIContent&); 77 // Called when a direct child of our host is removed. Tries to un-slot the 78 // child from the currently-assigned slot, if any. 79 void MaybeUnslotHostChild(nsIContent&); 80 81 // Shadow DOM v1 82 Element* Host() const { 83 MOZ_ASSERT(GetHost(), 84 "ShadowRoot always has a host, how did we create " 85 "this ShadowRoot?"); 86 return GetHost(); 87 } 88 89 ShadowRootMode Mode() const { return mMode; } 90 bool DelegatesFocus() const { 91 return mDelegatesFocus == Element::DelegatesFocus::Yes; 92 } 93 SlotAssignmentMode SlotAssignment() const { return mSlotAssignment; } 94 bool Clonable() const { return mIsClonable == IsClonable::Yes; } 95 bool IsClosed() const { return mMode == ShadowRootMode::Closed; } 96 bool Serializable() const { return mIsSerializable == IsSerializable::Yes; } 97 98 void RemoveSheetFromStyles(StyleSheet&); 99 void RuleAdded(StyleSheet&, css::Rule&); 100 void RuleRemoved(StyleSheet&, css::Rule&); 101 void RuleChanged(StyleSheet&, css::Rule*, const StyleRuleChange&); 102 void ImportRuleLoaded(StyleSheet&); 103 void SheetCloned(StyleSheet&); 104 void StyleSheetApplicableStateChanged(StyleSheet&); 105 106 // Adds a built-in author style-sheet to the shadow tree. 107 void AppendBuiltInStyleSheet(BuiltInStyleSheet); 108 109 /** 110 * Clones internal state, for example stylesheets, of aOther to 'this'. 111 */ 112 void CloneInternalDataFrom(ShadowRoot* aOther); 113 void InsertSheetAt(size_t aIndex, StyleSheet&); 114 115 // Calls UnbindFromTree for each of our kids, and also flags us as no longer 116 // being connected. 117 void Unbind(); 118 119 // Only intended for UA widgets / special shadow roots, or for handling 120 // failure cases when adopting (see BlastSubtreeToPieces). 121 // 122 // Forgets our shadow host and unbinds all our kids. 123 void Unattach(); 124 125 // Calls BindToTree on each of our kids, and also maybe flags us as being 126 // connected. 127 nsresult Bind(); 128 129 /** 130 * Explicitly invalidates the style and layout of the flattened-tree subtree 131 * rooted at the element. 132 * 133 * You need to use this whenever the flat tree is going to be shuffled in a 134 * way that layout doesn't understand via the usual ContentInserted / 135 * ContentAppended / ContentRemoved notifications. For example, if removing an 136 * element will cause a change in the flat tree such that other element will 137 * start showing up (like fallback content), this method needs to be called on 138 * an ancestor of that element. 139 * 140 * It is important that this runs _before_ actually shuffling the flat tree 141 * around, so that layout knows the actual tree that it needs to invalidate. 142 */ 143 void InvalidateStyleAndLayoutOnSubtree(Element*); 144 145 private: 146 void InsertSheetIntoAuthorData(size_t aIndex, StyleSheet&, 147 const nsTArray<RefPtr<StyleSheet>>&); 148 149 void AppendStyleSheet(StyleSheet& aSheet) { 150 InsertSheetAt(SheetCount(), aSheet); 151 } 152 153 /** 154 * Represents the insertion point in a slot for a given node. 155 */ 156 struct SlotInsertionPoint { 157 HTMLSlotElement* mSlot = nullptr; 158 Maybe<uint32_t> mIndex; 159 160 SlotInsertionPoint() = default; 161 SlotInsertionPoint(HTMLSlotElement* aSlot, const Maybe<uint32_t>& aIndex) 162 : mSlot(aSlot), mIndex(aIndex) {} 163 }; 164 165 /** 166 * Return the assignment corresponding to the content node at this particular 167 * point in time. 168 * 169 * It's the caller's responsibility to actually call InsertAssignedNode / 170 * AppendAssignedNode in the slot as needed. 171 */ 172 SlotInsertionPoint SlotInsertionPointFor(nsIContent&); 173 174 /** 175 * Returns the effective slot name for a given slottable. In most cases, this 176 * is just the value of the slot attribute, if any, or the empty string, but 177 * this also deals with the <details> shadow tree specially. 178 */ 179 void GetSlotNameFor(const nsIContent&, nsAString&) const; 180 181 /** 182 * Re-assign the current main summary if it has changed. 183 * 184 * Must be called only if mIsDetailsShadowTree is true. 185 */ 186 enum class SummaryChangeReason { Deletion, Insertion }; 187 void MaybeReassignMainSummary(SummaryChangeReason); 188 189 public: 190 void AddSlot(HTMLSlotElement* aSlot); 191 void RemoveSlot(HTMLSlotElement* aSlot); 192 bool HasSlots() const { return !mSlotMap.IsEmpty(); }; 193 HTMLSlotElement* GetDefaultSlot() const { 194 SlotArray* list = mSlotMap.Get(u""_ns); 195 return list ? (*list).AsSpan()[0] : nullptr; 196 } 197 198 void PartAdded(const Element&); 199 void PartRemoved(const Element&); 200 201 IMPL_EVENT_HANDLER(slotchange); 202 203 const nsTArray<const Element*>& Parts() const { return mParts; } 204 205 const StyleAuthorStyles* GetServoStyles() const { return mServoStyles.get(); } 206 207 StyleAuthorStyles* GetServoStyles() { return mServoStyles.get(); } 208 209 mozilla::ServoStyleRuleMap& ServoStyleRuleMap(); 210 211 JSObject* WrapNode(JSContext*, JS::Handle<JSObject*> aGivenProto) final; 212 213 void NodeInfoChanged(Document* aOldDoc) override; 214 215 void AddToIdTable(Element* aElement, nsAtom* aId); 216 void RemoveFromIdTable(Element* aElement, nsAtom* aId); 217 218 // WebIDL methods. 219 using mozilla::dom::DocumentOrShadowRoot::GetElementById; 220 221 Element* GetActiveElement(); 222 223 /** 224 * These methods allow UA Widget to insert DOM elements into the Shadow ROM 225 * without putting their DOM reflectors to content scope first. 226 * The inserted DOM will have their reflectors in the UA Widget scope. 227 */ 228 nsINode* ImportNodeAndAppendChildAt(nsINode& aParentNode, nsINode& aNode, 229 bool aDeep, mozilla::ErrorResult& rv); 230 231 nsINode* CreateElementAndAppendChildAt(nsINode& aParentNode, 232 const nsAString& aTagName, 233 mozilla::ErrorResult& rv); 234 235 bool IsUAWidget() const { return HasBeenInUAWidget(); } 236 237 void SetIsUAWidget() { 238 MOZ_ASSERT(!HasChildren()); 239 SetIsNativeAnonymousRoot(); 240 SetFlags(NODE_HAS_BEEN_IN_UA_WIDGET); 241 } 242 243 bool IsAvailableToElementInternals() const { 244 return mIsAvailableToElementInternals; 245 } 246 247 void SetAvailableToElementInternals() { 248 mIsAvailableToElementInternals = true; 249 } 250 251 void GetEventTargetParent(EventChainPreVisitor& aVisitor) override; 252 253 bool IsDeclarative() const { return mIsDeclarative == Declarative::Yes; } 254 void SetIsDeclarative(Declarative aIsDeclarative) { 255 mIsDeclarative = aIsDeclarative; 256 } 257 void SetIsDeclarative(bool aIsDeclarative) { 258 mIsDeclarative = aIsDeclarative ? Declarative::Yes : Declarative::No; 259 } 260 261 void SetHTML(const nsAString& aInnerHTML, const SetHTMLOptions& aOptions, 262 ErrorResult& aError); 263 264 MOZ_CAN_RUN_SCRIPT 265 void SetHTMLUnsafe(const TrustedHTMLOrString& aHTML, 266 const SetHTMLUnsafeOptions& aOptions, 267 nsIPrincipal* aSubjectPrincipal, ErrorResult& aError); 268 269 // @param aInnerHTML will always be of type `NullIsEmptyString`. 270 void GetInnerHTML(OwningTrustedHTMLOrNullIsEmptyString& aInnerHTML); 271 272 MOZ_CAN_RUN_SCRIPT void SetInnerHTML( 273 const TrustedHTMLOrNullIsEmptyString& aInnerHTML, 274 nsIPrincipal* aSubjectPrincipal, ErrorResult& aError); 275 276 void GetHTML(const GetHTMLOptions& aOptions, nsAString& aResult); 277 278 void GetReferenceTarget(nsAString& aResult) const { 279 mReferenceTarget->ToString(aResult); 280 } 281 nsAtom* ReferenceTarget() const { return mReferenceTarget; } 282 void SetReferenceTarget(const nsAString& aValue) { 283 SetReferenceTarget(NS_Atomize(aValue)); 284 } 285 void SetReferenceTarget(RefPtr<nsAtom> aTarget); 286 Element* GetReferenceTargetElement() const { 287 return mReferenceTarget->IsEmpty() ? nullptr 288 : GetElementById(mReferenceTarget); 289 } 290 291 protected: 292 // FIXME(emilio): This will need to become more fine-grained. 293 void ApplicableRulesChanged(); 294 295 virtual ~ShadowRoot(); 296 297 // Make sure that the first field is pointer-aligned so it doesn't get packed 298 // in the base class' padding, since otherwise rust-bindgen can't generate 299 // correct bindings for it, see 300 // https://github.com/rust-lang/rust-bindgen/issues/380 301 302 // The computed data from the style sheets. 303 BindgenUniquePtr<StyleAuthorStyles> mServoStyles; 304 UniquePtr<mozilla::ServoStyleRuleMap> mStyleRuleMap; 305 306 using SlotArray = TreeOrderedArray<HTMLSlotElement*>; 307 // Map from name of slot to an array of all slots in the shadow DOM with with 308 // the given name. The slots are stored as a weak pointer because the elements 309 // are in the shadow tree and should be kept alive by its parent. 310 nsClassHashtable<nsStringHashKey, SlotArray> mSlotMap; 311 312 // Unordered array of all elements that have a part attribute in this shadow 313 // tree. 314 nsTArray<const Element*> mParts; 315 316 const ShadowRootMode mMode; 317 318 Element::DelegatesFocus mDelegatesFocus; 319 320 const SlotAssignmentMode mSlotAssignment; 321 322 // Whether this is the <details> internal shadow tree. 323 bool mIsDetailsShadowTree : 1; 324 325 // https://dom.spec.whatwg.org/#shadowroot-available-to-element-internals 326 bool mIsAvailableToElementInternals : 1; 327 328 // https://dom.spec.whatwg.org/#shadowroot-declarative 329 Declarative mIsDeclarative; 330 331 // https://dom.spec.whatwg.org/#shadowroot-clonable 332 const IsClonable mIsClonable; 333 334 // https://dom.spec.whatwg.org/#shadowroot-serializable 335 const IsSerializable mIsSerializable; 336 337 RefPtr<nsAtom> mReferenceTarget; 338 339 nsresult Clone(dom::NodeInfo*, nsINode** aResult) const override; 340 }; 341 342 } // namespace dom 343 } // namespace mozilla 344 345 #endif // mozilla_dom_shadowroot_h__