2007-03-27 16:17:11 +04:00
|
|
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
2012-05-21 15:12:37 +04:00
|
|
|
/* 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/. */
|
2007-03-27 16:17:11 +04:00
|
|
|
|
2008-10-16 05:52:58 +04:00
|
|
|
#include "nsCoreUtils.h"
|
2007-07-05 20:02:55 +04:00
|
|
|
|
2007-08-24 08:54:45 +04:00
|
|
|
#include "nsIAccessibleTypes.h"
|
2007-07-05 20:02:55 +04:00
|
|
|
|
2019-01-02 16:05:23 +03:00
|
|
|
#include "mozilla/dom/Document.h"
|
2012-01-10 18:19:54 +04:00
|
|
|
#include "nsRange.h"
|
2017-02-02 18:32:58 +03:00
|
|
|
#include "nsXULElement.h"
|
2008-10-17 14:10:43 +04:00
|
|
|
#include "nsIDocShell.h"
|
2016-01-21 04:52:43 +03:00
|
|
|
#include "nsIObserverService.h"
|
2007-08-29 10:52:46 +04:00
|
|
|
#include "nsPresContext.h"
|
2007-09-25 09:48:51 +04:00
|
|
|
#include "nsIScrollableFrame.h"
|
2007-08-24 08:54:45 +04:00
|
|
|
#include "nsISelectionController.h"
|
2016-01-21 04:52:43 +03:00
|
|
|
#include "nsISimpleEnumerator.h"
|
2014-02-28 18:58:42 +04:00
|
|
|
#include "mozilla/dom/TouchEvent.h"
|
2017-02-02 18:32:58 +03:00
|
|
|
#include "mozilla/ErrorResult.h"
|
2014-03-17 10:56:53 +04:00
|
|
|
#include "mozilla/EventListenerManager.h"
|
2014-04-01 08:09:23 +04:00
|
|
|
#include "mozilla/EventStateManager.h"
|
2013-09-25 15:21:18 +04:00
|
|
|
#include "mozilla/MouseEvents.h"
|
2019-03-29 18:12:47 +03:00
|
|
|
#include "mozilla/PresShell.h"
|
2013-09-25 15:21:16 +04:00
|
|
|
#include "mozilla/TouchEvents.h"
|
2013-01-03 17:23:11 +04:00
|
|
|
#include "nsView.h"
|
2012-10-29 08:33:51 +04:00
|
|
|
#include "nsGkAtoms.h"
|
2007-08-24 08:54:45 +04:00
|
|
|
|
|
|
|
#include "nsComponentManagerUtils.h"
|
|
|
|
|
2018-12-04 19:25:30 +03:00
|
|
|
#include "XULTreeElement.h"
|
2021-08-22 13:21:55 +03:00
|
|
|
#include "nsIContentInlines.h"
|
2018-06-05 20:30:17 +03:00
|
|
|
#include "nsTreeColumns.h"
|
2021-08-22 13:21:55 +03:00
|
|
|
#include "mozilla/dom/DocumentInlines.h"
|
2014-01-21 01:52:04 +04:00
|
|
|
#include "mozilla/dom/Element.h"
|
2016-01-14 23:37:15 +03:00
|
|
|
#include "mozilla/dom/HTMLLabelElement.h"
|
2018-03-20 07:16:06 +03:00
|
|
|
#include "mozilla/dom/MouseEventBinding.h"
|
2018-03-27 07:35:22 +03:00
|
|
|
#include "mozilla/dom/Selection.h"
|
2012-08-01 22:31:10 +04:00
|
|
|
|
2013-08-02 11:05:16 +04:00
|
|
|
using namespace mozilla;
|
|
|
|
|
2020-05-01 07:28:35 +03:00
|
|
|
using mozilla::dom::DOMRect;
|
|
|
|
using mozilla::dom::Element;
|
|
|
|
using mozilla::dom::Selection;
|
|
|
|
using mozilla::dom::XULTreeElement;
|
|
|
|
|
2010-04-27 10:52:03 +04:00
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// nsCoreUtils
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
2016-01-14 23:37:15 +03:00
|
|
|
bool nsCoreUtils::IsLabelWithControl(nsIContent* aContent) {
|
2018-03-22 00:39:04 +03:00
|
|
|
dom::HTMLLabelElement* label = dom::HTMLLabelElement::FromNode(aContent);
|
2016-01-14 23:37:15 +03:00
|
|
|
if (label && label->GetControl()) return true;
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2010-02-03 18:00:25 +03:00
|
|
|
bool nsCoreUtils::HasClickListener(nsIContent* aContent) {
|
2011-10-17 18:59:28 +04:00
|
|
|
NS_ENSURE_TRUE(aContent, false);
|
2014-03-17 10:56:53 +04:00
|
|
|
EventListenerManager* listenerManager =
|
2013-10-23 03:32:04 +04:00
|
|
|
aContent->GetExistingListenerManager();
|
2007-05-09 01:44:04 +04:00
|
|
|
|
2010-02-03 18:00:25 +03:00
|
|
|
return listenerManager &&
|
2012-10-29 08:33:51 +04:00
|
|
|
(listenerManager->HasListenersFor(nsGkAtoms::onclick) ||
|
|
|
|
listenerManager->HasListenersFor(nsGkAtoms::onmousedown) ||
|
|
|
|
listenerManager->HasListenersFor(nsGkAtoms::onmouseup));
|
2007-05-09 01:44:04 +04:00
|
|
|
}
|
|
|
|
|
2018-12-04 19:25:30 +03:00
|
|
|
void nsCoreUtils::DispatchClickEvent(XULTreeElement* aTree, int32_t aRowIndex,
|
2018-06-06 06:01:36 +03:00
|
|
|
nsTreeColumn* aColumn,
|
2014-10-15 00:15:21 +04:00
|
|
|
const nsAString& aPseudoElt) {
|
2018-12-04 19:25:41 +03:00
|
|
|
RefPtr<dom::Element> tcElm = aTree->GetTreeBody();
|
2009-08-20 10:45:19 +04:00
|
|
|
if (!tcElm) return;
|
|
|
|
|
2019-01-02 16:05:23 +03:00
|
|
|
Document* document = tcElm->GetUncomposedDoc();
|
2009-08-20 10:45:19 +04:00
|
|
|
if (!document) return;
|
|
|
|
|
2019-03-29 18:12:47 +03:00
|
|
|
RefPtr<PresShell> presShell = document->GetPresShell();
|
|
|
|
if (!presShell) {
|
|
|
|
return;
|
|
|
|
}
|
2009-08-20 10:45:19 +04:00
|
|
|
|
|
|
|
// Ensure row is visible.
|
2018-12-04 19:25:30 +03:00
|
|
|
aTree->EnsureRowIsVisible(aRowIndex);
|
2009-08-20 10:45:19 +04:00
|
|
|
|
|
|
|
// Calculate x and y coordinates.
|
2018-12-04 19:25:41 +03:00
|
|
|
nsresult rv;
|
|
|
|
nsIntRect rect =
|
|
|
|
aTree->GetCoordsForCellItem(aRowIndex, aColumn, aPseudoElt, rv);
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
return;
|
|
|
|
}
|
2009-08-20 10:45:19 +04:00
|
|
|
|
2019-03-01 20:26:37 +03:00
|
|
|
RefPtr<DOMRect> treeBodyRect = tcElm->GetBoundingClientRect();
|
|
|
|
int32_t tcX = (int32_t)treeBodyRect->X();
|
|
|
|
int32_t tcY = (int32_t)treeBodyRect->Y();
|
2009-08-20 10:45:19 +04:00
|
|
|
|
|
|
|
// Dispatch mouse events.
|
2018-04-27 06:36:30 +03:00
|
|
|
AutoWeakFrame tcFrame = tcElm->GetPrimaryFrame();
|
2009-08-20 10:45:19 +04:00
|
|
|
nsIFrame* rootFrame = presShell->GetRootFrame();
|
|
|
|
|
|
|
|
nsPoint offset;
|
2019-04-13 15:13:13 +03:00
|
|
|
nsCOMPtr<nsIWidget> rootWidget =
|
|
|
|
rootFrame->GetView()->GetNearestWidget(&offset);
|
2009-08-20 10:45:19 +04:00
|
|
|
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<nsPresContext> presContext = presShell->GetPresContext();
|
2009-08-20 10:45:19 +04:00
|
|
|
|
2018-12-04 19:25:41 +03:00
|
|
|
int32_t cnvdX = presContext->CSSPixelsToDevPixels(tcX + int32_t(rect.x) + 1) +
|
2009-08-20 10:45:19 +04:00
|
|
|
presContext->AppUnitsToDevPixels(offset.x);
|
2018-12-04 19:25:41 +03:00
|
|
|
int32_t cnvdY = presContext->CSSPixelsToDevPixels(tcY + int32_t(rect.y) + 1) +
|
2009-08-20 10:45:19 +04:00
|
|
|
presContext->AppUnitsToDevPixels(offset.y);
|
|
|
|
|
2013-07-25 19:59:08 +04:00
|
|
|
// XUL is just desktop, so there is no real reason for senfing touch events.
|
2015-08-29 02:58:30 +03:00
|
|
|
DispatchMouseEvent(eMouseDown, cnvdX, cnvdY, tcElm, tcFrame, presShell,
|
2018-04-27 06:36:30 +03:00
|
|
|
rootWidget);
|
2009-08-20 10:45:19 +04:00
|
|
|
|
2015-08-29 02:58:30 +03:00
|
|
|
DispatchMouseEvent(eMouseUp, cnvdX, cnvdY, tcElm, tcFrame, presShell,
|
2018-04-27 06:36:30 +03:00
|
|
|
rootWidget);
|
2009-08-20 10:45:19 +04:00
|
|
|
}
|
|
|
|
|
2015-08-26 15:56:59 +03:00
|
|
|
void nsCoreUtils::DispatchMouseEvent(EventMessage aMessage, int32_t aX,
|
2009-08-20 10:45:19 +04:00
|
|
|
int32_t aY, nsIContent* aContent,
|
2019-04-13 15:13:15 +03:00
|
|
|
nsIFrame* aFrame, PresShell* aPresShell,
|
2009-08-20 10:45:19 +04:00
|
|
|
nsIWidget* aRootWidget) {
|
2015-08-26 15:56:59 +03:00
|
|
|
WidgetMouseEvent event(true, aMessage, aRootWidget, WidgetMouseEvent::eReal,
|
2013-10-02 10:38:27 +04:00
|
|
|
WidgetMouseEvent::eNormal);
|
2008-08-06 16:16:54 +04:00
|
|
|
|
2016-04-18 17:09:02 +03:00
|
|
|
event.mRefPoint = LayoutDeviceIntPoint(aX, aY);
|
2009-08-20 10:45:19 +04:00
|
|
|
|
2016-05-10 17:29:14 +03:00
|
|
|
event.mClickCount = 1;
|
2020-06-19 21:02:41 +03:00
|
|
|
event.mButton = MouseButton::ePrimary;
|
2016-03-28 07:29:42 +03:00
|
|
|
event.mTime = PR_IntervalNow();
|
2019-04-21 21:19:43 +03:00
|
|
|
event.mInputSource = dom::MouseEvent_Binding::MOZ_SOURCE_UNKNOWN;
|
2008-08-06 16:16:54 +04:00
|
|
|
|
2009-08-20 10:45:19 +04:00
|
|
|
nsEventStatus status = nsEventStatus_eIgnore;
|
|
|
|
aPresShell->HandleEventWithTarget(&event, aFrame, aContent, &status);
|
2008-08-06 16:16:54 +04:00
|
|
|
}
|
|
|
|
|
2015-08-26 15:56:59 +03:00
|
|
|
void nsCoreUtils::DispatchTouchEvent(EventMessage aMessage, int32_t aX,
|
2013-07-25 19:59:08 +04:00
|
|
|
int32_t aY, nsIContent* aContent,
|
2019-04-13 15:13:15 +03:00
|
|
|
nsIFrame* aFrame, PresShell* aPresShell,
|
2013-07-25 19:59:08 +04:00
|
|
|
nsIWidget* aRootWidget) {
|
2016-07-18 17:26:38 +03:00
|
|
|
nsIDocShell* docShell = nullptr;
|
|
|
|
if (aPresShell->GetDocument()) {
|
|
|
|
docShell = aPresShell->GetDocument()->GetDocShell();
|
|
|
|
}
|
|
|
|
if (!dom::TouchEvent::PrefEnabled(docShell)) {
|
2013-07-25 19:59:08 +04:00
|
|
|
return;
|
2016-07-18 17:26:38 +03:00
|
|
|
}
|
2013-07-25 19:59:08 +04:00
|
|
|
|
2015-08-26 15:56:59 +03:00
|
|
|
WidgetTouchEvent event(true, aMessage, aRootWidget);
|
2013-07-25 19:59:08 +04:00
|
|
|
|
2016-03-28 07:29:42 +03:00
|
|
|
event.mTime = PR_IntervalNow();
|
2013-07-25 19:59:08 +04:00
|
|
|
|
|
|
|
// XXX: Touch has an identifier of -1 to hint that it is synthesized.
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<dom::Touch> t = new dom::Touch(-1, LayoutDeviceIntPoint(aX, aY),
|
2015-11-10 08:37:31 +03:00
|
|
|
LayoutDeviceIntPoint(1, 1), 0.0f, 1.0f);
|
2018-05-25 18:02:59 +03:00
|
|
|
t->SetTouchTarget(aContent);
|
2016-03-30 12:44:28 +03:00
|
|
|
event.mTouches.AppendElement(t);
|
2013-07-25 19:59:08 +04:00
|
|
|
nsEventStatus status = nsEventStatus_eIgnore;
|
|
|
|
aPresShell->HandleEventWithTarget(&event, aFrame, aContent, &status);
|
|
|
|
}
|
|
|
|
|
2012-10-13 10:34:21 +04:00
|
|
|
uint32_t nsCoreUtils::GetAccessKeyFor(nsIContent* aContent) {
|
2007-08-29 10:52:46 +04:00
|
|
|
// Accesskeys are registered by @accesskey attribute only. At first check
|
|
|
|
// whether it is presented on the given element to avoid the slow
|
2014-04-01 08:09:23 +04:00
|
|
|
// EventStateManager::GetRegisteredAccessKey() method.
|
2021-02-20 02:14:32 +03:00
|
|
|
if (!aContent->IsElement() || !aContent->AsElement()->HasAttr(
|
|
|
|
kNameSpaceID_None, nsGkAtoms::accesskey)) {
|
2007-08-29 10:52:46 +04:00
|
|
|
return 0;
|
2021-02-20 02:14:32 +03:00
|
|
|
}
|
2007-08-29 10:52:46 +04:00
|
|
|
|
2018-02-21 01:00:10 +03:00
|
|
|
nsPresContext* presContext = aContent->OwnerDoc()->GetPresContext();
|
2007-08-29 10:52:46 +04:00
|
|
|
if (!presContext) return 0;
|
|
|
|
|
2014-04-01 08:09:23 +04:00
|
|
|
EventStateManager* esm = presContext->EventStateManager();
|
2007-08-29 10:52:46 +04:00
|
|
|
if (!esm) return 0;
|
|
|
|
|
2017-12-07 21:13:50 +03:00
|
|
|
return esm->GetRegisteredAccessKey(aContent->AsElement());
|
2007-08-29 10:52:46 +04:00
|
|
|
}
|
|
|
|
|
2010-06-11 12:23:18 +04:00
|
|
|
nsIContent* nsCoreUtils::GetDOMElementFor(nsIContent* aContent) {
|
|
|
|
if (aContent->IsElement()) return aContent;
|
2008-10-08 16:50:36 +04:00
|
|
|
|
2013-05-02 02:50:08 +04:00
|
|
|
if (aContent->IsText()) return aContent->GetFlattenedTreeParent();
|
2008-10-08 16:50:36 +04:00
|
|
|
|
2012-07-30 18:20:58 +04:00
|
|
|
return nullptr;
|
2008-07-17 16:06:24 +04:00
|
|
|
}
|
|
|
|
|
2012-08-22 19:56:38 +04:00
|
|
|
nsINode* nsCoreUtils::GetDOMNodeFromDOMPoint(nsINode* aNode, uint32_t aOffset) {
|
2010-05-25 12:12:43 +04:00
|
|
|
if (aNode && aNode->IsElement()) {
|
2012-08-22 19:56:38 +04:00
|
|
|
uint32_t childCount = aNode->GetChildCount();
|
2012-07-22 14:35:49 +04:00
|
|
|
NS_ASSERTION(aOffset <= childCount, "Wrong offset of the DOM point!");
|
2008-12-16 13:14:20 +03:00
|
|
|
|
|
|
|
// The offset can be after last child of container node that means DOM point
|
|
|
|
// is placed immediately after the last child. In this case use the DOM node
|
|
|
|
// from the given DOM point is used as result node.
|
2018-01-03 15:59:54 +03:00
|
|
|
if (aOffset != childCount) return aNode->GetChildAt_Deprecated(aOffset);
|
2008-12-16 13:14:20 +03:00
|
|
|
}
|
|
|
|
|
2010-05-25 12:12:43 +04:00
|
|
|
return aNode;
|
2008-12-16 13:14:20 +03:00
|
|
|
}
|
|
|
|
|
2010-01-27 14:43:25 +03:00
|
|
|
bool nsCoreUtils::IsAncestorOf(nsINode* aPossibleAncestorNode,
|
2010-06-10 07:29:56 +04:00
|
|
|
nsINode* aPossibleDescendantNode,
|
|
|
|
nsINode* aRootNode) {
|
2011-10-17 18:59:28 +04:00
|
|
|
NS_ENSURE_TRUE(aPossibleAncestorNode && aPossibleDescendantNode, false);
|
2007-08-14 22:47:49 +04:00
|
|
|
|
2010-01-27 14:43:25 +03:00
|
|
|
nsINode* parentNode = aPossibleDescendantNode;
|
2012-10-09 16:31:24 +04:00
|
|
|
while ((parentNode = parentNode->GetParentNode()) &&
|
2010-06-11 12:23:04 +04:00
|
|
|
parentNode != aRootNode) {
|
2010-01-27 14:43:25 +03:00
|
|
|
if (parentNode == aPossibleAncestorNode) return true;
|
2007-08-14 22:47:49 +04:00
|
|
|
}
|
2010-01-27 14:43:25 +03:00
|
|
|
|
2011-10-17 18:59:28 +04:00
|
|
|
return false;
|
2007-08-14 22:47:49 +04:00
|
|
|
}
|
|
|
|
|
2012-04-06 22:08:24 +04:00
|
|
|
nsresult nsCoreUtils::ScrollSubstringTo(nsIFrame* aFrame, nsRange* aRange,
|
2012-08-22 19:56:38 +04:00
|
|
|
uint32_t aScrollType) {
|
2019-04-30 03:07:49 +03:00
|
|
|
ScrollAxis vertical, horizontal;
|
2012-03-20 06:09:50 +04:00
|
|
|
ConvertScrollTypeToPercents(aScrollType, &vertical, &horizontal);
|
2007-09-25 09:48:51 +04:00
|
|
|
|
2012-04-06 22:08:24 +04:00
|
|
|
return ScrollSubstringTo(aFrame, aRange, vertical, horizontal);
|
2007-09-25 09:48:51 +04:00
|
|
|
}
|
|
|
|
|
2012-04-06 22:08:24 +04:00
|
|
|
nsresult nsCoreUtils::ScrollSubstringTo(nsIFrame* aFrame, nsRange* aRange,
|
2019-04-30 03:07:49 +03:00
|
|
|
ScrollAxis aVertical,
|
|
|
|
ScrollAxis aHorizontal) {
|
2018-03-27 07:35:22 +03:00
|
|
|
if (!aFrame || !aRange) {
|
2007-08-24 08:54:45 +04:00
|
|
|
return NS_ERROR_FAILURE;
|
2018-03-27 07:35:22 +03:00
|
|
|
}
|
2007-08-24 08:54:45 +04:00
|
|
|
|
|
|
|
nsPresContext* presContext = aFrame->PresContext();
|
|
|
|
|
|
|
|
nsCOMPtr<nsISelectionController> selCon;
|
|
|
|
aFrame->GetSelectionController(presContext, getter_AddRefs(selCon));
|
|
|
|
NS_ENSURE_TRUE(selCon, NS_ERROR_FAILURE);
|
|
|
|
|
2018-03-27 07:35:22 +03:00
|
|
|
RefPtr<dom::Selection> selection =
|
2018-05-08 20:52:36 +03:00
|
|
|
selCon->GetSelection(nsISelectionController::SELECTION_ACCESSIBILITY);
|
2007-08-24 08:54:45 +04:00
|
|
|
|
2018-03-27 07:35:23 +03:00
|
|
|
selection->RemoveAllRanges(IgnoreErrors());
|
2019-07-02 16:16:12 +03:00
|
|
|
selection->AddRangeAndSelectFramesAndNotifyListeners(*aRange, IgnoreErrors());
|
2007-08-24 08:54:45 +04:00
|
|
|
|
2018-05-08 20:52:38 +03:00
|
|
|
selection->ScrollIntoView(nsISelectionController::SELECTION_ANCHOR_REGION,
|
|
|
|
aVertical, aHorizontal,
|
|
|
|
Selection::SCROLL_SYNCHRONOUS);
|
2007-08-24 08:54:45 +04:00
|
|
|
|
2018-05-08 20:52:41 +03:00
|
|
|
selection->CollapseToStart(IgnoreErrors());
|
2007-08-24 08:54:45 +04:00
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2008-10-16 05:52:58 +04:00
|
|
|
void nsCoreUtils::ScrollFrameToPoint(nsIFrame* aScrollableFrame,
|
|
|
|
nsIFrame* aFrame,
|
2022-01-19 02:31:21 +03:00
|
|
|
const LayoutDeviceIntPoint& aPoint) {
|
2012-10-19 19:10:28 +04:00
|
|
|
nsIScrollableFrame* scrollableFrame = do_QueryFrame(aScrollableFrame);
|
2007-09-25 09:48:51 +04:00
|
|
|
if (!scrollableFrame) return;
|
|
|
|
|
2022-01-19 02:31:21 +03:00
|
|
|
nsPoint point = LayoutDeviceIntPoint::ToAppUnits(
|
|
|
|
aPoint, aFrame->PresContext()->AppUnitsPerDevPixel());
|
2012-10-19 19:10:28 +04:00
|
|
|
nsRect frameRect = aFrame->GetScreenRectInAppUnits();
|
2018-01-12 20:07:29 +03:00
|
|
|
nsPoint deltaPoint = point - frameRect.TopLeft();
|
2007-09-25 09:48:51 +04:00
|
|
|
|
|
|
|
nsPoint scrollPoint = scrollableFrame->GetScrollPosition();
|
|
|
|
scrollPoint -= deltaPoint;
|
|
|
|
|
2019-04-26 02:03:04 +03:00
|
|
|
scrollableFrame->ScrollTo(scrollPoint, ScrollMode::Instant);
|
2007-09-25 09:48:51 +04:00
|
|
|
}
|
|
|
|
|
2019-04-30 03:07:49 +03:00
|
|
|
void nsCoreUtils::ConvertScrollTypeToPercents(uint32_t aScrollType,
|
|
|
|
ScrollAxis* aVertical,
|
|
|
|
ScrollAxis* aHorizontal) {
|
2019-04-25 08:04:15 +03:00
|
|
|
WhereToScroll whereY, whereX;
|
|
|
|
WhenToScroll whenY, whenX;
|
2007-08-24 08:54:45 +04:00
|
|
|
switch (aScrollType) {
|
|
|
|
case nsIAccessibleScrollType::SCROLL_TYPE_TOP_LEFT:
|
2019-04-25 08:04:15 +03:00
|
|
|
whereY = kScrollToTop;
|
|
|
|
whenY = WhenToScroll::Always;
|
|
|
|
whereX = kScrollToLeft;
|
|
|
|
whenX = WhenToScroll::Always;
|
2007-08-24 08:54:45 +04:00
|
|
|
break;
|
|
|
|
case nsIAccessibleScrollType::SCROLL_TYPE_BOTTOM_RIGHT:
|
2019-04-25 08:04:15 +03:00
|
|
|
whereY = kScrollToBottom;
|
|
|
|
whenY = WhenToScroll::Always;
|
|
|
|
whereX = kScrollToRight;
|
|
|
|
whenX = WhenToScroll::Always;
|
2007-08-24 08:54:45 +04:00
|
|
|
break;
|
|
|
|
case nsIAccessibleScrollType::SCROLL_TYPE_TOP_EDGE:
|
2019-04-25 08:04:15 +03:00
|
|
|
whereY = kScrollToTop;
|
|
|
|
whenY = WhenToScroll::Always;
|
|
|
|
whereX = kScrollMinimum;
|
|
|
|
whenX = WhenToScroll::IfNotFullyVisible;
|
2007-08-24 08:54:45 +04:00
|
|
|
break;
|
|
|
|
case nsIAccessibleScrollType::SCROLL_TYPE_BOTTOM_EDGE:
|
2019-04-25 08:04:15 +03:00
|
|
|
whereY = kScrollToBottom;
|
|
|
|
whenY = WhenToScroll::Always;
|
|
|
|
whereX = kScrollMinimum;
|
|
|
|
whenX = WhenToScroll::IfNotFullyVisible;
|
2007-08-24 08:54:45 +04:00
|
|
|
break;
|
|
|
|
case nsIAccessibleScrollType::SCROLL_TYPE_LEFT_EDGE:
|
2019-04-25 08:04:15 +03:00
|
|
|
whereY = kScrollMinimum;
|
|
|
|
whenY = WhenToScroll::IfNotFullyVisible;
|
|
|
|
whereX = kScrollToLeft;
|
|
|
|
whenX = WhenToScroll::Always;
|
2007-08-24 08:54:45 +04:00
|
|
|
break;
|
|
|
|
case nsIAccessibleScrollType::SCROLL_TYPE_RIGHT_EDGE:
|
2019-04-25 08:04:15 +03:00
|
|
|
whereY = kScrollMinimum;
|
|
|
|
whenY = WhenToScroll::IfNotFullyVisible;
|
|
|
|
whereX = kScrollToRight;
|
|
|
|
whenX = WhenToScroll::Always;
|
2007-08-24 08:54:45 +04:00
|
|
|
break;
|
|
|
|
default:
|
2019-04-25 08:04:15 +03:00
|
|
|
whereY = kScrollMinimum;
|
|
|
|
whenY = WhenToScroll::IfNotFullyVisible;
|
|
|
|
whereX = kScrollMinimum;
|
|
|
|
whenX = WhenToScroll::IfNotFullyVisible;
|
2007-08-24 08:54:45 +04:00
|
|
|
}
|
2019-04-30 03:07:49 +03:00
|
|
|
*aVertical = ScrollAxis(whereY, whenY);
|
|
|
|
*aHorizontal = ScrollAxis(whereX, whenX);
|
2007-08-24 08:54:45 +04:00
|
|
|
}
|
|
|
|
|
2013-02-13 02:02:51 +04:00
|
|
|
already_AddRefed<nsIDocShell> nsCoreUtils::GetDocShellFor(nsINode* aNode) {
|
2012-07-30 18:20:58 +04:00
|
|
|
if (!aNode) return nullptr;
|
2007-09-05 11:39:09 +04:00
|
|
|
|
2013-11-15 20:32:12 +04:00
|
|
|
nsCOMPtr<nsIDocShell> docShell = aNode->OwnerDoc()->GetDocShell();
|
2013-02-13 02:02:51 +04:00
|
|
|
return docShell.forget();
|
2007-09-05 11:39:09 +04:00
|
|
|
}
|
|
|
|
|
2019-01-02 16:05:23 +03:00
|
|
|
bool nsCoreUtils::IsRootDocument(Document* aDocument) {
|
2013-11-15 20:32:12 +04:00
|
|
|
nsCOMPtr<nsIDocShellTreeItem> docShellTreeItem = aDocument->GetDocShell();
|
2010-06-08 20:39:58 +04:00
|
|
|
NS_ASSERTION(docShellTreeItem, "No document shell for document!");
|
|
|
|
|
|
|
|
nsCOMPtr<nsIDocShellTreeItem> parentTreeItem;
|
2019-07-26 19:48:31 +03:00
|
|
|
docShellTreeItem->GetInProcessParent(getter_AddRefs(parentTreeItem));
|
2010-06-08 20:39:58 +04:00
|
|
|
|
|
|
|
return !parentTreeItem;
|
|
|
|
}
|
|
|
|
|
2020-06-10 08:03:05 +03:00
|
|
|
bool nsCoreUtils::IsTopLevelContentDocInProcess(Document* aDocumentNode) {
|
2021-01-05 12:47:12 +03:00
|
|
|
mozilla::dom::BrowsingContext* bc = aDocumentNode->GetBrowsingContext();
|
2020-06-10 08:03:07 +03:00
|
|
|
return bc->IsContent() && (
|
|
|
|
// Tab document.
|
|
|
|
bc->IsTop() ||
|
|
|
|
// Out-of-process iframe.
|
|
|
|
!bc->GetParent()->IsInProcess());
|
2011-07-22 04:49:35 +04:00
|
|
|
}
|
|
|
|
|
2019-01-02 16:05:23 +03:00
|
|
|
bool nsCoreUtils::IsErrorPage(Document* aDocument) {
|
2010-06-08 20:39:58 +04:00
|
|
|
nsIURI* uri = aDocument->GetDocumentURI();
|
2019-08-07 22:49:40 +03:00
|
|
|
if (!uri->SchemeIs("about")) {
|
|
|
|
return false;
|
|
|
|
}
|
2010-06-08 20:39:58 +04:00
|
|
|
|
2012-09-02 06:35:17 +04:00
|
|
|
nsAutoCString path;
|
2017-07-29 14:50:21 +03:00
|
|
|
uri->GetPathQueryRef(path);
|
2010-06-08 20:39:58 +04:00
|
|
|
|
|
|
|
constexpr auto neterror = "neterror"_ns;
|
2011-05-21 11:00:14 +04:00
|
|
|
constexpr auto certerror = "certerror"_ns;
|
|
|
|
|
|
|
|
return StringBeginsWith(path, neterror) || StringBeginsWith(path, certerror);
|
2010-06-08 20:39:58 +04:00
|
|
|
}
|
|
|
|
|
2020-11-23 19:07:43 +03:00
|
|
|
PresShell* nsCoreUtils::GetPresShellFor(nsINode* aNode) {
|
|
|
|
return aNode->OwnerDoc()->GetPresShell();
|
|
|
|
}
|
|
|
|
|
2008-10-16 05:52:58 +04:00
|
|
|
bool nsCoreUtils::GetID(nsIContent* aContent, nsAString& aID) {
|
2017-12-07 21:13:50 +03:00
|
|
|
return aContent->IsElement() &&
|
|
|
|
aContent->AsElement()->GetAttr(kNameSpaceID_None, nsGkAtoms::id, aID);
|
2007-09-19 01:36:41 +04:00
|
|
|
}
|
2007-09-25 05:19:03 +04:00
|
|
|
|
2017-10-03 01:05:19 +03:00
|
|
|
bool nsCoreUtils::GetUIntAttr(nsIContent* aContent, nsAtom* aAttr,
|
|
|
|
int32_t* aUInt) {
|
2010-01-12 22:07:38 +03:00
|
|
|
nsAutoString value;
|
2017-12-07 21:13:50 +03:00
|
|
|
if (!aContent->IsElement()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
aContent->AsElement()->GetAttr(kNameSpaceID_None, aAttr, value);
|
2010-01-12 22:07:38 +03:00
|
|
|
if (!value.IsEmpty()) {
|
2012-07-27 17:59:29 +04:00
|
|
|
nsresult error = NS_OK;
|
2012-08-22 19:56:38 +04:00
|
|
|
int32_t integer = value.ToInteger(&error);
|
2010-01-12 22:07:38 +03:00
|
|
|
if (NS_SUCCEEDED(error) && integer > 0) {
|
|
|
|
*aUInt = integer;
|
2011-10-17 18:59:28 +04:00
|
|
|
return true;
|
2010-01-12 22:07:38 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-10-17 18:59:28 +04:00
|
|
|
return false;
|
2010-01-12 22:07:38 +03:00
|
|
|
}
|
|
|
|
|
2008-10-16 05:52:58 +04:00
|
|
|
void nsCoreUtils::GetLanguageFor(nsIContent* aContent, nsIContent* aRootContent,
|
|
|
|
nsAString& aLanguage) {
|
2008-07-17 16:06:24 +04:00
|
|
|
aLanguage.Truncate();
|
|
|
|
|
|
|
|
nsIContent* walkUp = aContent;
|
|
|
|
while (walkUp && walkUp != aRootContent &&
|
2017-12-07 21:13:50 +03:00
|
|
|
(!walkUp->IsElement() ||
|
|
|
|
!walkUp->AsElement()->GetAttr(kNameSpaceID_None, nsGkAtoms::lang,
|
2021-02-20 02:14:32 +03:00
|
|
|
aLanguage))) {
|
2008-07-17 16:06:24 +04:00
|
|
|
walkUp = walkUp->GetParent();
|
2021-02-20 02:14:32 +03:00
|
|
|
}
|
2008-07-17 16:06:24 +04:00
|
|
|
}
|
2008-10-17 14:10:43 +04:00
|
|
|
|
2018-12-04 19:25:30 +03:00
|
|
|
XULTreeElement* nsCoreUtils::GetTree(nsIContent* aContent) {
|
2009-08-20 10:45:19 +04:00
|
|
|
// Find DOMNode's parents recursively until reach the <tree> tag
|
2010-06-11 12:23:18 +04:00
|
|
|
nsIContent* currentContent = aContent;
|
|
|
|
while (currentContent) {
|
2011-06-04 01:35:17 +04:00
|
|
|
if (currentContent->NodeInfo()->Equals(nsGkAtoms::tree, kNameSpaceID_XUL)) {
|
2018-12-04 19:25:30 +03:00
|
|
|
return XULTreeElement::FromNode(currentContent);
|
2009-08-20 10:45:19 +04:00
|
|
|
}
|
2013-05-02 02:50:08 +04:00
|
|
|
currentContent = currentContent->GetFlattenedTreeParent();
|
2009-08-20 10:45:19 +04:00
|
|
|
}
|
2010-06-11 12:23:18 +04:00
|
|
|
|
2012-07-30 18:20:58 +04:00
|
|
|
return nullptr;
|
2009-08-20 10:45:19 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
already_AddRefed<nsTreeColumn> nsCoreUtils::GetFirstSensibleColumn(
|
2020-04-15 04:01:12 +03:00
|
|
|
XULTreeElement* aTree, FlushType aFlushType) {
|
2020-03-24 22:07:30 +03:00
|
|
|
if (!aTree) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2020-04-15 04:01:12 +03:00
|
|
|
RefPtr<nsTreeColumns> cols = aTree->GetColumns(aFlushType);
|
2020-03-24 22:07:30 +03:00
|
|
|
if (!cols) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
2009-08-20 10:45:19 +04:00
|
|
|
|
2018-06-05 20:30:17 +03:00
|
|
|
RefPtr<nsTreeColumn> column = cols->GetFirstColumn();
|
2009-08-20 10:45:19 +04:00
|
|
|
if (column && IsColumnHidden(column)) return GetNextSensibleColumn(column);
|
|
|
|
|
|
|
|
return column.forget();
|
|
|
|
}
|
|
|
|
|
2018-12-04 19:25:30 +03:00
|
|
|
uint32_t nsCoreUtils::GetSensibleColumnCount(XULTreeElement* aTree) {
|
2012-08-22 19:56:38 +04:00
|
|
|
uint32_t count = 0;
|
2020-03-24 22:07:30 +03:00
|
|
|
if (!aTree) {
|
|
|
|
return count;
|
|
|
|
}
|
2009-08-20 10:45:19 +04:00
|
|
|
|
2018-12-04 19:25:41 +03:00
|
|
|
RefPtr<nsTreeColumns> cols = aTree->GetColumns();
|
2020-03-24 22:07:30 +03:00
|
|
|
if (!cols) {
|
|
|
|
return count;
|
|
|
|
}
|
2009-08-20 10:45:19 +04:00
|
|
|
|
2018-06-05 20:30:17 +03:00
|
|
|
nsTreeColumn* column = cols->GetFirstColumn();
|
2009-08-20 10:45:19 +04:00
|
|
|
|
|
|
|
while (column) {
|
|
|
|
if (!IsColumnHidden(column)) count++;
|
|
|
|
|
2018-06-05 20:30:17 +03:00
|
|
|
column = column->GetNext();
|
2009-08-20 10:45:19 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
return count;
|
|
|
|
}
|
|
|
|
|
2012-08-22 19:56:38 +04:00
|
|
|
already_AddRefed<nsTreeColumn> nsCoreUtils::GetSensibleColumnAt(
|
2018-12-04 19:25:30 +03:00
|
|
|
XULTreeElement* aTree, uint32_t aIndex) {
|
2020-03-24 22:07:30 +03:00
|
|
|
if (!aTree) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2012-08-22 19:56:38 +04:00
|
|
|
uint32_t idx = aIndex;
|
2009-08-20 10:45:19 +04:00
|
|
|
|
2018-06-06 06:01:36 +03:00
|
|
|
nsCOMPtr<nsTreeColumn> column = GetFirstSensibleColumn(aTree);
|
2009-08-20 10:45:19 +04:00
|
|
|
while (column) {
|
|
|
|
if (idx == 0) return column.forget();
|
|
|
|
|
|
|
|
idx--;
|
|
|
|
column = GetNextSensibleColumn(column);
|
|
|
|
}
|
|
|
|
|
2012-07-30 18:20:58 +04:00
|
|
|
return nullptr;
|
2009-08-20 10:45:19 +04:00
|
|
|
}
|
|
|
|
|
2018-06-06 06:01:37 +03:00
|
|
|
already_AddRefed<nsTreeColumn> nsCoreUtils::GetNextSensibleColumn(
|
|
|
|
nsTreeColumn* aColumn) {
|
2020-03-24 22:07:30 +03:00
|
|
|
if (!aColumn) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2018-06-06 06:01:37 +03:00
|
|
|
RefPtr<nsTreeColumn> nextColumn = aColumn->GetNext();
|
2009-08-20 10:45:19 +04:00
|
|
|
|
|
|
|
while (nextColumn && IsColumnHidden(nextColumn)) {
|
2018-06-06 06:01:36 +03:00
|
|
|
nextColumn = nextColumn->GetNext();
|
2009-08-20 10:45:19 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
return nextColumn.forget();
|
|
|
|
}
|
|
|
|
|
2018-06-06 06:01:37 +03:00
|
|
|
already_AddRefed<nsTreeColumn> nsCoreUtils::GetPreviousSensibleColumn(
|
|
|
|
nsTreeColumn* aColumn) {
|
2020-03-24 22:07:30 +03:00
|
|
|
if (!aColumn) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2018-06-06 06:01:37 +03:00
|
|
|
RefPtr<nsTreeColumn> prevColumn = aColumn->GetPrevious();
|
2009-08-20 10:45:19 +04:00
|
|
|
|
|
|
|
while (prevColumn && IsColumnHidden(prevColumn)) {
|
2018-06-06 06:01:36 +03:00
|
|
|
prevColumn = prevColumn->GetPrevious();
|
2009-08-20 10:45:19 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
return prevColumn.forget();
|
|
|
|
}
|
|
|
|
|
2018-06-06 06:01:37 +03:00
|
|
|
bool nsCoreUtils::IsColumnHidden(nsTreeColumn* aColumn) {
|
2020-03-24 22:07:30 +03:00
|
|
|
if (!aColumn) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2018-06-06 06:01:37 +03:00
|
|
|
Element* element = aColumn->Element();
|
2018-04-27 06:36:30 +03:00
|
|
|
return element->AttrValueIs(kNameSpaceID_None, nsGkAtoms::hidden,
|
2011-06-04 01:35:17 +04:00
|
|
|
nsGkAtoms::_true, eCaseMatters);
|
2009-08-20 10:45:19 +04:00
|
|
|
}
|
2009-11-10 08:58:52 +03:00
|
|
|
|
2019-04-13 15:13:15 +03:00
|
|
|
void nsCoreUtils::ScrollTo(PresShell* aPresShell, nsIContent* aContent,
|
2012-08-22 19:56:38 +04:00
|
|
|
uint32_t aScrollType) {
|
2019-04-30 03:07:49 +03:00
|
|
|
ScrollAxis vertical, horizontal;
|
2012-04-10 04:39:00 +04:00
|
|
|
ConvertScrollTypeToPercents(aScrollType, &vertical, &horizontal);
|
|
|
|
aPresShell->ScrollContentIntoView(aContent, vertical, horizontal,
|
2019-04-25 08:04:15 +03:00
|
|
|
ScrollFlags::ScrollOverflowHidden);
|
2012-04-10 04:39:00 +04:00
|
|
|
}
|
|
|
|
|
2020-11-23 19:08:40 +03:00
|
|
|
bool nsCoreUtils::IsHTMLTableHeader(nsIContent* aContent) {
|
|
|
|
return aContent->NodeInfo()->Equals(nsGkAtoms::th) ||
|
|
|
|
(aContent->IsElement() &&
|
|
|
|
aContent->AsElement()->HasAttr(kNameSpaceID_None, nsGkAtoms::scope));
|
|
|
|
}
|
|
|
|
|
2017-06-20 12:19:52 +03:00
|
|
|
bool nsCoreUtils::IsWhitespaceString(const nsAString& aString) {
|
|
|
|
nsAString::const_char_iterator iterBegin, iterEnd;
|
2013-07-18 19:09:45 +04:00
|
|
|
|
|
|
|
aString.BeginReading(iterBegin);
|
|
|
|
aString.EndReading(iterEnd);
|
|
|
|
|
|
|
|
while (iterBegin != iterEnd && IsWhitespace(*iterBegin)) ++iterBegin;
|
|
|
|
|
|
|
|
return iterBegin == iterEnd;
|
|
|
|
}
|
2016-01-21 04:52:43 +03:00
|
|
|
|
|
|
|
bool nsCoreUtils::AccEventObserversExist() {
|
|
|
|
nsCOMPtr<nsIObserverService> obsService = services::GetObserverService();
|
|
|
|
NS_ENSURE_TRUE(obsService, false);
|
|
|
|
|
|
|
|
nsCOMPtr<nsISimpleEnumerator> observers;
|
|
|
|
obsService->EnumerateObservers(NS_ACCESSIBLE_EVENT_TOPIC,
|
|
|
|
getter_AddRefs(observers));
|
|
|
|
NS_ENSURE_TRUE(observers, false);
|
|
|
|
|
|
|
|
bool hasObservers = false;
|
|
|
|
observers->HasMoreElements(&hasObservers);
|
|
|
|
|
|
|
|
return hasObservers;
|
|
|
|
}
|
|
|
|
|
|
|
|
void nsCoreUtils::DispatchAccEvent(RefPtr<nsIAccessibleEvent> event) {
|
|
|
|
nsCOMPtr<nsIObserverService> obsService = services::GetObserverService();
|
|
|
|
NS_ENSURE_TRUE_VOID(obsService);
|
|
|
|
|
|
|
|
obsService->NotifyObservers(event, NS_ACCESSIBLE_EVENT_TOPIC, nullptr);
|
|
|
|
}
|
2019-08-01 19:19:06 +03:00
|
|
|
|
|
|
|
bool nsCoreUtils::IsDisplayContents(nsIContent* aContent) {
|
Bug 1744009 - Accessibility fixes for new combobox layout code. r=eeejay
In terms of the C++ code, this patch does basically one thing, which is
allowing creating option / optgroup accessibles without a frame for
comboboxes, and tracking mutations like layout does.
It seems this should be straight-forward, but handling mutations got a
bit complicated. We don't want to forcibly re-create accessibles, so we
want to re-use the PruneOrInsertSubtree logic that ContentInserted uses.
But determining whether we need to create the accessible requires
having flushed styles, so I added a ScheduleAccessibilitySubtreeUpdate
API to trigger that from WillRefresh once style and layout are
up-to-date.
The rest of the test updates should be sort of straight-forward. They
reflect two changes:
* <option> accessibles are leaves now (so they don't have text
children). Note that we still have the right native name and so on,
using the same logic we use to render the label.
* In 1proc tests, the focus no longer goes to the <option>, and uses
the same code-path that e10s does (moving focus to a <menulist> in
the parent process). Since that wasn't easy to test for (afaict) and
we have browser tests to cover that
(browser_treeupdate_select_dropdown.js, etc), I've decided to just
remove the tests that relied on the previous code-path, as they were
testing for a codepath that users weren't hitting anyways.
I've tested this with JAWS and Orca and behavior seems unchanged to my
knowledge.
Differential Revision: https://phabricator.services.mozilla.com/D133098
2022-01-17 14:10:05 +03:00
|
|
|
auto* element = Element::FromNodeOrNull(aContent);
|
|
|
|
return element && element->IsDisplayContents();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool nsCoreUtils::CanCreateAccessibleWithoutFrame(nsIContent* aContent) {
|
|
|
|
auto* element = Element::FromNodeOrNull(aContent);
|
|
|
|
if (!element) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (!element->HasServoData() || Servo_Element_IsDisplayNone(element)) {
|
|
|
|
// Out of the flat tree or in a display: none subtree.
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (element->IsDisplayContents()) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
// We don't have a frame, but we're not display: contents either.
|
|
|
|
// For now, only create accessibles for <option>/<optgroup> as our combobox
|
|
|
|
// select code depends on it.
|
|
|
|
return element->IsAnyOfHTMLElements(nsGkAtoms::option, nsGkAtoms::optgroup);
|
2019-08-01 19:19:06 +03:00
|
|
|
}
|
2021-02-09 03:44:21 +03:00
|
|
|
|
|
|
|
bool nsCoreUtils::IsDocumentVisibleConsideringInProcessAncestors(
|
|
|
|
const Document* aDocument) {
|
|
|
|
const Document* parent = aDocument;
|
|
|
|
do {
|
|
|
|
if (!parent->IsVisible()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
} while ((parent = parent->GetInProcessParentDocument()));
|
|
|
|
return true;
|
|
|
|
}
|