blob: 9e4e8a4a2b1114626e40552432a19fb6c321e5b8 [file] [log] [blame]
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "flutter_platform_node_delegate.h"
#include <utility>
#include "flutter/shell/platform/common/accessibility_bridge.h"
#include "flutter/third_party/accessibility/ax/ax_action_data.h"
#include "flutter/third_party/accessibility/ax/ax_tree_manager_map.h"
#include "flutter/third_party/accessibility/gfx/geometry/rect_conversions.h"
namespace flutter {
FlutterPlatformNodeDelegate::FlutterPlatformNodeDelegate() = default;
FlutterPlatformNodeDelegate::~FlutterPlatformNodeDelegate() = default;
void FlutterPlatformNodeDelegate::Init(std::weak_ptr<OwnerBridge> bridge,
ui::AXNode* node) {
bridge_ = std::move(bridge);
ax_node_ = node;
}
ui::AXNode* FlutterPlatformNodeDelegate::GetAXNode() const {
return ax_node_;
}
bool FlutterPlatformNodeDelegate::AccessibilityPerformAction(
const ui::AXActionData& data) {
AccessibilityNodeId target = ax_node_->id();
auto bridge_ptr = bridge_.lock();
BASE_DCHECK(bridge_ptr);
switch (data.action) {
case ax::mojom::Action::kDoDefault:
bridge_ptr->DispatchAccessibilityAction(
target, FlutterSemanticsAction::kFlutterSemanticsActionTap, {});
return true;
case ax::mojom::Action::kFocus:
bridge_ptr->SetLastFocusedId(target);
bridge_ptr->DispatchAccessibilityAction(
target,
FlutterSemanticsAction::
kFlutterSemanticsActionDidGainAccessibilityFocus,
{});
return true;
case ax::mojom::Action::kScrollToMakeVisible:
bridge_ptr->DispatchAccessibilityAction(
target, FlutterSemanticsAction::kFlutterSemanticsActionShowOnScreen,
{});
return true;
// TODO(chunhtai): support more actions.
default:
return false;
}
return false;
}
const ui::AXNodeData& FlutterPlatformNodeDelegate::GetData() const {
return ax_node_->data();
}
gfx::NativeViewAccessible FlutterPlatformNodeDelegate::GetParent() {
if (!ax_node_->parent()) {
return nullptr;
}
auto bridge_ptr = bridge_.lock();
BASE_DCHECK(bridge_ptr);
return bridge_ptr->GetNativeAccessibleFromId(ax_node_->parent()->id());
}
gfx::NativeViewAccessible FlutterPlatformNodeDelegate::GetFocus() {
auto bridge_ptr = bridge_.lock();
BASE_DCHECK(bridge_ptr);
AccessibilityNodeId last_focused = bridge_ptr->GetLastFocusedId();
if (last_focused == ui::AXNode::kInvalidAXID) {
return nullptr;
}
return bridge_ptr->GetNativeAccessibleFromId(last_focused);
}
int FlutterPlatformNodeDelegate::GetChildCount() const {
return static_cast<int>(ax_node_->GetUnignoredChildCount());
}
gfx::NativeViewAccessible FlutterPlatformNodeDelegate::ChildAtIndex(int index) {
auto bridge_ptr = bridge_.lock();
BASE_DCHECK(bridge_ptr);
AccessibilityNodeId child = ax_node_->GetUnignoredChildAtIndex(index)->id();
return bridge_ptr->GetNativeAccessibleFromId(child);
}
gfx::Rect FlutterPlatformNodeDelegate::GetBoundsRect(
const ui::AXCoordinateSystem coordinate_system,
const ui::AXClippingBehavior clipping_behavior,
ui::AXOffscreenResult* offscreen_result) const {
auto bridge_ptr = bridge_.lock();
BASE_DCHECK(bridge_ptr);
// TODO(chunhtai): We need to apply screen dpr in here.
// https://github.com/flutter/flutter/issues/74283
const bool clip_bounds =
clipping_behavior == ui::AXClippingBehavior::kClipped;
bool offscreen = false;
gfx::RectF bounds =
bridge_ptr->RelativeToGlobalBounds(ax_node_, offscreen, clip_bounds);
if (offscreen_result != nullptr) {
*offscreen_result = offscreen ? ui::AXOffscreenResult::kOffscreen
: ui::AXOffscreenResult::kOnscreen;
}
return gfx::ToEnclosingRect(bounds);
}
std::weak_ptr<FlutterPlatformNodeDelegate::OwnerBridge>
FlutterPlatformNodeDelegate::GetOwnerBridge() const {
return bridge_;
}
ui::AXPlatformNode* FlutterPlatformNodeDelegate::GetPlatformNode() const {
return nullptr;
}
gfx::NativeViewAccessible
FlutterPlatformNodeDelegate::GetLowestPlatformAncestor() const {
auto bridge_ptr = bridge_.lock();
BASE_DCHECK(bridge_ptr);
auto lowest_platform_ancestor = ax_node_->GetLowestPlatformAncestor();
if (lowest_platform_ancestor) {
return bridge_ptr->GetNativeAccessibleFromId(
ax_node_->GetLowestPlatformAncestor()->id());
}
return nullptr;
}
ui::AXNodePosition::AXPositionInstance
FlutterPlatformNodeDelegate::CreateTextPositionAt(int offset) const {
return ui::AXNodePosition::CreatePosition(*ax_node_, offset);
}
ui::AXPlatformNode* FlutterPlatformNodeDelegate::GetFromNodeID(
int32_t node_id) {
ui::AXTreeManager* tree_manager =
ui::AXTreeManagerMap::GetInstance().GetManager(
ax_node_->tree()->GetAXTreeID());
AccessibilityBridge* platform_manager =
static_cast<AccessibilityBridge*>(tree_manager);
return platform_manager->GetPlatformNodeFromTree(node_id);
}
ui::AXPlatformNode* FlutterPlatformNodeDelegate::GetFromTreeIDAndNodeID(
const ui::AXTreeID& tree_id,
int32_t node_id) {
ui::AXTreeManager* tree_manager =
ui::AXTreeManagerMap::GetInstance().GetManager(tree_id);
AccessibilityBridge* platform_manager =
static_cast<AccessibilityBridge*>(tree_manager);
return platform_manager->GetPlatformNodeFromTree(node_id);
}
const ui::AXTree::Selection FlutterPlatformNodeDelegate::GetUnignoredSelection()
const {
return ax_node_->GetUnignoredSelection();
}
} // namespace flutter