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#ifndef FLUTTER_LIB_UI_WINDOW_PLATFORM_CONFIGURATION_H_
6#define FLUTTER_LIB_UI_WINDOW_PLATFORM_CONFIGURATION_H_
7
8#include <memory>
9#include <set>
10#include <string>
11#include <unordered_map>
12#include <vector>
13
14#include "flutter/fml/time/time_point.h"
15#include "flutter/lib/ui/semantics/semantics_update.h"
16#include "flutter/lib/ui/window/platform_message.h"
17#include "flutter/lib/ui/window/pointer_data_packet.h"
18#include "flutter/lib/ui/window/viewport_metrics.h"
19#include "flutter/lib/ui/window/window.h"
20#include "third_party/tonic/dart_persistent_value.h"
21
22namespace tonic {
23class DartLibraryNatives;
24
25// So tonic::ToDart<std::vector<int64_t>> returns List<int> instead of
26// List<dynamic>.
27template <>
28struct DartListFactory<int64_t> {
29 static Dart_Handle NewList(intptr_t length) {
30 return Dart_NewListOf(Dart_CoreType_Int, length);
31 }
32};
33
34} // namespace tonic
35
36namespace flutter {
37class FontCollection;
38class PlatformMessage;
39class Scene;
40
41//--------------------------------------------------------------------------
42/// @brief An enum for defining the different kinds of accessibility features
43/// that can be enabled by the platform.
44///
45/// Must match the `AccessibilityFeatureFlag` enum in framework.
46enum class AccessibilityFeatureFlag : int32_t {
47 kAccessibleNavigation = 1 << 0,
48 kInvertColors = 1 << 1,
49 kDisableAnimations = 1 << 2,
50 kBoldText = 1 << 3,
51 kReduceMotion = 1 << 4,
52 kHighContrast = 1 << 5,
53};
54
55//--------------------------------------------------------------------------
56/// @brief A client interface that the `RuntimeController` uses to define
57/// handlers for `PlatformConfiguration` requests.
58///
59/// @see `PlatformConfiguration`
60///
61class PlatformConfigurationClient {
62 public:
63 //--------------------------------------------------------------------------
64 /// @brief The route or path that the embedder requested when the
65 /// application was launched.
66 ///
67 /// This will be the string "`/`" if no particular route was
68 /// requested.
69 ///
70 virtual std::string DefaultRouteName() = 0;
71
72 //--------------------------------------------------------------------------
73 /// @brief Requests that, at the next appropriate opportunity, a new
74 /// frame be scheduled for rendering.
75 ///
76 virtual void ScheduleFrame() = 0;
77
78 //--------------------------------------------------------------------------
79 /// @brief Updates the client's rendering on the GPU with the newly
80 /// provided Scene.
81 ///
82 virtual void Render(Scene* scene) = 0;
83
84 //--------------------------------------------------------------------------
85 /// @brief Receives a updated semantics tree from the Framework.
86 ///
87 /// @param[in] update The updated semantic tree to apply.
88 ///
89 virtual void UpdateSemantics(SemanticsUpdate* update) = 0;
90
91 //--------------------------------------------------------------------------
92 /// @brief When the Flutter application has a message to send to the
93 /// underlying platform, the message needs to be forwarded to
94 /// the platform on the appropriate thread (via the platform
95 /// task runner). The PlatformConfiguration delegates this task
96 /// to the engine via this method.
97 ///
98 /// @see `PlatformView::HandlePlatformMessage`
99 ///
100 /// @param[in] message The message from the Flutter application to send to
101 /// the underlying platform.
102 ///
103 virtual void HandlePlatformMessage(fml::RefPtr<PlatformMessage> message) = 0;
104
105 //--------------------------------------------------------------------------
106 /// @brief Returns the current collection of fonts available on the
107 /// platform.
108 ///
109 /// This function reads an XML file and makes font families and
110 /// collections of them. MinikinFontForTest is used for FontFamily
111 /// creation.
112 virtual FontCollection& GetFontCollection() = 0;
113
114 //--------------------------------------------------------------------------
115 /// @brief Notifies this client of the name of the root isolate and its
116 /// port when that isolate is launched, restarted (in the
117 /// cold-restart scenario) or the application itself updates the
118 /// name of the root isolate (via `Window.setIsolateDebugName`
119 /// in `window.dart`). The name of the isolate is meaningless to
120 /// the engine but is used in instrumentation and tooling.
121 /// Currently, this information is to update the service
122 /// protocol list of available root isolates running in the VM
123 /// and their names so that the appropriate isolate can be
124 /// selected in the tools for debugging and instrumentation.
125 ///
126 /// @param[in] isolate_name The isolate name
127 /// @param[in] isolate_port The isolate port
128 ///
129 virtual void UpdateIsolateDescription(const std::string isolate_name,
130 int64_t isolate_port) = 0;
131
132 //--------------------------------------------------------------------------
133 /// @brief Notifies this client that the application has an opinion about
134 /// whether its frame timings need to be reported backed to it.
135 /// Due to the asynchronous nature of rendering in Flutter, it is
136 /// not possible for the application to determine the total time
137 /// it took to render a specific frame. While the layer-tree is
138 /// constructed on the UI thread, it needs to be rendering on the
139 /// raster thread. Dart code cannot execute on this thread. So any
140 /// instrumentation about the frame times gathered on this thread
141 /// needs to be aggregated and sent back to the UI thread for
142 /// processing in Dart.
143 ///
144 /// When the application indicates that frame times need to be
145 /// reported, it collects this information till a specified number
146 /// of data points are gathered. Then this information is sent
147 /// back to Dart code via `Engine::ReportTimings`.
148 ///
149 /// This option is engine counterpart of the
150 /// `Window._setNeedsReportTimings` in `window.dart`.
151 ///
152 /// @param[in] needs_reporting If reporting information should be collected
153 /// and send back to Dart.
154 ///
155 virtual void SetNeedsReportTimings(bool value) = 0;
156
157 //--------------------------------------------------------------------------
158 /// @brief The embedder can specify data that the isolate can request
159 /// synchronously on launch. This accessor fetches that data.
160 ///
161 /// This data is persistent for the duration of the Flutter
162 /// application and is available even after isolate restarts.
163 /// Because of this lifecycle, the size of this data must be kept
164 /// to a minimum.
165 ///
166 /// For asynchronous communication between the embedder and
167 /// isolate, a platform channel may be used.
168 ///
169 /// @return A map of the isolate data that the framework can request upon
170 /// launch.
171 ///
172 virtual std::shared_ptr<const fml::Mapping> GetPersistentIsolateData() = 0;
173
174 //--------------------------------------------------------------------------
175 /// @brief Directly invokes platform-specific APIs to compute the
176 /// locale the platform would have natively resolved to.
177 ///
178 /// @param[in] supported_locale_data The vector of strings that represents
179 /// the locales supported by the app.
180 /// Each locale consists of three
181 /// strings: languageCode, countryCode,
182 /// and scriptCode in that order.
183 ///
184 /// @return A vector of 3 strings languageCode, countryCode, and
185 /// scriptCode that represents the locale selected by the
186 /// platform. Empty strings mean the value was unassigned. Empty
187 /// vector represents a null locale.
188 ///
189 virtual std::unique_ptr<std::vector<std::string>>
190 ComputePlatformResolvedLocale(
191 const std::vector<std::string>& supported_locale_data) = 0;
192
193 protected:
194 virtual ~PlatformConfigurationClient();
195};
196
197//----------------------------------------------------------------------------
198/// @brief A class for holding and distributing platform-level information
199/// to and from the Dart code in Flutter's framework.
200///
201/// It handles communication between the engine and the framework,
202/// and owns the main window.
203///
204/// It communicates with the RuntimeController through the use of a
205/// PlatformConfigurationClient interface, which the
206/// RuntimeController defines.
207///
208class PlatformConfiguration final {
209 public:
210 //----------------------------------------------------------------------------
211 /// @brief Creates a new PlatformConfiguration, typically created by the
212 /// RuntimeController.
213 ///
214 /// @param[in] client The `PlatformConfigurationClient` to be injected into
215 /// the PlatformConfiguration. This client is used to
216 /// forward requests to the RuntimeController.
217 ///
218 explicit PlatformConfiguration(PlatformConfigurationClient* client);
219
220 // PlatformConfiguration is not copyable.
221 PlatformConfiguration(const PlatformConfiguration&) = delete;
222 PlatformConfiguration& operator=(const PlatformConfiguration&) = delete;
223
224 ~PlatformConfiguration();
225
226 //----------------------------------------------------------------------------
227 /// @brief Access to the platform configuration client (which typically
228 /// is implemented by the RuntimeController).
229 ///
230 /// @return Returns the client used to construct this
231 /// PlatformConfiguration.
232 ///
233 PlatformConfigurationClient* client() const { return client_; }
234
235 //----------------------------------------------------------------------------
236 /// @brief Called by the RuntimeController once it has created the root
237 /// isolate, so that the PlatformController can get a handle to
238 /// the 'dart:ui' library.
239 ///
240 /// It uses the handle to call the hooks in hooks.dart.
241 ///
242 void DidCreateIsolate();
243
244 //----------------------------------------------------------------------------
245 /// @brief Update the specified locale data in the framework.
246 ///
247 /// @deprecated The persistent isolate data must be used for this purpose
248 /// instead.
249 ///
250 /// @param[in] locale_data The locale data. This should consist of groups of
251 /// 4 strings, each group representing a single locale.
252 ///
253 void UpdateLocales(const std::vector<std::string>& locales);
254
255 //----------------------------------------------------------------------------
256 /// @brief Update the user settings data in the framework.
257 ///
258 /// @deprecated The persistent isolate data must be used for this purpose
259 /// instead.
260 ///
261 /// @param[in] data The user settings data.
262 ///
263 void UpdateUserSettingsData(const std::string& data);
264
265 //----------------------------------------------------------------------------
266 /// @brief Updates the lifecycle state data in the framework.
267 ///
268 /// @deprecated The persistent isolate data must be used for this purpose
269 /// instead.
270 ///
271 /// @param[in] data The lifecycle state data.
272 ///
273 void UpdateLifecycleState(const std::string& data);
274
275 //----------------------------------------------------------------------------
276 /// @brief Notifies the PlatformConfiguration that the embedder has
277 /// expressed an opinion about whether the accessibility tree
278 /// should be generated or not. This call originates in the
279 /// platform view and is forwarded to the PlatformConfiguration
280 /// here by the engine.
281 ///
282 /// @param[in] enabled Whether the accessibility tree is enabled or
283 /// disabled.
284 ///
285 void UpdateSemanticsEnabled(bool enabled);
286
287 //----------------------------------------------------------------------------
288 /// @brief Forward the preference of accessibility features that must be
289 /// enabled in the semantics tree to the framwork.
290 ///
291 /// @param[in] flags The accessibility features that must be generated in
292 /// the semantics tree.
293 ///
294 void UpdateAccessibilityFeatures(int32_t flags);
295
296 //----------------------------------------------------------------------------
297 /// @brief Notifies the PlatformConfiguration that the client has sent
298 /// it a message. This call originates in the platform view and
299 /// has been forwarded through the engine to here.
300 ///
301 /// @param[in] message The message sent from the embedder to the Dart
302 /// application.
303 ///
304 void DispatchPlatformMessage(fml::RefPtr<PlatformMessage> message);
305
306 //----------------------------------------------------------------------------
307 /// @brief Notifies the framework that the embedder encountered an
308 /// accessibility related action on the specified node. This call
309 /// originates on the platform view and has been forwarded to the
310 /// platform configuration here by the engine.
311 ///
312 /// @param[in] id The identifier of the accessibility node.
313 /// @param[in] action The accessibility related action performed on the
314 /// node of the specified ID.
315 /// @param[in] args Optional data that applies to the specified action.
316 ///
317 void DispatchSemanticsAction(int32_t id,
318 SemanticsAction action,
319 std::vector<uint8_t> args);
320
321 //----------------------------------------------------------------------------
322 /// @brief Notifies the framework that it is time to begin working on a
323 /// new
324 /// frame previously scheduled via a call to
325 /// `PlatformConfigurationClient::ScheduleFrame`. This call
326 /// originates in the animator.
327 ///
328 /// The frame time given as the argument indicates the point at
329 /// which the current frame interval began. It is very slightly
330 /// (because of scheduling overhead) in the past. If a new layer
331 /// tree is not produced and given to the GPU task runner within
332 /// one frame interval from this point, the Flutter application
333 /// will jank.
334 ///
335 /// This method calls the `::_beginFrame` method in `hooks.dart`.
336 ///
337 /// @param[in] frame_time The point at which the current frame interval
338 /// began. May be used by animation interpolators,
339 /// physics simulations, etc..
340 ///
341 void BeginFrame(fml::TimePoint frame_time);
342
343 //----------------------------------------------------------------------------
344 /// @brief Dart code cannot fully measure the time it takes for a
345 /// specific frame to be rendered. This is because Dart code only
346 /// runs on the UI task runner. That is only a small part of the
347 /// overall frame workload. The GPU task runner frame workload is
348 /// executed on a thread where Dart code cannot run (and hence
349 /// instrument). Besides, due to the pipelined nature of rendering
350 /// in Flutter, there may be multiple frame workloads being
351 /// processed at any given time. However, for non-Timeline based
352 /// profiling, it is useful for trace collection and processing to
353 /// happen in Dart. To do this, the GPU task runner frame
354 /// workloads need to be instrumented separately. After a set
355 /// number of these profiles have been gathered, they need to be
356 /// reported back to Dart code. The engine reports this extra
357 /// instrumentation information back to the framework by invoking
358 /// this method at predefined intervals.
359 ///
360 /// @see `FrameTiming`
361 ///
362 /// @param[in] timings Collection of `FrameTiming::kCount` * `n` timestamps
363 /// for `n` frames whose timings have not been reported
364 /// yet. A collection of integers is reported here for
365 /// easier conversions to Dart objects. The timestamps
366 /// are measured against the system monotonic clock
367 /// measured in microseconds.
368 ///
369 void ReportTimings(std::vector<int64_t> timings);
370
371 //----------------------------------------------------------------------------
372 /// @brief Registers the native handlers for Dart functions that this
373 /// class handles.
374 ///
375 /// @param[in] natives The natives registry that the functions will be
376 /// registered with.
377 ///
378 static void RegisterNatives(tonic::DartLibraryNatives* natives);
379
380 //----------------------------------------------------------------------------
381 /// @brief Retrieves the Window managed by the PlatformConfiguration.
382 ///
383 /// @return a pointer to the Window.
384 ///
385 Window* window() const { return window_.get(); }
386
387 //----------------------------------------------------------------------------
388 /// @brief Responds to a previous platform message to the engine from the
389 /// framework.
390 ///
391 /// @param[in] response_id The unique id that identifies the original platform
392 /// message to respond to.
393 /// @param[in] data The data to send back in the response.
394 ///
395 void CompletePlatformMessageResponse(int response_id,
396 std::vector<uint8_t> data);
397
398 //----------------------------------------------------------------------------
399 /// @brief Responds to a previous platform message to the engine from the
400 /// framework with an empty response.
401 ///
402 /// @param[in] response_id The unique id that identifies the original platform
403 /// message to respond to.
404 ///
405 void CompletePlatformMessageEmptyResponse(int response_id);
406
407 private:
408 PlatformConfigurationClient* client_;
409 tonic::DartPersistentValue library_;
410
411 std::unique_ptr<Window> window_;
412
413 // We use id 0 to mean that no response is expected.
414 int next_response_id_ = 1;
415 std::unordered_map<int, fml::RefPtr<PlatformMessageResponse>>
416 pending_responses_;
417};
418
419} // namespace flutter
420
421#endif // FLUTTER_LIB_UI_WINDOW_PLATFORM_CONFIGURATION_H_
422