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 #include <memory>
7 
8 #include <utility>
9 
10 #include "flutter/common/task_runners.h"
11 #include "flutter/fml/synchronization/waitable_event.h"
12 #include "flutter/fml/trace_event.h"
13 #include "flutter/shell/common/shell_io_manager.h"
14 #import "flutter/shell/platform/darwin/ios/framework/Source/FlutterViewController_Internal.h"
15 #import "flutter/shell/platform/darwin/ios/framework/Source/vsync_waiter_ios.h"
16 
17 namespace flutter {
18 
19 PlatformViewIOS::AccessibilityBridgePtr::AccessibilityBridgePtr(
20  const std::function<void(bool)>& set_semantics_enabled)
21  : AccessibilityBridgePtr(set_semantics_enabled, nullptr) {}
22 
23 PlatformViewIOS::AccessibilityBridgePtr::AccessibilityBridgePtr(
24  const std::function<void(bool)>& set_semantics_enabled,
25  AccessibilityBridge* bridge)
26  : accessibility_bridge_(bridge), set_semantics_enabled_(set_semantics_enabled) {
27  if (bridge) {
28  set_semantics_enabled_(true);
29  }
30 }
31 
32 PlatformViewIOS::AccessibilityBridgePtr::~AccessibilityBridgePtr() {
33  if (accessibility_bridge_) {
34  set_semantics_enabled_(false);
35  }
36 }
37 
38 void PlatformViewIOS::AccessibilityBridgePtr::reset(AccessibilityBridge* bridge) {
39  if (accessibility_bridge_) {
40  set_semantics_enabled_(false);
41  }
42  accessibility_bridge_.reset(bridge);
43  if (accessibility_bridge_) {
44  set_semantics_enabled_(true);
45  }
46 }
47 
49  PlatformView::Delegate& delegate,
50  const std::shared_ptr<IOSContext>& context,
51  const std::shared_ptr<FlutterPlatformViewsController>& platform_views_controller,
52  flutter::TaskRunners task_runners)
53  : PlatformView(delegate, std::move(task_runners)),
54  ios_context_(context),
55  platform_views_controller_(platform_views_controller),
56  accessibility_bridge_([this](bool enabled) { PlatformView::SetSemanticsEnabled(enabled); }) {}
57 
59  PlatformView::Delegate& delegate,
60  IOSRenderingAPI rendering_api,
61  const std::shared_ptr<FlutterPlatformViewsController>& platform_views_controller,
62  flutter::TaskRunners task_runners)
63  : PlatformViewIOS(delegate,
64  IOSContext::Create(rendering_api),
65  platform_views_controller,
66  task_runners) {}
67 
69 
71  return platform_message_router_;
72 }
73 
74 // |PlatformView|
75 void PlatformViewIOS::HandlePlatformMessage(std::unique_ptr<flutter::PlatformMessage> message) {
76  platform_message_router_.HandlePlatformMessage(std::move(message));
77 }
78 
80  return owner_controller_;
81 }
82 
85  std::lock_guard<std::mutex> guard(ios_surface_mutex_);
86  if (ios_surface_ || !owner_controller) {
88  ios_surface_.reset();
89  accessibility_bridge_.reset();
90  }
91  owner_controller_ = owner_controller;
92 
93  // Add an observer that will clear out the owner_controller_ ivar and
94  // the accessibility_bridge_ in case the view controller is deleted.
95  dealloc_view_controller_observer_.reset(
96  [[[NSNotificationCenter defaultCenter] addObserverForName:FlutterViewControllerWillDealloc
97  object:owner_controller_.get()
98  queue:[NSOperationQueue mainQueue]
99  usingBlock:^(NSNotification* note) {
100  // Implicit copy of 'this' is fine.
101  accessibility_bridge_.reset();
102  owner_controller_.reset();
103  }] retain]);
104 
105  if (owner_controller_ && [owner_controller_.get() isViewLoaded]) {
106  this->attachView();
107  }
108  // Do not call `NotifyCreated()` here - let FlutterViewController take care
109  // of that when its Viewport is sized. If `NotifyCreated()` is called here,
110  // it can occasionally get invoked before the viewport is sized resulting in
111  // a framebuffer that will not be able to completely attach.
112 }
113 
115  FML_DCHECK(owner_controller_);
116  FML_DCHECK(owner_controller_.get().isViewLoaded)
117  << "FlutterViewController's view should be loaded "
118  "before attaching to PlatformViewIOS.";
119  auto flutter_view = static_cast<FlutterView*>(owner_controller_.get().view);
120  auto ca_layer = fml::scoped_nsobject<CALayer>{[[flutter_view layer] retain]};
121  ios_surface_ = IOSSurface::Create(ios_context_, ca_layer);
122  FML_DCHECK(ios_surface_ != nullptr);
123 
124  if (accessibility_bridge_) {
125  accessibility_bridge_.reset(new AccessibilityBridge(
126  owner_controller_.get(), this, [owner_controller_.get() platformViewsController]));
127  }
128 }
129 
131  return [](DefaultPointerDataDispatcher::Delegate& delegate) {
132  return std::make_unique<SmoothPointerDataDispatcher>(delegate);
133  };
134 }
135 
137  NSObject<FlutterTexture>* texture) {
138  RegisterTexture(ios_context_->CreateExternalTexture(
139  texture_id, fml::scoped_nsobject<NSObject<FlutterTexture>>{[texture retain]}));
140 }
141 
142 // |PlatformView|
143 std::unique_ptr<Surface> PlatformViewIOS::CreateRenderingSurface() {
145  std::lock_guard<std::mutex> guard(ios_surface_mutex_);
146  if (!ios_surface_) {
147  FML_DLOG(INFO) << "Could not CreateRenderingSurface, this PlatformViewIOS "
148  "has no ViewController.";
149  return nullptr;
150  }
151  return ios_surface_->CreateGPUSurface(ios_context_->GetMainContext().get());
152 }
153 
154 // |PlatformView|
155 std::shared_ptr<ExternalViewEmbedder> PlatformViewIOS::CreateExternalViewEmbedder() {
156  return std::make_shared<IOSExternalViewEmbedder>(platform_views_controller_, ios_context_);
157 }
158 
159 // |PlatformView|
160 sk_sp<GrDirectContext> PlatformViewIOS::CreateResourceContext() const {
161  return ios_context_->CreateResourceContext();
162 }
163 
164 // |PlatformView|
166  if (!owner_controller_) {
167  FML_LOG(WARNING) << "Could not set semantics to enabled, this "
168  "PlatformViewIOS has no ViewController.";
169  return;
170  }
171  if (enabled && !accessibility_bridge_) {
172  accessibility_bridge_.reset(new AccessibilityBridge(
173  owner_controller_.get(), this, [owner_controller_.get() platformViewsController]));
174  } else if (!enabled && accessibility_bridge_) {
175  accessibility_bridge_.reset();
176  } else {
178  }
179 }
180 
181 // |shell:PlatformView|
182 void PlatformViewIOS::SetAccessibilityFeatures(int32_t flags) {
184 }
185 
186 // |PlatformView|
187 void PlatformViewIOS::UpdateSemantics(flutter::SemanticsNodeUpdates update,
189  FML_DCHECK(owner_controller_);
190  if (accessibility_bridge_) {
191  accessibility_bridge_->UpdateSemantics(std::move(update), std::move(actions));
192  [[NSNotificationCenter defaultCenter] postNotificationName:FlutterSemanticsUpdateNotification
193  object:owner_controller_.get()];
194  }
195 }
196 
197 // |PlatformView|
198 std::unique_ptr<VsyncWaiter> PlatformViewIOS::CreateVSyncWaiter() {
199  return std::make_unique<VsyncWaiterIOS>(task_runners_);
200 }
201 
202 void PlatformViewIOS::OnPreEngineRestart() const {
203  if (accessibility_bridge_) {
204  accessibility_bridge_->clearState();
205  }
206  if (!owner_controller_) {
207  return;
208  }
209  [owner_controller_.get() platformViewsController]->Reset();
210  [[owner_controller_.get() restorationPlugin] reset];
211 }
212 
213 std::unique_ptr<std::vector<std::string>> PlatformViewIOS::ComputePlatformResolvedLocales(
214  const std::vector<std::string>& supported_locale_data) {
215  size_t localeDataLength = 3;
216  NSMutableArray<NSString*>* supported_locale_identifiers =
217  [NSMutableArray arrayWithCapacity:supported_locale_data.size() / localeDataLength];
218  for (size_t i = 0; i < supported_locale_data.size(); i += localeDataLength) {
219  NSDictionary<NSString*, NSString*>* dict = @{
220  NSLocaleLanguageCode : [NSString stringWithUTF8String:supported_locale_data[i].c_str()],
221  NSLocaleCountryCode : [NSString stringWithUTF8String:supported_locale_data[i + 1].c_str()],
222  NSLocaleScriptCode : [NSString stringWithUTF8String:supported_locale_data[i + 2].c_str()]
223  };
224  [supported_locale_identifiers addObject:[NSLocale localeIdentifierFromComponents:dict]];
225  }
226  NSArray<NSString*>* result =
227  [NSBundle preferredLocalizationsFromArray:supported_locale_identifiers];
228 
229  // Output format should be either empty or 3 strings for language, country, and script.
230  std::unique_ptr<std::vector<std::string>> out = std::make_unique<std::vector<std::string>>();
231 
232  if (result != nullptr && [result count] > 0) {
233  if (@available(ios 10.0, *)) {
234  NSLocale* locale = [NSLocale localeWithLocaleIdentifier:[result firstObject]];
235  NSString* languageCode = [locale languageCode];
236  out->emplace_back(languageCode == nullptr ? "" : languageCode.UTF8String);
237  NSString* countryCode = [locale countryCode];
238  out->emplace_back(countryCode == nullptr ? "" : countryCode.UTF8String);
239  NSString* scriptCode = [locale scriptCode];
240  out->emplace_back(scriptCode == nullptr ? "" : scriptCode.UTF8String);
241  }
242  }
243  return out;
244 }
245 
246 PlatformViewIOS::ScopedObserver::ScopedObserver() : observer_(nil) {}
247 
248 PlatformViewIOS::ScopedObserver::~ScopedObserver() {
249  if (observer_) {
250  [[NSNotificationCenter defaultCenter] removeObserver:observer_];
251  [observer_ release];
252  }
253 }
254 
255 void PlatformViewIOS::ScopedObserver::reset(id<NSObject> observer) {
256  if (observer != observer_) {
257  if (observer_) {
258  [[NSNotificationCenter defaultCenter] removeObserver:observer_];
259  [observer_ release];
260  }
261  observer_ = observer;
262  }
263 }
264 
265 } // namespace flutter
G_BEGIN_DECLS FlTexture * texture
#define FML_DCHECK(condition)
Definition: logging.h:86
const TaskRunners task_runners_
virtual void SetAccessibilityFeatures(int32_t flags)
Used by the embedder to specify the features to enable in the accessibility tree generated by the iso...
NSNotificationName const FlutterViewControllerWillDealloc
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
int64_t texture_id
GAsyncResult * result
FLUTTER_DARWIN_EXPORT NSNotificationName const FlutterSemanticsUpdateNotification
#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:47
void HandlePlatformMessage(std::unique_ptr< 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...
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
static std::unique_ptr< IOSSurface > Create(std::shared_ptr< IOSContext > context, fml::scoped_nsobject< CALayer > layer)
Definition: ios_surface.mm:18
Used to forward events from the platform view to interested subsystems. This forwarding is done by th...
Definition: platform_view.h:54
void SetOwnerViewController(fml::WeakPtr< FlutterViewController > owner_controller)
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
PlatformViewIOS(PlatformView::Delegate &delegate, const std::shared_ptr< IOSContext > &context, const std::shared_ptr< FlutterPlatformViewsController > &platform_views_controller, flutter::TaskRunners task_runners)