| // Copyright 2024 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #import "ui/accessibility/platform/browser_accessibility_ios.h" |
| |
| #import "base/apple/foundation_util.h" |
| #import "base/memory/ptr_util.h" |
| #import "ui/accessibility/platform/browser_accessibility_manager_ios.h" |
| #import "ui/accessibility/platform/ax_platform_node_ios.h" |
| #import "ui/accessibility/platform/ax_platform_node_ui_kit_element.h" |
| |
| namespace ui { |
| |
| // static |
| std::unique_ptr<BrowserAccessibility> BrowserAccessibility::Create( |
| BrowserAccessibilityManager* manager, |
| AXNode* node) { |
| return base::WrapUnique(new BrowserAccessibilityIOS(manager, node)); |
| } |
| |
| BrowserAccessibilityIOS::BrowserAccessibilityIOS( |
| BrowserAccessibilityManager* manager, |
| AXNode* node) |
| : BrowserAccessibility(manager, node) {} |
| |
| BrowserAccessibilityIOS::~BrowserAccessibilityIOS() = default; |
| |
| void BrowserAccessibilityIOS::OnDataChanged() { |
| BrowserAccessibility::OnDataChanged(); |
| |
| if (platform_node_) { |
| // TODO(crbug.com/336611337): Investigate why this needs to be called |
| // unconditionally rather than just for children changes. |
| [base::apple::ObjCCastStrict<AXPlatformNodeUIKitElement>( |
| platform_node_->GetNativeViewAccessible().Get()) childrenChanged]; |
| return; |
| } |
| |
| CreatePlatformNode(); |
| } |
| |
| size_t BrowserAccessibilityIOS::PlatformChildCount() const { |
| size_t child_count = BrowserAccessibility::PlatformChildCount(); |
| |
| // If this is a table, include the extra fake nodes generated by |
| // AXTableInfo, for the column nodes and the table header container, all of |
| // which are important only on macOS and iOS. |
| // TODO(crbug.com/336611337): Find a way to share all the extra table nodes |
| // logic with BrowserAccessibilityMac. |
| const std::vector<raw_ptr<AXNode, VectorExperimental>>* extra_mac_nodes = |
| node()->GetExtraMacNodes(); |
| if (!extra_mac_nodes) { |
| return child_count; |
| } |
| |
| return child_count + extra_mac_nodes->size(); |
| } |
| |
| BrowserAccessibility* BrowserAccessibilityIOS::PlatformGetChild( |
| size_t child_index) const { |
| if (child_index < BrowserAccessibility::PlatformChildCount()) { |
| return BrowserAccessibility::PlatformGetChild(child_index); |
| } |
| |
| if (child_index >= PlatformChildCount()) { |
| return nullptr; |
| } |
| |
| // If this is a table, include the extra fake nodes generated by |
| // AXTableInfo, for the column nodes and the table header container, all of |
| // which are only important on macOS and iOS. |
| const std::vector<raw_ptr<AXNode, VectorExperimental>>* extra_mac_nodes = |
| node()->GetExtraMacNodes(); |
| if (!extra_mac_nodes || extra_mac_nodes->empty()) { |
| return nullptr; |
| } |
| |
| child_index -= BrowserAccessibility::PlatformChildCount(); |
| if (child_index < extra_mac_nodes->size()) { |
| return manager_->GetFromAXNode((*extra_mac_nodes)[child_index]); |
| } |
| |
| return nullptr; |
| } |
| |
| BrowserAccessibility* BrowserAccessibilityIOS::PlatformGetFirstChild() const { |
| return PlatformGetChild(0); |
| } |
| |
| BrowserAccessibility* BrowserAccessibilityIOS::PlatformGetLastChild() const { |
| const std::vector<raw_ptr<AXNode, VectorExperimental>>* extra_mac_nodes = |
| node()->GetExtraMacNodes(); |
| if (extra_mac_nodes && !extra_mac_nodes->empty()) { |
| return manager_->GetFromAXNode(extra_mac_nodes->back()); |
| } |
| return BrowserAccessibility::PlatformGetLastChild(); |
| } |
| |
| BrowserAccessibility* BrowserAccessibilityIOS::PlatformGetNextSibling() const { |
| BrowserAccessibility* parent = PlatformGetParent(); |
| if (parent) { |
| size_t next_child_index = node()->GetUnignoredIndexInParent() + 1; |
| if (next_child_index >= parent->InternalChildCount() && |
| next_child_index < parent->PlatformChildCount()) { |
| // Get the extra_mac_node. |
| return parent->PlatformGetChild(next_child_index); |
| } else if (next_child_index >= parent->PlatformChildCount()) { |
| return nullptr; |
| } |
| } |
| return BrowserAccessibility::PlatformGetNextSibling(); |
| } |
| |
| BrowserAccessibility* BrowserAccessibilityIOS::PlatformGetPreviousSibling() |
| const { |
| BrowserAccessibility* parent = PlatformGetParent(); |
| if (parent) { |
| size_t child_index = node()->GetUnignoredIndexInParent(); |
| if (child_index > parent->InternalChildCount() && |
| child_index <= parent->PlatformChildCount()) { |
| // Get the extra_mac_node. |
| return parent->PlatformGetChild(child_index - 1); |
| } else if (child_index == 0) { |
| return nullptr; |
| } |
| } |
| return BrowserAccessibility::PlatformGetPreviousSibling(); |
| } |
| |
| gfx::NativeViewAccessible BrowserAccessibilityIOS::GetNativeViewAccessible() { |
| return platform_node_ ? platform_node_->GetNativeViewAccessible() |
| : gfx::NativeViewAccessible(); |
| } |
| |
| AXPlatformNode* BrowserAccessibilityIOS::GetAXPlatformNode() const { |
| return platform_node_.get(); |
| } |
| |
| float BrowserAccessibilityIOS::GetDeviceScaleFactor() const { |
| return manager_->device_scale_factor(); |
| } |
| |
| void BrowserAccessibilityIOS::CreatePlatformNode() { |
| CHECK(!platform_node_); |
| platform_node_ = AXPlatformNode::Create(*this); |
| platform_node()->SetIOSDelegate(this); |
| } |
| |
| } // namespace ui |