commit 35f6ad218775c11df3ed619a58ca5d92368b460f
parent 8f9b2d7dad176ad0b574e9fdb820000a529a5e67
Author: Eitan Isaacson <eitan@monotonous.org>
Date: Tue, 21 Oct 2025 16:58:06 +0000
Bug 1942799 - P1: Intro IsEditable(Root) to distinguish editable content. r=morgan
Differential Revision: https://phabricator.services.mozilla.com/D268627
Diffstat:
10 files changed, 64 insertions(+), 17 deletions(-)
diff --git a/accessible/basetypes/Accessible.cpp b/accessible/basetypes/Accessible.cpp
@@ -199,6 +199,35 @@ bool Accessible::IsTextRole() {
return true;
}
+bool Accessible::IsEditableRoot() const {
+ if (IsTextField()) {
+ // A text field is always an editable root.
+ return true;
+ }
+
+ const nsRoleMapEntry* roleMapEntry = ARIARoleMap();
+ if (roleMapEntry && (roleMapEntry->role == roles::ENTRY ||
+ roleMapEntry->role == roles::SEARCHBOX)) {
+ // An aria text field is always an editable root.
+ return true;
+ }
+
+ if (!IsEditable()) {
+ return false;
+ }
+
+ if (IsDoc()) {
+ return true;
+ }
+
+ Accessible* parent = Parent();
+ if (parent && !parent->IsEditable()) {
+ return true;
+ }
+
+ return false;
+}
+
uint32_t Accessible::StartOffset() {
MOZ_ASSERT(IsLink(), "StartOffset is called not on hyper link!");
Accessible* parent = Parent();
diff --git a/accessible/basetypes/Accessible.h b/accessible/basetypes/Accessible.h
@@ -623,6 +623,10 @@ class Accessible {
*/
bool IsTextRole();
+ virtual bool IsEditable() const = 0;
+
+ bool IsEditableRoot() const;
+
bool IsGenericHyperText() const { return mType == eHyperTextType; }
bool IsHTMLBr() const { return mType == eHTMLBRType; }
diff --git a/accessible/generic/HyperTextAccessible.cpp b/accessible/generic/HyperTextAccessible.cpp
@@ -85,13 +85,6 @@ uint64_t HyperTextAccessible::NativeState() const {
return states;
}
-bool HyperTextAccessible::IsEditable() const {
- if (!mContent) {
- return false;
- }
- return mContent->AsElement()->State().HasState(dom::ElementState::READWRITE);
-}
-
uint32_t HyperTextAccessible::DOMPointToOffset(nsINode* aNode,
int32_t aNodeOffset,
bool aIsEndOffset) const {
diff --git a/accessible/generic/HyperTextAccessible.h b/accessible/generic/HyperTextAccessible.h
@@ -59,11 +59,6 @@ class HyperTextAccessible : public AccessibleWrap,
LocalAccessible* aChild) override;
virtual Relation RelationByType(RelationType aType) const override;
- /**
- * Return whether the associated content is editable.
- */
- bool IsEditable() const;
-
// HyperTextAccessible (static helper method)
// Convert content offset to rendered text offset
diff --git a/accessible/generic/LocalAccessible.cpp b/accessible/generic/LocalAccessible.cpp
@@ -2534,6 +2534,11 @@ bool LocalAccessible::IsPopover() const {
return el && el->IsHTMLElement() && el->HasAttr(nsGkAtoms::popover);
}
+bool LocalAccessible::IsEditable() const {
+ dom::Element* el = Elm();
+ return el && el->State().HasState(dom::ElementState::READWRITE);
+}
+
void LocalAccessible::AppendTextTo(nsAString& aText, uint32_t aStartOffset,
uint32_t aLength) {
// Return text representation of non-text accessible within hypertext
diff --git a/accessible/generic/LocalAccessible.h b/accessible/generic/LocalAccessible.h
@@ -429,6 +429,8 @@ class LocalAccessible : public nsISupports, public Accessible {
virtual bool IsPopover() const override;
+ virtual bool IsEditable() const override;
+
/**
* Get a pointer to accessibility interface for this node, which is specific
* to the OS/accessibility toolkit we're running on.
diff --git a/accessible/ipc/RemoteAccessible.cpp b/accessible/ipc/RemoteAccessible.cpp
@@ -1561,6 +1561,22 @@ bool RemoteAccessible::IsPopover() const {
return mCachedFields && mCachedFields->HasAttribute(CacheKey::PopupType);
}
+bool RemoteAccessible::IsEditable() const {
+ if (RequestDomainsIfInactive(CacheDomain::State)) {
+ return false;
+ }
+
+ if (mCachedFields) {
+ if (auto rawState =
+ mCachedFields->GetAttribute<uint64_t>(CacheKey::State)) {
+ VERIFY_CACHE(CacheDomain::State);
+ return (*rawState & states::EDITABLE) != 0;
+ }
+ }
+
+ return false;
+}
+
#if !defined(XP_WIN)
void RemoteAccessible::Announce(const nsString& aAnnouncement,
uint16_t aPriority) {
diff --git a/accessible/ipc/RemoteAccessible.h b/accessible/ipc/RemoteAccessible.h
@@ -392,6 +392,8 @@ class RemoteAccessible : public Accessible, public HyperTextAccessibleBase {
virtual bool HasPrimaryAction() const override;
+ virtual bool IsEditable() const override;
+
#if !defined(XP_WIN)
void Announce(const nsString& aAnnouncement, uint16_t aPriority);
#endif // !defined(XP_WIN)
diff --git a/accessible/xul/XULTreeGridAccessible.cpp b/accessible/xul/XULTreeGridAccessible.cpp
@@ -455,7 +455,7 @@ nsRect XULTreeGridCellAccessible::BoundsInAppUnits() const {
bool XULTreeGridCellAccessible::HasPrimaryAction() const {
return mColumn->Cycler() ||
(mColumn->Type() == dom::TreeColumn_Binding::TYPE_CHECKBOX &&
- IsEditable());
+ IsEditableCell());
}
void XULTreeGridCellAccessible::ActionNameAt(uint8_t aIndex, nsAString& aName) {
@@ -469,7 +469,7 @@ void XULTreeGridCellAccessible::ActionNameAt(uint8_t aIndex, nsAString& aName) {
}
if (mColumn->Type() == dom::TreeColumn_Binding::TYPE_CHECKBOX &&
- IsEditable()) {
+ IsEditableCell()) {
nsAutoString value;
mTreeView->GetCellValue(mRow, mColumn, value);
if (value.EqualsLiteral("true")) {
@@ -647,7 +647,7 @@ void XULTreeGridCellAccessible::DispatchClickEvent(
////////////////////////////////////////////////////////////////////////////////
// XULTreeGridCellAccessible: protected implementation
-bool XULTreeGridCellAccessible::IsEditable() const {
+bool XULTreeGridCellAccessible::IsEditableCell() const {
// XXX: logic corresponds to tree.xml, it's preferable to have interface
// method to check it.
bool isEditable = false;
diff --git a/accessible/xul/XULTreeGridAccessible.h b/accessible/xul/XULTreeGridAccessible.h
@@ -171,9 +171,10 @@ class XULTreeGridCellAccessible : public LeafAccessible,
// XULTreeGridCellAccessible
/**
- * Return true if value of cell can be modified.
+ * Return true if value of cell can be changed. Accounting for the state of
+ * its column.
*/
- bool IsEditable() const;
+ bool IsEditableCell() const;
enum { eAction_Click = 0 };