diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index 4cd5031ebf219..8c82cc0e3845f 100755 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -399,6 +399,9 @@ FILE: ../../../flutter/lib/ui/ui_benchmarks.cc FILE: ../../../flutter/lib/ui/ui_dart_state.cc FILE: ../../../flutter/lib/ui/ui_dart_state.h FILE: ../../../flutter/lib/ui/window.dart +FILE: ../../../flutter/lib/ui/window/platform_configuration.cc +FILE: ../../../flutter/lib/ui/window/platform_configuration.h +FILE: ../../../flutter/lib/ui/window/platform_configuration_unittests.cc FILE: ../../../flutter/lib/ui/window/platform_message.cc FILE: ../../../flutter/lib/ui/window/platform_message.h FILE: ../../../flutter/lib/ui/window/platform_message_response.cc @@ -575,6 +578,8 @@ FILE: ../../../flutter/runtime/dart_vm_unittests.cc FILE: ../../../flutter/runtime/embedder_resources.cc FILE: ../../../flutter/runtime/embedder_resources.h FILE: ../../../flutter/runtime/fixtures/runtime_test.dart +FILE: ../../../flutter/runtime/platform_data.cc +FILE: ../../../flutter/runtime/platform_data.h FILE: ../../../flutter/runtime/ptrace_ios.cc FILE: ../../../flutter/runtime/ptrace_ios.h FILE: ../../../flutter/runtime/runtime_controller.cc @@ -587,8 +592,6 @@ FILE: ../../../flutter/runtime/skia_concurrent_executor.cc FILE: ../../../flutter/runtime/skia_concurrent_executor.h FILE: ../../../flutter/runtime/test_font_data.cc FILE: ../../../flutter/runtime/test_font_data.h -FILE: ../../../flutter/runtime/window_data.cc -FILE: ../../../flutter/runtime/window_data.h FILE: ../../../flutter/shell/common/animator.cc FILE: ../../../flutter/shell/common/animator.h FILE: ../../../flutter/shell/common/animator_unittests.cc diff --git a/lib/ui/BUILD.gn b/lib/ui/BUILD.gn index 103699d640692..b0454b381b55c 100644 --- a/lib/ui/BUILD.gn +++ b/lib/ui/BUILD.gn @@ -93,6 +93,8 @@ source_set_maybe_fuchsia_legacy("ui") { "text/text_box.h", "ui_dart_state.cc", "ui_dart_state.h", + "window/platform_configuration.cc", + "window/platform_configuration.h", "window/platform_message.cc", "window/platform_message.h", "window/platform_message_response.cc", @@ -180,6 +182,7 @@ if (enable_unittests) { sources = [ "painting/image_encoding_unittests.cc", "painting/vertices_unittests.cc", + "window/platform_configuration_unittests.cc", "window/pointer_data_packet_converter_unittests.cc", ] diff --git a/lib/ui/compositing/scene.cc b/lib/ui/compositing/scene.cc index f5403ecae9a61..d70033a346b09 100644 --- a/lib/ui/compositing/scene.cc +++ b/lib/ui/compositing/scene.cc @@ -8,6 +8,7 @@ #include "flutter/lib/ui/painting/image.h" #include "flutter/lib/ui/painting/picture.h" #include "flutter/lib/ui/ui_dart_state.h" +#include "flutter/lib/ui/window/platform_configuration.h" #include "flutter/lib/ui/window/window.h" #include "third_party/skia/include/core/SkImageInfo.h" #include "third_party/skia/include/core/SkSurface.h" @@ -41,7 +42,10 @@ Scene::Scene(std::shared_ptr rootLayer, uint32_t rasterizerTracingThreshold, bool checkerboardRasterCacheImages, bool checkerboardOffscreenLayers) { - auto viewport_metrics = UIDartState::Current()->window()->viewport_metrics(); + auto viewport_metrics = UIDartState::Current() + ->platform_configuration() + ->window() + ->viewport_metrics(); layer_tree_ = std::make_unique( SkISize::Make(viewport_metrics.physical_width, diff --git a/lib/ui/dart_ui.cc b/lib/ui/dart_ui.cc index a02bf3523d612..f9f89d6f22d67 100644 --- a/lib/ui/dart_ui.cc +++ b/lib/ui/dart_ui.cc @@ -30,7 +30,7 @@ #include "flutter/lib/ui/text/font_collection.h" #include "flutter/lib/ui/text/paragraph.h" #include "flutter/lib/ui/text/paragraph_builder.h" -#include "flutter/lib/ui/window/window.h" +#include "flutter/lib/ui/window/platform_configuration.h" #include "third_party/tonic/converter/dart_converter.h" #include "third_party/tonic/logging/dart_error.h" @@ -85,7 +85,7 @@ void DartUI::InitForGlobal() { SemanticsUpdate::RegisterNatives(g_natives); SemanticsUpdateBuilder::RegisterNatives(g_natives); Vertices::RegisterNatives(g_natives); - Window::RegisterNatives(g_natives); + PlatformConfiguration::RegisterNatives(g_natives); #if defined(LEGACY_FUCHSIA_EMBEDDER) SceneHost::RegisterNatives(g_natives); #endif diff --git a/lib/ui/fixtures/ui_test.dart b/lib/ui/fixtures/ui_test.dart index 717f9b7fd335f..e2fcdaa7c3e8b 100644 --- a/lib/ui/fixtures/ui_test.dart +++ b/lib/ui/fixtures/ui_test.dart @@ -34,6 +34,7 @@ void createVertices() { ); _validateVertices(vertices); } + void _validateVertices(Vertices vertices) native 'ValidateVertices'; @pragma('vm:entry-point') @@ -42,8 +43,10 @@ void frameCallback(FrameInfo info) { } @pragma('vm:entry-point') -void messageCallback(dynamic data) { -} +void messageCallback(dynamic data) {} + +@pragma('vm:entry-point') +void validateConfiguration() native 'ValidateConfiguration'; // Draw a circle on a Canvas that has a PictureRecorder. Take the image from diff --git a/lib/ui/hooks.dart b/lib/ui/hooks.dart index 39bab12406fb8..c01095412a606 100644 --- a/lib/ui/hooks.dart +++ b/lib/ui/hooks.dart @@ -238,7 +238,7 @@ void _runMainZoned(Function startMainIsolateFunction, }, null); } -void _reportUnhandledException(String error, String stackTrace) native 'Window_reportUnhandledException'; +void _reportUnhandledException(String error, String stackTrace) native 'PlatformConfiguration_reportUnhandledException'; /// Invokes [callback] inside the given [zone]. void _invoke(void callback()?, Zone zone) { diff --git a/lib/ui/painting/canvas.cc b/lib/ui/painting/canvas.cc index be28e8c964bbc..129226d36a4ce 100644 --- a/lib/ui/painting/canvas.cc +++ b/lib/ui/painting/canvas.cc @@ -11,6 +11,7 @@ #include "flutter/lib/ui/painting/image.h" #include "flutter/lib/ui/painting/matrix.h" #include "flutter/lib/ui/ui_dart_state.h" +#include "flutter/lib/ui/window/platform_configuration.h" #include "flutter/lib/ui/window/window.h" #include "third_party/skia/include/core/SkBitmap.h" #include "third_party/skia/include/core/SkCanvas.h" @@ -474,8 +475,11 @@ void Canvas::drawShadow(const CanvasPath* path, ToDart("Canvas.drawShader called with non-genuine Path.")); return; } - SkScalar dpr = - UIDartState::Current()->window()->viewport_metrics().device_pixel_ratio; + SkScalar dpr = UIDartState::Current() + ->platform_configuration() + ->window() + ->viewport_metrics() + .device_pixel_ratio; external_allocation_size_ += path->path().approximateBytesUsed(); flutter::PhysicalShapeLayer::DrawShadow(canvas_, path->path(), color, elevation, transparentOccluder, dpr); diff --git a/lib/ui/text/font_collection.cc b/lib/ui/text/font_collection.cc index 38d931b402ea7..7405941da41ed 100644 --- a/lib/ui/text/font_collection.cc +++ b/lib/ui/text/font_collection.cc @@ -8,7 +8,7 @@ #include "flutter/lib/ui/text/asset_manager_font_provider.h" #include "flutter/lib/ui/ui_dart_state.h" -#include "flutter/lib/ui/window/window.h" +#include "flutter/lib/ui/window/platform_configuration.h" #include "flutter/runtime/test_font_data.h" #include "rapidjson/document.h" #include "rapidjson/rapidjson.h" @@ -30,8 +30,10 @@ namespace { void LoadFontFromList(tonic::Uint8List& font_data, // NOLINT Dart_Handle callback, std::string family_name) { - FontCollection& font_collection = - UIDartState::Current()->window()->client()->GetFontCollection(); + FontCollection& font_collection = UIDartState::Current() + ->platform_configuration() + ->client() + ->GetFontCollection(); font_collection.LoadFontFromList(font_data.data(), font_data.num_elements(), family_name); font_data.Release(); diff --git a/lib/ui/text/paragraph_builder.cc b/lib/ui/text/paragraph_builder.cc index 396ce50f5cfca..679fc887ac89a 100644 --- a/lib/ui/text/paragraph_builder.cc +++ b/lib/ui/text/paragraph_builder.cc @@ -10,7 +10,7 @@ #include "flutter/fml/task_runner.h" #include "flutter/lib/ui/text/font_collection.h" #include "flutter/lib/ui/ui_dart_state.h" -#include "flutter/lib/ui/window/window.h" +#include "flutter/lib/ui/window/platform_configuration.h" #include "flutter/third_party/txt/src/txt/font_style.h" #include "flutter/third_party/txt/src/txt/font_weight.h" #include "flutter/third_party/txt/src/txt/paragraph_style.h" @@ -288,8 +288,10 @@ ParagraphBuilder::ParagraphBuilder( style.locale = locale; } - FontCollection& font_collection = - UIDartState::Current()->window()->client()->GetFontCollection(); + FontCollection& font_collection = UIDartState::Current() + ->platform_configuration() + ->client() + ->GetFontCollection(); #if FLUTTER_ENABLE_SKSHAPER #define FLUTTER_PARAGRAPH_BUILDER txt::ParagraphBuilder::CreateSkiaBuilder diff --git a/lib/ui/ui_dart_state.cc b/lib/ui/ui_dart_state.cc index 1bd00e35ae972..4b1a35b980e73 100644 --- a/lib/ui/ui_dart_state.cc +++ b/lib/ui/ui_dart_state.cc @@ -5,7 +5,7 @@ #include "flutter/lib/ui/ui_dart_state.h" #include "flutter/fml/message_loop.h" -#include "flutter/lib/ui/window/window.h" +#include "flutter/lib/ui/window/platform_configuration.h" #include "third_party/tonic/converter/dart_converter.h" #include "third_party/tonic/dart_message_handler.h" @@ -73,8 +73,9 @@ void UIDartState::ThrowIfUIOperationsProhibited() { void UIDartState::SetDebugName(const std::string debug_name) { debug_name_ = debug_name; - if (window_) { - window_->client()->UpdateIsolateDescription(debug_name_, main_port_); + if (platform_configuration_) { + platform_configuration_->client()->UpdateIsolateDescription(debug_name_, + main_port_); } } @@ -82,10 +83,12 @@ UIDartState* UIDartState::Current() { return static_cast(DartState::Current()); } -void UIDartState::SetWindow(std::unique_ptr window) { - window_ = std::move(window); - if (window_) { - window_->client()->UpdateIsolateDescription(debug_name_, main_port_); +void UIDartState::SetPlatformConfiguration( + std::unique_ptr platform_configuration) { + platform_configuration_ = std::move(platform_configuration); + if (platform_configuration_) { + platform_configuration_->client()->UpdateIsolateDescription(debug_name_, + main_port_); } } diff --git a/lib/ui/ui_dart_state.h b/lib/ui/ui_dart_state.h index fd21146d24dd4..116b5716c3be7 100644 --- a/lib/ui/ui_dart_state.h +++ b/lib/ui/ui_dart_state.h @@ -27,7 +27,7 @@ namespace flutter { class FontSelector; -class Window; +class PlatformConfiguration; class UIDartState : public tonic::DartState { public: @@ -44,7 +44,9 @@ class UIDartState : public tonic::DartState { const std::string& logger_prefix() const { return logger_prefix_; } - Window* window() const { return window_.get(); } + PlatformConfiguration* platform_configuration() const { + return platform_configuration_.get(); + } const TaskRunners& GetTaskRunners() const; @@ -97,7 +99,8 @@ class UIDartState : public tonic::DartState { ~UIDartState() override; - void SetWindow(std::unique_ptr window); + void SetPlatformConfiguration( + std::unique_ptr platform_configuration); const std::string& GetAdvisoryScriptURI() const; @@ -119,7 +122,7 @@ class UIDartState : public tonic::DartState { Dart_Port main_port_ = ILLEGAL_PORT; const bool is_root_isolate_; std::string debug_name_; - std::unique_ptr window_; + std::unique_ptr platform_configuration_; tonic::DartMicrotaskQueue microtask_queue_; UnhandledExceptionCallback unhandled_exception_callback_; const std::shared_ptr isolate_name_server_; diff --git a/lib/ui/window.dart b/lib/ui/window.dart index 5d99e42781fd6..03fcfb0b14e75 100644 --- a/lib/ui/window.dart +++ b/lib/ui/window.dart @@ -823,7 +823,7 @@ class Window { } return null; } - List _computePlatformResolvedLocale(List supportedLocalesData) native 'Window_computePlatformResolvedLocale'; + List _computePlatformResolvedLocale(List supportedLocalesData) native 'PlatformConfiguration_computePlatformResolvedLocale'; /// A callback that is invoked whenever [locale] changes value. /// @@ -1001,7 +1001,7 @@ class Window { } late _SetNeedsReportTimingsFunc _setNeedsReportTimings; - void _nativeSetNeedsReportTimings(bool value) native 'Window_setNeedsReportTimings'; + void _nativeSetNeedsReportTimings(bool value) native 'PlatformConfiguration_setNeedsReportTimings'; /// A callback that is invoked when pointer data is available. /// @@ -1051,7 +1051,7 @@ class Window { /// * [SystemChannels.navigation], which handles subsequent navigation /// requests from the embedder. String get defaultRouteName => _defaultRouteName(); - String _defaultRouteName() native 'Window_defaultRouteName'; + String _defaultRouteName() native 'PlatformConfiguration_defaultRouteName'; /// Requests that, at the next appropriate opportunity, the [onBeginFrame] /// and [onDrawFrame] callbacks be invoked. @@ -1060,7 +1060,7 @@ class Window { /// /// * [SchedulerBinding], the Flutter framework class which manages the /// scheduling of frames. - void scheduleFrame() native 'Window_scheduleFrame'; + void scheduleFrame() native 'PlatformConfiguration_scheduleFrame'; /// Updates the application's rendering on the GPU with the newly provided /// [Scene]. This function must be called within the scope of the @@ -1086,7 +1086,7 @@ class Window { /// scheduling of frames. /// * [RendererBinding], the Flutter framework class which manages layout and /// painting. - void render(Scene scene) native 'Window_render'; + void render(Scene scene) native 'PlatformConfiguration_render'; /// Whether the user has requested that [updateSemantics] be called when /// the semantic contents of window changes. @@ -1126,7 +1126,7 @@ class Window { /// Additional accessibility features that may be enabled by the platform. AccessibilityFeatures get accessibilityFeatures => _accessibilityFeatures; - // The zero value matches the default value in `window_data.h`. + // The zero value matches the default value in `platform_data.h`. AccessibilityFeatures _accessibilityFeatures = const AccessibilityFeatures._(0); /// A callback that is invoked when the value of [accessibilityFeatures] changes. @@ -1148,7 +1148,7 @@ class Window { /// /// In either case, this function disposes the given update, which means the /// semantics update cannot be used further. - void updateSemantics(SemanticsUpdate update) native 'Window_updateSemantics'; + void updateSemantics(SemanticsUpdate update) native 'PlatformConfiguration_updateSemantics'; /// Set the debug name associated with this window's root isolate. /// @@ -1158,7 +1158,7 @@ class Window { /// This can be combined with flutter tools `--isolate-filter` flag to debug /// specific root isolates. For example: `flutter attach --isolate-filter=[name]`. /// Note that this does not rename any child isolates of the root. - void setIsolateDebugName(String name) native 'Window_setIsolateDebugName'; + void setIsolateDebugName(String name) native 'PlatformConfiguration_setIsolateDebugName'; /// Sends a message to a platform-specific plugin. /// @@ -1179,7 +1179,7 @@ class Window { } String? _sendPlatformMessage(String name, PlatformMessageResponseCallback? callback, - ByteData? data) native 'Window_sendPlatformMessage'; + ByteData? data) native 'PlatformConfiguration_sendPlatformMessage'; /// Called whenever this window receives a message from a platform-specific /// plugin. @@ -1204,7 +1204,7 @@ class Window { /// Called by [_dispatchPlatformMessage]. void _respondToPlatformMessage(int responseId, ByteData? data) - native 'Window_respondToPlatformMessage'; + native 'PlatformConfiguration_respondToPlatformMessage'; /// Wraps the given [callback] in another callback that ensures that the /// original callback is called in the zone it was registered in. @@ -1230,7 +1230,7 @@ class Window { /// /// For asynchronous communication between the embedder and isolate, a /// platform channel may be used. - ByteData? getPersistentIsolateData() native 'Window_getPersistentIsolateData'; + ByteData? getPersistentIsolateData() native 'PlatformConfiguration_getPersistentIsolateData'; } /// Additional accessibility features that may be enabled by the platform. diff --git a/lib/ui/window/platform_configuration.cc b/lib/ui/window/platform_configuration.cc new file mode 100644 index 0000000000000..3ce180e3bce71 --- /dev/null +++ b/lib/ui/window/platform_configuration.cc @@ -0,0 +1,437 @@ +// 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. + +#include "flutter/lib/ui/window/platform_configuration.h" + +#include "flutter/lib/ui/compositing/scene.h" +#include "flutter/lib/ui/ui_dart_state.h" +#include "flutter/lib/ui/window/platform_message_response_dart.h" +#include "flutter/lib/ui/window/window.h" +#include "third_party/tonic/converter/dart_converter.h" +#include "third_party/tonic/dart_args.h" +#include "third_party/tonic/dart_library_natives.h" +#include "third_party/tonic/dart_microtask_queue.h" +#include "third_party/tonic/logging/dart_invoke.h" +#include "third_party/tonic/typed_data/dart_byte_data.h" + +namespace flutter { +namespace { + +void DefaultRouteName(Dart_NativeArguments args) { + UIDartState::ThrowIfUIOperationsProhibited(); + std::string routeName = UIDartState::Current() + ->platform_configuration() + ->client() + ->DefaultRouteName(); + Dart_SetReturnValue(args, tonic::StdStringToDart(routeName)); +} + +void ScheduleFrame(Dart_NativeArguments args) { + UIDartState::ThrowIfUIOperationsProhibited(); + UIDartState::Current()->platform_configuration()->client()->ScheduleFrame(); +} + +void Render(Dart_NativeArguments args) { + UIDartState::ThrowIfUIOperationsProhibited(); + Dart_Handle exception = nullptr; + Scene* scene = + tonic::DartConverter::FromArguments(args, 1, exception); + if (exception) { + Dart_ThrowException(exception); + return; + } + UIDartState::Current()->platform_configuration()->client()->Render(scene); +} + +void UpdateSemantics(Dart_NativeArguments args) { + UIDartState::ThrowIfUIOperationsProhibited(); + Dart_Handle exception = nullptr; + SemanticsUpdate* update = + tonic::DartConverter::FromArguments(args, 1, exception); + if (exception) { + Dart_ThrowException(exception); + return; + } + UIDartState::Current()->platform_configuration()->client()->UpdateSemantics( + update); +} + +void SetIsolateDebugName(Dart_NativeArguments args) { + UIDartState::ThrowIfUIOperationsProhibited(); + Dart_Handle exception = nullptr; + const std::string name = + tonic::DartConverter::FromArguments(args, 1, exception); + if (exception) { + Dart_ThrowException(exception); + return; + } + UIDartState::Current()->SetDebugName(name); +} + +void SetNeedsReportTimings(Dart_NativeArguments args) { + UIDartState::ThrowIfUIOperationsProhibited(); + Dart_Handle exception = nullptr; + bool value = tonic::DartConverter::FromArguments(args, 1, exception); + UIDartState::Current() + ->platform_configuration() + ->client() + ->SetNeedsReportTimings(value); +} + +void ReportUnhandledException(Dart_NativeArguments args) { + UIDartState::ThrowIfUIOperationsProhibited(); + + Dart_Handle exception = nullptr; + + auto error_name = + tonic::DartConverter::FromArguments(args, 0, exception); + if (exception) { + Dart_ThrowException(exception); + return; + } + + auto stack_trace = + tonic::DartConverter::FromArguments(args, 1, exception); + if (exception) { + Dart_ThrowException(exception); + return; + } + + UIDartState::Current()->ReportUnhandledException(std::move(error_name), + std::move(stack_trace)); +} + +Dart_Handle SendPlatformMessage(Dart_Handle window, + const std::string& name, + Dart_Handle callback, + Dart_Handle data_handle) { + UIDartState* dart_state = UIDartState::Current(); + + if (!dart_state->platform_configuration()) { + return tonic::ToDart( + "Platform messages can only be sent from the main isolate"); + } + + fml::RefPtr response; + if (!Dart_IsNull(callback)) { + response = fml::MakeRefCounted( + tonic::DartPersistentValue(dart_state, callback), + dart_state->GetTaskRunners().GetUITaskRunner()); + } + if (Dart_IsNull(data_handle)) { + dart_state->platform_configuration()->client()->HandlePlatformMessage( + fml::MakeRefCounted(name, response)); + } else { + tonic::DartByteData data(data_handle); + const uint8_t* buffer = static_cast(data.data()); + dart_state->platform_configuration()->client()->HandlePlatformMessage( + fml::MakeRefCounted( + name, std::vector(buffer, buffer + data.length_in_bytes()), + response)); + } + + return Dart_Null(); +} + +void _SendPlatformMessage(Dart_NativeArguments args) { + tonic::DartCallStatic(&SendPlatformMessage, args); +} + +void RespondToPlatformMessage(Dart_Handle window, + int response_id, + const tonic::DartByteData& data) { + if (Dart_IsNull(data.dart_handle())) { + UIDartState::Current() + ->platform_configuration() + ->CompletePlatformMessageEmptyResponse(response_id); + } else { + // TODO(engine): Avoid this copy. + const uint8_t* buffer = static_cast(data.data()); + UIDartState::Current() + ->platform_configuration() + ->CompletePlatformMessageResponse( + response_id, + std::vector(buffer, buffer + data.length_in_bytes())); + } +} + +void _RespondToPlatformMessage(Dart_NativeArguments args) { + tonic::DartCallStatic(&RespondToPlatformMessage, args); +} + +void GetPersistentIsolateData(Dart_NativeArguments args) { + UIDartState::ThrowIfUIOperationsProhibited(); + + auto persistent_isolate_data = UIDartState::Current() + ->platform_configuration() + ->client() + ->GetPersistentIsolateData(); + + if (!persistent_isolate_data) { + Dart_SetReturnValue(args, Dart_Null()); + return; + } + + Dart_SetReturnValue( + args, tonic::DartByteData::Create(persistent_isolate_data->GetMapping(), + persistent_isolate_data->GetSize())); +} + +Dart_Handle ToByteData(const std::vector& buffer) { + return tonic::DartByteData::Create(buffer.data(), buffer.size()); +} + +} // namespace + +PlatformConfigurationClient::~PlatformConfigurationClient() {} + +PlatformConfiguration::PlatformConfiguration( + PlatformConfigurationClient* client) + : client_(client) {} + +PlatformConfiguration::~PlatformConfiguration() {} + +void PlatformConfiguration::DidCreateIsolate() { + library_.Set(tonic::DartState::Current(), + Dart_LookupLibrary(tonic::ToDart("dart:ui"))); + window_.reset(new Window({1.0, 0.0, 0.0})); +} + +void PlatformConfiguration::UpdateLocales( + const std::vector& locales) { + std::shared_ptr dart_state = library_.dart_state().lock(); + if (!dart_state) { + return; + } + tonic::DartState::Scope scope(dart_state); + tonic::LogIfError(tonic::DartInvokeField( + library_.value(), "_updateLocales", + { + tonic::ToDart>(locales), + })); +} + +void PlatformConfiguration::UpdateUserSettingsData(const std::string& data) { + std::shared_ptr dart_state = library_.dart_state().lock(); + if (!dart_state) { + return; + } + tonic::DartState::Scope scope(dart_state); + + tonic::LogIfError(tonic::DartInvokeField(library_.value(), + "_updateUserSettingsData", + { + tonic::StdStringToDart(data), + })); +} + +void PlatformConfiguration::UpdateLifecycleState(const std::string& data) { + std::shared_ptr dart_state = library_.dart_state().lock(); + if (!dart_state) { + return; + } + tonic::DartState::Scope scope(dart_state); + tonic::LogIfError(tonic::DartInvokeField(library_.value(), + "_updateLifecycleState", + { + tonic::StdStringToDart(data), + })); +} + +void PlatformConfiguration::UpdateSemanticsEnabled(bool enabled) { + std::shared_ptr dart_state = library_.dart_state().lock(); + if (!dart_state) { + return; + } + tonic::DartState::Scope scope(dart_state); + UIDartState::ThrowIfUIOperationsProhibited(); + + tonic::LogIfError(tonic::DartInvokeField( + library_.value(), "_updateSemanticsEnabled", {tonic::ToDart(enabled)})); +} + +void PlatformConfiguration::UpdateAccessibilityFeatures(int32_t values) { + std::shared_ptr dart_state = library_.dart_state().lock(); + if (!dart_state) { + return; + } + tonic::DartState::Scope scope(dart_state); + + tonic::LogIfError(tonic::DartInvokeField(library_.value(), + "_updateAccessibilityFeatures", + {tonic::ToDart(values)})); +} + +void PlatformConfiguration::DispatchPlatformMessage( + fml::RefPtr message) { + std::shared_ptr dart_state = library_.dart_state().lock(); + if (!dart_state) { + FML_DLOG(WARNING) + << "Dropping platform message for lack of DartState on channel: " + << message->channel(); + return; + } + tonic::DartState::Scope scope(dart_state); + Dart_Handle data_handle = + (message->hasData()) ? ToByteData(message->data()) : Dart_Null(); + if (Dart_IsError(data_handle)) { + FML_DLOG(WARNING) + << "Dropping platform message because of a Dart error on channel: " + << message->channel(); + return; + } + + int response_id = 0; + if (auto response = message->response()) { + response_id = next_response_id_++; + pending_responses_[response_id] = response; + } + + tonic::LogIfError( + tonic::DartInvokeField(library_.value(), "_dispatchPlatformMessage", + {tonic::ToDart(message->channel()), data_handle, + tonic::ToDart(response_id)})); +} + +void PlatformConfiguration::DispatchSemanticsAction(int32_t id, + SemanticsAction action, + std::vector args) { + std::shared_ptr dart_state = library_.dart_state().lock(); + if (!dart_state) { + return; + } + tonic::DartState::Scope scope(dart_state); + + Dart_Handle args_handle = (args.empty()) ? Dart_Null() : ToByteData(args); + + if (Dart_IsError(args_handle)) { + return; + } + + tonic::LogIfError(tonic::DartInvokeField( + library_.value(), "_dispatchSemanticsAction", + {tonic::ToDart(id), tonic::ToDart(static_cast(action)), + args_handle})); +} + +void PlatformConfiguration::BeginFrame(fml::TimePoint frameTime) { + std::shared_ptr dart_state = library_.dart_state().lock(); + if (!dart_state) { + return; + } + tonic::DartState::Scope scope(dart_state); + + int64_t microseconds = (frameTime - fml::TimePoint()).ToMicroseconds(); + + tonic::LogIfError(tonic::DartInvokeField(library_.value(), "_beginFrame", + { + Dart_NewInteger(microseconds), + })); + + UIDartState::Current()->FlushMicrotasksNow(); + + tonic::LogIfError(tonic::DartInvokeField(library_.value(), "_drawFrame", {})); +} + +void PlatformConfiguration::ReportTimings(std::vector timings) { + std::shared_ptr dart_state = library_.dart_state().lock(); + if (!dart_state) { + return; + } + tonic::DartState::Scope scope(dart_state); + + Dart_Handle data_handle = + Dart_NewTypedData(Dart_TypedData_kInt64, timings.size()); + + Dart_TypedData_Type type; + void* data = nullptr; + intptr_t num_acquired = 0; + FML_CHECK(!Dart_IsError( + Dart_TypedDataAcquireData(data_handle, &type, &data, &num_acquired))); + FML_DCHECK(num_acquired == static_cast(timings.size())); + + memcpy(data, timings.data(), sizeof(int64_t) * timings.size()); + FML_CHECK(Dart_TypedDataReleaseData(data_handle)); + + tonic::LogIfError(tonic::DartInvokeField(library_.value(), "_reportTimings", + { + data_handle, + })); +} + +void PlatformConfiguration::CompletePlatformMessageEmptyResponse( + int response_id) { + if (!response_id) { + return; + } + auto it = pending_responses_.find(response_id); + if (it == pending_responses_.end()) { + return; + } + auto response = std::move(it->second); + pending_responses_.erase(it); + response->CompleteEmpty(); +} + +void PlatformConfiguration::CompletePlatformMessageResponse( + int response_id, + std::vector data) { + if (!response_id) { + return; + } + auto it = pending_responses_.find(response_id); + if (it == pending_responses_.end()) { + return; + } + auto response = std::move(it->second); + pending_responses_.erase(it); + response->Complete(std::make_unique(std::move(data))); +} + +Dart_Handle ComputePlatformResolvedLocale(Dart_Handle supportedLocalesHandle) { + std::vector supportedLocales = + tonic::DartConverter>::FromDart( + supportedLocalesHandle); + + std::vector results = + *UIDartState::Current() + ->platform_configuration() + ->client() + ->ComputePlatformResolvedLocale(supportedLocales); + + return tonic::DartConverter>::ToDart(results); +} + +static void _ComputePlatformResolvedLocale(Dart_NativeArguments args) { + UIDartState::ThrowIfUIOperationsProhibited(); + Dart_Handle result = + ComputePlatformResolvedLocale(Dart_GetNativeArgument(args, 1)); + Dart_SetReturnValue(args, result); +} + +void PlatformConfiguration::RegisterNatives( + tonic::DartLibraryNatives* natives) { + natives->Register({ + {"PlatformConfiguration_defaultRouteName", DefaultRouteName, 1, true}, + {"PlatformConfiguration_scheduleFrame", ScheduleFrame, 1, true}, + {"PlatformConfiguration_sendPlatformMessage", _SendPlatformMessage, 4, + true}, + {"PlatformConfiguration_respondToPlatformMessage", + _RespondToPlatformMessage, 3, true}, + {"PlatformConfiguration_render", Render, 2, true}, + {"PlatformConfiguration_updateSemantics", UpdateSemantics, 2, true}, + {"PlatformConfiguration_setIsolateDebugName", SetIsolateDebugName, 2, + true}, + {"PlatformConfiguration_reportUnhandledException", + ReportUnhandledException, 2, true}, + {"PlatformConfiguration_setNeedsReportTimings", SetNeedsReportTimings, 2, + true}, + {"PlatformConfiguration_getPersistentIsolateData", + GetPersistentIsolateData, 1, true}, + {"PlatformConfiguration_computePlatformResolvedLocale", + _ComputePlatformResolvedLocale, 2, true}, + }); +} + +} // namespace flutter diff --git a/lib/ui/window/platform_configuration.h b/lib/ui/window/platform_configuration.h new file mode 100644 index 0000000000000..4652c7c5dcdbb --- /dev/null +++ b/lib/ui/window/platform_configuration.h @@ -0,0 +1,421 @@ +// 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 +#include +#include +#include +#include + +#include "flutter/fml/time/time_point.h" +#include "flutter/lib/ui/semantics/semantics_update.h" +#include "flutter/lib/ui/window/platform_message.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" + +namespace tonic { +class DartLibraryNatives; + +// So tonic::ToDart> returns List instead of +// List. +template <> +struct DartListFactory { + static Dart_Handle NewList(intptr_t length) { + return Dart_NewListOf(Dart_CoreType_Int, length); + } +}; + +} // namespace tonic + +namespace flutter { +class FontCollection; +class PlatformMessage; +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, +}; + +//-------------------------------------------------------------------------- +/// @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(fml::RefPtr 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 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 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> + ComputePlatformResolvedLocale( + const std::vector& supported_locale_data) = 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& 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(fml::RefPtr 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, + std::vector 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 GPU 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.. + /// + void BeginFrame(fml::TimePoint frame_time); + + //---------------------------------------------------------------------------- + /// @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 GPU 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 GPU 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::kCount` * `n` timestamps + /// for `n` frames whose timings have not been reported + /// yet. 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 timings); + + //---------------------------------------------------------------------------- + /// @brief Registers the native handlers for Dart functions that this + /// class handles. + /// + /// @param[in] natives The natives registry that the functions will be + /// registered with. + /// + static void RegisterNatives(tonic::DartLibraryNatives* natives); + + //---------------------------------------------------------------------------- + /// @brief Retrieves the Window managed by the PlatformConfiguration. + /// + /// @return a pointer to the Window. + /// + Window* window() const { return window_.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 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); + + private: + PlatformConfigurationClient* client_; + tonic::DartPersistentValue library_; + + std::unique_ptr window_; + + // We use id 0 to mean that no response is expected. + int next_response_id_ = 1; + std::unordered_map> + pending_responses_; +}; + +} // namespace flutter + +#endif // FLUTTER_LIB_UI_WINDOW_PLATFORM_CONFIGURATION_H_ diff --git a/lib/ui/window/platform_configuration_unittests.cc b/lib/ui/window/platform_configuration_unittests.cc new file mode 100644 index 0000000000000..903b6d748e2dc --- /dev/null +++ b/lib/ui/window/platform_configuration_unittests.cc @@ -0,0 +1,139 @@ +// 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. + +#define FML_USED_ON_EMBEDDER + +#include + +#include "flutter/lib/ui/window/platform_configuration.h" + +#include "flutter/common/task_runners.h" +#include "flutter/fml/synchronization/waitable_event.h" +#include "flutter/lib/ui/painting/vertices.h" +#include "flutter/runtime/dart_vm.h" +#include "flutter/shell/common/shell_test.h" +#include "flutter/shell/common/thread_host.h" +#include "flutter/testing/testing.h" + +namespace flutter { +namespace testing { + +class DummyPlatformConfigurationClient : public PlatformConfigurationClient { + public: + DummyPlatformConfigurationClient() { + std::vector data; + isolate_data_.reset(new ::fml::DataMapping(data)); + } + std::string DefaultRouteName() override { return "TestRoute"; } + void ScheduleFrame() override {} + void Render(Scene* scene) override {} + void UpdateSemantics(SemanticsUpdate* update) override {} + void HandlePlatformMessage(fml::RefPtr message) override {} + FontCollection& GetFontCollection() override { return font_collection_; } + void UpdateIsolateDescription(const std::string isolate_name, + int64_t isolate_port) override {} + void SetNeedsReportTimings(bool value) override {} + std::shared_ptr GetPersistentIsolateData() override { + return isolate_data_; + } + std::unique_ptr> ComputePlatformResolvedLocale( + const std::vector& supported_locale_data) override { + return nullptr; + }; + + private: + FontCollection font_collection_; + std::shared_ptr isolate_data_; +}; + +TEST_F(ShellTest, PlatformConfigurationInitialization) { + auto message_latch = std::make_shared(); + + auto nativeValidateConfiguration = [message_latch]( + Dart_NativeArguments args) { + PlatformConfiguration* configuration = + UIDartState::Current()->platform_configuration(); + ASSERT_NE(configuration->window(), nullptr); + ASSERT_EQ(configuration->window()->viewport_metrics().device_pixel_ratio, + 1.0); + ASSERT_EQ(configuration->window()->viewport_metrics().physical_width, 0.0); + ASSERT_EQ(configuration->window()->viewport_metrics().physical_height, 0.0); + + message_latch->Signal(); + }; + + Settings settings = CreateSettingsForFixture(); + TaskRunners task_runners("test", // label + GetCurrentTaskRunner(), // platform + CreateNewThread(), // raster + CreateNewThread(), // ui + CreateNewThread() // io + ); + + AddNativeCallback("ValidateConfiguration", + CREATE_NATIVE_ENTRY(nativeValidateConfiguration)); + + std::unique_ptr shell = + CreateShell(std::move(settings), std::move(task_runners)); + + ASSERT_TRUE(shell->IsSetup()); + auto run_configuration = RunConfiguration::InferFromSettings(settings); + run_configuration.SetEntrypoint("validateConfiguration"); + + shell->RunEngine(std::move(run_configuration), [&](auto result) { + ASSERT_EQ(result, Engine::RunStatus::Success); + }); + + message_latch->Wait(); + DestroyShell(std::move(shell), std::move(task_runners)); +} + +TEST_F(ShellTest, PlatformConfigurationWindowMetricsUpdate) { + auto message_latch = std::make_shared(); + + auto nativeValidateConfiguration = [message_latch]( + Dart_NativeArguments args) { + PlatformConfiguration* configuration = + UIDartState::Current()->platform_configuration(); + + ASSERT_NE(configuration->window(), nullptr); + configuration->window()->UpdateWindowMetrics( + ViewportMetrics{2.0, 10.0, 20.0}); + ASSERT_EQ(configuration->window()->viewport_metrics().device_pixel_ratio, + 2.0); + ASSERT_EQ(configuration->window()->viewport_metrics().physical_width, 10.0); + ASSERT_EQ(configuration->window()->viewport_metrics().physical_height, + 20.0); + + message_latch->Signal(); + }; + + Settings settings = CreateSettingsForFixture(); + TaskRunners task_runners("test", // label + GetCurrentTaskRunner(), // platform + CreateNewThread(), // raster + CreateNewThread(), // ui + CreateNewThread() // io + ); + + AddNativeCallback("ValidateConfiguration", + CREATE_NATIVE_ENTRY(nativeValidateConfiguration)); + + std::unique_ptr shell = + CreateShell(std::move(settings), std::move(task_runners)); + + ASSERT_TRUE(shell->IsSetup()); + auto run_configuration = RunConfiguration::InferFromSettings(settings); + run_configuration.SetEntrypoint("validateConfiguration"); + + shell->RunEngine(std::move(run_configuration), [&](auto result) { + ASSERT_EQ(result, Engine::RunStatus::Success); + }); + + message_latch->Wait(); + DestroyShell(std::move(shell), std::move(task_runners)); +} + +} // namespace testing +} // namespace flutter diff --git a/lib/ui/window/viewport_metrics.cc b/lib/ui/window/viewport_metrics.cc index 0b6dab6d4c1e0..329cea01c036a 100644 --- a/lib/ui/window/viewport_metrics.cc +++ b/lib/ui/window/viewport_metrics.cc @@ -80,4 +80,16 @@ ViewportMetrics::ViewportMetrics(double p_device_pixel_ratio, FML_DCHECK(device_pixel_ratio > 0); } +ViewportMetrics::ViewportMetrics(double p_device_pixel_ratio, + double p_physical_width, + double p_physical_height) + : device_pixel_ratio(p_device_pixel_ratio), + physical_width(p_physical_width), + physical_height(p_physical_height) { + // Ensure we don't have nonsensical dimensions. + FML_DCHECK(physical_width >= 0); + FML_DCHECK(physical_height >= 0); + FML_DCHECK(device_pixel_ratio > 0); +} + } // namespace flutter diff --git a/lib/ui/window/viewport_metrics.h b/lib/ui/window/viewport_metrics.h index f60adbfcee110..d4a7311ad95f3 100644 --- a/lib/ui/window/viewport_metrics.h +++ b/lib/ui/window/viewport_metrics.h @@ -52,6 +52,12 @@ struct ViewportMetrics { double p_physical_view_inset_bottom, double p_physical_view_inset_left); + // Create a ViewportMetrics instance that doesn't include depth, padding, or + // insets. + ViewportMetrics(double p_device_pixel_ratio, + double p_physical_width, + double p_physical_height); + double device_pixel_ratio = 1.0; double physical_width = 0; double physical_height = 0; diff --git a/lib/ui/window/window.cc b/lib/ui/window/window.cc index 9dc964ad6ef5c..d583682888313 100644 --- a/lib/ui/window/window.cc +++ b/lib/ui/window/window.cc @@ -4,183 +4,35 @@ #include "flutter/lib/ui/window/window.h" -#include "flutter/lib/ui/compositing/scene.h" -#include "flutter/lib/ui/ui_dart_state.h" -#include "flutter/lib/ui/window/platform_message_response_dart.h" #include "third_party/tonic/converter/dart_converter.h" #include "third_party/tonic/dart_args.h" -#include "third_party/tonic/dart_library_natives.h" -#include "third_party/tonic/dart_microtask_queue.h" #include "third_party/tonic/logging/dart_invoke.h" #include "third_party/tonic/typed_data/dart_byte_data.h" namespace flutter { -namespace { -void DefaultRouteName(Dart_NativeArguments args) { - UIDartState::ThrowIfUIOperationsProhibited(); - std::string routeName = - UIDartState::Current()->window()->client()->DefaultRouteName(); - Dart_SetReturnValue(args, tonic::StdStringToDart(routeName)); -} - -void ScheduleFrame(Dart_NativeArguments args) { - UIDartState::ThrowIfUIOperationsProhibited(); - UIDartState::Current()->window()->client()->ScheduleFrame(); -} - -void Render(Dart_NativeArguments args) { - UIDartState::ThrowIfUIOperationsProhibited(); - Dart_Handle exception = nullptr; - Scene* scene = - tonic::DartConverter::FromArguments(args, 1, exception); - if (exception) { - Dart_ThrowException(exception); - return; - } - UIDartState::Current()->window()->client()->Render(scene); -} - -void UpdateSemantics(Dart_NativeArguments args) { - UIDartState::ThrowIfUIOperationsProhibited(); - Dart_Handle exception = nullptr; - SemanticsUpdate* update = - tonic::DartConverter::FromArguments(args, 1, exception); - if (exception) { - Dart_ThrowException(exception); - return; - } - UIDartState::Current()->window()->client()->UpdateSemantics(update); -} - -void SetIsolateDebugName(Dart_NativeArguments args) { - UIDartState::ThrowIfUIOperationsProhibited(); - Dart_Handle exception = nullptr; - const std::string name = - tonic::DartConverter::FromArguments(args, 1, exception); - if (exception) { - Dart_ThrowException(exception); - return; - } - UIDartState::Current()->SetDebugName(name); -} - -void SetNeedsReportTimings(Dart_NativeArguments args) { - UIDartState::ThrowIfUIOperationsProhibited(); - Dart_Handle exception = nullptr; - bool value = tonic::DartConverter::FromArguments(args, 1, exception); - UIDartState::Current()->window()->client()->SetNeedsReportTimings(value); +Window::Window(ViewportMetrics metrics) : viewport_metrics_(metrics) { + library_.Set(tonic::DartState::Current(), + Dart_LookupLibrary(tonic::ToDart("dart:ui"))); } -void ReportUnhandledException(Dart_NativeArguments args) { - UIDartState::ThrowIfUIOperationsProhibited(); - - Dart_Handle exception = nullptr; - - auto error_name = - tonic::DartConverter::FromArguments(args, 0, exception); - if (exception) { - Dart_ThrowException(exception); - return; - } +Window::~Window() {} - auto stack_trace = - tonic::DartConverter::FromArguments(args, 1, exception); - if (exception) { - Dart_ThrowException(exception); +void Window::DispatchPointerDataPacket(const PointerDataPacket& packet) { + std::shared_ptr dart_state = library_.dart_state().lock(); + if (!dart_state) { return; } + tonic::DartState::Scope scope(dart_state); - UIDartState::Current()->ReportUnhandledException(std::move(error_name), - std::move(stack_trace)); -} - -Dart_Handle SendPlatformMessage(Dart_Handle window, - const std::string& name, - Dart_Handle callback, - Dart_Handle data_handle) { - UIDartState* dart_state = UIDartState::Current(); - - if (!dart_state->window()) { - return tonic::ToDart( - "Platform messages can only be sent from the main isolate"); - } - - fml::RefPtr response; - if (!Dart_IsNull(callback)) { - response = fml::MakeRefCounted( - tonic::DartPersistentValue(dart_state, callback), - dart_state->GetTaskRunners().GetUITaskRunner()); - } - if (Dart_IsNull(data_handle)) { - dart_state->window()->client()->HandlePlatformMessage( - fml::MakeRefCounted(name, response)); - } else { - tonic::DartByteData data(data_handle); - const uint8_t* buffer = static_cast(data.data()); - dart_state->window()->client()->HandlePlatformMessage( - fml::MakeRefCounted( - name, std::vector(buffer, buffer + data.length_in_bytes()), - response)); - } - - return Dart_Null(); -} - -void _SendPlatformMessage(Dart_NativeArguments args) { - tonic::DartCallStatic(&SendPlatformMessage, args); -} - -void RespondToPlatformMessage(Dart_Handle window, - int response_id, - const tonic::DartByteData& data) { - if (Dart_IsNull(data.dart_handle())) { - UIDartState::Current()->window()->CompletePlatformMessageEmptyResponse( - response_id); - } else { - // TODO(engine): Avoid this copy. - const uint8_t* buffer = static_cast(data.data()); - UIDartState::Current()->window()->CompletePlatformMessageResponse( - response_id, - std::vector(buffer, buffer + data.length_in_bytes())); - } -} - -void _RespondToPlatformMessage(Dart_NativeArguments args) { - tonic::DartCallStatic(&RespondToPlatformMessage, args); -} - -void GetPersistentIsolateData(Dart_NativeArguments args) { - UIDartState::ThrowIfUIOperationsProhibited(); - - auto persistent_isolate_data = - UIDartState::Current()->window()->client()->GetPersistentIsolateData(); - - if (!persistent_isolate_data) { - Dart_SetReturnValue(args, Dart_Null()); + const std::vector& buffer = packet.data(); + Dart_Handle data_handle = + tonic::DartByteData::Create(buffer.data(), buffer.size()); + if (Dart_IsError(data_handle)) { return; } - - Dart_SetReturnValue( - args, tonic::DartByteData::Create(persistent_isolate_data->GetMapping(), - persistent_isolate_data->GetSize())); -} - -Dart_Handle ToByteData(const std::vector& buffer) { - return tonic::DartByteData::Create(buffer.data(), buffer.size()); -} - -} // namespace - -WindowClient::~WindowClient() {} - -Window::Window(WindowClient* client) : client_(client) {} - -Window::~Window() {} - -void Window::DidCreateIsolate() { - library_.Set(tonic::DartState::Current(), - Dart_LookupLibrary(tonic::ToDart("dart:ui"))); + tonic::LogIfError(tonic::DartInvokeField( + library_.value(), "_dispatchPointerDataPacket", {data_handle})); } void Window::UpdateWindowMetrics(const ViewportMetrics& metrics) { @@ -213,244 +65,4 @@ void Window::UpdateWindowMetrics(const ViewportMetrics& metrics) { })); } -void Window::UpdateLocales(const std::vector& locales) { - std::shared_ptr dart_state = library_.dart_state().lock(); - if (!dart_state) { - return; - } - tonic::DartState::Scope scope(dart_state); - tonic::LogIfError(tonic::DartInvokeField( - library_.value(), "_updateLocales", - { - tonic::ToDart>(locales), - })); -} - -void Window::UpdateUserSettingsData(const std::string& data) { - std::shared_ptr dart_state = library_.dart_state().lock(); - if (!dart_state) { - return; - } - tonic::DartState::Scope scope(dart_state); - - tonic::LogIfError(tonic::DartInvokeField(library_.value(), - "_updateUserSettingsData", - { - tonic::StdStringToDart(data), - })); -} - -void Window::UpdateLifecycleState(const std::string& data) { - std::shared_ptr dart_state = library_.dart_state().lock(); - if (!dart_state) { - return; - } - tonic::DartState::Scope scope(dart_state); - tonic::LogIfError(tonic::DartInvokeField(library_.value(), - "_updateLifecycleState", - { - tonic::StdStringToDart(data), - })); -} - -void Window::UpdateSemanticsEnabled(bool enabled) { - std::shared_ptr dart_state = library_.dart_state().lock(); - if (!dart_state) { - return; - } - tonic::DartState::Scope scope(dart_state); - UIDartState::ThrowIfUIOperationsProhibited(); - - tonic::LogIfError(tonic::DartInvokeField( - library_.value(), "_updateSemanticsEnabled", {tonic::ToDart(enabled)})); -} - -void Window::UpdateAccessibilityFeatures(int32_t values) { - std::shared_ptr dart_state = library_.dart_state().lock(); - if (!dart_state) { - return; - } - tonic::DartState::Scope scope(dart_state); - - tonic::LogIfError(tonic::DartInvokeField(library_.value(), - "_updateAccessibilityFeatures", - {tonic::ToDart(values)})); -} - -void Window::DispatchPlatformMessage(fml::RefPtr message) { - std::shared_ptr dart_state = library_.dart_state().lock(); - if (!dart_state) { - FML_DLOG(WARNING) - << "Dropping platform message for lack of DartState on channel: " - << message->channel(); - return; - } - tonic::DartState::Scope scope(dart_state); - Dart_Handle data_handle = - (message->hasData()) ? ToByteData(message->data()) : Dart_Null(); - if (Dart_IsError(data_handle)) { - FML_DLOG(WARNING) - << "Dropping platform message because of a Dart error on channel: " - << message->channel(); - return; - } - - int response_id = 0; - if (auto response = message->response()) { - response_id = next_response_id_++; - pending_responses_[response_id] = response; - } - - tonic::LogIfError( - tonic::DartInvokeField(library_.value(), "_dispatchPlatformMessage", - {tonic::ToDart(message->channel()), data_handle, - tonic::ToDart(response_id)})); -} - -void Window::DispatchPointerDataPacket(const PointerDataPacket& packet) { - std::shared_ptr dart_state = library_.dart_state().lock(); - if (!dart_state) { - return; - } - tonic::DartState::Scope scope(dart_state); - - Dart_Handle data_handle = ToByteData(packet.data()); - if (Dart_IsError(data_handle)) { - return; - } - tonic::LogIfError(tonic::DartInvokeField( - library_.value(), "_dispatchPointerDataPacket", {data_handle})); -} - -void Window::DispatchSemanticsAction(int32_t id, - SemanticsAction action, - std::vector args) { - std::shared_ptr dart_state = library_.dart_state().lock(); - if (!dart_state) { - return; - } - tonic::DartState::Scope scope(dart_state); - - Dart_Handle args_handle = (args.empty()) ? Dart_Null() : ToByteData(args); - - if (Dart_IsError(args_handle)) { - return; - } - - tonic::LogIfError(tonic::DartInvokeField( - library_.value(), "_dispatchSemanticsAction", - {tonic::ToDart(id), tonic::ToDart(static_cast(action)), - args_handle})); -} - -void Window::BeginFrame(fml::TimePoint frameTime) { - std::shared_ptr dart_state = library_.dart_state().lock(); - if (!dart_state) { - return; - } - tonic::DartState::Scope scope(dart_state); - - int64_t microseconds = (frameTime - fml::TimePoint()).ToMicroseconds(); - - tonic::LogIfError(tonic::DartInvokeField(library_.value(), "_beginFrame", - { - Dart_NewInteger(microseconds), - })); - - UIDartState::Current()->FlushMicrotasksNow(); - - tonic::LogIfError(tonic::DartInvokeField(library_.value(), "_drawFrame", {})); -} - -void Window::ReportTimings(std::vector timings) { - std::shared_ptr dart_state = library_.dart_state().lock(); - if (!dart_state) { - return; - } - tonic::DartState::Scope scope(dart_state); - - Dart_Handle data_handle = - Dart_NewTypedData(Dart_TypedData_kInt64, timings.size()); - - Dart_TypedData_Type type; - void* data = nullptr; - intptr_t num_acquired = 0; - FML_CHECK(!Dart_IsError( - Dart_TypedDataAcquireData(data_handle, &type, &data, &num_acquired))); - FML_DCHECK(num_acquired == static_cast(timings.size())); - - memcpy(data, timings.data(), sizeof(int64_t) * timings.size()); - FML_CHECK(Dart_TypedDataReleaseData(data_handle)); - - tonic::LogIfError(tonic::DartInvokeField(library_.value(), "_reportTimings", - { - data_handle, - })); -} - -void Window::CompletePlatformMessageEmptyResponse(int response_id) { - if (!response_id) { - return; - } - auto it = pending_responses_.find(response_id); - if (it == pending_responses_.end()) { - return; - } - auto response = std::move(it->second); - pending_responses_.erase(it); - response->CompleteEmpty(); -} - -void Window::CompletePlatformMessageResponse(int response_id, - std::vector data) { - if (!response_id) { - return; - } - auto it = pending_responses_.find(response_id); - if (it == pending_responses_.end()) { - return; - } - auto response = std::move(it->second); - pending_responses_.erase(it); - response->Complete(std::make_unique(std::move(data))); -} - -Dart_Handle ComputePlatformResolvedLocale(Dart_Handle supportedLocalesHandle) { - std::vector supportedLocales = - tonic::DartConverter>::FromDart( - supportedLocalesHandle); - - std::vector results = - *UIDartState::Current() - ->window() - ->client() - ->ComputePlatformResolvedLocale(supportedLocales); - - return tonic::DartConverter>::ToDart(results); -} - -static void _ComputePlatformResolvedLocale(Dart_NativeArguments args) { - UIDartState::ThrowIfUIOperationsProhibited(); - Dart_Handle result = - ComputePlatformResolvedLocale(Dart_GetNativeArgument(args, 1)); - Dart_SetReturnValue(args, result); -} - -void Window::RegisterNatives(tonic::DartLibraryNatives* natives) { - natives->Register({ - {"Window_defaultRouteName", DefaultRouteName, 1, true}, - {"Window_scheduleFrame", ScheduleFrame, 1, true}, - {"Window_sendPlatformMessage", _SendPlatformMessage, 4, true}, - {"Window_respondToPlatformMessage", _RespondToPlatformMessage, 3, true}, - {"Window_render", Render, 2, true}, - {"Window_updateSemantics", UpdateSemantics, 2, true}, - {"Window_setIsolateDebugName", SetIsolateDebugName, 2, true}, - {"Window_reportUnhandledException", ReportUnhandledException, 2, true}, - {"Window_setNeedsReportTimings", SetNeedsReportTimings, 2, true}, - {"Window_getPersistentIsolateData", GetPersistentIsolateData, 1, true}, - {"Window_computePlatformResolvedLocale", _ComputePlatformResolvedLocale, - 2, true}, - }); -} - } // namespace flutter diff --git a/lib/ui/window/window.h b/lib/ui/window/window.h index 1e68b09d8095a..172cf6b8c2ae5 100644 --- a/lib/ui/window/window.h +++ b/lib/ui/window/window.h @@ -9,102 +9,27 @@ #include #include -#include "flutter/fml/time/time_point.h" -#include "flutter/lib/ui/semantics/semantics_update.h" #include "flutter/lib/ui/window/platform_message.h" #include "flutter/lib/ui/window/pointer_data_packet.h" #include "flutter/lib/ui/window/viewport_metrics.h" #include "third_party/skia/include/gpu/GrDirectContext.h" #include "third_party/tonic/dart_persistent_value.h" -namespace tonic { -class DartLibraryNatives; - -// So tonice::ToDart> returns List instead of -// List. -template <> -struct DartListFactory { - static Dart_Handle NewList(intptr_t length) { - return Dart_NewListOf(Dart_CoreType_Int, length); - } -}; - -} // namespace tonic - namespace flutter { -class FontCollection; -class Scene; - -// Must match the AccessibilityFeatureFlag enum in window.dart. -enum class AccessibilityFeatureFlag : int32_t { - kAccessibleNavigation = 1 << 0, - kInvertColors = 1 << 1, - kDisableAnimations = 1 << 2, - kBoldText = 1 << 3, - kReduceMotion = 1 << 4, - kHighContrast = 1 << 5, -}; - -class WindowClient { - public: - virtual std::string DefaultRouteName() = 0; - virtual void ScheduleFrame() = 0; - virtual void Render(Scene* scene) = 0; - virtual void UpdateSemantics(SemanticsUpdate* update) = 0; - virtual void HandlePlatformMessage(fml::RefPtr message) = 0; - virtual FontCollection& GetFontCollection() = 0; - virtual void UpdateIsolateDescription(const std::string isolate_name, - int64_t isolate_port) = 0; - virtual void SetNeedsReportTimings(bool value) = 0; - virtual std::shared_ptr GetPersistentIsolateData() = 0; - virtual std::unique_ptr> - ComputePlatformResolvedLocale( - const std::vector& supported_locale_data) = 0; - - protected: - virtual ~WindowClient(); -}; - class Window final { public: - explicit Window(WindowClient* client); + explicit Window(ViewportMetrics metrics); ~Window(); - WindowClient* client() const { return client_; } + const ViewportMetrics& viewport_metrics() const { return viewport_metrics_; } - const ViewportMetrics& viewport_metrics() { return viewport_metrics_; } - - void DidCreateIsolate(); - void UpdateWindowMetrics(const ViewportMetrics& metrics); - void UpdateLocales(const std::vector& locales); - void UpdateUserSettingsData(const std::string& data); - void UpdateLifecycleState(const std::string& data); - void UpdateSemanticsEnabled(bool enabled); - void UpdateAccessibilityFeatures(int32_t flags); - void DispatchPlatformMessage(fml::RefPtr message); void DispatchPointerDataPacket(const PointerDataPacket& packet); - void DispatchSemanticsAction(int32_t id, - SemanticsAction action, - std::vector args); - void BeginFrame(fml::TimePoint frameTime); - void ReportTimings(std::vector timings); - - void CompletePlatformMessageResponse(int response_id, - std::vector data); - void CompletePlatformMessageEmptyResponse(int response_id); - - static void RegisterNatives(tonic::DartLibraryNatives* natives); + void UpdateWindowMetrics(const ViewportMetrics& metrics); private: - WindowClient* client_; tonic::DartPersistentValue library_; ViewportMetrics viewport_metrics_; - - // We use id 0 to mean that no response is expected. - int next_response_id_ = 1; - std::unordered_map> - pending_responses_; }; } // namespace flutter diff --git a/runtime/BUILD.gn b/runtime/BUILD.gn index 9bd85d53d581f..bdadbbb1d5bee 100644 --- a/runtime/BUILD.gn +++ b/runtime/BUILD.gn @@ -53,6 +53,8 @@ source_set_maybe_fuchsia_legacy("runtime") { "dart_vm_lifecycle.h", "embedder_resources.cc", "embedder_resources.h", + "platform_data.cc", + "platform_data.h", "ptrace_ios.cc", "ptrace_ios.h", "runtime_controller.cc", @@ -63,8 +65,6 @@ source_set_maybe_fuchsia_legacy("runtime") { "service_protocol.h", "skia_concurrent_executor.cc", "skia_concurrent_executor.h", - "window_data.cc", - "window_data.h", ] public_deps = [ "//third_party/rapidjson" ] diff --git a/runtime/dart_isolate.cc b/runtime/dart_isolate.cc index 53459a9415b75..79572a51b4b16 100644 --- a/runtime/dart_isolate.cc +++ b/runtime/dart_isolate.cc @@ -57,7 +57,7 @@ std::weak_ptr DartIsolate::CreateRootIsolate( const Settings& settings, fml::RefPtr isolate_snapshot, TaskRunners task_runners, - std::unique_ptr window, + std::unique_ptr platform_configuration, fml::WeakPtr snapshot_delegate, fml::WeakPtr io_manager, fml::RefPtr unref_queue, @@ -112,7 +112,8 @@ std::weak_ptr DartIsolate::CreateRootIsolate( std::shared_ptr* root_isolate_data = static_cast*>(Dart_IsolateData(vm_isolate)); - (*root_isolate_data)->SetWindow(std::move(window)); + (*root_isolate_data) + ->SetPlatformConfiguration(std::move(platform_configuration)); return (*root_isolate_data)->GetWeakIsolatePtr(); } @@ -598,7 +599,7 @@ Dart_Isolate DartIsolate::DartCreateAndStartServiceIsolate( vm_data->GetSettings(), // settings vm_data->GetIsolateSnapshot(), // isolate snapshot null_task_runners, // task runners - nullptr, // window + nullptr, // platform_configuration {}, // snapshot delegate {}, // IO Manager {}, // Skia unref queue diff --git a/runtime/dart_isolate.h b/runtime/dart_isolate.h index 7f59aa7dc28d0..770a99094b8ea 100644 --- a/runtime/dart_isolate.h +++ b/runtime/dart_isolate.h @@ -16,7 +16,7 @@ #include "flutter/lib/ui/io_manager.h" #include "flutter/lib/ui/snapshot_delegate.h" #include "flutter/lib/ui/ui_dart_state.h" -#include "flutter/lib/ui/window/window.h" +#include "flutter/lib/ui/window/platform_configuration.h" #include "flutter/runtime/dart_snapshot.h" #include "third_party/dart/runtime/include/dart_api.h" #include "third_party/tonic/dart_state.h" @@ -192,7 +192,7 @@ class DartIsolate : public UIDartState { const Settings& settings, fml::RefPtr isolate_snapshot, TaskRunners task_runners, - std::unique_ptr window, + std::unique_ptr platform_configuration, fml::WeakPtr snapshot_delegate, fml::WeakPtr io_manager, fml::RefPtr skia_unref_queue, diff --git a/runtime/window_data.cc b/runtime/platform_data.cc similarity index 63% rename from runtime/window_data.cc rename to runtime/platform_data.cc index a92839d5e8a5d..15b9628599b47 100644 --- a/runtime/window_data.cc +++ b/runtime/platform_data.cc @@ -2,11 +2,11 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "flutter/runtime/window_data.h" +#include "flutter/runtime/platform_data.h" namespace flutter { -WindowData::WindowData() = default; +PlatformData::PlatformData() = default; -WindowData::~WindowData() = default; +PlatformData::~PlatformData() = default; } // namespace flutter diff --git a/runtime/window_data.h b/runtime/platform_data.h similarity index 81% rename from runtime/window_data.h rename to runtime/platform_data.h index e234d2f558162..bb7fdd95fb6bb 100644 --- a/runtime/window_data.h +++ b/runtime/platform_data.h @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef FLUTTER_RUNTIME_WINDOW_DATA_H_ -#define FLUTTER_RUNTIME_WINDOW_DATA_H_ +#ifndef FLUTTER_RUNTIME_PLATFORM_DATA_H_ +#define FLUTTER_RUNTIME_PLATFORM_DATA_H_ #include "flutter/lib/ui/window/viewport_metrics.h" @@ -23,12 +23,12 @@ namespace flutter { /// /// See also: /// -/// * flutter::Shell::Create, which takes a window_data to initialize the +/// * flutter::Shell::Create, which takes a platform_data to initialize the /// ui.Window attached to it. -struct WindowData { - WindowData(); +struct PlatformData { + PlatformData(); - ~WindowData(); + ~PlatformData(); ViewportMetrics viewport_metrics; std::string language_code; @@ -45,4 +45,4 @@ struct WindowData { } // namespace flutter -#endif // FLUTTER_RUNTIME_WINDOW_DATA_H_ +#endif // FLUTTER_RUNTIME_PLATFORM_DATA_H_ diff --git a/runtime/runtime_controller.cc b/runtime/runtime_controller.cc index aa557d2abf716..0c4d50c75b02e 100644 --- a/runtime/runtime_controller.cc +++ b/runtime/runtime_controller.cc @@ -8,8 +8,10 @@ #include "flutter/fml/trace_event.h" #include "flutter/lib/ui/compositing/scene.h" #include "flutter/lib/ui/ui_dart_state.h" +#include "flutter/lib/ui/window/platform_configuration.h" #include "flutter/lib/ui/window/window.h" #include "flutter/runtime/runtime_delegate.h" +#include "lib/ui/window/viewport_metrics.h" #include "third_party/tonic/dart_message_handler.h" namespace flutter { @@ -26,7 +28,7 @@ RuntimeController::RuntimeController( std::string p_advisory_script_uri, std::string p_advisory_script_entrypoint, const std::function& idle_notification_callback, - const WindowData& p_window_data, + const PlatformData& p_platform_data, const fml::closure& p_isolate_create_callback, const fml::closure& p_isolate_shutdown_callback, std::shared_ptr p_persistent_isolate_data) @@ -41,7 +43,7 @@ RuntimeController::RuntimeController( advisory_script_uri_(p_advisory_script_uri), advisory_script_entrypoint_(p_advisory_script_entrypoint), idle_notification_callback_(idle_notification_callback), - window_data_(std::move(p_window_data)), + platform_data_(std::move(p_platform_data)), isolate_create_callback_(p_isolate_create_callback), isolate_shutdown_callback_(p_isolate_shutdown_callback), persistent_isolate_data_(std::move(p_persistent_isolate_data)) { @@ -49,20 +51,21 @@ RuntimeController::RuntimeController( // It will be run at a later point when the engine provides a run // configuration and then runs the isolate. auto strong_root_isolate = - DartIsolate::CreateRootIsolate(vm_->GetVMData()->GetSettings(), // - isolate_snapshot_, // - task_runners_, // - std::make_unique(this), // - snapshot_delegate_, // - io_manager_, // - unref_queue_, // - image_decoder_, // - p_advisory_script_uri, // - p_advisory_script_entrypoint, // - nullptr, // - isolate_create_callback_, // - isolate_shutdown_callback_ // - ) + DartIsolate::CreateRootIsolate( + vm_->GetVMData()->GetSettings(), // + isolate_snapshot_, // + task_runners_, // + std::make_unique(this), // + snapshot_delegate_, // + io_manager_, // + unref_queue_, // + image_decoder_, // + p_advisory_script_uri, // + p_advisory_script_entrypoint, // + nullptr, // + isolate_create_callback_, // + isolate_shutdown_callback_ // + ) .lock(); FML_CHECK(strong_root_isolate) << "Could not create root isolate."; @@ -74,9 +77,9 @@ RuntimeController::RuntimeController( root_isolate_return_code_ = {true, code}; }); - if (auto* window = GetWindowIfAvailable()) { + if (auto* platform_configuration = GetPlatformConfigurationIfAvailable()) { tonic::DartState::Scope scope(strong_root_isolate); - window->DidCreateIsolate(); + platform_configuration->DidCreateIsolate(); if (!FlushRuntimeStateToIsolate()) { FML_DLOG(ERROR) << "Could not setup initial isolate state."; } @@ -121,7 +124,7 @@ std::unique_ptr RuntimeController::Clone() const { advisory_script_uri_, // advisory_script_entrypoint_, // idle_notification_callback_, // - window_data_, // + platform_data_, // isolate_create_callback_, // isolate_shutdown_callback_, // persistent_isolate_data_ // @@ -129,30 +132,32 @@ std::unique_ptr RuntimeController::Clone() const { } bool RuntimeController::FlushRuntimeStateToIsolate() { - return SetViewportMetrics(window_data_.viewport_metrics) && - SetLocales(window_data_.locale_data) && - SetSemanticsEnabled(window_data_.semantics_enabled) && - SetAccessibilityFeatures(window_data_.accessibility_feature_flags_) && - SetUserSettingsData(window_data_.user_settings_data) && - SetLifecycleState(window_data_.lifecycle_state); + return SetViewportMetrics(platform_data_.viewport_metrics) && + SetLocales(platform_data_.locale_data) && + SetSemanticsEnabled(platform_data_.semantics_enabled) && + SetAccessibilityFeatures( + platform_data_.accessibility_feature_flags_) && + SetUserSettingsData(platform_data_.user_settings_data) && + SetLifecycleState(platform_data_.lifecycle_state); } bool RuntimeController::SetViewportMetrics(const ViewportMetrics& metrics) { - window_data_.viewport_metrics = metrics; + platform_data_.viewport_metrics = metrics; - if (auto* window = GetWindowIfAvailable()) { - window->UpdateWindowMetrics(metrics); + if (auto* platform_configuration = GetPlatformConfigurationIfAvailable()) { + platform_configuration->window()->UpdateWindowMetrics(metrics); return true; } + return false; } bool RuntimeController::SetLocales( const std::vector& locale_data) { - window_data_.locale_data = locale_data; + platform_data_.locale_data = locale_data; - if (auto* window = GetWindowIfAvailable()) { - window->UpdateLocales(locale_data); + if (auto* platform_configuration = GetPlatformConfigurationIfAvailable()) { + platform_configuration->UpdateLocales(locale_data); return true; } @@ -160,10 +165,11 @@ bool RuntimeController::SetLocales( } bool RuntimeController::SetUserSettingsData(const std::string& data) { - window_data_.user_settings_data = data; + platform_data_.user_settings_data = data; - if (auto* window = GetWindowIfAvailable()) { - window->UpdateUserSettingsData(window_data_.user_settings_data); + if (auto* platform_configuration = GetPlatformConfigurationIfAvailable()) { + platform_configuration->UpdateUserSettingsData( + platform_data_.user_settings_data); return true; } @@ -171,10 +177,11 @@ bool RuntimeController::SetUserSettingsData(const std::string& data) { } bool RuntimeController::SetLifecycleState(const std::string& data) { - window_data_.lifecycle_state = data; + platform_data_.lifecycle_state = data; - if (auto* window = GetWindowIfAvailable()) { - window->UpdateLifecycleState(window_data_.lifecycle_state); + if (auto* platform_configuration = GetPlatformConfigurationIfAvailable()) { + platform_configuration->UpdateLifecycleState( + platform_data_.lifecycle_state); return true; } @@ -182,10 +189,11 @@ bool RuntimeController::SetLifecycleState(const std::string& data) { } bool RuntimeController::SetSemanticsEnabled(bool enabled) { - window_data_.semantics_enabled = enabled; + platform_data_.semantics_enabled = enabled; - if (auto* window = GetWindowIfAvailable()) { - window->UpdateSemanticsEnabled(window_data_.semantics_enabled); + if (auto* platform_configuration = GetPlatformConfigurationIfAvailable()) { + platform_configuration->UpdateSemanticsEnabled( + platform_data_.semantics_enabled); return true; } @@ -193,10 +201,10 @@ bool RuntimeController::SetSemanticsEnabled(bool enabled) { } bool RuntimeController::SetAccessibilityFeatures(int32_t flags) { - window_data_.accessibility_feature_flags_ = flags; - if (auto* window = GetWindowIfAvailable()) { - window->UpdateAccessibilityFeatures( - window_data_.accessibility_feature_flags_); + platform_data_.accessibility_feature_flags_ = flags; + if (auto* platform_configuration = GetPlatformConfigurationIfAvailable()) { + platform_configuration->UpdateAccessibilityFeatures( + platform_data_.accessibility_feature_flags_); return true; } @@ -204,18 +212,20 @@ bool RuntimeController::SetAccessibilityFeatures(int32_t flags) { } bool RuntimeController::BeginFrame(fml::TimePoint frame_time) { - if (auto* window = GetWindowIfAvailable()) { - window->BeginFrame(frame_time); + if (auto* platform_configuration = GetPlatformConfigurationIfAvailable()) { + platform_configuration->BeginFrame(frame_time); return true; } + return false; } bool RuntimeController::ReportTimings(std::vector timings) { - if (auto* window = GetWindowIfAvailable()) { - window->ReportTimings(std::move(timings)); + if (auto* platform_configuration = GetPlatformConfigurationIfAvailable()) { + platform_configuration->ReportTimings(std::move(timings)); return true; } + return false; } @@ -239,23 +249,25 @@ bool RuntimeController::NotifyIdle(int64_t deadline) { bool RuntimeController::DispatchPlatformMessage( fml::RefPtr message) { - if (auto* window = GetWindowIfAvailable()) { + if (auto* platform_configuration = GetPlatformConfigurationIfAvailable()) { TRACE_EVENT1("flutter", "RuntimeController::DispatchPlatformMessage", "mode", "basic"); - window->DispatchPlatformMessage(std::move(message)); + platform_configuration->DispatchPlatformMessage(std::move(message)); return true; } + return false; } bool RuntimeController::DispatchPointerDataPacket( const PointerDataPacket& packet) { - if (auto* window = GetWindowIfAvailable()) { + if (auto* platform_configuration = GetPlatformConfigurationIfAvailable()) { TRACE_EVENT1("flutter", "RuntimeController::DispatchPointerDataPacket", "mode", "basic"); - window->DispatchPointerDataPacket(packet); + platform_configuration->window()->DispatchPointerDataPacket(packet); return true; } + return false; } @@ -264,69 +276,72 @@ bool RuntimeController::DispatchSemanticsAction(int32_t id, std::vector args) { TRACE_EVENT1("flutter", "RuntimeController::DispatchSemanticsAction", "mode", "basic"); - if (auto* window = GetWindowIfAvailable()) { - window->DispatchSemanticsAction(id, action, std::move(args)); + if (auto* platform_configuration = GetPlatformConfigurationIfAvailable()) { + platform_configuration->DispatchSemanticsAction(id, action, + std::move(args)); return true; } + return false; } -Window* RuntimeController::GetWindowIfAvailable() { +PlatformConfiguration* +RuntimeController::GetPlatformConfigurationIfAvailable() { std::shared_ptr root_isolate = root_isolate_.lock(); - return root_isolate ? root_isolate->window() : nullptr; + return root_isolate ? root_isolate->platform_configuration() : nullptr; } -// |WindowClient| +// |PlatformConfigurationClient| std::string RuntimeController::DefaultRouteName() { return client_.DefaultRouteName(); } -// |WindowClient| +// |PlatformConfigurationClient| void RuntimeController::ScheduleFrame() { client_.ScheduleFrame(); } -// |WindowClient| +// |PlatformConfigurationClient| void RuntimeController::Render(Scene* scene) { client_.Render(scene->takeLayerTree()); } -// |WindowClient| +// |PlatformConfigurationClient| void RuntimeController::UpdateSemantics(SemanticsUpdate* update) { - if (window_data_.semantics_enabled) { + if (platform_data_.semantics_enabled) { client_.UpdateSemantics(update->takeNodes(), update->takeActions()); } } -// |WindowClient| +// |PlatformConfigurationClient| void RuntimeController::HandlePlatformMessage( fml::RefPtr message) { client_.HandlePlatformMessage(std::move(message)); } -// |WindowClient| +// |PlatformConfigurationClient| FontCollection& RuntimeController::GetFontCollection() { return client_.GetFontCollection(); } -// |WindowClient| +// |PlatformConfigurationClient| void RuntimeController::UpdateIsolateDescription(const std::string isolate_name, int64_t isolate_port) { client_.UpdateIsolateDescription(isolate_name, isolate_port); } -// |WindowClient| +// |PlatformConfigurationClient| void RuntimeController::SetNeedsReportTimings(bool value) { client_.SetNeedsReportTimings(value); } -// |WindowClient| +// |PlatformConfigurationClient| std::shared_ptr RuntimeController::GetPersistentIsolateData() { return persistent_isolate_data_; } -// |WindowClient| +// |PlatformConfigurationClient| std::unique_ptr> RuntimeController::ComputePlatformResolvedLocale( const std::vector& supported_locale_data) { diff --git a/runtime/runtime_controller.h b/runtime/runtime_controller.h index ad89cbeae064b..e67b5847ce0ac 100644 --- a/runtime/runtime_controller.h +++ b/runtime/runtime_controller.h @@ -14,10 +14,10 @@ #include "flutter/lib/ui/io_manager.h" #include "flutter/lib/ui/text/font_collection.h" #include "flutter/lib/ui/ui_dart_state.h" +#include "flutter/lib/ui/window/platform_configuration.h" #include "flutter/lib/ui/window/pointer_data_packet.h" -#include "flutter/lib/ui/window/window.h" #include "flutter/runtime/dart_vm.h" -#include "flutter/runtime/window_data.h" +#include "flutter/runtime/platform_data.h" #include "rapidjson/document.h" #include "rapidjson/stringbuffer.h" @@ -38,7 +38,7 @@ class Window; /// used by the engine to copy the currently accumulated window state so it can /// be referenced by the new runtime controller. /// -class RuntimeController final : public WindowClient { +class RuntimeController final : public PlatformConfigurationClient { public: //---------------------------------------------------------------------------- /// @brief Creates a new instance of a runtime controller. This is @@ -90,7 +90,7 @@ class RuntimeController final : public WindowClient { /// code in isolate scope when the VM /// is about to be notified that the /// engine is going to be idle. - /// @param[in] window_data The window data (if exists). + /// @param[in] platform_data The window data (if exists). /// @param[in] isolate_create_callback The isolate create callback. This /// allows callers to run native code /// in isolate scope on the UI task @@ -117,12 +117,12 @@ class RuntimeController final : public WindowClient { std::string advisory_script_uri, std::string advisory_script_entrypoint, const std::function& idle_notification_callback, - const WindowData& window_data, + const PlatformData& platform_data, const fml::closure& isolate_create_callback, const fml::closure& isolate_shutdown_callback, std::shared_ptr persistent_isolate_data); - // |WindowClient| + // |PlatformConfigurationClient| ~RuntimeController() override; //---------------------------------------------------------------------------- @@ -136,11 +136,11 @@ class RuntimeController final : public WindowClient { std::unique_ptr Clone() const; //---------------------------------------------------------------------------- - /// @brief Forward the specified window metrics to the running isolate. + /// @brief Forward the specified viewport metrics to the running isolate. /// If the isolate is not running, these metrics will be saved and /// flushed to the isolate when it starts. /// - /// @param[in] metrics The metrics. + /// @param[in] metrics The viewport metrics. /// /// @return If the window metrics were forwarded to the running isolate. /// @@ -466,46 +466,46 @@ class RuntimeController final : public WindowClient { std::string advisory_script_uri_; std::string advisory_script_entrypoint_; std::function idle_notification_callback_; - WindowData window_data_; + PlatformData platform_data_; std::weak_ptr root_isolate_; std::pair root_isolate_return_code_ = {false, 0}; const fml::closure isolate_create_callback_; const fml::closure isolate_shutdown_callback_; std::shared_ptr persistent_isolate_data_; - Window* GetWindowIfAvailable(); + PlatformConfiguration* GetPlatformConfigurationIfAvailable(); bool FlushRuntimeStateToIsolate(); - // |WindowClient| + // |PlatformConfigurationClient| std::string DefaultRouteName() override; - // |WindowClient| + // |PlatformConfigurationClient| void ScheduleFrame() override; - // |WindowClient| + // |PlatformConfigurationClient| void Render(Scene* scene) override; - // |WindowClient| + // |PlatformConfigurationClient| void UpdateSemantics(SemanticsUpdate* update) override; - // |WindowClient| + // |PlatformConfigurationClient| void HandlePlatformMessage(fml::RefPtr message) override; - // |WindowClient| + // |PlatformConfigurationClient| FontCollection& GetFontCollection() override; - // |WindowClient| + // |PlatformConfigurationClient| void UpdateIsolateDescription(const std::string isolate_name, int64_t isolate_port) override; - // |WindowClient| + // |PlatformConfigurationClient| void SetNeedsReportTimings(bool value) override; - // |WindowClient| + // |PlatformConfigurationClient| std::shared_ptr GetPersistentIsolateData() override; - // |WindowClient| + // |PlatformConfigurationClient| std::unique_ptr> ComputePlatformResolvedLocale( const std::vector& supported_locale_data) override; diff --git a/shell/common/engine.cc b/shell/common/engine.cc index 438a1945b9f50..1249615cf6d38 100644 --- a/shell/common/engine.cc +++ b/shell/common/engine.cc @@ -40,7 +40,7 @@ Engine::Engine(Delegate& delegate, DartVM& vm, fml::RefPtr isolate_snapshot, TaskRunners task_runners, - const WindowData window_data, + const PlatformData platform_data, Settings settings, std::unique_ptr animator, fml::WeakPtr io_manager, @@ -71,7 +71,7 @@ Engine::Engine(Delegate& delegate, settings_.advisory_script_uri, // advisory script uri settings_.advisory_script_entrypoint, // advisory script entrypoint settings_.idle_notification_callback, // idle notification callback - window_data, // window data + platform_data, // platform data settings_.isolate_create_callback, // isolate create callback settings_.isolate_shutdown_callback, // isolate shutdown callback settings_.persistent_isolate_data // persistent isolate data @@ -276,7 +276,8 @@ void Engine::SetViewportMetrics(const ViewportMetrics& metrics) { bool dimensions_changed = viewport_metrics_.physical_height != metrics.physical_height || viewport_metrics_.physical_width != metrics.physical_width || - viewport_metrics_.physical_depth != metrics.physical_depth; + viewport_metrics_.physical_depth != metrics.physical_depth || + viewport_metrics_.device_pixel_ratio != metrics.device_pixel_ratio; viewport_metrics_ = metrics; runtime_controller_->SetViewportMetrics(viewport_metrics_); if (animator_) { diff --git a/shell/common/engine.h b/shell/common/engine.h index d7e516617afc1..bbbcc264c6d42 100644 --- a/shell/common/engine.h +++ b/shell/common/engine.h @@ -295,7 +295,7 @@ class Engine final : public RuntimeDelegate, PointerDataDispatcher::Delegate { DartVM& vm, fml::RefPtr isolate_snapshot, TaskRunners task_runners, - const WindowData window_data, + const PlatformData platform_data, Settings settings, std::unique_ptr animator, fml::WeakPtr io_manager, @@ -421,7 +421,7 @@ class Engine final : public RuntimeDelegate, PointerDataDispatcher::Delegate { /// one frame interval from this point, the Flutter application /// will jank. /// - /// If an root isolate is running, this method calls the + /// If a root isolate is running, this method calls the /// `::_beginFrame` method in `hooks.dart`. If a root isolate is /// not running, this call does nothing. /// @@ -701,9 +701,10 @@ class Engine final : public RuntimeDelegate, PointerDataDispatcher::Delegate { //---------------------------------------------------------------------------- /// @brief Notifies the engine that the embedder has expressed an opinion - /// about where the accessibility tree should be generated or not. - /// This call originates in the platform view and is forwarded to - /// the engine here on the UI task runner by the shell. + /// about whether the accessibility tree should be generated or + /// not. This call originates in the platform view and is + /// forwarded to the engine here on the UI task runner by the + /// shell. /// /// @param[in] enabled Whether the accessibility tree is enabled or /// disabled. diff --git a/shell/common/pointer_data_dispatcher.h b/shell/common/pointer_data_dispatcher.h index c222bee8d699e..208c8b0d2878e 100644 --- a/shell/common/pointer_data_dispatcher.h +++ b/shell/common/pointer_data_dispatcher.h @@ -23,7 +23,7 @@ class PointerDataDispatcher; /// delivered packets, and dispatches them in sync with the VSYNC signal. /// /// This object will be owned by the engine because it relies on the engine's -/// `Animator` (which owns `VsyncWaiter`) and `RuntomeController` to do the +/// `Animator` (which owns `VsyncWaiter`) and `RuntimeController` to do the /// filtering. This object is currently designed to be only called from the UI /// thread (no thread safety is guaranteed). /// diff --git a/shell/common/shell.cc b/shell/common/shell.cc index 9137ebcd945a8..725a0539d1226 100644 --- a/shell/common/shell.cc +++ b/shell/common/shell.cc @@ -43,7 +43,7 @@ constexpr char kFontChange[] = "fontsChange"; std::unique_ptr Shell::CreateShellOnPlatformThread( DartVMRef vm, TaskRunners task_runners, - const WindowData window_data, + const PlatformData platform_data, Settings settings, fml::RefPtr isolate_snapshot, const Shell::CreateCallback& on_create_platform_view, @@ -134,7 +134,7 @@ std::unique_ptr Shell::CreateShellOnPlatformThread( fml::MakeCopyable([&engine_promise, // shell = shell.get(), // &dispatcher_maker, // - &window_data, // + &platform_data, // isolate_snapshot = std::move(isolate_snapshot), // vsync_waiter = std::move(vsync_waiter), // &weak_io_manager_future, // @@ -155,7 +155,7 @@ std::unique_ptr Shell::CreateShellOnPlatformThread( *shell->GetDartVM(), // std::move(isolate_snapshot), // task_runners, // - window_data, // + platform_data, // shell->GetSettings(), // std::move(animator), // weak_io_manager_future.get(), // @@ -242,17 +242,17 @@ std::unique_ptr Shell::Create( Settings settings, const Shell::CreateCallback& on_create_platform_view, const Shell::CreateCallback& on_create_rasterizer) { - return Shell::Create(std::move(task_runners), // - WindowData{/* default window data */}, // - std::move(settings), // - std::move(on_create_platform_view), // - std::move(on_create_rasterizer) // + return Shell::Create(std::move(task_runners), // + PlatformData{/* default platform data */}, // + std::move(settings), // + std::move(on_create_platform_view), // + std::move(on_create_rasterizer) // ); } std::unique_ptr Shell::Create( TaskRunners task_runners, - const WindowData window_data, + const PlatformData platform_data, Settings settings, Shell::CreateCallback on_create_platform_view, Shell::CreateCallback on_create_rasterizer) { @@ -267,7 +267,7 @@ std::unique_ptr Shell::Create( auto vm_data = vm->GetVMData(); return Shell::Create(std::move(task_runners), // - std::move(window_data), // + std::move(platform_data), // std::move(settings), // vm_data->GetIsolateSnapshot(), // isolate snapshot on_create_platform_view, // @@ -278,7 +278,7 @@ std::unique_ptr Shell::Create( std::unique_ptr Shell::Create( TaskRunners task_runners, - const WindowData window_data, + const PlatformData platform_data, Settings settings, fml::RefPtr isolate_snapshot, const Shell::CreateCallback& on_create_platform_view, @@ -302,7 +302,7 @@ std::unique_ptr Shell::Create( vm = std::move(vm), // &shell, // task_runners = std::move(task_runners), // - window_data, // + platform_data, // settings, // isolate_snapshot = std::move(isolate_snapshot), // on_create_platform_view, // @@ -310,7 +310,7 @@ std::unique_ptr Shell::Create( ]() mutable { shell = CreateShellOnPlatformThread(std::move(vm), std::move(task_runners), // - window_data, // + platform_data, // settings, // std::move(isolate_snapshot), // on_create_platform_view, // diff --git a/shell/common/shell.h b/shell/common/shell.h index fd1a30d3f4e35..b5f612331f7d6 100644 --- a/shell/common/shell.h +++ b/shell/common/shell.h @@ -138,7 +138,7 @@ class Shell final : public PlatformView::Delegate, /// the Dart VM. /// /// @param[in] task_runners The task runners - /// @param[in] window_data The default data for setting up + /// @param[in] platform_data The default data for setting up /// ui.Window that attached to this /// intance. /// @param[in] settings The settings @@ -161,7 +161,7 @@ class Shell final : public PlatformView::Delegate, /// static std::unique_ptr Create( TaskRunners task_runners, - const WindowData window_data, + const PlatformData platform_data, Settings settings, CreateCallback on_create_platform_view, CreateCallback on_create_rasterizer); @@ -176,7 +176,7 @@ class Shell final : public PlatformView::Delegate, /// requires the specification of a running VM instance. /// /// @param[in] task_runners The task runners - /// @param[in] window_data The default data for setting up + /// @param[in] platform_data The default data for setting up /// ui.Window that attached to this /// intance. /// @param[in] settings The settings @@ -203,7 +203,7 @@ class Shell final : public PlatformView::Delegate, /// static std::unique_ptr Create( TaskRunners task_runners, - const WindowData window_data, + const PlatformData platform_data, Settings settings, fml::RefPtr isolate_snapshot, const CreateCallback& on_create_platform_view, @@ -426,7 +426,7 @@ class Shell final : public PlatformView::Delegate, static std::unique_ptr CreateShellOnPlatformThread( DartVMRef vm, TaskRunners task_runners, - const WindowData window_data, + const PlatformData platform_data, Settings settings, fml::RefPtr isolate_snapshot, const Shell::CreateCallback& on_create_platform_view, diff --git a/shell/common/shell_test.cc b/shell/common/shell_test.cc index c8ebf642e056f..5d44e2cfe5151 100644 --- a/shell/common/shell_test.cc +++ b/shell/common/shell_test.cc @@ -100,10 +100,7 @@ void ShellTest::PumpOneFrame(Shell* shell, double width, double height, LayerTreeBuilder builder) { - PumpOneFrame(shell, - flutter::ViewportMetrics{1, width, height, flutter::kUnsetDepth, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - std::move(builder)); + PumpOneFrame(shell, {1.0, width, height}, std::move(builder)); } void ShellTest::PumpOneFrame(Shell* shell, diff --git a/shell/common/shell_unittests.cc b/shell/common/shell_unittests.cc index 5f82ee64b5b50..55b2e1b837f05 100644 --- a/shell/common/shell_unittests.cc +++ b/shell/common/shell_unittests.cc @@ -684,7 +684,7 @@ TEST_F(ShellTest, WaitForFirstFrameZeroSizeFrame) { configuration.SetEntrypoint("emptyMain"); RunEngine(shell.get(), std::move(configuration)); - PumpOneFrame(shell.get(), {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}); + PumpOneFrame(shell.get(), {1.0, 0.0, 0.0}); fml::Status result = shell->WaitForFirstFrame(fml::TimeDelta::FromMilliseconds(1000)); ASSERT_FALSE(result.ok()); @@ -802,8 +802,7 @@ TEST_F(ShellTest, SetResourceCacheSize) { fml::TaskRunner::RunNowOrPostTask( shell->GetTaskRunners().GetPlatformTaskRunner(), [&shell]() { - shell->GetPlatformView()->SetViewportMetrics( - {1.0, 400, 200, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}); + shell->GetPlatformView()->SetViewportMetrics({1.0, 400, 200}); }); PumpOneFrame(shell.get()); @@ -822,8 +821,7 @@ TEST_F(ShellTest, SetResourceCacheSize) { fml::TaskRunner::RunNowOrPostTask( shell->GetTaskRunners().GetPlatformTaskRunner(), [&shell]() { - shell->GetPlatformView()->SetViewportMetrics( - {1.0, 800, 400, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}); + shell->GetPlatformView()->SetViewportMetrics({1.0, 800, 400}); }); PumpOneFrame(shell.get()); @@ -841,8 +839,7 @@ TEST_F(ShellTest, SetResourceCacheSizeEarly) { fml::TaskRunner::RunNowOrPostTask( shell->GetTaskRunners().GetPlatformTaskRunner(), [&shell]() { - shell->GetPlatformView()->SetViewportMetrics( - {1.0, 400, 200, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}); + shell->GetPlatformView()->SetViewportMetrics({1.0, 400, 200}); }); PumpOneFrame(shell.get()); @@ -870,8 +867,7 @@ TEST_F(ShellTest, SetResourceCacheSizeNotifiesDart) { fml::TaskRunner::RunNowOrPostTask( shell->GetTaskRunners().GetPlatformTaskRunner(), [&shell]() { - shell->GetPlatformView()->SetViewportMetrics( - {1.0, 400, 200, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}); + shell->GetPlatformView()->SetViewportMetrics({1.0, 400, 200}); }); PumpOneFrame(shell.get()); @@ -1235,7 +1231,7 @@ TEST_F(ShellTest, CanDecompressImageFromAsset) { } TEST_F(ShellTest, OnServiceProtocolGetSkSLsWorks) { - // Create 2 dummpy SkSL cache file IE (base32 encoding of A), II (base32 + // Create 2 dummy SkSL cache file IE (base32 encoding of A), II (base32 // encoding of B) with content x and y. fml::ScopedTemporaryDirectory temp_dir; PersistentCache::SetCacheDirectoryPath(temp_dir.path()); diff --git a/shell/platform/android/android_shell_holder.cc b/shell/platform/android/android_shell_holder.cc index c9667dcb7edf3..a928efe85d232 100644 --- a/shell/platform/android/android_shell_holder.cc +++ b/shell/platform/android/android_shell_holder.cc @@ -22,10 +22,10 @@ namespace flutter { -static WindowData GetDefaultWindowData() { - WindowData window_data; - window_data.lifecycle_state = "AppLifecycleState.detached"; - return window_data; +static PlatformData GetDefaultPlatformData() { + PlatformData platform_data; + platform_data.lifecycle_state = "AppLifecycleState.detached"; + return platform_data; } bool AndroidShellHolder::use_embedded_view; @@ -121,9 +121,9 @@ AndroidShellHolder::AndroidShellHolder( ); shell_ = - Shell::Create(task_runners, // task runners - GetDefaultWindowData(), // window data - settings_, // settings + Shell::Create(task_runners, // task runners + GetDefaultPlatformData(), // window data + settings_, // settings on_create_platform_view, // platform view create callback on_create_rasterizer // rasterizer create callback ); @@ -137,9 +137,9 @@ AndroidShellHolder::AndroidShellHolder( ); shell_ = - Shell::Create(task_runners, // task runners - GetDefaultWindowData(), // window data - settings_, // settings + Shell::Create(task_runners, // task runners + GetDefaultPlatformData(), // window data + settings_, // settings on_create_platform_view, // platform view create callback on_create_rasterizer // rasterizer create callback ); diff --git a/shell/platform/android/android_shell_holder.h b/shell/platform/android/android_shell_holder.h index 6fb6695801733..28ad8610882f7 100644 --- a/shell/platform/android/android_shell_holder.h +++ b/shell/platform/android/android_shell_holder.h @@ -10,7 +10,7 @@ #include "flutter/fml/macros.h" #include "flutter/fml/unique_fd.h" #include "flutter/lib/ui/window/viewport_metrics.h" -#include "flutter/runtime/window_data.h" +#include "flutter/runtime/platform_data.h" #include "flutter/shell/common/run_configuration.h" #include "flutter/shell/common/shell.h" #include "flutter/shell/common/thread_host.h" diff --git a/shell/platform/android/io/flutter/embedding/android/FlutterView.java b/shell/platform/android/io/flutter/embedding/android/FlutterView.java index 76b0f2461141c..860d9c4786025 100644 --- a/shell/platform/android/io/flutter/embedding/android/FlutterView.java +++ b/shell/platform/android/io/flutter/embedding/android/FlutterView.java @@ -1063,7 +1063,7 @@ public FlutterEngine getAttachedFlutterEngine() { } /** - * Adds a {@link FlutterEngineAttachmentListener}, which is notifed whenever this {@code + * Adds a {@link FlutterEngineAttachmentListener}, which is notified whenever this {@code * FlutterView} attached to/detaches from a {@link FlutterEngine}. */ @VisibleForTesting diff --git a/shell/platform/darwin/ios/framework/Source/FlutterDartProject.mm b/shell/platform/darwin/ios/framework/Source/FlutterDartProject.mm index 3e8bc4727b64b..c9bf2ba962e16 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterDartProject.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterDartProject.mm @@ -168,12 +168,12 @@ - (instancetype)initWithPrecompiledDartBundle:(nullable NSBundle*)bundle { return self; } -#pragma mark - WindowData accessors +#pragma mark - PlatformData accessors -- (const flutter::WindowData)defaultWindowData { - flutter::WindowData windowData; - windowData.lifecycle_state = std::string("AppLifecycleState.detached"); - return windowData; +- (const flutter::PlatformData)defaultPlatformData { + flutter::PlatformData PlatformData; + PlatformData.lifecycle_state = std::string("AppLifecycleState.detached"); + return PlatformData; } #pragma mark - Settings accessors @@ -261,6 +261,6 @@ - (void)setPersistentIsolateData:(NSData*)data { ); } -#pragma mark - windowData utilities +#pragma mark - PlatformData utilities @end diff --git a/shell/platform/darwin/ios/framework/Source/FlutterDartProject_Internal.h b/shell/platform/darwin/ios/framework/Source/FlutterDartProject_Internal.h index b21a38a9be6fd..9ac366f5fcc0c 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterDartProject_Internal.h +++ b/shell/platform/darwin/ios/framework/Source/FlutterDartProject_Internal.h @@ -6,7 +6,7 @@ #define SHELL_PLATFORM_IOS_FRAMEWORK_SOURCE_FLUTTERDARTPROJECT_INTERNAL_H_ #include "flutter/common/settings.h" -#include "flutter/runtime/window_data.h" +#include "flutter/runtime/platform_data.h" #include "flutter/shell/common/engine.h" #include "flutter/shell/platform/darwin/ios/framework/Headers/FlutterDartProject.h" @@ -15,7 +15,7 @@ NS_ASSUME_NONNULL_BEGIN @interface FlutterDartProject () - (const flutter::Settings&)settings; -- (const flutter::WindowData)defaultWindowData; +- (const flutter::PlatformData)defaultPlatformData; - (flutter::RunConfiguration)runConfiguration; - (flutter::RunConfiguration)runConfigurationForEntrypoint:(nullable NSString*)entrypointOrNil; diff --git a/shell/platform/darwin/ios/framework/Source/FlutterEngine.mm b/shell/platform/darwin/ios/framework/Source/FlutterEngine.mm index 57d531ec7420d..51a741fa4109f 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterEngine.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterEngine.mm @@ -17,6 +17,9 @@ #include "flutter/shell/common/switches.h" #include "flutter/shell/common/thread_host.h" #include "flutter/shell/platform/darwin/common/command_line.h" +#include "flutter/shell/platform/darwin/ios/rendering_api_selection.h" +#include "flutter/shell/profiling/sampling_profiler.h" + #import "flutter/shell/platform/darwin/ios/framework/Source/FlutterBinaryMessengerRelay.h" #import "flutter/shell/platform/darwin/ios/framework/Source/FlutterDartProject_Internal.h" #import "flutter/shell/platform/darwin/ios/framework/Source/FlutterObservatoryPublisher.h" @@ -28,8 +31,6 @@ #import "flutter/shell/platform/darwin/ios/framework/Source/profiler_metrics_ios.h" #import "flutter/shell/platform/darwin/ios/ios_surface.h" #import "flutter/shell/platform/darwin/ios/platform_view_ios.h" -#include "flutter/shell/platform/darwin/ios/rendering_api_selection.h" -#include "flutter/shell/profiling/sampling_profiler.h" NSString* const FlutterDefaultDartEntrypoint = nil; static constexpr int kNumProfilerSamplesPerSec = 5; @@ -445,7 +446,7 @@ - (BOOL)createShell:(NSString*)entrypoint libraryURI:(NSString*)libraryURI { static size_t shellCount = 1; auto settings = [_dartProject.get() settings]; - auto windowData = [_dartProject.get() defaultWindowData]; + auto platformData = [_dartProject.get() defaultPlatformData]; if (libraryURI) { FML_DCHECK(entrypoint) << "Must specify entrypoint if specifying library"; @@ -510,10 +511,10 @@ - (BOOL)createShell:(NSString*)entrypoint libraryURI:(NSString*)libraryURI { ); // Create the shell. This is a blocking operation. _shell = flutter::Shell::Create(std::move(task_runners), // task runners - std::move(windowData), // window data + std::move(platformData), // platform data std::move(settings), // settings on_create_platform_view, // platform view creation - on_create_rasterizer // rasterzier creation + on_create_rasterizer // rasterizer creation ); } else { flutter::TaskRunners task_runners(threadLabel.UTF8String, // label @@ -524,10 +525,10 @@ - (BOOL)createShell:(NSString*)entrypoint libraryURI:(NSString*)libraryURI { ); // Create the shell. This is a blocking operation. _shell = flutter::Shell::Create(std::move(task_runners), // task runners - std::move(windowData), // window data + std::move(platformData), // platform data std::move(settings), // settings on_create_platform_view, // platform view creation - on_create_rasterizer // rasterzier creation + on_create_rasterizer // rasterizer creation ); } diff --git a/shell/platform/embedder/embedder.h b/shell/platform/embedder/embedder.h index 6277ccd4e80c8..3a6126300f8b7 100644 --- a/shell/platform/embedder/embedder.h +++ b/shell/platform/embedder/embedder.h @@ -9,6 +9,39 @@ #include #include +// This file defines an Application Binary Interface (ABI), which requires more +// stability than regular code to remain functional for exchanging messages +// between different versions of the embedding and the engine, to allow for both +// forward and backward compatibility. +// +// Specifically, +// - The order, type, and size of the struct members below must remain the same, +// and members should not be removed. +// - New structures that are part of the ABI must be defined with "size_t +// struct_size;" as their first member, which should be initialized using +// "sizeof(Type)". +// - Enum values must not change or be removed. +// - Enum members without explicit values must not be reordered. +// - Function signatures (names, argument counts, argument order, and argument +// type) cannot change. +// - The core behavior of existing functions cannot change. +// +// These changes are allowed: +// - Adding new struct members at the end of a structure. +// - Adding new enum members with a new value. +// - Renaming a struct member as long as its type, size, and intent remain the +// same. +// - Renaming an enum member as long as its value and intent remains the same. +// +// It is expected that struct members and implicitly-valued enums will not +// always be declared in an order that is optimal for the reader, since members +// will be added over time, and they can't be reordered. +// +// Existing functions should continue to appear from the caller's point of view +// to operate as they did when they were first introduced, so introduce a new +// function instead of modifying the core behavior of a function (and continue +// to support the existing function with the previous behavior). + #if defined(__cplusplus) extern "C" { #endif diff --git a/shell/platform/embedder/embedder_engine.h b/shell/platform/embedder/embedder_engine.h index 124f8af0cf9aa..151b489bb9465 100644 --- a/shell/platform/embedder/embedder_engine.h +++ b/shell/platform/embedder/embedder_engine.h @@ -12,7 +12,6 @@ #include "flutter/shell/common/shell.h" #include "flutter/shell/common/thread_host.h" #include "flutter/shell/platform/embedder/embedder.h" -#include "flutter/shell/platform/embedder/embedder_engine.h" #include "flutter/shell/platform/embedder/embedder_external_texture_gl.h" #include "flutter/shell/platform/embedder/embedder_thread_host.h" diff --git a/shell/platform/fuchsia/flutter/engine.cc b/shell/platform/fuchsia/flutter/engine.cc index 1d5a2eca8c67f..7868a19671c1a 100644 --- a/shell/platform/fuchsia/flutter/engine.cc +++ b/shell/platform/fuchsia/flutter/engine.cc @@ -257,7 +257,7 @@ Engine::Engine(Delegate& delegate, TRACE_EVENT0("flutter", "CreateShell"); shell_ = flutter::Shell::Create( task_runners, // host task runners - flutter::WindowData(), // default window data + flutter::PlatformData(), // default window data settings_, // shell launch settings std::move(isolate_snapshot), // isolate snapshot on_create_platform_view, // platform view create callback diff --git a/shell/testing/tester_main.cc b/shell/testing/tester_main.cc index 8d14e6376e4a8..63029a065ce7d 100644 --- a/shell/testing/tester_main.cc +++ b/shell/testing/tester_main.cc @@ -235,10 +235,10 @@ int RunTester(const flutter::Settings& settings, } }); - flutter::ViewportMetrics metrics; + flutter::ViewportMetrics metrics{}; metrics.device_pixel_ratio = 3.0; - metrics.physical_width = 2400; // 800 at 3x resolution - metrics.physical_height = 1800; // 600 at 3x resolution + metrics.physical_width = 2400.0; // 800 at 3x resolution. + metrics.physical_height = 1800.0; // 600 at 3x resolution. shell->GetPlatformView()->SetViewportMetrics(metrics); // Run the message loop and wait for the script to do its thing.