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 #ifndef mozilla_dom_DocumentOrShadowRoot_h__
8 #define mozilla_dom_DocumentOrShadowRoot_h__
10 #include "mozilla/dom/NameSpaceConstants.h"
11 #include "mozilla/IdentifierMapEntry.h"
12 #include "mozilla/RelativeTo.h"
13 #include "nsClassHashtable.h"
14 #include "nsContentListDeclarations.h"
18 class nsCycleCollectionTraversalCallback
;
21 class nsIRadioVisitor
;
34 class DocumentOrShadowRoot
;
35 class HTMLInputElement
;
36 struct nsRadioGroupStruct
;
43 * A class meant to be shared by ShadowRoot and Document, that holds a list of
46 * TODO(emilio, bug 1418159): In the future this should hold most of the
47 * relevant style state, this should allow us to fix bug 548397.
49 class DocumentOrShadowRoot
{
56 // These should always be non-null, but can't use a reference because
57 // dereferencing `this` on initializer lists is UB, apparently, see
59 explicit DocumentOrShadowRoot(Document
*);
60 explicit DocumentOrShadowRoot(ShadowRoot
*);
62 // Unusual argument naming is because of cycle collection macros.
63 static void Traverse(DocumentOrShadowRoot
* tmp
,
64 nsCycleCollectionTraversalCallback
& cb
);
65 static void Unlink(DocumentOrShadowRoot
* tmp
);
67 nsINode
& AsNode() { return *mAsNode
; }
69 const nsINode
& AsNode() const { return *mAsNode
; }
71 StyleSheet
* SheetAt(size_t aIndex
) const {
72 return mStyleSheets
.SafeElementAt(aIndex
);
75 size_t SheetCount() const { return mStyleSheets
.Length(); }
77 size_t AdoptedSheetCount() const { return mAdoptedStyleSheets
.Length(); }
80 * Returns an index for the sheet in relative style order.
81 * If there are non-applicable sheets, then this index may
82 * not match 1:1 with the sheet's actual index in the style set.
84 * Handles sheets from both mStyleSheets and mAdoptedStyleSheets
86 int32_t StyleOrderIndexOfSheet(const StyleSheet
& aSheet
) const;
88 StyleSheetList
* StyleSheets();
90 void GetAdoptedStyleSheets(nsTArray
<RefPtr
<StyleSheet
>>&) const;
92 void RemoveStyleSheet(StyleSheet
&);
94 Element
* GetElementById(const nsAString
& aElementId
);
97 * This method returns _all_ the elements in this scope which have id
98 * aElementId, if there are any. Otherwise it returns null.
100 * This is useful for stuff like QuerySelector optimization and such.
102 inline const nsTArray
<Element
*>* GetAllElementsForId(
103 const nsAString
& aElementId
) const;
105 already_AddRefed
<nsContentList
> GetElementsByTagName(
106 const nsAString
& aTagName
) {
107 return NS_GetContentList(&AsNode(), kNameSpaceID_Unknown
, aTagName
);
110 already_AddRefed
<nsContentList
> GetElementsByTagNameNS(
111 const nsAString
& aNamespaceURI
, const nsAString
& aLocalName
);
113 already_AddRefed
<nsContentList
> GetElementsByTagNameNS(
114 const nsAString
& aNamespaceURI
, const nsAString
& aLocalName
,
115 mozilla::ErrorResult
&);
117 already_AddRefed
<nsContentList
> GetElementsByClassName(
118 const nsAString
& aClasses
);
120 ~DocumentOrShadowRoot();
122 Element
* GetPointerLockElement();
123 Element
* GetFullscreenElement();
125 Element
* ElementFromPoint(float aX
, float aY
);
126 nsINode
* NodeFromPoint(float aX
, float aY
);
128 void ElementsFromPoint(float aX
, float aY
, nsTArray
<RefPtr
<Element
>>&);
129 void NodesFromPoint(float aX
, float aY
, nsTArray
<RefPtr
<nsINode
>>&);
132 * Helper for elementFromPoint implementation that allows
133 * ignoring the scroll frame and/or avoiding layout flushes.
135 * @see nsIDOMWindowUtils::elementFromPoint
137 Element
* ElementFromPointHelper(float aX
, float aY
,
138 bool aIgnoreRootScrollFrame
,
140 ViewportType aViewportType
);
142 void NodesFromRect(float aX
, float aY
, float aTopSize
, float aRightSize
,
143 float aBottomSize
, float aLeftSize
,
144 bool aIgnoreRootScrollFrame
, bool aFlushLayout
,
145 bool aOnlyVisible
, nsTArray
<RefPtr
<nsINode
>>&);
148 * This gets fired when the element that an id refers to changes.
149 * This fires at difficult times. It is generally not safe to do anything
150 * which could modify the DOM in any way. Use
151 * nsContentUtils::AddScriptRunner.
152 * @return true to keep the callback in the callback set, false
155 typedef bool (*IDTargetObserver
)(Element
* aOldElement
, Element
* aNewelement
,
159 * Add an IDTargetObserver for a specific ID. The IDTargetObserver
160 * will be fired whenever the content associated with the ID changes
161 * in the future. If aForImage is true, mozSetImageElement can override
162 * what content is associated with the ID. In that case the IDTargetObserver
163 * will be notified at those times when the result of LookupImageElement
165 * At most one (aObserver, aData, aForImage) triple can be
166 * registered for each ID.
167 * @return the content currently associated with the ID.
169 Element
* AddIDTargetObserver(nsAtom
* aID
, IDTargetObserver aObserver
,
170 void* aData
, bool aForImage
);
173 * Remove the (aObserver, aData, aForImage) triple for a specific ID, if
176 void RemoveIDTargetObserver(nsAtom
* aID
, IDTargetObserver aObserver
,
177 void* aData
, bool aForImage
);
180 * Lookup an image element using its associated ID, which is usually provided
181 * by |-moz-element()|. Similar to GetElementById, with the difference that
182 * elements set using mozSetImageElement have higher priority.
183 * @param aId the ID associated the element we want to lookup
184 * @return the element associated with |aId|
186 Element
* LookupImageElement(const nsAString
& aElementId
);
189 * Check that aId is not empty and log a message to the console
191 * @returns true if aId looks correct, false otherwise.
193 inline bool CheckGetElementByIdArg(const nsAString
& aId
) {
195 ReportEmptyGetElementByIdArg();
201 void ReportEmptyGetElementByIdArg();
205 void GetAnimations(nsTArray
<RefPtr
<Animation
>>& aAnimations
);
207 // nsIRadioGroupContainer
208 NS_IMETHOD
WalkRadioGroup(const nsAString
& aName
, nsIRadioVisitor
* aVisitor
,
210 void SetCurrentRadioButton(const nsAString
& aName
, HTMLInputElement
* aRadio
);
211 HTMLInputElement
* GetCurrentRadioButton(const nsAString
& aName
);
212 nsresult
GetNextRadioButton(const nsAString
& aName
, const bool aPrevious
,
213 HTMLInputElement
* aFocusedRadio
,
214 HTMLInputElement
** aRadioOut
);
215 void AddToRadioGroup(const nsAString
& aName
, HTMLInputElement
* aRadio
);
216 void RemoveFromRadioGroup(const nsAString
& aName
, HTMLInputElement
* aRadio
);
217 uint32_t GetRequiredRadioCount(const nsAString
& aName
) const;
218 void RadioRequiredWillChange(const nsAString
& aName
, bool aRequiredAdded
);
219 bool GetValueMissingState(const nsAString
& aName
) const;
220 void SetValueMissingState(const nsAString
& aName
, bool aValue
);
223 nsRadioGroupStruct
* GetRadioGroup(const nsAString
& aName
) const;
224 nsRadioGroupStruct
* GetOrCreateRadioGroup(const nsAString
& aName
);
226 nsIContent
* Retarget(nsIContent
* aContent
) const;
228 void SetAdoptedStyleSheets(
229 const Sequence
<OwningNonNull
<StyleSheet
>>& aAdoptedStyleSheets
,
232 // This is needed because ServoStyleSet / ServoAuthorData don't deal with
233 // duplicate stylesheets (and it's unclear we'd want to support that as it'd
234 // be a bunch of duplicate work), while adopted stylesheets do need to deal
236 template <typename Callback
>
237 void EnumerateUniqueAdoptedStyleSheetsBackToFront(Callback aCallback
) {
238 StyleSheetSet
set(mAdoptedStyleSheets
.Length());
239 for (StyleSheet
* sheet
: Reversed(mAdoptedStyleSheets
)) {
240 if (MOZ_UNLIKELY(!set
.EnsureInserted(sheet
))) {
248 // Cycle collection helper functions
249 void TraverseSheetRefInStylesIfApplicable(
250 StyleSheet
&, nsCycleCollectionTraversalCallback
&);
251 void TraverseStyleSheets(nsTArray
<RefPtr
<StyleSheet
>>&, const char*,
252 nsCycleCollectionTraversalCallback
&);
253 void UnlinkStyleSheets(nsTArray
<RefPtr
<StyleSheet
>>&);
255 using StyleSheetSet
= nsTHashtable
<nsPtrHashKey
<const StyleSheet
>>;
256 void RemoveSheetFromStylesIfApplicable(StyleSheet
&);
257 void ClearAdoptedStyleSheets();
260 * Clone's the argument's adopted style sheets into this.
261 * This should only be used when cloning a static document for printing.
263 void CloneAdoptedSheetsFrom(const DocumentOrShadowRoot
&);
265 void InsertSheetAt(size_t aIndex
, StyleSheet
& aSheet
);
267 void AddSizeOfExcludingThis(nsWindowSizes
&) const;
268 void AddSizeOfOwnedSheetArrayExcludingThis(
269 nsWindowSizes
&, const nsTArray
<RefPtr
<StyleSheet
>>&) const;
272 * If focused element's subtree root is this document or shadow root, return
273 * focused element, otherwise, get the shadow host recursively until the
274 * shadow host's subtree root is this document or shadow root.
276 Element
* GetRetargetedFocusedElement();
278 nsTArray
<RefPtr
<StyleSheet
>> mStyleSheets
;
279 RefPtr
<StyleSheetList
> mDOMStyleSheets
;
282 * Style sheets that are adopted by assinging to the `adoptedStyleSheets`
283 * WebIDL atribute. These can only be constructed stylesheets.
285 nsTArray
<RefPtr
<StyleSheet
>> mAdoptedStyleSheets
;
288 * mIdentifierMap works as follows for IDs:
289 * 1) Attribute changes affect the table immediately (removing and adding
290 * entries as needed).
291 * 2) Removals from the DOM affect the table immediately
292 * 3) Additions to the DOM always update existing entries for names, and add
295 nsTHashtable
<IdentifierMapEntry
> mIdentifierMap
;
297 nsClassHashtable
<nsStringHashKey
, nsRadioGroupStruct
> mRadioGroups
;
299 // Always non-null, see comment in the constructor as to why a pointer instead
305 inline const nsTArray
<Element
*>* DocumentOrShadowRoot::GetAllElementsForId(
306 const nsAString
& aElementId
) const {
307 if (aElementId
.IsEmpty()) {
311 IdentifierMapEntry
* entry
= mIdentifierMap
.GetEntry(aElementId
);
312 return entry
? &entry
->GetIdElements() : nullptr;
317 } // namespace mozilla