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 | |
22 | namespace tonic { |
23 | class DartLibraryNatives; |
24 | |
25 | // So tonic::ToDart<std::vector<int64_t>> returns List<int> instead of |
26 | // List<dynamic>. |
27 | template <> |
28 | struct 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 | |
36 | namespace flutter { |
37 | class FontCollection; |
38 | class PlatformMessage; |
39 | class 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. |
46 | enum 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 | /// |
61 | class 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 | /// |
208 | class 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 | |