| // 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 |