Flutter Engine
The Flutter Engine
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
5#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterPlatformNodeDelegateMac.h"
6
7#import "flutter/shell/platform/darwin/macos/framework/Headers/FlutterAppDelegate.h"
8#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterEngine_Internal.h"
9#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterTextInputSemanticsObject.h"
10#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterViewController_Internal.h"
11
12#include "flutter/shell/platform/common/accessibility_bridge.h"
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
21namespace flutter { // namespace
22
24 std::weak_ptr<AccessibilityBridge> bridge,
25 __weak FlutterViewController* view_controller)
26 : bridge_(std::move(bridge)), view_controller_(view_controller) {}
27
28void 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
39 // Destroy() also calls delete on itself.
40 ax_platform_node_->Destroy();
41}
42
44 NSCAssert(ax_platform_node_, @"Platform node does not exist.");
45 return ax_platform_node_->GetNativeViewAccessible();
46}
47
50 if (!parent) {
51 NSCAssert(view_controller_.viewLoaded, @"Flutter view must be loaded");
52 return view_controller_.flutterView;
53 }
54 return parent;
55}
56
58 const ui::AXCoordinateSystem coordinate_system,
59 const ui::AXClippingBehavior clipping_behavior,
60 ui::AXOffscreenResult* offscreen_result) const {
62 coordinate_system, clipping_behavior, offscreen_result);
63 gfx::RectF local_bounds_f(local_bounds);
64 gfx::RectF screen_bounds = ConvertBoundsFromLocalToScreen(local_bounds_f);
65 return gfx::ToEnclosingRect(ConvertBoundsFromScreenToGlobal(screen_bounds));
66}
67
69 FlutterAppDelegate* appDelegate = (FlutterAppDelegate*)[NSApp delegate];
70 return appDelegate.mainFlutterWindow;
71}
72
74 if (GetAXNode()->IsIgnored()) {
75 return "";
76 }
77
79 if (!text.empty()) {
80 return text;
81 };
82 auto bridge_ptr = bridge_.lock();
83 NSCAssert(bridge_ptr, @"Accessibility bridge in flutter engine must not be null.");
84 for (int32_t child : GetData().child_ids) {
85 auto delegate_child = bridge_ptr->GetFlutterPlatformNodeDelegateFromID(child).lock();
86 if (!delegate_child) {
87 continue;
88 }
89 text += std::static_pointer_cast<FlutterPlatformNodeDelegateMac>(delegate_child)
90 ->GetLiveRegionText();
91 }
92 return text;
93}
94
95gfx::RectF FlutterPlatformNodeDelegateMac::ConvertBoundsFromLocalToScreen(
96 const gfx::RectF& local_bounds) const {
97 // Converts to NSRect to use NSView rect conversion.
98 NSRect ns_local_bounds =
99 NSMakeRect(local_bounds.x(), local_bounds.y(), local_bounds.width(), local_bounds.height());
100 // The macOS XY coordinates start at bottom-left and increase toward top-right,
101 // which is different from the Flutter's XY coordinates that start at top-left
102 // increasing to bottom-right. Therefore, this method needs to flip the y coordinate when
103 // it converts the bounds from flutter coordinates to macOS coordinates.
104 ns_local_bounds.origin.y = -ns_local_bounds.origin.y - ns_local_bounds.size.height;
105
106 NSCAssert(view_controller_.viewLoaded, @"Flutter view must be loaded.");
107 NSRect ns_view_bounds = [view_controller_.flutterView convertRectFromBacking:ns_local_bounds];
108 NSRect ns_window_bounds = [view_controller_.flutterView convertRect:ns_view_bounds toView:nil];
109 NSRect ns_screen_bounds =
110 [[view_controller_.flutterView window] convertRectToScreen:ns_window_bounds];
111 gfx::RectF screen_bounds(ns_screen_bounds.origin.x, ns_screen_bounds.origin.y,
112 ns_screen_bounds.size.width, ns_screen_bounds.size.height);
113 return screen_bounds;
114}
115
116gfx::RectF FlutterPlatformNodeDelegateMac::ConvertBoundsFromScreenToGlobal(
117 const gfx::RectF& screen_bounds) const {
118 // The VoiceOver seems to only accept bounds that are relative to primary screen.
119 // Thus, this method uses [[NSScreen screens] firstObject] instead of [NSScreen mainScreen].
120 NSScreen* screen = [[NSScreen screens] firstObject];
121 NSRect primary_screen_bounds = [screen frame];
122 // The screen is flipped against y axis.
123 float flipped_y = primary_screen_bounds.size.height - screen_bounds.y() - screen_bounds.height();
124 return {screen_bounds.x(), flipped_y, screen_bounds.width(), screen_bounds.height()};
125}
126
127} // namespace flutter
gfx::NativeViewAccessible GetNativeViewAccessible() override
gfx::NativeViewAccessible GetParent() override
gfx::NativeViewAccessible GetNSWindow() override
FlutterPlatformNodeDelegateMac(std::weak_ptr< AccessibilityBridge > bridge, __weak FlutterViewController *view_controller)
gfx::Rect GetBoundsRect(const ui::AXCoordinateSystem coordinate_system, const ui::AXClippingBehavior clipping_behavior, ui::AXOffscreenResult *offscreen_result) const override
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 ...
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...
gfx::NativeViewAccessible GetParent() override
gfx::Rect GetBoundsRect(const ui::AXCoordinateSystem coordinate_system, const ui::AXClippingBehavior clipping_behavior, ui::AXOffscreenResult *offscreen_result) const override
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 ...
ui::AXNode * GetAXNode() const
Gets the underlying ax node for this platform node delegate.
const ui::AXNodeData & GetData() const override
The ax platform node for a text field.
constexpr float y() const
Definition: rect_f.h:50
constexpr float width() const
Definition: rect_f.h:53
constexpr float height() const
Definition: rect_f.h:56
constexpr const SizeF & size() const
Definition: rect_f.h:62
constexpr float x() const
Definition: rect_f.h:47
Definition: rect.h:36
constexpr float height() const
Definition: size_f.h:29
static AXPlatformNode * Create(AXPlatformNodeDelegate *delegate)
virtual gfx::NativeViewAccessible GetNativeViewAccessible()=0
virtual void Destroy()
GLFWwindow * window
Definition: main.cc:45
double frame
Definition: examples.cpp:31
IBOutlet NSWindow * mainFlutterWindow
std::u16string text
Rect ToEnclosingRect(const RectF &r)
UnimplementedNativeViewAccessible * NativeViewAccessible
Definition: ref_ptr.h:256
const std::string & GetStringAttribute(ax::mojom::StringAttribute attribute) const