Flutter macOS Embedder
FlutterPlatformNodeDelegateMac.mm
Go to the documentation of this file.
1 // Copyright 2013 The Flutter Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
6 
11 
13 #include "flutter/third_party/accessibility/ax/ax_action_data.h"
14 #include "flutter/third_party/accessibility/ax/ax_node_position.h"
15 #include "flutter/third_party/accessibility/ax/platform/ax_platform_node.h"
16 #include "flutter/third_party/accessibility/ax/platform/ax_platform_node_base.h"
17 #include "flutter/third_party/accessibility/base/string_utils.h"
18 #include "flutter/third_party/accessibility/gfx/geometry/rect_conversions.h"
19 #include "flutter/third_party/accessibility/gfx/mac/coordinate_conversion.h"
20 
21 namespace flutter { // namespace
22 
24  std::weak_ptr<AccessibilityBridge> bridge,
25  __weak FlutterViewController* view_controller)
26  : bridge_(std::move(bridge)), view_controller_(view_controller) {}
27 
28 void FlutterPlatformNodeDelegateMac::Init(std::weak_ptr<OwnerBridge> bridge, ui::AXNode* node) {
30  if (GetData().IsTextField()) {
31  ax_platform_node_ = new FlutterTextPlatformNode(this, view_controller_);
32  } else {
33  ax_platform_node_ = ui::AXPlatformNode::Create(this);
34  }
35  NSCAssert(ax_platform_node_, @"Failed to create platform node.");
36 }
37 
38 void FlutterPlatformNodeDelegateMac::NodeDataChanged(const ui::AXNodeData& old_node_data,
39  const ui::AXNodeData& new_node_data) {
40  if (old_node_data.IsTextField() && !new_node_data.IsTextField()) {
41  ax_platform_node_->Destroy();
42  ax_platform_node_ = ui::AXPlatformNode::Create(this);
43  } else if (!old_node_data.IsTextField() && new_node_data.IsTextField()) {
44  ax_platform_node_->Destroy();
45  ax_platform_node_ = new FlutterTextPlatformNode(this, view_controller_);
46  }
47 }
48 
50  // Destroy() also calls delete on itself.
51  ax_platform_node_->Destroy();
52 }
53 
55  NSCAssert(ax_platform_node_, @"Platform node does not exist.");
56  return ax_platform_node_->GetNativeViewAccessible();
57 }
58 
59 gfx::NativeViewAccessible FlutterPlatformNodeDelegateMac::GetParent() {
60  gfx::NativeViewAccessible parent = FlutterPlatformNodeDelegate::GetParent();
61  if (!parent) {
62  NSCAssert(view_controller_.viewLoaded, @"Flutter view must be loaded");
63  return view_controller_.flutterView;
64  }
65  return parent;
66 }
67 
69  const ui::AXCoordinateSystem coordinate_system,
70  const ui::AXClippingBehavior clipping_behavior,
71  ui::AXOffscreenResult* offscreen_result) const {
72  gfx::Rect local_bounds = FlutterPlatformNodeDelegate::GetBoundsRect(
73  coordinate_system, clipping_behavior, offscreen_result);
74  gfx::RectF local_bounds_f(local_bounds);
75  gfx::RectF screen_bounds = ConvertBoundsFromLocalToScreen(local_bounds_f);
76  return gfx::ToEnclosingRect(ConvertBoundsFromScreenToGlobal(screen_bounds));
77 }
78 
79 gfx::NativeViewAccessible FlutterPlatformNodeDelegateMac::GetNSWindow() {
80  FlutterAppDelegate* appDelegate = (FlutterAppDelegate*)[NSApp delegate];
81  return appDelegate.mainFlutterWindow;
82 }
83 
85  if (GetAXNode()->IsIgnored()) {
86  return "";
87  }
88 
89  std::string text = GetData().GetStringAttribute(ax::mojom::StringAttribute::kName);
90  if (!text.empty()) {
91  return text;
92  };
93  auto bridge_ptr = bridge_.lock();
94  NSCAssert(bridge_ptr, @"Accessibility bridge in flutter engine must not be null.");
95  for (int32_t child : GetData().child_ids) {
96  auto delegate_child = bridge_ptr->GetFlutterPlatformNodeDelegateFromID(child).lock();
97  if (!delegate_child) {
98  continue;
99  }
100  text += std::static_pointer_cast<FlutterPlatformNodeDelegateMac>(delegate_child)
101  ->GetLiveRegionText();
102  }
103  return text;
104 }
105 
106 gfx::RectF FlutterPlatformNodeDelegateMac::ConvertBoundsFromLocalToScreen(
107  const gfx::RectF& local_bounds) const {
108  // Converts to NSRect to use NSView rect conversion.
109  NSRect ns_local_bounds =
110  NSMakeRect(local_bounds.x(), local_bounds.y(), local_bounds.width(), local_bounds.height());
111  // The macOS XY coordinates start at bottom-left and increase toward top-right,
112  // which is different from the Flutter's XY coordinates that start at top-left
113  // increasing to bottom-right. Therefore, this method needs to flip the y coordinate when
114  // it converts the bounds from flutter coordinates to macOS coordinates.
115  ns_local_bounds.origin.y = -ns_local_bounds.origin.y - ns_local_bounds.size.height;
116 
117  NSCAssert(view_controller_.viewLoaded, @"Flutter view must be loaded.");
118  NSRect ns_view_bounds = [view_controller_.flutterView convertRectFromBacking:ns_local_bounds];
119  NSRect ns_window_bounds = [view_controller_.flutterView convertRect:ns_view_bounds toView:nil];
120  NSRect ns_screen_bounds =
121  [[view_controller_.flutterView window] convertRectToScreen:ns_window_bounds];
122  gfx::RectF screen_bounds(ns_screen_bounds.origin.x, ns_screen_bounds.origin.y,
123  ns_screen_bounds.size.width, ns_screen_bounds.size.height);
124  return screen_bounds;
125 }
126 
127 gfx::RectF FlutterPlatformNodeDelegateMac::ConvertBoundsFromScreenToGlobal(
128  const gfx::RectF& screen_bounds) const {
129  // The VoiceOver seems to only accept bounds that are relative to primary screen.
130  // Thus, this method uses [[NSScreen screens] firstObject] instead of [NSScreen mainScreen].
131  NSScreen* screen = [[NSScreen screens] firstObject];
132  NSRect primary_screen_bounds = [screen frame];
133  // The screen is flipped against y axis.
134  float flipped_y = primary_screen_bounds.size.height - screen_bounds.y() - screen_bounds.height();
135  return {screen_bounds.x(), flipped_y, screen_bounds.width(), screen_bounds.height()};
136 }
137 
138 } // namespace flutter
flutter::FlutterPlatformNodeDelegateMac::Init
void Init(std::weak_ptr< OwnerBridge > bridge, ui::AXNode *node) override
Called only once, immediately after construction. The constructor doesn't take any arguments because ...
Definition: FlutterPlatformNodeDelegateMac.mm:28
flutter::FlutterPlatformNodeDelegateMac::GetLiveRegionText
std::string GetLiveRegionText() const
Gets the live region text of this node in UTF-8 format. This is useful to determine the changes in be...
Definition: FlutterPlatformNodeDelegateMac.mm:84
FlutterViewController
Definition: FlutterViewController.h:73
flutter::FlutterTextPlatformNode
The ax platform node for a text field.
Definition: FlutterTextInputSemanticsObject.h:22
flutter::FlutterPlatformNodeDelegate::Init
virtual void Init(std::weak_ptr< OwnerBridge > bridge, ui::AXNode *node)
Called only once, immediately after construction. The constructor doesn't take any arguments because ...
Definition: flutter_platform_node_delegate.cc:20
FlutterEngine_Internal.h
flutter::FlutterPlatformNodeDelegateMac::FlutterPlatformNodeDelegateMac
FlutterPlatformNodeDelegateMac(std::weak_ptr< AccessibilityBridge > bridge, __weak FlutterViewController *view_controller)
Definition: FlutterPlatformNodeDelegateMac.mm:23
flutter::FlutterPlatformNodeDelegate::GetData
const ui::AXNodeData & GetData() const override
Definition: flutter_platform_node_delegate.cc:60
flutter::FlutterPlatformNodeDelegateMac::GetNSWindow
gfx::NativeViewAccessible GetNSWindow() override
Definition: FlutterPlatformNodeDelegateMac.mm:79
flutter::FlutterPlatformNodeDelegate::GetBoundsRect
gfx::Rect GetBoundsRect(const ui::AXCoordinateSystem coordinate_system, const ui::AXClippingBehavior clipping_behavior, ui::AXOffscreenResult *offscreen_result) const override
Definition: flutter_platform_node_delegate.cc:94
FlutterPlatformNodeDelegateMac.h
flutter::FlutterPlatformNodeDelegateMac::GetParent
gfx::NativeViewAccessible GetParent() override
Definition: FlutterPlatformNodeDelegateMac.mm:59
flutter
Definition: AccessibilityBridgeMac.h:16
FlutterAppDelegate
Definition: FlutterAppDelegate.h:54
flutter::FlutterPlatformNodeDelegateMac::NodeDataChanged
void NodeDataChanged(const ui::AXNodeData &old_node_data, const ui::AXNodeData &new_node_data) override
Definition: FlutterPlatformNodeDelegateMac.mm:38
FlutterAppDelegate.h
flutter::FlutterPlatformNodeDelegateMac::~FlutterPlatformNodeDelegateMac
virtual ~FlutterPlatformNodeDelegateMac()
Definition: FlutterPlatformNodeDelegateMac.mm:49
FlutterAppDelegate::mainFlutterWindow
IBOutlet NSWindow * mainFlutterWindow
Definition: FlutterAppDelegate.h:65
flutter::FlutterPlatformNodeDelegateMac::GetBoundsRect
gfx::Rect GetBoundsRect(const ui::AXCoordinateSystem coordinate_system, const ui::AXClippingBehavior clipping_behavior, ui::AXOffscreenResult *offscreen_result) const override
Definition: FlutterPlatformNodeDelegateMac.mm:68
flutter::FlutterPlatformNodeDelegate::GetAXNode
ui::AXNode * GetAXNode() const
Gets the underlying ax node for this platform node delegate.
Definition: flutter_platform_node_delegate.cc:26
flutter::FlutterPlatformNodeDelegateMac::GetNativeViewAccessible
gfx::NativeViewAccessible GetNativeViewAccessible() override
Definition: FlutterPlatformNodeDelegateMac.mm:54
FlutterViewController_Internal.h
flutter::FlutterPlatformNodeDelegate::GetParent
gfx::NativeViewAccessible GetParent() override
Definition: flutter_platform_node_delegate.cc:64
FlutterTextInputSemanticsObject.h
accessibility_bridge.h