Flutter Engine
platform_view_ios.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/ios/platform_view_ios.h"
6 
7 #include <utility>
8 
9 #include "flutter/common/task_runners.h"
10 #include "flutter/fml/synchronization/waitable_event.h"
11 #include "flutter/fml/trace_event.h"
12 #include "flutter/shell/common/shell_io_manager.h"
13 #import "flutter/shell/platform/darwin/ios/framework/Source/FlutterViewController_Internal.h"
14 #import "flutter/shell/platform/darwin/ios/framework/Source/vsync_waiter_ios.h"
15 
16 namespace flutter {
17 
18 PlatformViewIOS::AccessibilityBridgePtr::AccessibilityBridgePtr(
19  const std::function<void(bool)>& set_semantics_enabled)
20  : AccessibilityBridgePtr(set_semantics_enabled, nullptr) {}
21 
22 PlatformViewIOS::AccessibilityBridgePtr::AccessibilityBridgePtr(
23  const std::function<void(bool)>& set_semantics_enabled,
24  AccessibilityBridge* bridge)
25  : accessibility_bridge_(bridge), set_semantics_enabled_(set_semantics_enabled) {
26  if (bridge) {
27  set_semantics_enabled_(true);
28  }
29 }
30 
31 PlatformViewIOS::AccessibilityBridgePtr::~AccessibilityBridgePtr() {
32  if (accessibility_bridge_) {
33  set_semantics_enabled_(false);
34  }
35 }
36 
37 void PlatformViewIOS::AccessibilityBridgePtr::reset(AccessibilityBridge* bridge) {
38  if (accessibility_bridge_) {
39  set_semantics_enabled_(false);
40  }
41  accessibility_bridge_.reset(bridge);
42  if (accessibility_bridge_) {
43  set_semantics_enabled_(true);
44  }
45 }
46 
48  IOSRenderingAPI rendering_api,
49  flutter::TaskRunners task_runners)
50  : PlatformView(delegate, std::move(task_runners)),
51  ios_context_(IOSContext::Create(rendering_api)),
52  accessibility_bridge_([this](bool enabled) { PlatformView::SetSemanticsEnabled(enabled); }) {}
53 
55 
57  return platform_message_router_;
58 }
59 
60 // |PlatformView|
61 void PlatformViewIOS::HandlePlatformMessage(fml::RefPtr<flutter::PlatformMessage> message) {
62  platform_message_router_.HandlePlatformMessage(std::move(message));
63 }
64 
66  return owner_controller_;
67 }
68 
71  std::lock_guard<std::mutex> guard(ios_surface_mutex_);
72  if (ios_surface_ || !owner_controller) {
74  ios_surface_.reset();
75  accessibility_bridge_.reset();
76  }
77  owner_controller_ = owner_controller;
78 
79  // Add an observer that will clear out the owner_controller_ ivar and
80  // the accessibility_bridge_ in case the view controller is deleted.
81  dealloc_view_controller_observer_.reset(
82  [[[NSNotificationCenter defaultCenter] addObserverForName:FlutterViewControllerWillDealloc
83  object:owner_controller_.get()
84  queue:[NSOperationQueue mainQueue]
85  usingBlock:^(NSNotification* note) {
86  // Implicit copy of 'this' is fine.
87  accessibility_bridge_.reset();
88  owner_controller_.reset();
89  }] retain]);
90 
91  if (owner_controller_ && [owner_controller_.get() isViewLoaded]) {
92  this->attachView();
93  }
94  // Do not call `NotifyCreated()` here - let FlutterViewController take care
95  // of that when its Viewport is sized. If `NotifyCreated()` is called here,
96  // it can occasionally get invoked before the viewport is sized resulting in
97  // a framebuffer that will not be able to completely attach.
98 }
99 
101  FML_DCHECK(owner_controller_);
102  FML_DCHECK(owner_controller_.get().isViewLoaded)
103  << "FlutterViewController's view should be loaded "
104  "before attaching to PlatformViewIOS.";
105  ios_surface_ =
106  [static_cast<FlutterView*>(owner_controller_.get().view) createSurface:ios_context_];
107  FML_DCHECK(ios_surface_ != nullptr);
108 
109  if (accessibility_bridge_) {
110  accessibility_bridge_.reset(new AccessibilityBridge(
111  owner_controller_.get(), this, [owner_controller_.get() platformViewsController]));
112  }
113 }
114 
116  return [](DefaultPointerDataDispatcher::Delegate& delegate) {
117  return std::make_unique<SmoothPointerDataDispatcher>(delegate);
118  };
119 }
120 
122  NSObject<FlutterTexture>* texture) {
123  RegisterTexture(ios_context_->CreateExternalTexture(
124  texture_id, fml::scoped_nsobject<NSObject<FlutterTexture>>{[texture retain]}));
125 }
126 
127 // |PlatformView|
128 std::unique_ptr<Surface> PlatformViewIOS::CreateRenderingSurface() {
130  std::lock_guard<std::mutex> guard(ios_surface_mutex_);
131  if (!ios_surface_) {
132  FML_DLOG(INFO) << "Could not CreateRenderingSurface, this PlatformViewIOS "
133  "has no ViewController.";
134  return nullptr;
135  }
136  return ios_surface_->CreateGPUSurface();
137 }
138 
139 // |PlatformView|
140 sk_sp<GrDirectContext> PlatformViewIOS::CreateResourceContext() const {
141  return ios_context_->CreateResourceContext();
142 }
143 
144 // |PlatformView|
146  if (!owner_controller_) {
147  FML_LOG(WARNING) << "Could not set semantics to enabled, this "
148  "PlatformViewIOS has no ViewController.";
149  return;
150  }
151  if (enabled && !accessibility_bridge_) {
152  accessibility_bridge_.reset(new AccessibilityBridge(
153  owner_controller_.get(), this, [owner_controller_.get() platformViewsController]));
154  } else if (!enabled && accessibility_bridge_) {
155  accessibility_bridge_.reset();
156  } else {
158  }
159 }
160 
161 // |shell:PlatformView|
162 void PlatformViewIOS::SetAccessibilityFeatures(int32_t flags) {
164 }
165 
166 // |PlatformView|
167 void PlatformViewIOS::UpdateSemantics(flutter::SemanticsNodeUpdates update,
169  FML_DCHECK(owner_controller_);
170  if (accessibility_bridge_) {
171  accessibility_bridge_->UpdateSemantics(std::move(update), std::move(actions));
172  [[NSNotificationCenter defaultCenter] postNotificationName:FlutterSemanticsUpdateNotification
173  object:owner_controller_.get()];
174  }
175 }
176 
177 // |PlatformView|
178 std::unique_ptr<VsyncWaiter> PlatformViewIOS::CreateVSyncWaiter() {
179  return std::make_unique<VsyncWaiterIOS>(task_runners_);
180 }
181 
182 void PlatformViewIOS::OnPreEngineRestart() const {
183  if (accessibility_bridge_) {
184  accessibility_bridge_->clearState();
185  }
186  if (!owner_controller_) {
187  return;
188  }
189  [owner_controller_.get() platformViewsController]->Reset();
190 }
191 
192 std::unique_ptr<std::vector<std::string>> PlatformViewIOS::ComputePlatformResolvedLocales(
193  const std::vector<std::string>& supported_locale_data) {
194  size_t localeDataLength = 3;
195  NSMutableArray<NSString*>* supported_locale_identifiers =
196  [NSMutableArray arrayWithCapacity:supported_locale_data.size() / localeDataLength];
197  for (size_t i = 0; i < supported_locale_data.size(); i += localeDataLength) {
198  NSDictionary<NSString*, NSString*>* dict = @{
199  NSLocaleLanguageCode : [NSString stringWithUTF8String:supported_locale_data[i].c_str()],
200  NSLocaleCountryCode : [NSString stringWithUTF8String:supported_locale_data[i + 1].c_str()],
201  NSLocaleScriptCode : [NSString stringWithUTF8String:supported_locale_data[i + 2].c_str()]
202  };
203  [supported_locale_identifiers addObject:[NSLocale localeIdentifierFromComponents:dict]];
204  }
205  NSArray<NSString*>* result =
206  [NSBundle preferredLocalizationsFromArray:supported_locale_identifiers];
207 
208  // Output format should be either empty or 3 strings for language, country, and script.
209  std::unique_ptr<std::vector<std::string>> out = std::make_unique<std::vector<std::string>>();
210 
211  if (result != nullptr && [result count] > 0) {
212  if (@available(ios 10.0, *)) {
213  NSLocale* locale = [NSLocale localeWithLocaleIdentifier:[result firstObject]];
214  NSString* languageCode = [locale languageCode];
215  out->emplace_back(languageCode == nullptr ? "" : languageCode.UTF8String);
216  NSString* countryCode = [locale countryCode];
217  out->emplace_back(countryCode == nullptr ? "" : countryCode.UTF8String);
218  NSString* scriptCode = [locale scriptCode];
219  out->emplace_back(scriptCode == nullptr ? "" : scriptCode.UTF8String);
220  }
221  }
222  return out;
223 }
224 
225 PlatformViewIOS::ScopedObserver::ScopedObserver() : observer_(nil) {}
226 
227 PlatformViewIOS::ScopedObserver::~ScopedObserver() {
228  if (observer_) {
229  [[NSNotificationCenter defaultCenter] removeObserver:observer_];
230  [observer_ release];
231  }
232 }
233 
234 void PlatformViewIOS::ScopedObserver::reset(id<NSObject> observer) {
235  if (observer != observer_) {
236  if (observer_) {
237  [[NSNotificationCenter defaultCenter] removeObserver:observer_];
238  [observer_ release];
239  }
240  observer_ = observer;
241  }
242 }
243 
244 } // namespace flutter
#define FML_DCHECK(condition)
Definition: logging.h:86
const TaskRunners task_runners_
FLUTTER_EXPORT NSNotificationName const FlutterSemanticsUpdateNotification
virtual void SetAccessibilityFeatures(int32_t flags)
Used by the embedder to specify the features to enable in the accessibility tree generated by the iso...
void RegisterExternalTexture(int64_t id, NSObject< FlutterTexture > *texture)
Definition: ref_ptr.h:252
Dart_NativeFunction function
Definition: fuchsia.cc:51
The interface for Engine to implement.
fml::RefPtr< fml::TaskRunner > GetPlatformTaskRunner() const
Definition: task_runners.cc:30
std::unordered_map< int32_t, SemanticsNode > SemanticsNodeUpdates
#define FML_LOG(severity)
Definition: logging.h:65
std::function< std::unique_ptr< PointerDataDispatcher >(PointerDataDispatcher::Delegate &)> PointerDataDispatcherMaker
Signature for constructing PointerDataDispatcher.
Manages the lifetime of the on-screen and off-screen rendering contexts on iOS. On-screen contexts ar...
Definition: ios_context.h:33
fml::RefPtr< fml::TaskRunner > GetRasterTaskRunner() const
Definition: task_runners.cc:42
Platform views are created by the shell on the platform task runner. Unless explicitly specified...
Definition: platform_view.h:44
void HandlePlatformMessage(fml::RefPtr< flutter::PlatformMessage > message) const
PointerDataDispatcherMaker GetDispatcherMaker() override
Returns a platform-specific PointerDataDispatcherMaker so the Engine can construct the PointerDataPac...
PlatformMessageRouter & GetPlatformMessageRouter()
virtual void SetSemanticsEnabled(bool enabled)
Used by embedder to notify the running isolate hosted by the engine on the UI thread that the accessi...
void SetSemanticsEnabled(bool enabled) override
Used by embedder to notify the running isolate hosted by the engine on the UI thread that the accessi...
virtual void NotifyDestroyed()
Used by embedders to notify the shell that the platform view has been destroyed. This notification us...
void RegisterTexture(std::shared_ptr< flutter::Texture > texture)
Used by the embedder to specify a texture that it wants the rasterizer to composite within the Flutte...
NSNotificationName const FlutterViewControllerWillDealloc
virtual bool RunsTasksOnCurrentThread()
Definition: task_runner.cc:43
#define FML_DLOG(severity)
Definition: logging.h:85
std::unordered_map< int32_t, CustomAccessibilityAction > CustomAccessibilityActionUpdates
fml::WeakPtr< FlutterViewController > GetOwnerViewController() const
Used to forward events from the platform view to interested subsystems. This forwarding is done by th...
Definition: platform_view.h:51
void SetOwnerViewController(fml::WeakPtr< FlutterViewController > owner_controller)
PlatformViewIOS(PlatformView::Delegate &delegate, IOSRenderingAPI rendering_api, flutter::TaskRunners task_runners)
DEF_SWITCHES_START snapshot asset Path to the directory containing the four files specified by VmSnapshotInstructions and IsolateSnapshotInstructions vm snapshot The VM instructions snapshot that will be memory mapped as read and executable SnapshotAssetPath must be present isolate snapshot The isolate instructions snapshot that will be memory mapped as read and executable SnapshotAssetPath must be present icu symbol Prefix for the symbols representing ICU data linked into the Flutter library dart flags
Definition: switches.h:66