| // Copyright 2013 The Flutter Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| #ifndef FLUTTER_LIB_UI_WINDOW_PLATFORM_CONFIGURATION_H_ | |
| #define FLUTTER_LIB_UI_WINDOW_PLATFORM_CONFIGURATION_H_ | |
| #include <functional> | |
| #include <memory> | |
| #include <string> | |
| #include <unordered_map> | |
| #include <vector> | |
| #include "flutter/assets/asset_manager.h" | |
| #include "flutter/fml/time/time_point.h" | |
| #include "flutter/lib/ui/semantics/semantics_update.h" | |
| #include "flutter/lib/ui/window/pointer_data_packet.h" | |
| #include "flutter/lib/ui/window/viewport_metrics.h" | |
| #include "flutter/lib/ui/window/window.h" | |
| #include "third_party/tonic/dart_persistent_value.h" | |
| #include "third_party/tonic/typed_data/dart_byte_data.h" | |
| namespace flutter { | |
| class FontCollection; | |
| class PlatformMessage; | |
| class PlatformMessageHandler; | |
| class Scene; | |
| //-------------------------------------------------------------------------- | |
| /// @brief An enum for defining the different kinds of accessibility features | |
| /// that can be enabled by the platform. | |
| /// | |
| /// Must match the `AccessibilityFeatureFlag` enum in framework. | |
| enum class AccessibilityFeatureFlag : int32_t { | |
| kAccessibleNavigation = 1 << 0, | |
| kInvertColors = 1 << 1, | |
| kDisableAnimations = 1 << 2, | |
| kBoldText = 1 << 3, | |
| kReduceMotion = 1 << 4, | |
| kHighContrast = 1 << 5, | |
| kOnOffSwitchLabels = 1 << 6, | |
| }; | |
| //-------------------------------------------------------------------------- | |
| /// @brief A client interface that the `RuntimeController` uses to define | |
| /// handlers for `PlatformConfiguration` requests. | |
| /// | |
| /// @see `PlatformConfiguration` | |
| /// | |
| class PlatformConfigurationClient { | |
| public: | |
| //-------------------------------------------------------------------------- | |
| /// @brief The route or path that the embedder requested when the | |
| /// application was launched. | |
| /// | |
| /// This will be the string "`/`" if no particular route was | |
| /// requested. | |
| /// | |
| virtual std::string DefaultRouteName() = 0; | |
| //-------------------------------------------------------------------------- | |
| /// @brief Requests that, at the next appropriate opportunity, a new | |
| /// frame be scheduled for rendering. | |
| /// | |
| virtual void ScheduleFrame() = 0; | |
| //-------------------------------------------------------------------------- | |
| /// @brief Updates the client's rendering on the GPU with the newly | |
| /// provided Scene. | |
| /// | |
| virtual void Render(Scene* scene) = 0; | |
| //-------------------------------------------------------------------------- | |
| /// @brief Receives a updated semantics tree from the Framework. | |
| /// | |
| /// @param[in] update The updated semantic tree to apply. | |
| /// | |
| virtual void UpdateSemantics(SemanticsUpdate* update) = 0; | |
| //-------------------------------------------------------------------------- | |
| /// @brief When the Flutter application has a message to send to the | |
| /// underlying platform, the message needs to be forwarded to | |
| /// the platform on the appropriate thread (via the platform | |
| /// task runner). The PlatformConfiguration delegates this task | |
| /// to the engine via this method. | |
| /// | |
| /// @see `PlatformView::HandlePlatformMessage` | |
| /// | |
| /// @param[in] message The message from the Flutter application to send to | |
| /// the underlying platform. | |
| /// | |
| virtual void HandlePlatformMessage( | |
| std::unique_ptr<PlatformMessage> message) = 0; | |
| //-------------------------------------------------------------------------- | |
| /// @brief Returns the current collection of fonts available on the | |
| /// platform. | |
| /// | |
| /// This function reads an XML file and makes font families and | |
| /// collections of them. MinikinFontForTest is used for FontFamily | |
| /// creation. | |
| virtual FontCollection& GetFontCollection() = 0; | |
| //-------------------------------------------------------------------------- | |
| /// @brief Returns the current collection of assets available on the | |
| /// platform. | |
| virtual std::shared_ptr<AssetManager> GetAssetManager() = 0; | |
| //-------------------------------------------------------------------------- | |
| /// @brief Notifies this client of the name of the root isolate and its | |
| /// port when that isolate is launched, restarted (in the | |
| /// cold-restart scenario) or the application itself updates the | |
| /// name of the root isolate (via `Window.setIsolateDebugName` | |
| /// in `window.dart`). The name of the isolate is meaningless to | |
| /// the engine but is used in instrumentation and tooling. | |
| /// Currently, this information is to update the service | |
| /// protocol list of available root isolates running in the VM | |
| /// and their names so that the appropriate isolate can be | |
| /// selected in the tools for debugging and instrumentation. | |
| /// | |
| /// @param[in] isolate_name The isolate name | |
| /// @param[in] isolate_port The isolate port | |
| /// | |
| virtual void UpdateIsolateDescription(const std::string isolate_name, | |
| int64_t isolate_port) = 0; | |
| //-------------------------------------------------------------------------- | |
| /// @brief Notifies this client that the application has an opinion about | |
| /// whether its frame timings need to be reported backed to it. | |
| /// Due to the asynchronous nature of rendering in Flutter, it is | |
| /// not possible for the application to determine the total time | |
| /// it took to render a specific frame. While the layer-tree is | |
| /// constructed on the UI thread, it needs to be rendering on the | |
| /// raster thread. Dart code cannot execute on this thread. So any | |
| /// instrumentation about the frame times gathered on this thread | |
| /// needs to be aggregated and sent back to the UI thread for | |
| /// processing in Dart. | |
| /// | |
| /// When the application indicates that frame times need to be | |
| /// reported, it collects this information till a specified number | |
| /// of data points are gathered. Then this information is sent | |
| /// back to Dart code via `Engine::ReportTimings`. | |
| /// | |
| /// This option is engine counterpart of the | |
| /// `Window._setNeedsReportTimings` in `window.dart`. | |
| /// | |
| /// @param[in] needs_reporting If reporting information should be collected | |
| /// and send back to Dart. | |
| /// | |
| virtual void SetNeedsReportTimings(bool value) = 0; | |
| //-------------------------------------------------------------------------- | |
| /// @brief The embedder can specify data that the isolate can request | |
| /// synchronously on launch. This accessor fetches that data. | |
| /// | |
| /// This data is persistent for the duration of the Flutter | |
| /// application and is available even after isolate restarts. | |
| /// Because of this lifecycle, the size of this data must be kept | |
| /// to a minimum. | |
| /// | |
| /// For asynchronous communication between the embedder and | |
| /// isolate, a platform channel may be used. | |
| /// | |
| /// @return A map of the isolate data that the framework can request upon | |
| /// launch. | |
| /// | |
| virtual std::shared_ptr<const fml::Mapping> GetPersistentIsolateData() = 0; | |
| //-------------------------------------------------------------------------- | |
| /// @brief Directly invokes platform-specific APIs to compute the | |
| /// locale the platform would have natively resolved to. | |
| /// | |
| /// @param[in] supported_locale_data The vector of strings that represents | |
| /// the locales supported by the app. | |
| /// Each locale consists of three | |
| /// strings: languageCode, countryCode, | |
| /// and scriptCode in that order. | |
| /// | |
| /// @return A vector of 3 strings languageCode, countryCode, and | |
| /// scriptCode that represents the locale selected by the | |
| /// platform. Empty strings mean the value was unassigned. Empty | |
| /// vector represents a null locale. | |
| /// | |
| virtual std::unique_ptr<std::vector<std::string>> | |
| ComputePlatformResolvedLocale( | |
| const std::vector<std::string>& supported_locale_data) = 0; | |
| //-------------------------------------------------------------------------- | |
| /// @brief Invoked when the Dart VM requests that a deferred library | |
| /// be loaded. Notifies the engine that the deferred library | |
| /// identified by the specified loading unit id should be | |
| /// downloaded and loaded into the Dart VM via | |
| /// `LoadDartDeferredLibrary` | |
| /// | |
| /// Upon encountering errors or otherwise failing to load a | |
| /// loading unit with the specified id, the failure should be | |
| /// directly reported to dart by calling | |
| /// `LoadDartDeferredLibraryFailure` to ensure the waiting dart | |
| /// future completes with an error. | |
| /// | |
| /// @param[in] loading_unit_id The unique id of the deferred library's | |
| /// loading unit. This id is to be passed | |
| /// back into LoadDartDeferredLibrary | |
| /// in order to identify which deferred | |
| /// library to load. | |
| /// | |
| virtual void RequestDartDeferredLibrary(intptr_t loading_unit_id) = 0; | |
| protected: | |
| virtual ~PlatformConfigurationClient(); | |
| }; | |
| //---------------------------------------------------------------------------- | |
| /// @brief A class for holding and distributing platform-level information | |
| /// to and from the Dart code in Flutter's framework. | |
| /// | |
| /// It handles communication between the engine and the framework, | |
| /// and owns the main window. | |
| /// | |
| /// It communicates with the RuntimeController through the use of a | |
| /// PlatformConfigurationClient interface, which the | |
| /// RuntimeController defines. | |
| /// | |
| class PlatformConfiguration final { | |
| public: | |
| //---------------------------------------------------------------------------- | |
| /// @brief Creates a new PlatformConfiguration, typically created by the | |
| /// RuntimeController. | |
| /// | |
| /// @param[in] client The `PlatformConfigurationClient` to be injected into | |
| /// the PlatformConfiguration. This client is used to | |
| /// forward requests to the RuntimeController. | |
| /// | |
| explicit PlatformConfiguration(PlatformConfigurationClient* client); | |
| // PlatformConfiguration is not copyable. | |
| PlatformConfiguration(const PlatformConfiguration&) = delete; | |
| PlatformConfiguration& operator=(const PlatformConfiguration&) = delete; | |
| ~PlatformConfiguration(); | |
| //---------------------------------------------------------------------------- | |
| /// @brief Access to the platform configuration client (which typically | |
| /// is implemented by the RuntimeController). | |
| /// | |
| /// @return Returns the client used to construct this | |
| /// PlatformConfiguration. | |
| /// | |
| PlatformConfigurationClient* client() const { return client_; } | |
| //---------------------------------------------------------------------------- | |
| /// @brief Called by the RuntimeController once it has created the root | |
| /// isolate, so that the PlatformController can get a handle to | |
| /// the 'dart:ui' library. | |
| /// | |
| /// It uses the handle to call the hooks in hooks.dart. | |
| /// | |
| void DidCreateIsolate(); | |
| //---------------------------------------------------------------------------- | |
| /// @brief Update the specified locale data in the framework. | |
| /// | |
| /// @deprecated The persistent isolate data must be used for this purpose | |
| /// instead. | |
| /// | |
| /// @param[in] locale_data The locale data. This should consist of groups of | |
| /// 4 strings, each group representing a single locale. | |
| /// | |
| void UpdateLocales(const std::vector<std::string>& locales); | |
| //---------------------------------------------------------------------------- | |
| /// @brief Update the user settings data in the framework. | |
| /// | |
| /// @deprecated The persistent isolate data must be used for this purpose | |
| /// instead. | |
| /// | |
| /// @param[in] data The user settings data. | |
| /// | |
| void UpdateUserSettingsData(const std::string& data); | |
| //---------------------------------------------------------------------------- | |
| /// @brief Updates the lifecycle state data in the framework. | |
| /// | |
| /// @deprecated The persistent isolate data must be used for this purpose | |
| /// instead. | |
| /// | |
| /// @param[in] data The lifecycle state data. | |
| /// | |
| void UpdateLifecycleState(const std::string& data); | |
| //---------------------------------------------------------------------------- | |
| /// @brief Notifies the PlatformConfiguration that the embedder has | |
| /// expressed an opinion about whether the accessibility tree | |
| /// should be generated or not. This call originates in the | |
| /// platform view and is forwarded to the PlatformConfiguration | |
| /// here by the engine. | |
| /// | |
| /// @param[in] enabled Whether the accessibility tree is enabled or | |
| /// disabled. | |
| /// | |
| void UpdateSemanticsEnabled(bool enabled); | |
| //---------------------------------------------------------------------------- | |
| /// @brief Forward the preference of accessibility features that must be | |
| /// enabled in the semantics tree to the framwork. | |
| /// | |
| /// @param[in] flags The accessibility features that must be generated in | |
| /// the semantics tree. | |
| /// | |
| void UpdateAccessibilityFeatures(int32_t flags); | |
| //---------------------------------------------------------------------------- | |
| /// @brief Notifies the PlatformConfiguration that the client has sent | |
| /// it a message. This call originates in the platform view and | |
| /// has been forwarded through the engine to here. | |
| /// | |
| /// @param[in] message The message sent from the embedder to the Dart | |
| /// application. | |
| /// | |
| void DispatchPlatformMessage(std::unique_ptr<PlatformMessage> message); | |
| //---------------------------------------------------------------------------- | |
| /// @brief Notifies the framework that the embedder encountered an | |
| /// accessibility related action on the specified node. This call | |
| /// originates on the platform view and has been forwarded to the | |
| /// platform configuration here by the engine. | |
| /// | |
| /// @param[in] id The identifier of the accessibility node. | |
| /// @param[in] action The accessibility related action performed on the | |
| /// node of the specified ID. | |
| /// @param[in] args Optional data that applies to the specified action. | |
| /// | |
| void DispatchSemanticsAction(int32_t id, | |
| SemanticsAction action, | |
| fml::MallocMapping args); | |
| //---------------------------------------------------------------------------- | |
| /// @brief Notifies the framework that it is time to begin working on a | |
| /// new frame previously scheduled via a call to | |
| /// `PlatformConfigurationClient::ScheduleFrame`. This call | |
| /// originates in the animator. | |
| /// | |
| /// The frame time given as the argument indicates the point at | |
| /// which the current frame interval began. It is very slightly | |
| /// (because of scheduling overhead) in the past. If a new layer | |
| /// tree is not produced and given to the raster task runner | |
| /// within one frame interval from this point, the Flutter | |
| /// application will jank. | |
| /// | |
| /// This method calls the `::_beginFrame` method in `hooks.dart`. | |
| /// | |
| /// @param[in] frame_time The point at which the current frame interval | |
| /// began. May be used by animation interpolators, | |
| /// physics simulations, etc.. | |
| /// | |
| /// @param[in] frame_number The frame number recorded by the animator. Used | |
| /// by the framework to associate frame specific | |
| /// debug information with frame timings and timeline | |
| /// events. | |
| /// | |
| void BeginFrame(fml::TimePoint frame_time, uint64_t frame_number); | |
| //---------------------------------------------------------------------------- | |
| /// @brief Dart code cannot fully measure the time it takes for a | |
| /// specific frame to be rendered. This is because Dart code only | |
| /// runs on the UI task runner. That is only a small part of the | |
| /// overall frame workload. The raster task runner frame workload | |
| /// is executed on a thread where Dart code cannot run (and hence | |
| /// instrument). Besides, due to the pipelined nature of rendering | |
| /// in Flutter, there may be multiple frame workloads being | |
| /// processed at any given time. However, for non-Timeline based | |
| /// profiling, it is useful for trace collection and processing to | |
| /// happen in Dart. To do this, the raster task runner frame | |
| /// workloads need to be instrumented separately. After a set | |
| /// number of these profiles have been gathered, they need to be | |
| /// reported back to Dart code. The engine reports this extra | |
| /// instrumentation information back to the framework by invoking | |
| /// this method at predefined intervals. | |
| /// | |
| /// @see `FrameTiming` | |
| /// | |
| /// @param[in] timings Collection of `FrameTiming::kStatisticsCount` * 'n' | |
| /// values for `n` frames whose timings have not been | |
| /// reported yet. Many of the values are timestamps, but | |
| /// a collection of integers is reported here for easier | |
| /// conversions to Dart objects. The timestamps are | |
| /// measured against the system monotonic clock measured | |
| /// in microseconds. | |
| /// | |
| void ReportTimings(std::vector<int64_t> timings); | |
| //---------------------------------------------------------------------------- | |
| /// @brief Retrieves the Window with the given ID managed by the | |
| /// `PlatformConfiguration`. | |
| /// | |
| /// @param[in] window_id The id of the window to find and return. | |
| /// | |
| /// @return a pointer to the Window. | |
| /// | |
| Window* get_window(int window_id) { return windows_[window_id].get(); } | |
| //---------------------------------------------------------------------------- | |
| /// @brief Responds to a previous platform message to the engine from the | |
| /// framework. | |
| /// | |
| /// @param[in] response_id The unique id that identifies the original platform | |
| /// message to respond to. | |
| /// @param[in] data The data to send back in the response. | |
| /// | |
| void CompletePlatformMessageResponse(int response_id, | |
| std::vector<uint8_t> data); | |
| //---------------------------------------------------------------------------- | |
| /// @brief Responds to a previous platform message to the engine from the | |
| /// framework with an empty response. | |
| /// | |
| /// @param[in] response_id The unique id that identifies the original platform | |
| /// message to respond to. | |
| /// | |
| void CompletePlatformMessageEmptyResponse(int response_id); | |
| Dart_Handle on_error() { return on_error_.Get(); } | |
| private: | |
| PlatformConfigurationClient* client_; | |
| tonic::DartPersistentValue on_error_; | |
| tonic::DartPersistentValue update_locales_; | |
| tonic::DartPersistentValue update_user_settings_data_; | |
| tonic::DartPersistentValue update_lifecycle_state_; | |
| tonic::DartPersistentValue update_semantics_enabled_; | |
| tonic::DartPersistentValue update_accessibility_features_; | |
| tonic::DartPersistentValue dispatch_platform_message_; | |
| tonic::DartPersistentValue dispatch_semantics_action_; | |
| tonic::DartPersistentValue begin_frame_; | |
| tonic::DartPersistentValue draw_frame_; | |
| tonic::DartPersistentValue report_timings_; | |
| std::unordered_map<int64_t, std::unique_ptr<Window>> windows_; | |
| // ID starts at 1 because an ID of 0 indicates that no response is expected. | |
| int next_response_id_ = 1; | |
| std::unordered_map<int, fml::RefPtr<PlatformMessageResponse>> | |
| pending_responses_; | |
| }; | |
| //---------------------------------------------------------------------------- | |
| /// An inteface that the result of `Dart_CurrentIsolateGroupData` should | |
| /// implement for registering background isolates to work. | |
| class PlatformMessageHandlerStorage { | |
| public: | |
| virtual ~PlatformMessageHandlerStorage() = default; | |
| virtual void SetPlatformMessageHandler( | |
| int64_t root_isolate_token, | |
| std::weak_ptr<PlatformMessageHandler> handler) = 0; | |
| virtual std::weak_ptr<PlatformMessageHandler> GetPlatformMessageHandler( | |
| int64_t root_isolate_token) const = 0; | |
| }; | |
| //---------------------------------------------------------------------------- | |
| // API exposed as FFI calls in Dart. | |
| // | |
| // These are probably not supposed to be called directly, and should instead | |
| // be called through their sibling API in `PlatformConfiguration` or | |
| // `PlatformConfigurationClient`. | |
| // | |
| // These are intentionally undocumented. Refer instead to the sibling methods | |
| // above. | |
| //---------------------------------------------------------------------------- | |
| class PlatformConfigurationNativeApi { | |
| public: | |
| static std::string DefaultRouteName(); | |
| static void ScheduleFrame(); | |
| static void Render(Scene* scene); | |
| static void UpdateSemantics(SemanticsUpdate* update); | |
| static void SetNeedsReportTimings(bool value); | |
| static Dart_Handle GetPersistentIsolateData(); | |
| static Dart_Handle ComputePlatformResolvedLocale( | |
| Dart_Handle supportedLocalesHandle); | |
| static void SetIsolateDebugName(const std::string& name); | |
| static Dart_Handle SendPlatformMessage(const std::string& name, | |
| Dart_Handle callback, | |
| Dart_Handle data_handle); | |
| static Dart_Handle SendPortPlatformMessage(const std::string& name, | |
| Dart_Handle identifier, | |
| Dart_Handle send_port, | |
| Dart_Handle data_handle); | |
| static void RespondToPlatformMessage(int response_id, | |
| const tonic::DartByteData& data); | |
| //-------------------------------------------------------------------------- | |
| /// @brief Requests the Dart VM to adjusts the GC heuristics based on | |
| /// the requested `performance_mode`. Returns the old performance | |
| /// mode. | |
| /// | |
| /// Requesting a performance mode doesn't guarantee any | |
| /// performance characteristics. This is best effort, and should | |
| /// be used after careful consideration of the various GC | |
| /// trade-offs. | |
| /// | |
| /// @param[in] performance_mode The requested performance mode. Please refer | |
| /// to documentation of `Dart_PerformanceMode` | |
| /// for more details about what each performance | |
| /// mode does. | |
| /// | |
| static int RequestDartPerformanceMode(int mode); | |
| static int64_t GetRootIsolateToken(); | |
| static void RegisterBackgroundIsolate(int64_t root_isolate_token); | |
| }; | |
| } // namespace flutter | |
| #endif // FLUTTER_LIB_UI_WINDOW_PLATFORM_CONFIGURATION_H_ |