1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "nsCoreUtils.h"
8 #include "nsAttrValue.h"
9 #include "nsIAccessibleTypes.h"
11 #include "mozilla/dom/Document.h"
12 #include "nsAccUtils.h"
14 #include "nsXULElement.h"
15 #include "nsIDocShell.h"
16 #include "nsIObserverService.h"
17 #include "nsPresContext.h"
18 #include "nsIScrollableFrame.h"
19 #include "nsISelectionController.h"
20 #include "nsISimpleEnumerator.h"
21 #include "mozilla/dom/TouchEvent.h"
22 #include "mozilla/ErrorResult.h"
23 #include "mozilla/EventListenerManager.h"
24 #include "mozilla/EventStateManager.h"
25 #include "mozilla/MouseEvents.h"
26 #include "mozilla/PresShell.h"
27 #include "mozilla/TouchEvents.h"
29 #include "nsGkAtoms.h"
31 #include "nsComponentManagerUtils.h"
33 #include "XULTreeElement.h"
34 #include "nsIContentInlines.h"
35 #include "nsTreeColumns.h"
36 #include "mozilla/dom/DocumentInlines.h"
37 #include "mozilla/dom/Element.h"
38 #include "mozilla/dom/ElementInternals.h"
39 #include "mozilla/dom/HTMLLabelElement.h"
40 #include "mozilla/dom/MouseEventBinding.h"
41 #include "mozilla/dom/Selection.h"
43 using namespace mozilla
;
45 using mozilla::dom::DOMRect
;
46 using mozilla::dom::Element
;
47 using mozilla::dom::Selection
;
48 using mozilla::dom::XULTreeElement
;
50 using mozilla::a11y::nsAccUtils
;
52 ////////////////////////////////////////////////////////////////////////////////
54 ////////////////////////////////////////////////////////////////////////////////
56 bool nsCoreUtils::IsLabelWithControl(nsIContent
* aContent
) {
57 dom::HTMLLabelElement
* label
= dom::HTMLLabelElement::FromNode(aContent
);
58 if (label
&& label
->GetControl()) return true;
63 bool nsCoreUtils::HasClickListener(nsIContent
* aContent
) {
64 NS_ENSURE_TRUE(aContent
, false);
65 EventListenerManager
* listenerManager
=
66 aContent
->GetExistingListenerManager();
68 return listenerManager
&&
69 (listenerManager
->HasListenersFor(nsGkAtoms::onclick
) ||
70 listenerManager
->HasListenersFor(nsGkAtoms::onmousedown
) ||
71 listenerManager
->HasListenersFor(nsGkAtoms::onmouseup
));
74 void nsCoreUtils::DispatchClickEvent(XULTreeElement
* aTree
, int32_t aRowIndex
,
75 nsTreeColumn
* aColumn
,
76 const nsAString
& aPseudoElt
) {
77 RefPtr
<dom::Element
> tcElm
= aTree
->GetTreeBody();
80 Document
* document
= tcElm
->GetUncomposedDoc();
81 if (!document
) return;
83 RefPtr
<PresShell
> presShell
= document
->GetPresShell();
88 // Ensure row is visible.
89 aTree
->EnsureRowIsVisible(aRowIndex
);
91 // Calculate x and y coordinates.
94 aTree
->GetCoordsForCellItem(aRowIndex
, aColumn
, aPseudoElt
, rv
);
99 RefPtr
<DOMRect
> treeBodyRect
= tcElm
->GetBoundingClientRect();
100 int32_t tcX
= (int32_t)treeBodyRect
->X();
101 int32_t tcY
= (int32_t)treeBodyRect
->Y();
103 // Dispatch mouse events.
104 AutoWeakFrame tcFrame
= tcElm
->GetPrimaryFrame();
105 nsIFrame
* rootFrame
= presShell
->GetRootFrame();
108 nsCOMPtr
<nsIWidget
> rootWidget
=
109 rootFrame
->GetView()->GetNearestWidget(&offset
);
111 RefPtr
<nsPresContext
> presContext
= presShell
->GetPresContext();
113 int32_t cnvdX
= presContext
->CSSPixelsToDevPixels(tcX
+ int32_t(rect
.x
) + 1) +
114 presContext
->AppUnitsToDevPixels(offset
.x
);
115 int32_t cnvdY
= presContext
->CSSPixelsToDevPixels(tcY
+ int32_t(rect
.y
) + 1) +
116 presContext
->AppUnitsToDevPixels(offset
.y
);
118 // XUL is just desktop, so there is no real reason for senfing touch events.
119 DispatchMouseEvent(eMouseDown
, cnvdX
, cnvdY
, tcElm
, tcFrame
, presShell
,
122 DispatchMouseEvent(eMouseUp
, cnvdX
, cnvdY
, tcElm
, tcFrame
, presShell
,
126 void nsCoreUtils::DispatchMouseEvent(EventMessage aMessage
, int32_t aX
,
127 int32_t aY
, nsIContent
* aContent
,
128 nsIFrame
* aFrame
, PresShell
* aPresShell
,
129 nsIWidget
* aRootWidget
) {
130 WidgetMouseEvent
event(true, aMessage
, aRootWidget
, WidgetMouseEvent::eReal
,
131 WidgetMouseEvent::eNormal
);
133 event
.mRefPoint
= LayoutDeviceIntPoint(aX
, aY
);
135 event
.mClickCount
= 1;
136 event
.mButton
= MouseButton::ePrimary
;
137 event
.mInputSource
= dom::MouseEvent_Binding::MOZ_SOURCE_UNKNOWN
;
139 nsEventStatus status
= nsEventStatus_eIgnore
;
140 aPresShell
->HandleEventWithTarget(&event
, aFrame
, aContent
, &status
);
143 void nsCoreUtils::DispatchTouchEvent(EventMessage aMessage
, int32_t aX
,
144 int32_t aY
, nsIContent
* aContent
,
145 nsIFrame
* aFrame
, PresShell
* aPresShell
,
146 nsIWidget
* aRootWidget
) {
147 nsIDocShell
* docShell
= nullptr;
148 if (aPresShell
->GetDocument()) {
149 docShell
= aPresShell
->GetDocument()->GetDocShell();
151 if (!dom::TouchEvent::PrefEnabled(docShell
)) {
155 WidgetTouchEvent
event(true, aMessage
, aRootWidget
);
157 // XXX: Touch has an identifier of -1 to hint that it is synthesized.
158 RefPtr
<dom::Touch
> t
= new dom::Touch(-1, LayoutDeviceIntPoint(aX
, aY
),
159 LayoutDeviceIntPoint(1, 1), 0.0f
, 1.0f
);
160 t
->SetTouchTarget(aContent
);
161 event
.mTouches
.AppendElement(t
);
162 nsEventStatus status
= nsEventStatus_eIgnore
;
163 aPresShell
->HandleEventWithTarget(&event
, aFrame
, aContent
, &status
);
166 uint32_t nsCoreUtils::GetAccessKeyFor(nsIContent
* aContent
) {
167 // Accesskeys are registered by @accesskey attribute only. At first check
168 // whether it is presented on the given element to avoid the slow
169 // EventStateManager::GetRegisteredAccessKey() method.
170 if (!aContent
->IsElement() || !aContent
->AsElement()->HasAttr(
171 kNameSpaceID_None
, nsGkAtoms::accesskey
)) {
175 nsPresContext
* presContext
= aContent
->OwnerDoc()->GetPresContext();
176 if (!presContext
) return 0;
178 EventStateManager
* esm
= presContext
->EventStateManager();
181 return esm
->GetRegisteredAccessKey(aContent
->AsElement());
184 nsIContent
* nsCoreUtils::GetDOMElementFor(nsIContent
* aContent
) {
185 if (aContent
->IsElement()) return aContent
;
187 if (aContent
->IsText()) return aContent
->GetFlattenedTreeParent();
192 nsINode
* nsCoreUtils::GetDOMNodeFromDOMPoint(nsINode
* aNode
, uint32_t aOffset
) {
193 if (aNode
&& aNode
->IsElement()) {
194 uint32_t childCount
= aNode
->GetChildCount();
195 NS_ASSERTION(aOffset
<= childCount
, "Wrong offset of the DOM point!");
197 // The offset can be after last child of container node that means DOM point
198 // is placed immediately after the last child. In this case use the DOM node
199 // from the given DOM point is used as result node.
200 if (aOffset
!= childCount
) return aNode
->GetChildAt_Deprecated(aOffset
);
206 bool nsCoreUtils::IsAncestorOf(nsINode
* aPossibleAncestorNode
,
207 nsINode
* aPossibleDescendantNode
,
208 nsINode
* aRootNode
) {
209 NS_ENSURE_TRUE(aPossibleAncestorNode
&& aPossibleDescendantNode
, false);
211 nsINode
* parentNode
= aPossibleDescendantNode
;
212 while ((parentNode
= parentNode
->GetParentNode()) &&
213 parentNode
!= aRootNode
) {
214 if (parentNode
== aPossibleAncestorNode
) return true;
220 nsresult
nsCoreUtils::ScrollSubstringTo(nsIFrame
* aFrame
, nsRange
* aRange
,
221 uint32_t aScrollType
) {
222 ScrollAxis vertical
, horizontal
;
223 ConvertScrollTypeToPercents(aScrollType
, &vertical
, &horizontal
);
225 return ScrollSubstringTo(aFrame
, aRange
, vertical
, horizontal
);
228 nsresult
nsCoreUtils::ScrollSubstringTo(nsIFrame
* aFrame
, nsRange
* aRange
,
229 ScrollAxis aVertical
,
230 ScrollAxis aHorizontal
) {
231 if (!aFrame
|| !aRange
) {
232 return NS_ERROR_FAILURE
;
235 nsPresContext
* presContext
= aFrame
->PresContext();
237 nsCOMPtr
<nsISelectionController
> selCon
;
238 aFrame
->GetSelectionController(presContext
, getter_AddRefs(selCon
));
239 NS_ENSURE_TRUE(selCon
, NS_ERROR_FAILURE
);
241 RefPtr
<dom::Selection
> selection
=
242 selCon
->GetSelection(nsISelectionController::SELECTION_ACCESSIBILITY
);
244 selection
->RemoveAllRanges(IgnoreErrors());
245 selection
->AddRangeAndSelectFramesAndNotifyListeners(*aRange
, IgnoreErrors());
247 selection
->ScrollIntoView(nsISelectionController::SELECTION_ANCHOR_REGION
,
248 aVertical
, aHorizontal
,
249 Selection::SCROLL_SYNCHRONOUS
);
251 selection
->CollapseToStart(IgnoreErrors());
256 void nsCoreUtils::ScrollFrameToPoint(nsIFrame
* aScrollableFrame
,
258 const LayoutDeviceIntPoint
& aPoint
) {
259 nsIScrollableFrame
* scrollableFrame
= do_QueryFrame(aScrollableFrame
);
260 if (!scrollableFrame
) return;
262 nsPoint point
= LayoutDeviceIntPoint::ToAppUnits(
263 aPoint
, aFrame
->PresContext()->AppUnitsPerDevPixel());
264 nsRect frameRect
= aFrame
->GetScreenRectInAppUnits();
265 nsPoint deltaPoint
= point
- frameRect
.TopLeft();
267 nsPoint scrollPoint
= scrollableFrame
->GetScrollPosition();
268 scrollPoint
-= deltaPoint
;
270 scrollableFrame
->ScrollTo(scrollPoint
, ScrollMode::Instant
);
273 void nsCoreUtils::ConvertScrollTypeToPercents(uint32_t aScrollType
,
274 ScrollAxis
* aVertical
,
275 ScrollAxis
* aHorizontal
) {
276 WhereToScroll whereY
, whereX
;
277 WhenToScroll whenY
, whenX
;
278 switch (aScrollType
) {
279 case nsIAccessibleScrollType::SCROLL_TYPE_TOP_LEFT
:
280 whereY
= WhereToScroll::Start
;
281 whenY
= WhenToScroll::Always
;
282 whereX
= WhereToScroll::Start
;
283 whenX
= WhenToScroll::Always
;
285 case nsIAccessibleScrollType::SCROLL_TYPE_BOTTOM_RIGHT
:
286 whereY
= WhereToScroll::End
;
287 whenY
= WhenToScroll::Always
;
288 whereX
= WhereToScroll::End
;
289 whenX
= WhenToScroll::Always
;
291 case nsIAccessibleScrollType::SCROLL_TYPE_TOP_EDGE
:
292 whereY
= WhereToScroll::Start
;
293 whenY
= WhenToScroll::Always
;
294 whereX
= WhereToScroll::Nearest
;
295 whenX
= WhenToScroll::IfNotFullyVisible
;
297 case nsIAccessibleScrollType::SCROLL_TYPE_BOTTOM_EDGE
:
298 whereY
= WhereToScroll::End
;
299 whenY
= WhenToScroll::Always
;
300 whereX
= WhereToScroll::Nearest
;
301 whenX
= WhenToScroll::IfNotFullyVisible
;
303 case nsIAccessibleScrollType::SCROLL_TYPE_LEFT_EDGE
:
304 whereY
= WhereToScroll::Nearest
;
305 whenY
= WhenToScroll::IfNotFullyVisible
;
306 whereX
= WhereToScroll::Start
;
307 whenX
= WhenToScroll::Always
;
309 case nsIAccessibleScrollType::SCROLL_TYPE_RIGHT_EDGE
:
310 whereY
= WhereToScroll::Nearest
;
311 whenY
= WhenToScroll::IfNotFullyVisible
;
312 whereX
= WhereToScroll::End
;
313 whenX
= WhenToScroll::Always
;
316 whereY
= WhereToScroll::Center
;
317 whenY
= WhenToScroll::IfNotFullyVisible
;
318 whereX
= WhereToScroll::Center
;
319 whenX
= WhenToScroll::IfNotFullyVisible
;
321 *aVertical
= ScrollAxis(whereY
, whenY
);
322 *aHorizontal
= ScrollAxis(whereX
, whenX
);
325 already_AddRefed
<nsIDocShell
> nsCoreUtils::GetDocShellFor(nsINode
* aNode
) {
326 if (!aNode
) return nullptr;
328 nsCOMPtr
<nsIDocShell
> docShell
= aNode
->OwnerDoc()->GetDocShell();
329 return docShell
.forget();
332 bool nsCoreUtils::IsRootDocument(Document
* aDocument
) {
333 nsCOMPtr
<nsIDocShellTreeItem
> docShellTreeItem
= aDocument
->GetDocShell();
334 NS_ASSERTION(docShellTreeItem
, "No document shell for document!");
336 nsCOMPtr
<nsIDocShellTreeItem
> parentTreeItem
;
337 docShellTreeItem
->GetInProcessParent(getter_AddRefs(parentTreeItem
));
339 return !parentTreeItem
;
342 bool nsCoreUtils::IsTopLevelContentDocInProcess(Document
* aDocumentNode
) {
343 mozilla::dom::BrowsingContext
* bc
= aDocumentNode
->GetBrowsingContext();
344 return bc
->IsContent() && (
347 // Out-of-process iframe.
348 !bc
->GetParent()->IsInProcess());
351 bool nsCoreUtils::IsErrorPage(Document
* aDocument
) {
352 nsIURI
* uri
= aDocument
->GetDocumentURI();
353 if (!uri
->SchemeIs("about")) {
358 uri
->GetPathQueryRef(path
);
360 constexpr auto neterror
= "neterror"_ns
;
361 constexpr auto certerror
= "certerror"_ns
;
363 return StringBeginsWith(path
, neterror
) || StringBeginsWith(path
, certerror
);
366 PresShell
* nsCoreUtils::GetPresShellFor(nsINode
* aNode
) {
367 return aNode
->OwnerDoc()->GetPresShell();
370 bool nsCoreUtils::GetID(nsIContent
* aContent
, nsAString
& aID
) {
371 return aContent
->IsElement() &&
372 aContent
->AsElement()->GetAttr(nsGkAtoms::id
, aID
);
375 bool nsCoreUtils::GetUIntAttr(nsIContent
* aContent
, nsAtom
* aAttr
,
377 if (!aContent
->IsElement()) {
380 return GetUIntAttrValue(nsAccUtils::GetARIAAttr(aContent
->AsElement(), aAttr
),
384 bool nsCoreUtils::GetUIntAttrValue(const nsAttrValue
* aVal
, int32_t* aUInt
) {
389 aVal
->ToString(value
);
390 if (!value
.IsEmpty()) {
391 nsresult error
= NS_OK
;
392 int32_t integer
= value
.ToInteger(&error
);
393 if (NS_SUCCEEDED(error
) && integer
> 0) {
402 void nsCoreUtils::GetLanguageFor(nsIContent
* aContent
, nsIContent
* aRootContent
,
403 nsAString
& aLanguage
) {
404 aLanguage
.Truncate();
406 nsIContent
* walkUp
= aContent
;
407 while (walkUp
&& walkUp
!= aRootContent
&&
408 (!walkUp
->IsElement() ||
409 !walkUp
->AsElement()->GetAttr(nsGkAtoms::lang
, aLanguage
))) {
410 walkUp
= walkUp
->GetParent();
414 XULTreeElement
* nsCoreUtils::GetTree(nsIContent
* aContent
) {
415 // Find DOMNode's parents recursively until reach the <tree> tag
416 nsIContent
* currentContent
= aContent
;
417 while (currentContent
) {
418 if (currentContent
->NodeInfo()->Equals(nsGkAtoms::tree
, kNameSpaceID_XUL
)) {
419 return XULTreeElement::FromNode(currentContent
);
421 currentContent
= currentContent
->GetFlattenedTreeParent();
427 already_AddRefed
<nsTreeColumn
> nsCoreUtils::GetFirstSensibleColumn(
428 XULTreeElement
* aTree
, FlushType aFlushType
) {
433 RefPtr
<nsTreeColumns
> cols
= aTree
->GetColumns(aFlushType
);
438 RefPtr
<nsTreeColumn
> column
= cols
->GetFirstColumn();
439 if (column
&& IsColumnHidden(column
)) return GetNextSensibleColumn(column
);
441 return column
.forget();
444 uint32_t nsCoreUtils::GetSensibleColumnCount(XULTreeElement
* aTree
) {
450 RefPtr
<nsTreeColumns
> cols
= aTree
->GetColumns();
455 nsTreeColumn
* column
= cols
->GetFirstColumn();
458 if (!IsColumnHidden(column
)) count
++;
460 column
= column
->GetNext();
466 already_AddRefed
<nsTreeColumn
> nsCoreUtils::GetSensibleColumnAt(
467 XULTreeElement
* aTree
, uint32_t aIndex
) {
472 uint32_t idx
= aIndex
;
474 nsCOMPtr
<nsTreeColumn
> column
= GetFirstSensibleColumn(aTree
);
476 if (idx
== 0) return column
.forget();
479 column
= GetNextSensibleColumn(column
);
485 already_AddRefed
<nsTreeColumn
> nsCoreUtils::GetNextSensibleColumn(
486 nsTreeColumn
* aColumn
) {
491 RefPtr
<nsTreeColumn
> nextColumn
= aColumn
->GetNext();
493 while (nextColumn
&& IsColumnHidden(nextColumn
)) {
494 nextColumn
= nextColumn
->GetNext();
497 return nextColumn
.forget();
500 already_AddRefed
<nsTreeColumn
> nsCoreUtils::GetPreviousSensibleColumn(
501 nsTreeColumn
* aColumn
) {
506 RefPtr
<nsTreeColumn
> prevColumn
= aColumn
->GetPrevious();
508 while (prevColumn
&& IsColumnHidden(prevColumn
)) {
509 prevColumn
= prevColumn
->GetPrevious();
512 return prevColumn
.forget();
515 bool nsCoreUtils::IsColumnHidden(nsTreeColumn
* aColumn
) {
520 Element
* element
= aColumn
->Element();
521 return element
->AttrValueIs(kNameSpaceID_None
, nsGkAtoms::hidden
,
522 nsGkAtoms::_true
, eCaseMatters
);
525 void nsCoreUtils::ScrollTo(PresShell
* aPresShell
, nsIContent
* aContent
,
526 uint32_t aScrollType
) {
527 ScrollAxis vertical
, horizontal
;
528 ConvertScrollTypeToPercents(aScrollType
, &vertical
, &horizontal
);
529 aPresShell
->ScrollContentIntoView(aContent
, vertical
, horizontal
,
530 ScrollFlags::ScrollOverflowHidden
);
533 bool nsCoreUtils::IsHTMLTableHeader(nsIContent
* aContent
) {
534 return aContent
->NodeInfo()->Equals(nsGkAtoms::th
) ||
535 (aContent
->IsElement() &&
536 aContent
->AsElement()->HasAttr(nsGkAtoms::scope
));
539 bool nsCoreUtils::IsWhitespaceString(const nsAString
& aString
) {
540 nsAString::const_char_iterator iterBegin
, iterEnd
;
542 aString
.BeginReading(iterBegin
);
543 aString
.EndReading(iterEnd
);
545 while (iterBegin
!= iterEnd
&& IsWhitespace(*iterBegin
)) ++iterBegin
;
547 return iterBegin
== iterEnd
;
550 void nsCoreUtils::TrimNonBreakingSpaces(nsAString
& aString
) {
551 if (aString
.IsEmpty()) {
555 // Find the index past the last nbsp prefix character.
556 constexpr char16_t nbsp
{0xA0};
557 size_t startIndex
= 0;
558 while (aString
.CharAt(startIndex
) == nbsp
) {
562 // Find the index before the first nbsp suffix character.
563 size_t endIndex
= aString
.Length() - 1;
564 while (endIndex
> startIndex
&& aString
.CharAt(endIndex
) == nbsp
) {
567 if (startIndex
> endIndex
) {
572 // Trim the string down, removing the non-breaking space characters.
573 aString
= Substring(aString
, startIndex
, endIndex
- startIndex
+ 1);
576 bool nsCoreUtils::AccEventObserversExist() {
577 nsCOMPtr
<nsIObserverService
> obsService
= services::GetObserverService();
578 NS_ENSURE_TRUE(obsService
, false);
580 nsCOMPtr
<nsISimpleEnumerator
> observers
;
581 obsService
->EnumerateObservers(NS_ACCESSIBLE_EVENT_TOPIC
,
582 getter_AddRefs(observers
));
583 NS_ENSURE_TRUE(observers
, false);
585 bool hasObservers
= false;
586 observers
->HasMoreElements(&hasObservers
);
591 void nsCoreUtils::DispatchAccEvent(RefPtr
<nsIAccessibleEvent
> event
) {
592 nsCOMPtr
<nsIObserverService
> obsService
= services::GetObserverService();
593 NS_ENSURE_TRUE_VOID(obsService
);
595 obsService
->NotifyObservers(event
, NS_ACCESSIBLE_EVENT_TOPIC
, nullptr);
598 bool nsCoreUtils::IsDisplayContents(nsIContent
* aContent
) {
599 auto* element
= Element::FromNodeOrNull(aContent
);
600 return element
&& element
->IsDisplayContents();
603 bool nsCoreUtils::CanCreateAccessibleWithoutFrame(nsIContent
* aContent
) {
604 auto* element
= Element::FromNodeOrNull(aContent
);
608 if (!element
->HasServoData() || Servo_Element_IsDisplayNone(element
)) {
609 // Out of the flat tree or in a display: none subtree.
613 // If we aren't display: contents or option/optgroup we can't create an
614 // accessible without frame. Our select combobox code relies on the latter.
615 if (!element
->IsDisplayContents() &&
616 !element
->IsAnyOfHTMLElements(nsGkAtoms::option
, nsGkAtoms::optgroup
)) {
620 // Even if we're display: contents or optgroups, we might not be able to
621 // create an accessible if we're in a content-visibility: hidden subtree.
623 // To check that, find the closest ancestor element with a frame.
624 for (nsINode
* ancestor
= element
->GetFlattenedTreeParentNode();
625 ancestor
&& ancestor
->IsContent();
626 ancestor
= ancestor
->GetFlattenedTreeParentNode()) {
627 if (nsIFrame
* f
= ancestor
->AsContent()->GetPrimaryFrame()) {
628 if (f
->HidesContent(nsIFrame::IncludeContentVisibility::Hidden
) ||
629 f
->IsHiddenByContentVisibilityOnAnyAncestor(
630 nsIFrame::IncludeContentVisibility::Hidden
)) {
640 bool nsCoreUtils::IsDocumentVisibleConsideringInProcessAncestors(
641 const Document
* aDocument
) {
642 const Document
* parent
= aDocument
;
644 if (!parent
->IsVisible()) {
647 } while ((parent
= parent
->GetInProcessParentDocument()));
651 bool nsCoreUtils::IsDescendantOfAnyShadowIncludingAncestor(
652 nsINode
* aDescendant
, nsINode
* aStartAncestor
) {
653 const nsINode
* descRoot
= aDescendant
->SubtreeRoot();
654 nsINode
* ancRoot
= aStartAncestor
->SubtreeRoot();
656 if (ancRoot
== descRoot
) {
659 auto* shadow
= mozilla::dom::ShadowRoot::FromNode(ancRoot
);
660 if (!shadow
|| !shadow
->GetHost()) {
663 ancRoot
= shadow
->GetHost()->SubtreeRoot();
668 Element
* nsCoreUtils::GetAriaActiveDescendantElement(Element
* aElement
) {
669 if (Element
* activeDescendant
= aElement
->GetAriaActiveDescendantElement()) {
670 return activeDescendant
;
673 if (auto* element
= nsGenericHTMLElement::FromNode(aElement
)) {
674 if (auto* internals
= element
->GetInternals()) {
675 return internals
->GetAriaActiveDescendantElement();