From ef217c6c30abbb0d3cdb6592f27c151980ee8a0c Mon Sep 17 00:00:00 2001 From: Greg Spencer Date: Tue, 5 May 2020 18:46:12 -0700 Subject: [PATCH 1/8] Move platform specific information to PlatformConfiguration class. --- ci/licenses_golden/licenses_flutter | 7 +- lib/ui/BUILD.gn | 3 + lib/ui/compositing/scene.cc | 6 +- lib/ui/dart_ui.cc | 4 +- lib/ui/hooks.dart | 2 +- lib/ui/painting/canvas.cc | 11 +- lib/ui/text/font_collection.cc | 8 +- lib/ui/text/paragraph_builder.cc | 8 +- lib/ui/ui_dart_state.cc | 19 +- lib/ui/ui_dart_state.h | 11 +- lib/ui/window.dart | 22 +- lib/ui/window/platform_configuration.cc | 442 ++++++++++++++++++ lib/ui/window/platform_configuration.h | 126 +++++ .../platform_configuration_unittests.cc | 57 +++ lib/ui/window/viewport_metrics.cc | 12 + lib/ui/window/viewport_metrics.h | 6 + lib/ui/window/window.cc | 407 +--------------- lib/ui/window/window.h | 84 +--- runtime/BUILD.gn | 4 +- runtime/dart_isolate.cc | 7 +- runtime/dart_isolate.h | 4 +- runtime/{window_data.cc => platform_data.cc} | 6 +- runtime/{window_data.h => platform_data.h} | 14 +- runtime/runtime_controller.cc | 149 +++--- runtime/runtime_controller.h | 40 +- shell/common/engine.cc | 7 +- shell/common/engine.h | 2 +- shell/common/shell.cc | 26 +- shell/common/shell.h | 10 +- shell/common/shell_test.cc | 5 +- shell/common/shell_unittests.cc | 16 +- .../platform/android/android_shell_holder.cc | 20 +- shell/platform/android/android_shell_holder.h | 2 +- .../embedding/android/FlutterView.java | 2 +- .../framework/Source/FlutterDartProject.mm | 12 +- .../Source/FlutterDartProject_Internal.h | 4 +- .../ios/framework/Source/FlutterEngine.mm | 15 +- shell/platform/embedder/embedder.h | 54 +++ shell/platform/embedder/embedder_engine.h | 1 - shell/platform/fuchsia/flutter/engine.cc | 2 +- shell/testing/tester_main.cc | 7 +- 41 files changed, 954 insertions(+), 690 deletions(-) create mode 100644 lib/ui/window/platform_configuration.cc create mode 100644 lib/ui/window/platform_configuration.h create mode 100644 lib/ui/window/platform_configuration_unittests.cc rename runtime/{window_data.cc => platform_data.cc} (63%) rename runtime/{window_data.h => platform_data.h} (81%) diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index 0134ce99514dd..d92536927d64d 100755 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -395,6 +395,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 @@ -571,6 +574,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 @@ -583,8 +588,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 06a950461a53a..5fb7bc8b5f5db 100644 --- a/lib/ui/BUILD.gn +++ b/lib/ui/BUILD.gn @@ -89,6 +89,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..582954328034a 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() + ->get_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 313aefc5d336c..df5b0180258c6 100644 --- a/lib/ui/dart_ui.cc +++ b/lib/ui/dart_ui.cc @@ -28,7 +28,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" @@ -81,7 +81,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/hooks.dart b/lib/ui/hooks.dart index ff2dcaa127391..5fa85f1e849a4 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 0390c179d02c1..6b367a4df1a8b 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" @@ -421,11 +422,15 @@ void Canvas::drawShadow(const CanvasPath* path, SkColor color, double elevation, bool transparentOccluder) { - if (!path) + if (!path) { Dart_ThrowException( ToDart("Canvas.drawShader called with non-genuine Path.")); - SkScalar dpr = - UIDartState::Current()->window()->viewport_metrics().device_pixel_ratio; + } + SkScalar dpr = UIDartState::Current() + ->platform_configuration() + ->get_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 c59dac720875d..a133fa8d72286 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, 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 aeeb8a0b4ad8e..69c2f663af492 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 4d04a30d404c2..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,18 +73,23 @@ 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_); + } } 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_); + } } const TaskRunners& UIDartState::GetTaskRunners() const { diff --git a/lib/ui/ui_dart_state.h b/lib/ui/ui_dart_state.h index 2fdedc8094963..816fbb9840d48 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 815bee5a15565..d8baf1caa88a8 100644 --- a/lib/ui/window.dart +++ b/lib/ui/window.dart @@ -822,7 +822,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. /// @@ -1000,7 +1000,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. /// @@ -1050,7 +1050,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. @@ -1059,7 +1059,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 @@ -1085,7 +1085,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. @@ -1125,7 +1125,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. @@ -1147,7 +1147,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. /// @@ -1157,7 +1157,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. /// @@ -1178,7 +1178,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. @@ -1203,7 +1203,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. @@ -1229,7 +1229,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..9e41acce8276c --- /dev/null +++ b/lib/ui/window/platform_configuration.cc @@ -0,0 +1,442 @@ +// 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), window_(new Window({1.0, 0.0, 0.0})) {} + +PlatformConfiguration::~PlatformConfiguration() {} + +void PlatformConfiguration::DidCreateIsolate() { + library_.Set(tonic::DartState::Current(), + Dart_LookupLibrary(tonic::ToDart("dart:ui"))); +} + +void PlatformConfiguration::SetWindowMetrics( + const ViewportMetrics& window_metrics) { + window_->UpdateWindowMetrics(library_, window_metrics); +} + +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::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 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..4362efdf9907c --- /dev/null +++ b/lib/ui/window/platform_configuration.h @@ -0,0 +1,126 @@ +// 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; + +// 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, +}; + +class PlatformConfigurationClient { + 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 ~PlatformConfigurationClient(); +}; + +class PlatformConfiguration final { + public: + explicit PlatformConfiguration(PlatformConfigurationClient* client); + + ~PlatformConfiguration(); + + PlatformConfigurationClient* client() const { return client_; } + + void DidCreateIsolate(); + 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); + + //---------------------------------------------------------------------------- + /// @brief Retrieves the Window. + /// + /// @return the Window. + const Window& get_window() const { return *window_; } + + //---------------------------------------------------------------------------- + /// @brief Sets the viewport metrics of the Window. + /// + /// @param[in] window_metrics The viewport metrics to replace the old ones + /// with. + void SetWindowMetrics(const ViewportMetrics& window_metrics); + + 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..bcd9293ea1255 --- /dev/null +++ b/lib/ui/window/platform_configuration_unittests.cc @@ -0,0 +1,57 @@ +// 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 "dart_api.h" +#include "runtime/dart_isolate.h" +#define FML_USED_ON_EMBEDDER + +#include + +#include "flutter/lib/ui/window/platform_configuration.h" + +#include "flutter/fml/mapping.h" +#include "flutter/runtime/dart_vm.h" +#include "flutter/testing/testing.h" +#include "gtest/gtest.h" +#include "lib/ui/text/font_collection.h" + +namespace flutter { +namespace testing { + +class DummyPlatformConfigurationClient : public PlatformConfigurationClient { + public: + DummyPlatformConfigurationClient() { + std::vector data; + isolate_data_.reset(new ::fml::DataMapping(data)); + } + virtual std::string DefaultRouteName() { return "TestRoute"; } + virtual void ScheduleFrame() {} + virtual void Render(Scene* scene) {} + virtual void UpdateSemantics(SemanticsUpdate* update) {} + virtual void HandlePlatformMessage(fml::RefPtr message) {} + virtual FontCollection& GetFontCollection() { return font_collection_; } + virtual void UpdateIsolateDescription(const std::string isolate_name, + int64_t isolate_port) {} + virtual void SetNeedsReportTimings(bool value) {} + virtual std::shared_ptr GetPersistentIsolateData() { + return isolate_data_; + } + virtual std::unique_ptr> + ComputePlatformResolvedLocale( + const std::vector& supported_locale_data) { + return nullptr; + }; + + private: + FontCollection font_collection_; + std::shared_ptr isolate_data_; +}; + +TEST(PlatformConfigurationTest, PlatformConfigurationInitialization) { + DummyPlatformConfigurationClient client; + PlatformConfiguration configuration(&client); +} + +} // 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 7c1c0fa2ce421..8114f88143486 100644 --- a/lib/ui/window/window.cc +++ b/lib/ui/window/window.cc @@ -4,194 +4,28 @@ #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 "lib/ui/window/viewport_metrics.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); -} - -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->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()); - 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(ViewportMetrics metrics) : viewport_metrics_(metrics) {} Window::~Window() {} -void Window::DidCreateIsolate() { - library_.Set(tonic::DartState::Current(), - Dart_LookupLibrary(tonic::ToDart("dart:ui"))); -} - -void Window::UpdateWindowMetrics(const ViewportMetrics& metrics) { +void Window::UpdateWindowMetrics(const tonic::DartPersistentValue& library, + const ViewportMetrics& metrics) { viewport_metrics_ = metrics; - std::shared_ptr dart_state = library_.dart_state().lock(); - if (!dart_state) + 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(), "_updateWindowMetrics", + library.value(), "_updateWindowMetrics", { tonic::ToDart(metrics.device_pixel_ratio), tonic::ToDart(metrics.physical_width), @@ -212,229 +46,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 95055c70beddb..dcb06c9b73f08 100644 --- a/lib/ui/window/window.h +++ b/lib/ui/window/window.h @@ -9,102 +9,26 @@ #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/GrContext.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() { return viewport_metrics_; } + const ViewportMetrics& viewport_metrics() const { 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 tonic::DartPersistentValue& library, + 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 3cf9cb75739bd..76ab7ed822f0f 100644 --- a/runtime/BUILD.gn +++ b/runtime/BUILD.gn @@ -55,6 +55,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", @@ -65,8 +67,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 = [ diff --git a/runtime/dart_isolate.cc b/runtime/dart_isolate.cc index d23b38e752b3e..26b062ff491df 100644 --- a/runtime/dart_isolate.cc +++ b/runtime/dart_isolate.cc @@ -56,7 +56,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, @@ -111,7 +111,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(); } @@ -597,7 +598,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..4ab4ca795b495 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->SetWindowMetrics(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->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 7428cbf49828e..070637874ea60 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 e92a91a955742..848fc1584efcf 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, diff --git a/shell/common/shell.cc b/shell/common/shell.cc index 976d1befb37b5..7d04abc5f7cf8 100644 --- a/shell/common/shell.cc +++ b/shell/common/shell.cc @@ -42,7 +42,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, @@ -133,7 +133,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, // @@ -154,7 +154,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(), // @@ -241,17 +241,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) { @@ -266,7 +266,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, // @@ -277,7 +277,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, @@ -301,7 +301,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, // @@ -309,7 +309,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 a2b04b8a44543..acb3e0cf50fbd 100644 --- a/shell/common/shell_unittests.cc +++ b/shell/common/shell_unittests.cc @@ -683,7 +683,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()); @@ -801,8 +801,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()); @@ -821,8 +820,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()); @@ -840,8 +838,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()); @@ -869,8 +866,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()); @@ -1234,7 +1230,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 52b337978aed5..fd0468d234dc7 100644 --- a/shell/platform/android/io/flutter/embedding/android/FlutterView.java +++ b/shell/platform/android/io/flutter/embedding/android/FlutterView.java @@ -1021,7 +1021,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 84b027273b755..947d9d368025a 100644 --- a/shell/platform/embedder/embedder.h +++ b/shell/platform/embedder/embedder.h @@ -273,6 +273,9 @@ typedef bool (*TextureFrameCallback)(void* /* user data */, FlutterOpenGLTexture* /* texture out */); typedef void (*VsyncCallback)(void* /* user data */, intptr_t /* baton */); +/// The order, type, and size of these struct members must remain the same, and +/// members should not be removed. This is to allow for forward and backward +/// compatibility between the engine and the embedder. typedef struct { /// The size of this struct. Must be sizeof(FlutterOpenGLRendererConfig). size_t struct_size; @@ -311,6 +314,9 @@ typedef struct { TextureFrameCallback gl_external_texture_frame_callback; } FlutterOpenGLRendererConfig; +/// The order, type, and size of these struct members must remain the same, and +/// members should not be removed. This is to allow for forward and backward +/// compatibility between the engine and the embedder. typedef struct { /// The size of this struct. Must be sizeof(FlutterSoftwareRendererConfig). size_t struct_size; @@ -329,6 +335,9 @@ typedef struct { }; } FlutterRendererConfig; +/// The order, type, and size of these struct members must remain the same, and +/// members should not be removed. This is to allow for forward and backward +/// compatibility between the engine and the embedder. typedef struct { /// The size of this struct. Must be sizeof(FlutterWindowMetricsEvent). size_t struct_size; @@ -400,6 +409,9 @@ typedef enum { kFlutterPointerSignalKindScroll, } FlutterPointerSignalKind; +/// The order, type, and size of these struct members must remain the same, and +/// members should not be removed. This is to allow for forward and backward +/// compatibility between the engine and the embedder. typedef struct { /// The size of this struct. Must be sizeof(FlutterPointerEvent). size_t struct_size; @@ -434,6 +446,9 @@ struct _FlutterPlatformMessageResponseHandle; typedef struct _FlutterPlatformMessageResponseHandle FlutterPlatformMessageResponseHandle; +/// The order, type, and size of these struct members must remain the same, and +/// members should not be removed. This is to allow for forward and backward +/// compatibility between the engine and the embedder. typedef struct { /// The size of this struct. Must be sizeof(FlutterPlatformMessage). size_t struct_size; @@ -498,6 +513,10 @@ extern const int32_t kFlutterSemanticsNodeIdBatchEnd; /// (i.e., during PipelineOwner.flushSemantics), which happens after /// compositing. Updates are then pushed to embedders via the registered /// `FlutterUpdateSemanticsNodeCallback`. +/// +/// The order, type, and size of these struct members must remain the same, and +/// members should not be removed. This is to allow for forward and backward +/// compatibility between the engine and the embedder. typedef struct { /// The size of this struct. Must be sizeof(FlutterSemanticsNode). size_t struct_size; @@ -577,6 +596,10 @@ extern const int32_t kFlutterSemanticsCustomActionIdBatchEnd; /// Action overrides are custom actions that the application developer requests /// to be used in place of the standard actions in the `FlutterSemanticsAction` /// enum. +/// +/// The order, type, and size of these struct members must remain the same, and +/// members should not be removed. This is to allow for forward and backward +/// compatibility between the engine and the embedder. typedef struct { /// The size of the struct. Must be sizeof(FlutterSemanticsCustomAction). size_t struct_size; @@ -615,6 +638,10 @@ typedef void (*FlutterTaskRunnerPostTaskCallback)( /// on a specified thread. There should be a 1-1 relationship between a thread /// and a task runner. It is undefined behavior to run a task on a thread that /// is not associated with its task runner. +/// +/// The order, type, and size of these struct members must remain the same, and +/// members should not be removed. This is to allow for forward and backward +/// compatibility between the engine and the embedder. typedef struct { /// The size of this struct. Must be sizeof(FlutterTaskRunnerDescription). size_t struct_size; @@ -640,6 +667,9 @@ typedef struct { size_t identifier; } FlutterTaskRunnerDescription; +/// The order, type, and size of these struct members must remain the same, and +/// members should not be removed. This is to allow for forward and backward +/// compatibility between the engine and the embedder. typedef struct { /// The size of this struct. Must be sizeof(FlutterCustomTaskRunners). size_t struct_size; @@ -711,6 +741,9 @@ typedef struct { }; } FlutterPlatformViewMutation; +/// The order, type, and size of these struct members must remain the same, and +/// members should not be removed. This is to allow for forward and backward +/// compatibility between the engine and the embedder. typedef struct { /// The size of this struct. Must be sizeof(FlutterPlatformView). size_t struct_size; @@ -744,6 +777,9 @@ typedef enum { kFlutterBackingStoreTypeSoftware, } FlutterBackingStoreType; +/// The order, type, and size of these struct members must remain the same, and +/// members should not be removed. This is to allow for forward and backward +/// compatibility between the engine and the embedder. typedef struct { /// The size of this struct. Must be sizeof(FlutterBackingStore). size_t struct_size; @@ -764,6 +800,9 @@ typedef struct { }; } FlutterBackingStore; +/// The order, type, and size of these struct members must remain the same, and +/// members should not be removed. This is to allow for forward and backward +/// compatibility between the engine and the embedder. typedef struct { /// The size of this struct. Must be sizeof(FlutterBackingStoreConfig). size_t struct_size; @@ -779,6 +818,9 @@ typedef enum { kFlutterLayerContentTypePlatformView, } FlutterLayerContentType; +/// The order, type, and size of these struct members must remain the same, and +/// members should not be removed. This is to allow for forward and backward +/// compatibility between the engine and the embedder. typedef struct { /// This size of this struct. Must be sizeof(FlutterLayer). size_t struct_size; @@ -813,6 +855,9 @@ typedef bool (*FlutterLayersPresentCallback)(const FlutterLayer** layers, size_t layers_count, void* user_data); +/// The order, type, and size of these struct members must remain the same, and +/// members should not be removed. This is to allow for forward and backward +/// compatibility between the engine and the embedder. typedef struct { /// This size of this struct. Must be sizeof(FlutterCompositor). size_t struct_size; @@ -837,6 +882,9 @@ typedef struct { FlutterLayersPresentCallback present_layers_callback; } FlutterCompositor; +/// The order, type, and size of these struct members must remain the same, and +/// members should not be removed. This is to allow for forward and backward +/// compatibility between the engine and the embedder. typedef struct { /// This size of this struct. Must be sizeof(FlutterLocale). size_t struct_size; @@ -875,6 +923,9 @@ typedef enum { kFlutterEngineDartObjectTypeBuffer, } FlutterEngineDartObjectType; +/// The order, type, and size of these struct members must remain the same, and +/// members should not be removed. This is to allow for forward and backward +/// compatibility between the engine and the embedder. typedef struct { /// The size of this struct. Must be sizeof(FlutterEngineDartBuffer). size_t struct_size; @@ -1010,6 +1061,9 @@ FlutterEngineResult FlutterEngineCreateAOTData( FLUTTER_EXPORT FlutterEngineResult FlutterEngineCollectAOTData(FlutterEngineAOTData data); +/// The order, type, and size of these struct members must remain the same, and +/// members should not be removed. This is to allow for forward and backward +/// compatibility between the engine and the embedder. typedef struct { /// The size of this struct. Must be sizeof(FlutterProjectArgs). size_t struct_size; 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 73b6ce77257d0..7c5599127d8ed 100644 --- a/shell/testing/tester_main.cc +++ b/shell/testing/tester_main.cc @@ -234,11 +234,8 @@ int RunTester(const flutter::Settings& settings, } }); - 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 - shell->GetPlatformView()->SetViewportMetrics(metrics); + // 800x600 at 3x resolution. + shell->GetPlatformView()->SetViewportMetrics({3.0, 2400, 1800}); // Run the message loop and wait for the script to do its thing. fml::MessageLoop::GetCurrent().Run(); From a72edab5f38ae847296263d93fceb08bef4570a6 Mon Sep 17 00:00:00 2001 From: Greg Spencer Date: Fri, 10 Jul 2020 17:49:45 -0700 Subject: [PATCH 2/8] Add tests --- lib/ui/compositing/scene.cc | 2 +- lib/ui/painting/canvas.cc | 2 +- lib/ui/window/platform_configuration.h | 2 +- lib/ui/window/platform_configuration_unittests.cc | 15 +++++++++++++++ 4 files changed, 18 insertions(+), 3 deletions(-) diff --git a/lib/ui/compositing/scene.cc b/lib/ui/compositing/scene.cc index 582954328034a..00e619b945c7a 100644 --- a/lib/ui/compositing/scene.cc +++ b/lib/ui/compositing/scene.cc @@ -44,7 +44,7 @@ Scene::Scene(std::shared_ptr rootLayer, bool checkerboardOffscreenLayers) { auto viewport_metrics = UIDartState::Current() ->platform_configuration() - ->get_window() + ->window() .viewport_metrics(); layer_tree_ = std::make_unique( diff --git a/lib/ui/painting/canvas.cc b/lib/ui/painting/canvas.cc index 6b367a4df1a8b..22a8d4987e6ab 100644 --- a/lib/ui/painting/canvas.cc +++ b/lib/ui/painting/canvas.cc @@ -428,7 +428,7 @@ void Canvas::drawShadow(const CanvasPath* path, } SkScalar dpr = UIDartState::Current() ->platform_configuration() - ->get_window() + ->window() .viewport_metrics() .device_pixel_ratio; external_allocation_size_ += path->path().approximateBytesUsed(); diff --git a/lib/ui/window/platform_configuration.h b/lib/ui/window/platform_configuration.h index 4362efdf9907c..49229280d5ea4 100644 --- a/lib/ui/window/platform_configuration.h +++ b/lib/ui/window/platform_configuration.h @@ -100,7 +100,7 @@ class PlatformConfiguration final { /// @brief Retrieves the Window. /// /// @return the Window. - const Window& get_window() const { return *window_; } + const Window& window() const { return *window_; } //---------------------------------------------------------------------------- /// @brief Sets the viewport metrics of the Window. diff --git a/lib/ui/window/platform_configuration_unittests.cc b/lib/ui/window/platform_configuration_unittests.cc index bcd9293ea1255..9e966de7ef1e2 100644 --- a/lib/ui/window/platform_configuration_unittests.cc +++ b/lib/ui/window/platform_configuration_unittests.cc @@ -51,6 +51,21 @@ class DummyPlatformConfigurationClient : public PlatformConfigurationClient { TEST(PlatformConfigurationTest, PlatformConfigurationInitialization) { DummyPlatformConfigurationClient client; PlatformConfiguration configuration(&client); + + ASSERT_EQ(configuration.client(), &client); + 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); +} + +TEST(PlatformConfigurationTest, PlatformConfigurationWindowMetricsUpdate) { + DummyPlatformConfigurationClient client; + PlatformConfiguration configuration(&client); + + configuration.SetWindowMetrics({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); } } // namespace testing From 50cdd52173c8906710206ad132798250077e9534 Mon Sep 17 00:00:00 2001 From: Greg Spencer Date: Tue, 5 May 2020 18:46:12 -0700 Subject: [PATCH 3/8] Move platform specific information to PlatformConfiguration class. --- lib/ui/compositing/scene.cc | 2 +- lib/ui/painting/canvas.cc | 2 +- lib/ui/window/platform_configuration.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/ui/compositing/scene.cc b/lib/ui/compositing/scene.cc index 00e619b945c7a..582954328034a 100644 --- a/lib/ui/compositing/scene.cc +++ b/lib/ui/compositing/scene.cc @@ -44,7 +44,7 @@ Scene::Scene(std::shared_ptr rootLayer, bool checkerboardOffscreenLayers) { auto viewport_metrics = UIDartState::Current() ->platform_configuration() - ->window() + ->get_window() .viewport_metrics(); layer_tree_ = std::make_unique( diff --git a/lib/ui/painting/canvas.cc b/lib/ui/painting/canvas.cc index 22a8d4987e6ab..6b367a4df1a8b 100644 --- a/lib/ui/painting/canvas.cc +++ b/lib/ui/painting/canvas.cc @@ -428,7 +428,7 @@ void Canvas::drawShadow(const CanvasPath* path, } SkScalar dpr = UIDartState::Current() ->platform_configuration() - ->window() + ->get_window() .viewport_metrics() .device_pixel_ratio; external_allocation_size_ += path->path().approximateBytesUsed(); diff --git a/lib/ui/window/platform_configuration.h b/lib/ui/window/platform_configuration.h index 49229280d5ea4..4362efdf9907c 100644 --- a/lib/ui/window/platform_configuration.h +++ b/lib/ui/window/platform_configuration.h @@ -100,7 +100,7 @@ class PlatformConfiguration final { /// @brief Retrieves the Window. /// /// @return the Window. - const Window& window() const { return *window_; } + const Window& get_window() const { return *window_; } //---------------------------------------------------------------------------- /// @brief Sets the viewport metrics of the Window. From a11cf95645f77b6d83af38e1975ec4047a61d335 Mon Sep 17 00:00:00 2001 From: Greg Spencer Date: Tue, 5 May 2020 18:46:12 -0700 Subject: [PATCH 4/8] Move platform specific information to PlatformConfiguration class. --- lib/ui/hooks.dart | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/lib/ui/hooks.dart b/lib/ui/hooks.dart index 5fa85f1e849a4..7cfe09d0ef5e8 100644 --- a/lib/ui/hooks.dart +++ b/lib/ui/hooks.dart @@ -28,6 +28,25 @@ void _updateWindowMetrics( double systemGestureInsetBottom, double systemGestureInsetLeft, ) { + print(''' +Updated window metrics: + devicePixelRatio: $devicePixelRatio + width: $width + height: $height + depth: $depth + viewPaddingTop: $viewPaddingTop + viewPaddingRight: $viewPaddingRight + viewPaddingBottom: $viewPaddingBottom + viewPaddingLeft: $viewPaddingLeft + viewInsetTop: $viewInsetTop + viewInsetRight: $viewInsetRight + viewInsetBottom: $viewInsetBottom + viewInsetLeft: $viewInsetLeft + systemGestureInsetTop: $systemGestureInsetTop + systemGestureInsetRight: $systemGestureInsetRight + systemGestureInsetBottom: $systemGestureInsetBottom + systemGestureInsetLeft: $systemGestureInsetLeft +'''); window .._devicePixelRatio = devicePixelRatio .._physicalSize = Size(width, height) From 14457b2e5d482e467d5b61423df1fc599522dfff Mon Sep 17 00:00:00 2001 From: Greg Spencer Date: Tue, 5 May 2020 18:46:12 -0700 Subject: [PATCH 5/8] Move platform specific information to PlatformConfiguration class. --- lib/ui/window/window.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/ui/window/window.h b/lib/ui/window/window.h index dcb06c9b73f08..b2a5c14af65e3 100644 --- a/lib/ui/window/window.h +++ b/lib/ui/window/window.h @@ -22,6 +22,8 @@ class Window final { ~Window(); + const uint64_t get_window_id() const { return viewport_metrics_.view_id; } + const ViewportMetrics& viewport_metrics() const { return viewport_metrics_; } void UpdateWindowMetrics(const tonic::DartPersistentValue& library, From e17191db7528752c1978a896fb66e747f14e8e4f Mon Sep 17 00:00:00 2001 From: Greg Spencer Date: Tue, 5 May 2020 18:46:12 -0700 Subject: [PATCH 6/8] Add an engine API that knows about screens. --- ci/licenses_golden/licenses_flutter | 4 + examples/glfw/FlutterEmbedderGLFW.cc | 34 +++- lib/ui/BUILD.gn | 4 + lib/ui/compositing/scene.cc | 7 +- lib/ui/hooks.dart | 64 ++++-- lib/ui/painting/canvas.cc | 7 +- lib/ui/window/platform_configuration.cc | 107 +++++++++- lib/ui/window/platform_configuration.h | 54 ++++- .../platform_configuration_unittests.cc | 48 ++++- lib/ui/window/screen.cc | 50 +++++ lib/ui/window/screen.h | 36 ++++ lib/ui/window/screen_metrics.cc | 107 ++++++++++ lib/ui/window/screen_metrics.h | 83 ++++++++ lib/ui/window/viewport_metrics.cc | 30 ++- lib/ui/window/viewport_metrics.h | 22 +- lib/ui/window/window.cc | 3 + lib/ui/window/window.h | 2 +- runtime/platform_data.h | 4 +- runtime/runtime_controller.cc | 24 ++- runtime/runtime_controller.h | 13 +- shell/common/engine.cc | 30 ++- shell/common/engine.h | 17 +- shell/common/platform_view.cc | 7 +- shell/common/platform_view.h | 26 ++- shell/common/shell.cc | 24 ++- shell/common/shell.h | 6 +- shell/common/shell_test.cc | 26 ++- shell/common/shell_test.h | 8 +- shell/common/shell_unittests.cc | 15 +- .../embedding/android/FlutterView.java | 23 ++- .../flutter/embedding/engine/FlutterJNI.java | 81 ++++++++ .../engine/renderer/FlutterRenderer.java | 110 +++++++++- .../android/io/flutter/view/FlutterView.java | 129 ++++++++++-- .../android/platform_view_android_jni_impl.cc | 60 +++++- .../ios/framework/Source/FlutterEngine.mm | 8 + .../framework/Source/FlutterEngine_Internal.h | 2 + .../framework/Source/FlutterViewController.mm | 49 ++++- .../Source/accessibility_bridge_test.mm | 1 + .../macos/framework/Source/FlutterEngine.mm | 47 ++++- .../framework/Source/FlutterEngine_Internal.h | 7 +- shell/platform/embedder/embedder.cc | 111 +++++++++-- shell/platform/embedder/embedder.h | 37 +++- shell/platform/embedder/embedder_engine.cc | 17 +- shell/platform/embedder/embedder_engine.h | 4 +- .../embedder/tests/embedder_unittests.cc | 188 ++++++++++++------ .../platform/fuchsia/flutter/platform_view.cc | 55 +++-- .../fuchsia/flutter/platform_view_unittest.cc | 3 + shell/platform/glfw/flutter_glfw.cc | 41 +++- shell/platform/linux/fl_engine.cc | 40 +++- shell/platform/linux/fl_engine_private.h | 17 +- shell/platform/linux/fl_view.cc | 59 +++++- shell/platform/linux/testing/mock_engine.cc | 11 +- .../platform/windows/flutter_windows_view.cc | 49 +++-- shell/platform/windows/flutter_windows_view.h | 10 +- .../testing/win32_flutter_window_test.cc | 7 +- .../testing/win32_flutter_window_test.h | 2 +- .../windows/testing/win32_window_test.cc | 2 + .../windows/testing/win32_window_test.h | 3 + .../platform/windows/win32_flutter_window.cc | 20 +- shell/platform/windows/win32_flutter_window.h | 14 +- shell/platform/windows/win32_window.cc | 66 ++++-- shell/platform/windows/win32_window.h | 29 ++- .../platform/windows/window_binding_handler.h | 19 +- .../windows/window_binding_handler_delegate.h | 11 +- shell/testing/tester_main.cc | 4 +- 65 files changed, 1872 insertions(+), 326 deletions(-) create mode 100644 lib/ui/window/screen.cc create mode 100644 lib/ui/window/screen.h create mode 100644 lib/ui/window/screen_metrics.cc create mode 100644 lib/ui/window/screen_metrics.h diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index d92536927d64d..b4f3338405967 100755 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -411,6 +411,10 @@ FILE: ../../../flutter/lib/ui/window/pointer_data_packet.h FILE: ../../../flutter/lib/ui/window/pointer_data_packet_converter.cc FILE: ../../../flutter/lib/ui/window/pointer_data_packet_converter.h FILE: ../../../flutter/lib/ui/window/pointer_data_packet_converter_unittests.cc +FILE: ../../../flutter/lib/ui/window/screen.cc +FILE: ../../../flutter/lib/ui/window/screen.h +FILE: ../../../flutter/lib/ui/window/screen_metrics.cc +FILE: ../../../flutter/lib/ui/window/screen_metrics.h FILE: ../../../flutter/lib/ui/window/viewport_metrics.cc FILE: ../../../flutter/lib/ui/window/viewport_metrics.h FILE: ../../../flutter/lib/ui/window/window.cc diff --git a/examples/glfw/FlutterEmbedderGLFW.cc b/examples/glfw/FlutterEmbedderGLFW.cc index 92473c70c54b5..92a5512616992 100644 --- a/examples/glfw/FlutterEmbedderGLFW.cc +++ b/examples/glfw/FlutterEmbedderGLFW.cc @@ -68,14 +68,43 @@ static void GLFWKeyCallback(GLFWwindow* window, } void GLFWwindowSizeCallback(GLFWwindow* window, int width, int height) { + int left, top; + glfwGetWindowPos(window, &left, &top); FlutterWindowMetricsEvent event = {}; event.struct_size = sizeof(event); + event.window_id = 0; + event.left = left * g_pixelRatio; + event.top = top * g_pixelRatio; event.width = width * g_pixelRatio; event.height = height * g_pixelRatio; event.pixel_ratio = g_pixelRatio; + + // TODO(gspencergoog): Currently, there is only one window. This will change + // as multi-window support is added. See + // https://github.com/flutter/flutter/issues/60131 + FlutterEngineSendWindowMetricsEvent( + reinterpret_cast(glfwGetWindowUserPointer(window)), &event, + 1); +} + +void GLFWwindowPosCallback(GLFWwindow* window, int left, int top) { + int width, height; + glfwGetWindowSize(window, &width, &height); + FlutterWindowMetricsEvent event = {}; + event.struct_size = sizeof(event); + event.window_id = 0; + event.left = left * g_pixelRatio; + event.top = top * g_pixelRatio; + event.width = width * g_pixelRatio; + event.height = height * g_pixelRatio; + event.pixel_ratio = g_pixelRatio; + + // TODO(gspencergoog): Currently, there is only one window. This will change + // as multi-window support is added. See + // https://github.com/flutter/flutter/issues/60131 FlutterEngineSendWindowMetricsEvent( - reinterpret_cast(glfwGetWindowUserPointer(window)), - &event); + reinterpret_cast(glfwGetWindowUserPointer(window)), &event, + 1); } bool RunFlutter(GLFWwindow* window, @@ -150,6 +179,7 @@ int main(int argc, const char* argv[]) { glfwSetKeyCallback(window, GLFWKeyCallback); glfwSetWindowSizeCallback(window, GLFWwindowSizeCallback); + glfwSetWindowPosCallback(window, GLFWwindowPosCallback); glfwSetMouseButtonCallback(window, GLFWmouseButtonCallback); while (!glfwWindowShouldClose(window)) { diff --git a/lib/ui/BUILD.gn b/lib/ui/BUILD.gn index 5fb7bc8b5f5db..1dda3d74d2787 100644 --- a/lib/ui/BUILD.gn +++ b/lib/ui/BUILD.gn @@ -103,6 +103,10 @@ source_set_maybe_fuchsia_legacy("ui") { "window/pointer_data_packet.h", "window/pointer_data_packet_converter.cc", "window/pointer_data_packet_converter.h", + "window/screen.cc", + "window/screen.h", + "window/screen_metrics.cc", + "window/screen_metrics.h", "window/viewport_metrics.cc", "window/viewport_metrics.h", "window/window.cc", diff --git a/lib/ui/compositing/scene.cc b/lib/ui/compositing/scene.cc index 582954328034a..264baeda973b7 100644 --- a/lib/ui/compositing/scene.cc +++ b/lib/ui/compositing/scene.cc @@ -42,10 +42,13 @@ Scene::Scene(std::shared_ptr rootLayer, uint32_t rasterizerTracingThreshold, bool checkerboardRasterCacheImages, bool checkerboardOffscreenLayers) { + // TODO(gspencergoog): Currently, there is only one window. This will change + // as multi-window support is added. See + // https://github.com/flutter/flutter/issues/60131 auto viewport_metrics = UIDartState::Current() ->platform_configuration() - ->get_window() - .viewport_metrics(); + ->window(0) + ->viewport_metrics(); layer_tree_ = std::make_unique( SkISize::Make(viewport_metrics.physical_width, diff --git a/lib/ui/hooks.dart b/lib/ui/hooks.dart index 7cfe09d0ef5e8..4513f96865228 100644 --- a/lib/ui/hooks.dart +++ b/lib/ui/hooks.dart @@ -11,7 +11,10 @@ part of dart.ui; @pragma('vm:entry-point') // ignore: unused_element void _updateWindowMetrics( + Object windowId, double devicePixelRatio, + double left, + double top, double width, double height, double depth, @@ -28,25 +31,6 @@ void _updateWindowMetrics( double systemGestureInsetBottom, double systemGestureInsetLeft, ) { - print(''' -Updated window metrics: - devicePixelRatio: $devicePixelRatio - width: $width - height: $height - depth: $depth - viewPaddingTop: $viewPaddingTop - viewPaddingRight: $viewPaddingRight - viewPaddingBottom: $viewPaddingBottom - viewPaddingLeft: $viewPaddingLeft - viewInsetTop: $viewInsetTop - viewInsetRight: $viewInsetRight - viewInsetBottom: $viewInsetBottom - viewInsetLeft: $viewInsetLeft - systemGestureInsetTop: $systemGestureInsetTop - systemGestureInsetRight: $systemGestureInsetRight - systemGestureInsetBottom: $systemGestureInsetBottom - systemGestureInsetLeft: $systemGestureInsetLeft -'''); window .._devicePixelRatio = devicePixelRatio .._physicalSize = Size(width, height) @@ -74,6 +58,48 @@ Updated window metrics: _invoke(window.onMetricsChanged, window._onMetricsChangedZone); } +@pragma('vm:entry-point') +// ignore: unused_element +void _removeWindows(List removedIds) { + // TODO(gspencergoog): Remove given IDs from screen metrics once dart::ui + // understands screens. See https://github.com/flutter/flutter/issues/60131 + print('Removed windows: $removedIds'); +} + +@pragma('vm:entry-point') +// ignore: unused_element +void _updateScreenMetrics( + Object screenId, + double left, + double top, + double width, + double height, + double devicePixelRatio, + double viewPaddingTop, + double viewPaddingRight, + double viewPaddingBottom, + double viewPaddingLeft, + double viewInsetTop, + double viewInsetRight, + double viewInsetBottom, + double viewInsetLeft, + double systemGestureInsetTop, + double systemGestureInsetRight, + double systemGestureInsetBottom, + double systemGestureInsetLeft, + ) { + // TODO(gspencergoog): Once dart:ui understands screens, set their metrics + // here. See https://github.com/flutter/flutter/issues/60131 +} + +@pragma('vm:entry-point') +// ignore: unused_element +void _removeScreens(List removedIds) { + // TODO(gspencergoog): Remove given IDs from screen metrics once dart::ui + // understands screens. See https://github.com/flutter/flutter/issues/60131 + print('Removed screens: $removedIds'); +} + typedef _LocaleClosure = String? Function(); String? _localeClosure() { diff --git a/lib/ui/painting/canvas.cc b/lib/ui/painting/canvas.cc index 6b367a4df1a8b..fdbb424fc1921 100644 --- a/lib/ui/painting/canvas.cc +++ b/lib/ui/painting/canvas.cc @@ -426,10 +426,13 @@ void Canvas::drawShadow(const CanvasPath* path, Dart_ThrowException( ToDart("Canvas.drawShader called with non-genuine Path.")); } + // TODO(gspencergoog): Currently, there is only one window. This will change + // as multi-window support is added. See + // https://github.com/flutter/flutter/issues/60131 SkScalar dpr = UIDartState::Current() ->platform_configuration() - ->get_window() - .viewport_metrics() + ->window(0) + ->viewport_metrics() .device_pixel_ratio; external_allocation_size_ += path->path().approximateBytesUsed(); flutter::PhysicalShapeLayer::DrawShadow(canvas_, path->path(), color, diff --git a/lib/ui/window/platform_configuration.cc b/lib/ui/window/platform_configuration.cc index 9e41acce8276c..b6068d0f66e57 100644 --- a/lib/ui/window/platform_configuration.cc +++ b/lib/ui/window/platform_configuration.cc @@ -7,7 +7,9 @@ #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/screen.h" #include "flutter/lib/ui/window/window.h" +#include "lib/ui/window/screen_metrics.h" #include "third_party/tonic/converter/dart_converter.h" #include "third_party/tonic/dart_args.h" #include "third_party/tonic/dart_library_natives.h" @@ -188,7 +190,7 @@ PlatformConfigurationClient::~PlatformConfigurationClient() {} PlatformConfiguration::PlatformConfiguration( PlatformConfigurationClient* client) - : client_(client), window_(new Window({1.0, 0.0, 0.0})) {} + : client_(client) {} PlatformConfiguration::~PlatformConfiguration() {} @@ -197,11 +199,6 @@ void PlatformConfiguration::DidCreateIsolate() { Dart_LookupLibrary(tonic::ToDart("dart:ui"))); } -void PlatformConfiguration::SetWindowMetrics( - const ViewportMetrics& window_metrics) { - window_->UpdateWindowMetrics(library_, window_metrics); -} - void PlatformConfiguration::UpdateLocales( const std::vector& locales) { std::shared_ptr dart_state = library_.dart_state().lock(); @@ -439,4 +436,102 @@ void PlatformConfiguration::RegisterNatives( }); } +void PlatformConfiguration::SetWindowMetrics( + const std::vector& window_metrics) { + WindowMap updated; + for (const auto& metrics : window_metrics) { + WindowMap::iterator found = windows_.find(metrics.view_id); + if (found == windows_.end()) { + // A new window that needs to be added + std::shared_ptr new_window = std::make_shared(metrics); + updated.insert(std::make_pair(metrics.view_id, new_window)); + new_window->UpdateWindowMetrics(library_, metrics); + } else { + // An existing window that needs to be updated, add it to the updated + // list, and remove it from the existing screens. + (*found).second->UpdateWindowMetrics(library_, metrics); + updated.insert(*found); + windows_.erase(found); + } + } + + // Anything left in windows_ didn't exist in the window_metrics supplied, and + // so will be removed. + std::vector removed_ids; + for (const auto& entry : windows_) { + removed_ids.push_back(entry.first); + } + + windows_.swap(updated); + + std::shared_ptr dart_state = library_.dart_state().lock(); + if (!dart_state) { + return; + } + tonic::DartState::Scope scope(dart_state); + if (!removed_ids.empty()) { + tonic::LogIfError(tonic::DartInvokeField(library_.value(), "_removeWindows", + { + tonic::ToDart(removed_ids), + })); + } +} + +void PlatformConfiguration::SetScreenMetrics( + const std::vector& screen_metrics) { + ScreenMap updated; + for (const auto& metrics : screen_metrics) { + ScreenMap::iterator found = screens_.find(metrics.screen_id); + if (found == screens_.end()) { + // A new screen that needs to be added + std::shared_ptr new_screen = std::make_shared(metrics); + updated.insert(std::make_pair(metrics.screen_id, new_screen)); + new_screen->UpdateScreenMetrics(library_, metrics); + } else { + // An existing screen that needs to be updated, add it to the updated + // list, and remove it from the existing screens. + (*found).second->UpdateScreenMetrics(library_, metrics); + updated.insert(*found); + screens_.erase(found); + } + } + + // Anything left in screens_ didn't exist in the screen_metrics supplied, and + // so will be removed. + std::vector removed_ids; + for (const auto& entry : screens_) { + removed_ids.push_back(entry.first); + } + + screens_.swap(updated); + + std::shared_ptr dart_state = library_.dart_state().lock(); + if (!dart_state) { + return; + } + tonic::DartState::Scope scope(dart_state); + if (!removed_ids.empty()) { + tonic::LogIfError(tonic::DartInvokeField(library_.value(), "_removeScreens", + { + tonic::ToDart(removed_ids), + })); + } +} + +std::shared_ptr PlatformConfiguration::window(int64_t window_id) { + if (windows_.find(window_id) == windows_.end()) { + FML_DLOG(WARNING) << "Unable to find window with id " << window_id; + return nullptr; + } + return windows_.at(window_id); +} + +std::shared_ptr PlatformConfiguration::screen(int64_t screen_id) { + if (screens_.find(screen_id) == screens_.end()) { + FML_DLOG(WARNING) << "Unable to find screen with id " << screen_id; + return nullptr; + } + return screens_.at(screen_id); +} + } // namespace flutter diff --git a/lib/ui/window/platform_configuration.h b/lib/ui/window/platform_configuration.h index 4362efdf9907c..5722b1b6c7149 100644 --- a/lib/ui/window/platform_configuration.h +++ b/lib/ui/window/platform_configuration.h @@ -15,8 +15,10 @@ #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/screen.h" #include "flutter/lib/ui/window/viewport_metrics.h" #include "flutter/lib/ui/window/window.h" +#include "lib/ui/window/screen_metrics.h" #include "third_party/tonic/dart_persistent_value.h" namespace tonic { @@ -96,24 +98,60 @@ class PlatformConfiguration final { static void RegisterNatives(tonic::DartLibraryNatives* natives); + typedef std::unordered_map> ScreenMap; + typedef std::unordered_map> WindowMap; + + //---------------------------------------------------------------------------- + /// @brief Retrieves the Window with the window ID given by window_id. + /// + /// @param[in] window_id The identifier for the Window to retrieve. + /// + /// @return a shared_ptr to the Window, or nullptr if none is found. + std::shared_ptr window(int64_t window_id); + + //---------------------------------------------------------------------------- + /// @brief Retrieves the Screen with the screen ID given by window_id. + /// + /// @param[in] screen_id The identifier for the screen to retrieve. + /// + /// @return A shared_ptr to the Screen, or nullptr if none is found. + std::shared_ptr screen(int64_t screen_id); + + //---------------------------------------------------------------------------- + /// @brief Sets the viewport metrics of all viewports that exist. Any windows + /// not in this list are assumed to no longer exist, and will be + /// removed. + /// + /// @param[in] windows The list of viewport metrics to replace the old list + /// with. + void SetWindowMetrics(const std::vector& viewport_metrics); + + //---------------------------------------------------------------------------- + /// @brief Retrieves the map of window id to window. + /// + /// @return a const reference to the map of windows that exist. + const WindowMap& windows() { return windows_; } + //---------------------------------------------------------------------------- - /// @brief Retrieves the Window. + /// @brief Sets the screen metrics of all screens that exist. Any screens not + /// in this list are assumed to no longer exist, and will be removed. /// - /// @return the Window. - const Window& get_window() const { return *window_; } + /// @param[in] windows The list of windows to replace the old list with. + void SetScreenMetrics(const std::vector& screen_metrics); //---------------------------------------------------------------------------- - /// @brief Sets the viewport metrics of the Window. + /// @brief Retrieves the map of screen id to screen. /// - /// @param[in] window_metrics The viewport metrics to replace the old ones - /// with. - void SetWindowMetrics(const ViewportMetrics& window_metrics); + /// @return a const reference to the map of screens that exist. + const ScreenMap& screens() { return screens_; } private: PlatformConfigurationClient* client_; tonic::DartPersistentValue library_; + ViewportMetrics viewport_metrics_; - std::unique_ptr window_; + WindowMap windows_; + ScreenMap screens_; // We use id 0 to mean that no response is expected. int next_response_id_ = 1; diff --git a/lib/ui/window/platform_configuration_unittests.cc b/lib/ui/window/platform_configuration_unittests.cc index 9e966de7ef1e2..64724a1503172 100644 --- a/lib/ui/window/platform_configuration_unittests.cc +++ b/lib/ui/window/platform_configuration_unittests.cc @@ -7,6 +7,7 @@ #define FML_USED_ON_EMBEDDER #include +#include #include "flutter/lib/ui/window/platform_configuration.h" @@ -52,20 +53,53 @@ TEST(PlatformConfigurationTest, PlatformConfigurationInitialization) { DummyPlatformConfigurationClient client; PlatformConfiguration configuration(&client); + ASSERT_TRUE(configuration.windows().empty()); + ASSERT_TRUE(configuration.screens().empty()); ASSERT_EQ(configuration.client(), &client); - 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); } TEST(PlatformConfigurationTest, PlatformConfigurationWindowMetricsUpdate) { DummyPlatformConfigurationClient client; PlatformConfiguration configuration(&client); - configuration.SetWindowMetrics({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); + configuration.SetWindowMetrics( + {{1, 2.0, 1.0, 2.0, 10.0, 20.0}, {0, 1, 2, 3, 4, 5}}); + ASSERT_EQ(configuration.window(1)->viewport_metrics().view_id, 1); + ASSERT_EQ(configuration.window(1)->viewport_metrics().device_pixel_ratio, + 2.0); + ASSERT_EQ(configuration.window(1)->viewport_metrics().physical_left, 1.0); + ASSERT_EQ(configuration.window(1)->viewport_metrics().physical_top, 2.0); + ASSERT_EQ(configuration.window(1)->viewport_metrics().physical_width, 10.0); + ASSERT_EQ(configuration.window(1)->viewport_metrics().physical_height, 20.0); + + ASSERT_EQ(configuration.window(0)->viewport_metrics().view_id, 0); + ASSERT_EQ(configuration.window(0)->viewport_metrics().device_pixel_ratio, + 1.0); + ASSERT_EQ(configuration.window(0)->viewport_metrics().physical_left, 2.0); + ASSERT_EQ(configuration.window(0)->viewport_metrics().physical_top, 3.0); + ASSERT_EQ(configuration.window(0)->viewport_metrics().physical_width, 4.0); + ASSERT_EQ(configuration.window(0)->viewport_metrics().physical_height, 5.0); +} + +TEST(PlatformConfigurationTest, PlatformConfigurationScreenMetricsUpdate) { + DummyPlatformConfigurationClient client; + PlatformConfiguration configuration(&client); + + configuration.SetScreenMetrics( + {{1, 2.0, 1.0, 2.0, 10.0, 20.0}, {0, 1, 2, 3, 4, 5}}); + ASSERT_EQ(configuration.screen(1)->screen_metrics().screen_id, 1); + ASSERT_EQ(configuration.screen(1)->screen_metrics().device_pixel_ratio, 2.0); + ASSERT_EQ(configuration.screen(1)->screen_metrics().physical_left, 1.0); + ASSERT_EQ(configuration.screen(1)->screen_metrics().physical_top, 2.0); + ASSERT_EQ(configuration.screen(1)->screen_metrics().physical_width, 10.0); + ASSERT_EQ(configuration.screen(1)->screen_metrics().physical_height, 20.0); + + ASSERT_EQ(configuration.screen(0)->screen_metrics().screen_id, 0); + ASSERT_EQ(configuration.screen(0)->screen_metrics().device_pixel_ratio, 1.0); + ASSERT_EQ(configuration.screen(0)->screen_metrics().physical_left, 2.0); + ASSERT_EQ(configuration.screen(0)->screen_metrics().physical_top, 3.0); + ASSERT_EQ(configuration.screen(0)->screen_metrics().physical_width, 4.0); + ASSERT_EQ(configuration.screen(0)->screen_metrics().physical_height, 5.0); } } // namespace testing diff --git a/lib/ui/window/screen.cc b/lib/ui/window/screen.cc new file mode 100644 index 0000000000000..d497e01405376 --- /dev/null +++ b/lib/ui/window/screen.cc @@ -0,0 +1,50 @@ +// 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/screen.h" + +#include "lib/ui/window/screen_metrics.h" +#include "third_party/tonic/converter/dart_converter.h" +#include "third_party/tonic/dart_args.h" +#include "third_party/tonic/logging/dart_invoke.h" + +namespace flutter { +Screen::Screen(ScreenMetrics metrics) : screen_metrics_(metrics) {} + +Screen::~Screen() {} + +void Screen::UpdateScreenMetrics(const tonic::DartPersistentValue& library, + const ScreenMetrics& metrics) { + screen_metrics_ = metrics; + + 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(), "_updateScreenMetrics", + { + tonic::ToDart(metrics.screen_id), + tonic::ToDart(metrics.physical_left), + tonic::ToDart(metrics.physical_top), + tonic::ToDart(metrics.physical_width), + tonic::ToDart(metrics.physical_height), + tonic::ToDart(metrics.device_pixel_ratio), + tonic::ToDart(metrics.physical_padding_top), + tonic::ToDart(metrics.physical_padding_right), + tonic::ToDart(metrics.physical_padding_bottom), + tonic::ToDart(metrics.physical_padding_left), + tonic::ToDart(metrics.physical_view_inset_top), + tonic::ToDart(metrics.physical_view_inset_right), + tonic::ToDart(metrics.physical_view_inset_bottom), + tonic::ToDart(metrics.physical_view_inset_left), + tonic::ToDart(metrics.physical_system_gesture_inset_top), + tonic::ToDart(metrics.physical_system_gesture_inset_right), + tonic::ToDart(metrics.physical_system_gesture_inset_bottom), + tonic::ToDart(metrics.physical_system_gesture_inset_left), + })); +} + +} // namespace flutter diff --git a/lib/ui/window/screen.h b/lib/ui/window/screen.h new file mode 100644 index 0000000000000..b646dadec0870 --- /dev/null +++ b/lib/ui/window/screen.h @@ -0,0 +1,36 @@ +// 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_SCREEN_H_ +#define FLUTTER_LIB_UI_WINDOW_SCREEN_H_ + +#include +#include +#include + +#include "flutter/lib/ui/window/screen_metrics.h" +#include "third_party/tonic/dart_persistent_value.h" + +namespace flutter { + +class Screen final { + public: + explicit Screen(ScreenMetrics metrics); + + ~Screen(); + + const ScreenMetrics& screen_metrics() { return screen_metrics_; } + + int screen_id() { return screen_metrics_.screen_id; } + + void UpdateScreenMetrics(const tonic::DartPersistentValue& library, + const ScreenMetrics& metrics); + + private: + ScreenMetrics screen_metrics_; +}; + +} // namespace flutter + +#endif // FLUTTER_LIB_UI_WINDOW_SCREEN_H_ diff --git a/lib/ui/window/screen_metrics.cc b/lib/ui/window/screen_metrics.cc new file mode 100644 index 0000000000000..b6d91fb84a978 --- /dev/null +++ b/lib/ui/window/screen_metrics.cc @@ -0,0 +1,107 @@ +// 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/screen_metrics.h" + +#include "flutter/fml/logging.h" + +namespace flutter { + +ScreenMetrics::ScreenMetrics(int64_t p_screen_id, + double p_device_pixel_ratio, + double p_physical_left, + double p_physical_top, + double p_physical_width, + double p_physical_height, + double p_physical_padding_top, + double p_physical_padding_right, + double p_physical_padding_bottom, + double p_physical_padding_left, + double p_physical_view_inset_top, + double p_physical_view_inset_right, + double p_physical_view_inset_bottom, + double p_physical_view_inset_left, + double p_physical_system_gesture_inset_top, + double p_physical_system_gesture_inset_right, + double p_physical_system_gesture_inset_bottom, + double p_physical_system_gesture_inset_left) + : screen_id(p_screen_id), + device_pixel_ratio(p_device_pixel_ratio), + physical_left(p_physical_left), + physical_top(p_physical_top), + physical_width(p_physical_width), + physical_height(p_physical_height), + physical_padding_top(p_physical_padding_top), + physical_padding_right(p_physical_padding_right), + physical_padding_bottom(p_physical_padding_bottom), + physical_padding_left(p_physical_padding_left), + physical_view_inset_top(p_physical_view_inset_top), + physical_view_inset_right(p_physical_view_inset_right), + physical_view_inset_bottom(p_physical_view_inset_bottom), + physical_view_inset_left(p_physical_view_inset_left), + physical_system_gesture_inset_top(p_physical_system_gesture_inset_top), + physical_system_gesture_inset_right( + p_physical_system_gesture_inset_right), + physical_system_gesture_inset_bottom( + p_physical_system_gesture_inset_bottom), + physical_system_gesture_inset_left(p_physical_system_gesture_inset_left) { + // Ensure we don't have nonsensical dimensions. + FML_DCHECK(device_pixel_ratio > 0); + FML_DCHECK(physical_width >= 0); + FML_DCHECK(physical_height >= 0); +} + +ScreenMetrics::ScreenMetrics(int64_t p_screen_id, + double p_device_pixel_ratio, + double p_physical_left, + double p_physical_top, + double p_physical_width, + double p_physical_height, + double p_physical_padding_top, + double p_physical_padding_right, + double p_physical_padding_bottom, + double p_physical_padding_left, + double p_physical_view_inset_top, + double p_physical_view_inset_right, + double p_physical_view_inset_bottom, + double p_physical_view_inset_left) + : screen_id(p_screen_id), + device_pixel_ratio(p_device_pixel_ratio), + physical_left(p_physical_left), + physical_top(p_physical_top), + physical_width(p_physical_width), + physical_height(p_physical_height), + physical_padding_top(p_physical_padding_top), + physical_padding_right(p_physical_padding_right), + physical_padding_bottom(p_physical_padding_bottom), + physical_padding_left(p_physical_padding_left), + physical_view_inset_top(p_physical_view_inset_top), + physical_view_inset_right(p_physical_view_inset_right), + physical_view_inset_bottom(p_physical_view_inset_bottom), + physical_view_inset_left(p_physical_view_inset_left) { + // Ensure we don't have nonsensical dimensions. + FML_DCHECK(device_pixel_ratio > 0); + FML_DCHECK(physical_width >= 0); + FML_DCHECK(physical_height >= 0); +} + +ScreenMetrics::ScreenMetrics(int64_t p_screen_id, + double p_device_pixel_ratio, + double p_physical_left, + double p_physical_top, + double p_physical_width, + double p_physical_height) + : screen_id(p_screen_id), + device_pixel_ratio(p_device_pixel_ratio), + physical_left(p_physical_left), + physical_top(p_physical_top), + physical_width(p_physical_width), + physical_height(p_physical_height) { + // Ensure we don't have nonsensical dimensions. + FML_DCHECK(device_pixel_ratio > 0); + FML_DCHECK(physical_width >= 0); + FML_DCHECK(physical_height >= 0); +} + +} // namespace flutter diff --git a/lib/ui/window/screen_metrics.h b/lib/ui/window/screen_metrics.h new file mode 100644 index 0000000000000..568588f3df4ce --- /dev/null +++ b/lib/ui/window/screen_metrics.h @@ -0,0 +1,83 @@ +// 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_SCREEN_METRICS_H_ +#define FLUTTER_LIB_UI_WINDOW_SCREEN_METRICS_H_ + +#include + +#include + +namespace flutter { + +struct ScreenMetrics { + ScreenMetrics() = default; + ScreenMetrics(const ScreenMetrics& other) = default; + + // Create a ScreenMetrics instance. + ScreenMetrics(int64_t screen_id, + double p_device_pixel_ratio, + double p_physical_left, + double p_physical_top, + double p_physical_width, + double p_physical_height, + double p_physical_padding_top, + double p_physical_padding_right, + double p_physical_padding_bottom, + double p_physical_padding_left, + double p_physical_view_inset_top, + double p_physical_view_inset_right, + double p_physical_view_inset_bottom, + double p_physical_view_inset_left, + double p_physical_system_gesture_inset_top, + double p_physical_system_gesture_inset_right, + double p_physical_system_gesture_inset_bottom, + double p_physical_system_gesture_inset_left); + + // Create a ScreenMetrics instance without system gesture insets. + ScreenMetrics(int64_t screen_id, + double p_device_pixel_ratio, + double p_physical_left, + double p_physical_top, + double p_physical_width, + double p_physical_height, + double p_physical_padding_top, + double p_physical_padding_right, + double p_physical_padding_bottom, + double p_physical_padding_left, + double p_physical_view_inset_top, + double p_physical_view_inset_right, + double p_physical_view_inset_bottom, + double p_physical_view_inset_left); + + ScreenMetrics(int64_t screen_id, + double p_device_pixel_ratio, + double p_physical_left, + double p_physical_top, + double p_physical_width, + double p_physical_height); + + int64_t screen_id = -1; + double device_pixel_ratio = 1.0; + double physical_left = 0; + double physical_top = 0; + double physical_width = 0; + double physical_height = 0; + double physical_padding_top = 0; + double physical_padding_right = 0; + double physical_padding_bottom = 0; + double physical_padding_left = 0; + double physical_view_inset_top = 0; + double physical_view_inset_right = 0; + double physical_view_inset_bottom = 0; + double physical_view_inset_left = 0; + double physical_system_gesture_inset_top = 0; + double physical_system_gesture_inset_right = 0; + double physical_system_gesture_inset_bottom = 0; + double physical_system_gesture_inset_left = 0; +}; + +} // namespace flutter + +#endif // FLUTTER_LIB_UI_WINDOW_SCREEN_METRICS_H_ diff --git a/lib/ui/window/viewport_metrics.cc b/lib/ui/window/viewport_metrics.cc index 329cea01c036a..1d862b567af63 100644 --- a/lib/ui/window/viewport_metrics.cc +++ b/lib/ui/window/viewport_metrics.cc @@ -8,7 +8,10 @@ namespace flutter { -ViewportMetrics::ViewportMetrics(double p_device_pixel_ratio, +ViewportMetrics::ViewportMetrics(int64_t p_view_id, + double p_device_pixel_ratio, + double p_physical_left, + double p_physical_top, double p_physical_width, double p_physical_height, double p_physical_padding_top, @@ -23,7 +26,10 @@ ViewportMetrics::ViewportMetrics(double p_device_pixel_ratio, double p_physical_system_gesture_inset_right, double p_physical_system_gesture_inset_bottom, double p_physical_system_gesture_inset_left) - : device_pixel_ratio(p_device_pixel_ratio), + : view_id(p_view_id), + device_pixel_ratio(p_device_pixel_ratio), + physical_left(p_physical_left), + physical_top(p_physical_top), physical_width(p_physical_width), physical_height(p_physical_height), physical_padding_top(p_physical_padding_top), @@ -46,7 +52,10 @@ ViewportMetrics::ViewportMetrics(double p_device_pixel_ratio, FML_DCHECK(device_pixel_ratio > 0); } -ViewportMetrics::ViewportMetrics(double p_device_pixel_ratio, +ViewportMetrics::ViewportMetrics(int64_t p_view_id, + double p_device_pixel_ratio, + double p_physical_left, + double p_physical_top, double p_physical_width, double p_physical_height, double p_physical_depth, @@ -60,7 +69,10 @@ ViewportMetrics::ViewportMetrics(double p_device_pixel_ratio, double p_physical_view_inset_right, double p_physical_view_inset_bottom, double p_physical_view_inset_left) - : device_pixel_ratio(p_device_pixel_ratio), + : view_id(p_view_id), + device_pixel_ratio(p_device_pixel_ratio), + physical_left(p_physical_left), + physical_top(p_physical_top), physical_width(p_physical_width), physical_height(p_physical_height), physical_depth(p_physical_depth), @@ -80,10 +92,16 @@ ViewportMetrics::ViewportMetrics(double p_device_pixel_ratio, FML_DCHECK(device_pixel_ratio > 0); } -ViewportMetrics::ViewportMetrics(double p_device_pixel_ratio, +ViewportMetrics::ViewportMetrics(int64_t p_view_id, + double p_device_pixel_ratio, + double p_physical_left, + double p_physical_top, double p_physical_width, double p_physical_height) - : device_pixel_ratio(p_device_pixel_ratio), + : view_id(p_view_id), + device_pixel_ratio(p_device_pixel_ratio), + physical_left(p_physical_left), + physical_top(p_physical_top), physical_width(p_physical_width), physical_height(p_physical_height) { // Ensure we don't have nonsensical dimensions. diff --git a/lib/ui/window/viewport_metrics.h b/lib/ui/window/viewport_metrics.h index d4a7311ad95f3..75430ecd8f442 100644 --- a/lib/ui/window/viewport_metrics.h +++ b/lib/ui/window/viewport_metrics.h @@ -19,8 +19,11 @@ struct ViewportMetrics { ViewportMetrics() = default; ViewportMetrics(const ViewportMetrics& other) = default; - // Create a 2D ViewportMetrics instance. - ViewportMetrics(double p_device_pixel_ratio, + // Create a 2D ViewportMetrics instance that includes padding and insets + ViewportMetrics(int64_t p_view_id, + double p_device_pixel_ratio, + double p_physical_left, + double p_physical_top, double p_physical_width, double p_physical_height, double p_physical_padding_top, @@ -36,8 +39,11 @@ struct ViewportMetrics { double p_physical_system_gesture_inset_bottom, double p_physical_system_gesture_inset_left); - // Create a ViewportMetrics instance that contains z information. - ViewportMetrics(double p_device_pixel_ratio, + // Create a ViewportMetrics instance that contains z (depth) information. + ViewportMetrics(int64_t p_view_id, + double p_device_pixel_ratio, + double p_physical_left, + double p_physical_top, double p_physical_width, double p_physical_height, double p_physical_depth, @@ -54,11 +60,17 @@ struct ViewportMetrics { // Create a ViewportMetrics instance that doesn't include depth, padding, or // insets. - ViewportMetrics(double p_device_pixel_ratio, + ViewportMetrics(int64_t view_id, + double p_device_pixel_ratio, + double p_physical_left, + double p_physical_top, double p_physical_width, double p_physical_height); + int64_t view_id = -1; double device_pixel_ratio = 1.0; + double physical_left = 0; + double physical_top = 0; double physical_width = 0; double physical_height = 0; double physical_depth = kUnsetDepth; diff --git a/lib/ui/window/window.cc b/lib/ui/window/window.cc index 8114f88143486..b0cf0644fdee7 100644 --- a/lib/ui/window/window.cc +++ b/lib/ui/window/window.cc @@ -27,7 +27,10 @@ void Window::UpdateWindowMetrics(const tonic::DartPersistentValue& library, tonic::LogIfError(tonic::DartInvokeField( library.value(), "_updateWindowMetrics", { + tonic::ToDart(metrics.view_id), tonic::ToDart(metrics.device_pixel_ratio), + tonic::ToDart(metrics.physical_left), + tonic::ToDart(metrics.physical_top), tonic::ToDart(metrics.physical_width), tonic::ToDart(metrics.physical_height), tonic::ToDart(metrics.physical_depth), diff --git a/lib/ui/window/window.h b/lib/ui/window/window.h index b2a5c14af65e3..5919fb43bcfd9 100644 --- a/lib/ui/window/window.h +++ b/lib/ui/window/window.h @@ -22,7 +22,7 @@ class Window final { ~Window(); - const uint64_t get_window_id() const { return viewport_metrics_.view_id; } + int64_t window_id() const { return viewport_metrics_.view_id; } const ViewportMetrics& viewport_metrics() const { return viewport_metrics_; } diff --git a/runtime/platform_data.h b/runtime/platform_data.h index bb7fdd95fb6bb..5f2b9d16b9e97 100644 --- a/runtime/platform_data.h +++ b/runtime/platform_data.h @@ -5,6 +5,7 @@ #ifndef FLUTTER_RUNTIME_PLATFORM_DATA_H_ #define FLUTTER_RUNTIME_PLATFORM_DATA_H_ +#include "flutter/lib/ui/window/screen_metrics.h" #include "flutter/lib/ui/window/viewport_metrics.h" #include @@ -30,7 +31,8 @@ struct PlatformData { ~PlatformData(); - ViewportMetrics viewport_metrics; + std::vector screen_metrics; + std::vector viewport_metrics; std::string language_code; std::string country_code; std::string script_code; diff --git a/runtime/runtime_controller.cc b/runtime/runtime_controller.cc index 4ab4ca795b495..d2560c8b9f817 100644 --- a/runtime/runtime_controller.cc +++ b/runtime/runtime_controller.cc @@ -132,7 +132,8 @@ std::unique_ptr RuntimeController::Clone() const { } bool RuntimeController::FlushRuntimeStateToIsolate() { - return SetViewportMetrics(platform_data_.viewport_metrics) && + return SetScreenMetrics(platform_data_.screen_metrics) && + SetViewportMetrics(platform_data_.viewport_metrics) && SetLocales(platform_data_.locale_data) && SetSemanticsEnabled(platform_data_.semantics_enabled) && SetAccessibilityFeatures( @@ -141,14 +142,31 @@ bool RuntimeController::FlushRuntimeStateToIsolate() { SetLifecycleState(platform_data_.lifecycle_state); } -bool RuntimeController::SetViewportMetrics(const ViewportMetrics& metrics) { +bool RuntimeController::SetScreenMetrics( + const std::vector& metrics) { + platform_data_.screen_metrics = metrics; + + if (auto* platform_configuration = GetPlatformConfigurationIfAvailable()) { + platform_configuration->SetScreenMetrics(metrics); + return true; + } + FML_DLOG(ERROR) << "Unable to set ScreenMetrics on screens"; + return false; +} + +bool RuntimeController::SetViewportMetrics( + const std::vector& metrics) { platform_data_.viewport_metrics = metrics; + if (metrics.empty()) { + return true; + } + if (auto* platform_configuration = GetPlatformConfigurationIfAvailable()) { platform_configuration->SetWindowMetrics(metrics); return true; } - + FML_DLOG(ERROR) << "Unable to set ViewportMetrics on views"; return false; } diff --git a/runtime/runtime_controller.h b/runtime/runtime_controller.h index e67b5847ce0ac..5fc602877d815 100644 --- a/runtime/runtime_controller.h +++ b/runtime/runtime_controller.h @@ -135,6 +135,17 @@ class RuntimeController final : public PlatformConfigurationClient { /// std::unique_ptr Clone() const; + //---------------------------------------------------------------------------- + /// @brief Forward the specified screen 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 screen metrics for all screens. + /// + /// @return If the screen metrics were forwarded to the running isolate. + /// + bool SetScreenMetrics(const std::vector& metrics); + //---------------------------------------------------------------------------- /// @brief Forward the specified viewport metrics to the running isolate. /// If the isolate is not running, these metrics will be saved and @@ -144,7 +155,7 @@ class RuntimeController final : public PlatformConfigurationClient { /// /// @return If the window metrics were forwarded to the running isolate. /// - bool SetViewportMetrics(const ViewportMetrics& metrics); + bool SetViewportMetrics(const std::vector& metrics); //---------------------------------------------------------------------------- /// @brief Forward the specified locale data to the running isolate. If diff --git a/shell/common/engine.cc b/shell/common/engine.cc index 070637874ea60..10f1458cc81bb 100644 --- a/shell/common/engine.cc +++ b/shell/common/engine.cc @@ -272,20 +272,34 @@ void Engine::OnOutputSurfaceDestroyed() { StopAnimator(); } -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_.device_pixel_ratio != metrics.device_pixel_ratio; - viewport_metrics_ = metrics; - runtime_controller_->SetViewportMetrics(viewport_metrics_); +void Engine::SetScreenMetrics(const std::vector& metrics) { + screen_metrics_ = metrics; + runtime_controller_->SetScreenMetrics(screen_metrics_); +} + +void Engine::SetViewportMetrics(const std::vector& metrics) { + bool dimensions_changed = true; + if (metrics.size() == viewport_metrics_.size()) { + dimensions_changed = false; + for (size_t i = 0; i < metrics.size(); ++i) { + const ViewportMetrics& oldMetrics = viewport_metrics_[i]; + const ViewportMetrics& newMetrics = metrics[i]; + if (oldMetrics.physical_height != newMetrics.physical_height || + oldMetrics.physical_width != newMetrics.physical_width || + oldMetrics.physical_depth != newMetrics.physical_depth || + oldMetrics.device_pixel_ratio != newMetrics.device_pixel_ratio) { + dimensions_changed = true; + } + } + } if (animator_) { if (dimensions_changed) animator_->SetDimensionChangePending(); if (have_surface_) ScheduleFrame(); } + viewport_metrics_ = metrics; + runtime_controller_->SetViewportMetrics(metrics); } void Engine::DispatchPlatformMessage(fml::RefPtr message) { diff --git a/shell/common/engine.h b/shell/common/engine.h index 848fc1584efcf..fe21b8900f3f2 100644 --- a/shell/common/engine.h +++ b/shell/common/engine.h @@ -651,7 +651,19 @@ class Engine final : public RuntimeDelegate, PointerDataDispatcher::Delegate { /// /// @param[in] metrics The metrics /// - void SetViewportMetrics(const ViewportMetrics& metrics); + void SetViewportMetrics(const std::vector& metrics); + + //---------------------------------------------------------------------------- + /// @brief Updates the screen metrics for the currently running Flutter + /// application. The screen metrics detail the size and positions + /// of the screens that the rendering viewport is on, as well as + /// edge insets, if present. + /// + /// @see `ScreenMetrics` + /// + /// @param[in] metrics The list of screen metrics to set. + /// + void SetScreenMetrics(const std::vector& metrics); //---------------------------------------------------------------------------- /// @brief Notifies the engine that the embedder has sent it a message. @@ -765,7 +777,8 @@ class Engine final : public RuntimeDelegate, PointerDataDispatcher::Delegate { std::string last_entry_point_; std::string last_entry_point_library_; std::string initial_route_; - ViewportMetrics viewport_metrics_; + std::vector screen_metrics_; + std::vector viewport_metrics_; std::shared_ptr asset_manager_; bool activity_running_; bool have_surface_; diff --git a/shell/common/platform_view.cc b/shell/common/platform_view.cc index 146874933e739..7e0e3227ea94c 100644 --- a/shell/common/platform_view.cc +++ b/shell/common/platform_view.cc @@ -56,7 +56,12 @@ void PlatformView::SetAccessibilityFeatures(int32_t flags) { delegate_.OnPlatformViewSetAccessibilityFeatures(flags); } -void PlatformView::SetViewportMetrics(const ViewportMetrics& metrics) { +void PlatformView::SetScreenMetrics(const std::vector& metrics) { + delegate_.OnPlatformViewSetScreenMetrics(metrics); +} + +void PlatformView::SetViewportMetrics( + const std::vector& metrics) { delegate_.OnPlatformViewSetViewportMetrics(metrics); } diff --git a/shell/common/platform_view.h b/shell/common/platform_view.h index 5596a01e59230..c9cefe4913074 100644 --- a/shell/common/platform_view.h +++ b/shell/common/platform_view.h @@ -17,6 +17,7 @@ #include "flutter/lib/ui/window/platform_message.h" #include "flutter/lib/ui/window/pointer_data_packet.h" #include "flutter/lib/ui/window/pointer_data_packet_converter.h" +#include "flutter/lib/ui/window/screen_metrics.h" #include "flutter/lib/ui/window/viewport_metrics.h" #include "flutter/shell/common/pointer_data_dispatcher.h" #include "flutter/shell/common/vsync_waiter.h" @@ -88,6 +89,15 @@ class PlatformView { virtual void OnPlatformViewSetNextFrameCallback( const fml::closure& closure) = 0; + //-------------------------------------------------------------------------- + /// @brief Notifies the delegate that the screen metrics of the + /// platform screen have been updated. + /// + /// @param[in] metrics The updated screen metrics. + /// + virtual void OnPlatformViewSetScreenMetrics( + const std::vector& metrics) = 0; + //-------------------------------------------------------------------------- /// @brief Notifies the delegate the viewport metrics of the platform /// view have been updated. The rasterizer will need to be @@ -97,7 +107,7 @@ class PlatformView { /// @param[in] metrics The updated viewport metrics. /// virtual void OnPlatformViewSetViewportMetrics( - const ViewportMetrics& metrics) = 0; + const std::vector& metrics) = 0; //-------------------------------------------------------------------------- /// @brief Notifies the delegate that the platform has dispatched a @@ -369,6 +379,18 @@ class PlatformView { virtual void UpdateSemantics(SemanticsNodeUpdates updates, CustomAccessibilityActionUpdates actions); + //---------------------------------------------------------------------------- + /// @brief Used by embedders to specify updated screen metrics. In + /// response to this call, on the raster thread, the rasterizer + /// may need to be reconfigured to the updated viewport dimensions + /// if they are affected by the change in screen metrics. On the + /// UI thread, the framework may need to start generating a new + /// frame for the updated viewport metrics as well. + /// + /// @param[in] metrics The updated screen metrics. + /// + void SetScreenMetrics(const std::vector& metrics); + //---------------------------------------------------------------------------- /// @brief Used by embedders to specify the updated viewport metrics. In /// response to this call, on the raster thread, the rasterizer @@ -379,7 +401,7 @@ class PlatformView { /// /// @param[in] metrics The updated viewport metrics. /// - void SetViewportMetrics(const ViewportMetrics& metrics); + void SetViewportMetrics(const std::vector& metrics); //---------------------------------------------------------------------------- /// @brief Used by embedders to notify the shell that a platform view diff --git a/shell/common/shell.cc b/shell/common/shell.cc index 7d04abc5f7cf8..80e30f0d3e41a 100644 --- a/shell/common/shell.cc +++ b/shell/common/shell.cc @@ -770,13 +770,33 @@ void Shell::OnPlatformViewDestroyed() { } // |PlatformView::Delegate| -void Shell::OnPlatformViewSetViewportMetrics(const ViewportMetrics& metrics) { +void Shell::OnPlatformViewSetScreenMetrics( + const std::vector& metrics) { FML_DCHECK(is_setup_); FML_DCHECK(task_runners_.GetPlatformTaskRunner()->RunsTasksOnCurrentThread()); + task_runners_.GetUITaskRunner()->PostTask( + [engine = engine_->GetWeakPtr(), metrics]() { + if (engine) { + engine->SetScreenMetrics(metrics); + } + }); +} + +// |PlatformView::Delegate| +void Shell::OnPlatformViewSetViewportMetrics( + const std::vector& metrics) { + FML_DCHECK(is_setup_); + FML_DCHECK(task_runners_.GetPlatformTaskRunner()->RunsTasksOnCurrentThread()); + + // TODO(gspencergoog): Currently, there is only one window. This will change + // as multi-window support is added. See + // https://github.com/flutter/flutter/issues/60131 + // This is the formula Android uses. // https://android.googlesource.com/platform/frameworks/base/+/master/libs/hwui/renderthread/CacheManager.cpp#41 - size_t max_bytes = metrics.physical_width * metrics.physical_height * 12 * 4; + size_t max_bytes = + metrics[0].physical_width * metrics[0].physical_height * 12 * 4; task_runners_.GetRasterTaskRunner()->PostTask( [rasterizer = rasterizer_->GetWeakPtr(), max_bytes] { if (rasterizer) { diff --git a/shell/common/shell.h b/shell/common/shell.h index b5f612331f7d6..a901c3c27a7c4 100644 --- a/shell/common/shell.h +++ b/shell/common/shell.h @@ -445,9 +445,13 @@ class Shell final : public PlatformView::Delegate, // |PlatformView::Delegate| void OnPlatformViewDestroyed() override; + // |PlatformView::Delegate| + void OnPlatformViewSetScreenMetrics( + const std::vector& metrics) override; + // |PlatformView::Delegate| void OnPlatformViewSetViewportMetrics( - const ViewportMetrics& metrics) override; + const std::vector& metrics) override; // |PlatformView::Delegate| void OnPlatformViewDispatchPlatformMessage( diff --git a/shell/common/shell_test.cc b/shell/common/shell_test.cc index 5d44e2cfe5151..877e60e3b62f2 100644 --- a/shell/common/shell_test.cc +++ b/shell/common/shell_test.cc @@ -100,18 +100,23 @@ void ShellTest::PumpOneFrame(Shell* shell, double width, double height, LayerTreeBuilder builder) { - PumpOneFrame(shell, {1.0, width, height}, std::move(builder)); + PumpOneFrame(shell, {{0, 1.0, 0.0, 0.0, width, height}}, + {{0, 1.0, 0.0, 0.0, width, height}}, std::move(builder)); } -void ShellTest::PumpOneFrame(Shell* shell, - flutter::ViewportMetrics viewport_metrics, - LayerTreeBuilder builder) { +void ShellTest::PumpOneFrame( + Shell* shell, + std::vector screen_metrics, + std::vector viewport_metrics, + LayerTreeBuilder builder) { // Set viewport to nonempty, and call Animator::BeginFrame to make the layer // tree pipeline nonempty. Without either of this, the layer tree below // won't be rasterized. fml::AutoResetWaitableEvent latch; shell->GetTaskRunners().GetUITaskRunner()->PostTask( - [&latch, engine = shell->weak_engine_, viewport_metrics]() { + [&latch, engine = shell->weak_engine_, screen_metrics, + viewport_metrics]() { + engine->SetScreenMetrics(std::move(screen_metrics)); engine->SetViewportMetrics(std::move(viewport_metrics)); const auto frame_begin_time = fml::TimePoint::Now(); const auto frame_end_time = @@ -126,11 +131,14 @@ void ShellTest::PumpOneFrame(Shell* shell, fml::WeakPtr runtime_delegate = shell->weak_engine_; shell->GetTaskRunners().GetUITaskRunner()->PostTask( [&latch, runtime_delegate, &builder, viewport_metrics]() { + // TODO(gspencergoog): Currently, there is only one window. This will + // change as multi-window support is added. See + // https://github.com/flutter/flutter/issues/60131 auto layer_tree = std::make_unique( - SkISize::Make(viewport_metrics.physical_width, - viewport_metrics.physical_height), - static_cast(viewport_metrics.physical_depth), - static_cast(viewport_metrics.device_pixel_ratio)); + SkISize::Make(viewport_metrics[0].physical_width, + viewport_metrics[0].physical_height), + static_cast(viewport_metrics[0].physical_depth), + static_cast(viewport_metrics[0].device_pixel_ratio)); SkMatrix identity; identity.setIdentity(); auto root_layer = std::make_shared(identity); diff --git a/shell/common/shell_test.h b/shell/common/shell_test.h index 2b46881c3c68f..06616b43cf9f1 100644 --- a/shell/common/shell_test.h +++ b/shell/common/shell_test.h @@ -65,9 +65,11 @@ class ShellTest : public FixtureTest { double width = 1, double height = 1, LayerTreeBuilder = {}); - static void PumpOneFrame(Shell* shell, - flutter::ViewportMetrics viewport_metrics, - LayerTreeBuilder = {}); + static void PumpOneFrame( + Shell* shell, + std::vector screen_metrics, + std::vector viewport_metrics, + LayerTreeBuilder = {}); static void DispatchFakePointerData(Shell* shell); static void DispatchPointerData(Shell* shell, std::unique_ptr packet); diff --git a/shell/common/shell_unittests.cc b/shell/common/shell_unittests.cc index acb3e0cf50fbd..6792000923186 100644 --- a/shell/common/shell_unittests.cc +++ b/shell/common/shell_unittests.cc @@ -683,7 +683,8 @@ TEST_F(ShellTest, WaitForFirstFrameZeroSizeFrame) { configuration.SetEntrypoint("emptyMain"); RunEngine(shell.get(), std::move(configuration)); - PumpOneFrame(shell.get(), {1.0, 0.0, 0.0}); + PumpOneFrame(shell.get(), {{0, 1.0, 0.0, 0.0, 0.0, 0.0}}, + {{0, 1.0, 0.0, 0.0, 0.0, 0.0}}); fml::Status result = shell->WaitForFirstFrame(fml::TimeDelta::FromMilliseconds(1000)); ASSERT_FALSE(result.ok()); @@ -801,7 +802,8 @@ TEST_F(ShellTest, SetResourceCacheSize) { fml::TaskRunner::RunNowOrPostTask( shell->GetTaskRunners().GetPlatformTaskRunner(), [&shell]() { - shell->GetPlatformView()->SetViewportMetrics({1.0, 400, 200}); + shell->GetPlatformView()->SetViewportMetrics( + {{0, 1.0, 0.0, 0.0, 400, 200}}); }); PumpOneFrame(shell.get()); @@ -820,7 +822,8 @@ TEST_F(ShellTest, SetResourceCacheSize) { fml::TaskRunner::RunNowOrPostTask( shell->GetTaskRunners().GetPlatformTaskRunner(), [&shell]() { - shell->GetPlatformView()->SetViewportMetrics({1.0, 800, 400}); + shell->GetPlatformView()->SetViewportMetrics( + {{0, 1.0, 0.0, 0.0, 800, 400}}); }); PumpOneFrame(shell.get()); @@ -838,7 +841,8 @@ TEST_F(ShellTest, SetResourceCacheSizeEarly) { fml::TaskRunner::RunNowOrPostTask( shell->GetTaskRunners().GetPlatformTaskRunner(), [&shell]() { - shell->GetPlatformView()->SetViewportMetrics({1.0, 400, 200}); + shell->GetPlatformView()->SetViewportMetrics( + {{0, 1.0, 0.0, 0.0, 400, 200}}); }); PumpOneFrame(shell.get()); @@ -866,7 +870,8 @@ TEST_F(ShellTest, SetResourceCacheSizeNotifiesDart) { fml::TaskRunner::RunNowOrPostTask( shell->GetTaskRunners().GetPlatformTaskRunner(), [&shell]() { - shell->GetPlatformView()->SetViewportMetrics({1.0, 400, 200}); + shell->GetPlatformView()->SetViewportMetrics( + {{0, 1.0, 0.0, 0.0, 400, 200}}); }); PumpOneFrame(shell.get()); diff --git a/shell/platform/android/io/flutter/embedding/android/FlutterView.java b/shell/platform/android/io/flutter/embedding/android/FlutterView.java index fd0468d234dc7..c32e6136f3fc1 100644 --- a/shell/platform/android/io/flutter/embedding/android/FlutterView.java +++ b/shell/platform/android/io/flutter/embedding/android/FlutterView.java @@ -104,9 +104,10 @@ public class FlutterView extends FrameLayout implements MouseCursorPlugin.MouseC @Nullable private AndroidTouchProcessor androidTouchProcessor; @Nullable private AccessibilityBridge accessibilityBridge; - // Directly implemented View behavior that communicates with Flutter. + // Directly implemented view and screen behavior that communicates with Flutter. private final FlutterRenderer.ViewportMetrics viewportMetrics = new FlutterRenderer.ViewportMetrics(); + private final FlutterRenderer.ScreenMetrics screenMetrics = new FlutterRenderer.ScreenMetrics(); private final AccessibilityBridge.OnAccessibilityChangeListener onAccessibilityChangeListener = new AccessibilityBridge.OnAccessibilityChangeListener() { @@ -417,7 +418,7 @@ protected void onSizeChanged(int width, int height, int oldWidth, int oldHeight) + height); viewportMetrics.width = width; viewportMetrics.height = height; - sendViewportMetricsToFlutter(); + sendMetricsToFlutter(); } // TODO(garyq): Add support for notch cutout API: https://github.com/flutter/flutter/issues/56592 @@ -570,7 +571,7 @@ public final WindowInsets onApplyWindowInsets(@NonNull WindowInsets insets) { + ", Bottom: " + viewportMetrics.viewInsetBottom); - sendViewportMetricsToFlutter(); + sendMetricsToFlutter(); return newInsets; } @@ -615,7 +616,7 @@ protected boolean fitSystemWindows(@NonNull Rect insets) { + ", Right: " + viewportMetrics.viewInsetRight); - sendViewportMetricsToFlutter(); + sendMetricsToFlutter(); return true; } else { return super.fitSystemWindows(insets); @@ -882,7 +883,7 @@ public void attachToFlutterEngine(@NonNull FlutterEngine flutterEngine) { // Push View and Context related information from Android to Flutter. sendUserSettingsToFlutter(); localizationPlugin.sendLocalesToFlutter(getResources().getConfiguration()); - sendViewportMetricsToFlutter(); + sendMetricsToFlutter(); flutterEngine.getPlatformViewsController().attachToView(this); @@ -1068,17 +1069,21 @@ public void removeFlutterEngineAttachmentListener( .send(); } - // TODO(mattcarroll): consider introducing a system channel for this communication instead of JNI - private void sendViewportMetricsToFlutter() { + private void sendMetricsToFlutter() { if (!isAttachedToFlutterEngine()) { Log.w( TAG, - "Tried to send viewport metrics from Android to Flutter but this " + "Tried to send metrics from Android to Flutter but this " + "FlutterView was not attached to a FlutterEngine."); return; } - viewportMetrics.devicePixelRatio = getResources().getDisplayMetrics().density; + // TODO(gspencergoog): Currently, there is only one screen. This will change + // as screen support is added. See + // https://github.com/flutter/flutter/issues/60131 + screenMetrics.devicePixelRatio = getResources().getDisplayMetrics().density; + viewportMetrics.devicePixelRatio = screenMetrics.devicePixelRatio; + flutterEngine.getRenderer().setScreenMetrics(screenMetrics); flutterEngine.getRenderer().setViewportMetrics(viewportMetrics); } diff --git a/shell/platform/android/io/flutter/embedding/engine/FlutterJNI.java b/shell/platform/android/io/flutter/embedding/engine/FlutterJNI.java index 57630cc9e6a8e..7225935534bee 100644 --- a/shell/platform/android/io/flutter/embedding/engine/FlutterJNI.java +++ b/shell/platform/android/io/flutter/embedding/engine/FlutterJNI.java @@ -373,7 +373,10 @@ public void onSurfaceDestroyed() { */ @UiThread public void setViewportMetrics( + int viewId, float devicePixelRatio, + int physicalLeft, + int physicalTop, int physicalWidth, int physicalHeight, int physicalPaddingTop, @@ -392,7 +395,10 @@ public void setViewportMetrics( ensureAttachedToNative(); nativeSetViewportMetrics( nativePlatformViewId, + viewId, devicePixelRatio, + physicalLeft, + physicalTop, physicalWidth, physicalHeight, physicalPaddingTop, @@ -411,7 +417,82 @@ public void setViewportMetrics( private native void nativeSetViewportMetrics( long nativePlatformViewId, + long viewId, + float devicePixelRatio, + int physicalLeft, + int physicalTop, + int physicalWidth, + int physicalHeight, + int physicalPaddingTop, + int physicalPaddingRight, + int physicalPaddingBottom, + int physicalPaddingLeft, + int physicalViewInsetTop, + int physicalViewInsetRight, + int physicalViewInsetBottom, + int physicalViewInsetLeft, + int systemGestureInsetTop, + int systemGestureInsetRight, + int systemGestureInsetBottom, + int systemGestureInsetLeft); + + /** + * Call this method to notify Flutter of the current device viewport metrics that are applies to + * the Flutter UI that is being rendered. + * + *

This method should be invoked with initial values upon attaching to native. Then, it should + * be invoked any time those metrics change while {@code FlutterJNI} is attached to native. + */ + @UiThread + public void setScreenMetrics( + long screenId, + float devicePixelRatio, + int physicalLeft, + int physicalTop, + int physicalWidth, + int physicalHeight, + int physicalPaddingTop, + int physicalPaddingRight, + int physicalPaddingBottom, + int physicalPaddingLeft, + int physicalViewInsetTop, + int physicalViewInsetRight, + int physicalViewInsetBottom, + int physicalViewInsetLeft, + int systemGestureInsetTop, + int systemGestureInsetRight, + int systemGestureInsetBottom, + int systemGestureInsetLeft) { + ensureRunningOnMainThread(); + ensureAttachedToNative(); + nativeSetScreenMetrics( + nativePlatformViewId, + screenId, + devicePixelRatio, + physicalLeft, + physicalTop, + physicalWidth, + physicalHeight, + physicalPaddingTop, + physicalPaddingRight, + physicalPaddingBottom, + physicalPaddingLeft, + physicalViewInsetTop, + physicalViewInsetRight, + physicalViewInsetBottom, + physicalViewInsetLeft, + systemGestureInsetTop, + systemGestureInsetRight, + systemGestureInsetBottom, + systemGestureInsetLeft); + } + + private native void nativeSetScreenMetrics( + long nativePlatformViewId, + long screenId, float devicePixelRatio, + int physicalLeft, + int physicalTop, int physicalWidth, int physicalHeight, int physicalPaddingTop, diff --git a/shell/platform/android/io/flutter/embedding/engine/renderer/FlutterRenderer.java b/shell/platform/android/io/flutter/embedding/engine/renderer/FlutterRenderer.java index f0cd24adea675..b922b5a34aaa2 100644 --- a/shell/platform/android/io/flutter/embedding/engine/renderer/FlutterRenderer.java +++ b/shell/platform/android/io/flutter/embedding/engine/renderer/FlutterRenderer.java @@ -236,7 +236,16 @@ public void setViewportMetrics(@NonNull ViewportMetrics viewportMetrics) { Log.v( TAG, "Setting viewport metrics\n" - + "Size: " + + "View ID: " + + viewportMetrics.viewId + + "Screen ID: " + + viewportMetrics.devicePixelRatio + + "Geometry: " + + "(" + + viewportMetrics.left + + ", " + + viewportMetrics.top + + ") " + viewportMetrics.width + " x " + viewportMetrics.height @@ -269,7 +278,10 @@ public void setViewportMetrics(@NonNull ViewportMetrics viewportMetrics) { + viewportMetrics.viewInsetBottom); flutterJNI.setViewportMetrics( + viewportMetrics.viewId, viewportMetrics.devicePixelRatio, + viewportMetrics.left, + viewportMetrics.top, viewportMetrics.width, viewportMetrics.height, viewportMetrics.paddingTop, @@ -286,6 +298,72 @@ public void setViewportMetrics(@NonNull ViewportMetrics viewportMetrics) { viewportMetrics.systemGestureInsetLeft); } + public void setScreenMetrics(@NonNull ScreenMetrics screenMetrics) { + Log.v( + TAG, + "Setting viewport metrics\n" + + "Screen ID: " + + screenMetrics.screenId + + "Device Pixel Ratio: " + + screenMetrics.devicePixelRatio + + "Geometry: " + + "(" + + screenMetrics.left + + ", " + + screenMetrics.top + + ") " + + screenMetrics.width + + " x " + + screenMetrics.height + + "\n" + + "Padding - L: " + + screenMetrics.paddingLeft + + ", T: " + + screenMetrics.paddingTop + + ", R: " + + screenMetrics.paddingRight + + ", B: " + + screenMetrics.paddingBottom + + "\n" + + "Insets - L: " + + screenMetrics.viewInsetLeft + + ", T: " + + screenMetrics.viewInsetTop + + ", R: " + + screenMetrics.viewInsetRight + + ", B: " + + screenMetrics.viewInsetBottom + + "\n" + + "System Gesture Insets - L: " + + screenMetrics.systemGestureInsetLeft + + ", T: " + + screenMetrics.systemGestureInsetTop + + ", R: " + + screenMetrics.systemGestureInsetRight + + ", B: " + + screenMetrics.viewInsetBottom); + + flutterJNI.setScreenMetrics( + screenMetrics.screenId, + screenMetrics.devicePixelRatio, + screenMetrics.left, + screenMetrics.top, + screenMetrics.width, + screenMetrics.height, + screenMetrics.paddingTop, + screenMetrics.paddingRight, + screenMetrics.paddingBottom, + screenMetrics.paddingLeft, + screenMetrics.viewInsetTop, + screenMetrics.viewInsetRight, + screenMetrics.viewInsetBottom, + screenMetrics.viewInsetLeft, + screenMetrics.systemGestureInsetTop, + screenMetrics.systemGestureInsetRight, + screenMetrics.systemGestureInsetBottom, + screenMetrics.systemGestureInsetLeft); + } + // TODO(mattcarroll): describe the native behavior that this invokes // TODO(mattcarroll): determine if this is nullable or nonnull public Bitmap getBitmap() { @@ -340,7 +418,37 @@ public void dispatchSemanticsAction( * pixels, not logical pixels. */ public static final class ViewportMetrics { + public int viewId = 0; + public float devicePixelRatio = 1.0f; + public int left = 0; + public int top = 0; + public int width = 0; + public int height = 0; + public int paddingTop = 0; + public int paddingRight = 0; + public int paddingBottom = 0; + public int paddingLeft = 0; + public int viewInsetTop = 0; + public int viewInsetRight = 0; + public int viewInsetBottom = 0; + public int viewInsetLeft = 0; + public int systemGestureInsetTop = 0; + public int systemGestureInsetRight = 0; + public int systemGestureInsetBottom = 0; + public int systemGestureInsetLeft = 0; + } + + /** + * Mutable data structure that holds all screen metrics properties that Flutter cares about. + * + *

All distance measurements, e.g., width, height, padding, viewInsets, are measured in device + * pixels, not logical pixels. + */ + public static final class ScreenMetrics { + public int screenId = 0; public float devicePixelRatio = 1.0f; + public int left = 0; + public int top = 0; public int width = 0; public int height = 0; public int paddingTop = 0; diff --git a/shell/platform/android/io/flutter/view/FlutterView.java b/shell/platform/android/io/flutter/view/FlutterView.java index cd0446b95d446..2ce2e25c6a362 100644 --- a/shell/platform/android/io/flutter/view/FlutterView.java +++ b/shell/platform/android/io/flutter/view/FlutterView.java @@ -94,7 +94,31 @@ public interface Provider { private static final String TAG = "FlutterView"; static final class ViewportMetrics { + int viewId = 0; float devicePixelRatio = 1.0f; + int physicalLeft = 0; + int physicalTop = 0; + int physicalWidth = 0; + int physicalHeight = 0; + int physicalPaddingTop = 0; + int physicalPaddingRight = 0; + int physicalPaddingBottom = 0; + int physicalPaddingLeft = 0; + int physicalViewInsetTop = 0; + int physicalViewInsetRight = 0; + int physicalViewInsetBottom = 0; + int physicalViewInsetLeft = 0; + int systemGestureInsetTop = 0; + int systemGestureInsetRight = 0; + int systemGestureInsetBottom = 0; + int systemGestureInsetLeft = 0; + } + + static final class ScreenMetrics { + int screenId = 0; + float devicePixelRatio = 1.0f; + int physicalLeft = 0; + int physicalTop = 0; int physicalWidth = 0; int physicalHeight = 0; int physicalPaddingTop = 0; @@ -128,6 +152,7 @@ static final class ViewportMetrics { private final AndroidTouchProcessor androidTouchProcessor; private AccessibilityBridge mAccessibilityNodeProvider; private final SurfaceHolder.Callback mSurfaceCallback; + private final ScreenMetrics mScreenMetrics; private final ViewportMetrics mMetrics; private final List mActivityLifecycleListeners; private final List mFirstFrameListeners; @@ -170,8 +195,10 @@ public FlutterView(Context context, AttributeSet attrs, FlutterNativeView native dartExecutor = mNativeView.getDartExecutor(); flutterRenderer = new FlutterRenderer(mNativeView.getFlutterJNI()); mIsSoftwareRenderingEnabled = mNativeView.getFlutterJNI().nativeGetIsSoftwareRenderingEnabled(); + mScreenMetrics = new ScreenMetrics(); + mScreenMetrics.devicePixelRatio = context.getResources().getDisplayMetrics().density; mMetrics = new ViewportMetrics(); - mMetrics.devicePixelRatio = context.getResources().getDisplayMetrics().density; + mMetrics.devicePixelRatio = mScreenMetrics.devicePixelRatio; setFocusable(true); setFocusableInTouchMode(true); @@ -413,7 +440,7 @@ protected void onConfigurationChanged(Configuration newConfig) { } float getDevicePixelRatio() { - return mMetrics.devicePixelRatio; + return mScreenMetrics.devicePixelRatio; } public FlutterNativeView detach() { @@ -506,9 +533,15 @@ public boolean onGenericMotionEvent(MotionEvent event) { @Override protected void onSizeChanged(int width, int height, int oldWidth, int oldHeight) { + // TODO(gspencergoog): Currently, there is only one screen, and it is always + // the same size as the window. This will change as screen support is added. + // See https://github.com/flutter/flutter/issues/60131 mMetrics.physicalWidth = width; mMetrics.physicalHeight = height; + mScreenMetrics.physicalWidth = width; + mScreenMetrics.physicalHeight = height; updateViewportMetrics(); + updateScreenMetrics(); super.onSizeChanged(width, height, oldWidth, oldHeight); } @@ -599,35 +632,47 @@ public final WindowInsets onApplyWindowInsets(WindowInsets insets) { } // The padding on top should be removed when the statusbar is hidden. - mMetrics.physicalPaddingTop = statusBarHidden ? 0 : insets.getSystemWindowInsetTop(); - mMetrics.physicalPaddingRight = + mScreenMetrics.physicalPaddingTop = statusBarHidden ? 0 : insets.getSystemWindowInsetTop(); + mScreenMetrics.physicalPaddingRight = zeroSides == ZeroSides.RIGHT || zeroSides == ZeroSides.BOTH ? 0 : insets.getSystemWindowInsetRight(); - mMetrics.physicalPaddingBottom = 0; - mMetrics.physicalPaddingLeft = + mScreenMetrics.physicalPaddingBottom = 0; + mScreenMetrics.physicalPaddingLeft = zeroSides == ZeroSides.LEFT || zeroSides == ZeroSides.BOTH ? 0 : insets.getSystemWindowInsetLeft(); // Bottom system inset (keyboard) should adjust scrollable bottom edge (inset). - mMetrics.physicalViewInsetTop = 0; - mMetrics.physicalViewInsetRight = 0; + mScreenMetrics.physicalViewInsetTop = 0; + mScreenMetrics.physicalViewInsetRight = 0; // We perform hidden navbar and keyboard handling if the navbar is set to hidden. Otherwise, // the navbar padding should always be provided. - mMetrics.physicalViewInsetBottom = + mScreenMetrics.physicalViewInsetBottom = navigationBarHidden ? guessBottomKeyboardInset(insets) : insets.getSystemWindowInsetBottom(); - mMetrics.physicalViewInsetLeft = 0; + mScreenMetrics.physicalViewInsetLeft = 0; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { Insets systemGestureInsets = insets.getSystemGestureInsets(); - mMetrics.systemGestureInsetTop = systemGestureInsets.top; - mMetrics.systemGestureInsetRight = systemGestureInsets.right; - mMetrics.systemGestureInsetBottom = systemGestureInsets.bottom; - mMetrics.systemGestureInsetLeft = systemGestureInsets.left; + mScreenMetrics.systemGestureInsetTop = systemGestureInsets.top; + mScreenMetrics.systemGestureInsetRight = systemGestureInsets.right; + mScreenMetrics.systemGestureInsetBottom = systemGestureInsets.bottom; + mScreenMetrics.systemGestureInsetLeft = systemGestureInsets.left; } + // TODO(gspencergoog): Currently, there is only one screen, and it is always + // the same size as the window. This will change as screen support is added. + // See https://github.com/flutter/flutter/issues/60131 + mMetrics.physicalPaddingTop = mScreenMetrics.physicalPaddingTop; + mMetrics.physicalPaddingRight = mScreenMetrics.physicalPaddingRight; + mMetrics.physicalPaddingBottom = mScreenMetrics.physicalPaddingBottom; + mMetrics.physicalPaddingLeft = mScreenMetrics.physicalPaddingLeft; + mMetrics.physicalViewInsetTop = mScreenMetrics.physicalViewInsetTop; + mMetrics.physicalViewInsetRight = mScreenMetrics.physicalViewInsetRight; + mMetrics.physicalViewInsetBottom = mScreenMetrics.physicalViewInsetBottom; + mMetrics.physicalViewInsetLeft = mScreenMetrics.physicalViewInsetLeft; + updateScreenMetrics(); updateViewportMetrics(); return super.onApplyWindowInsets(insets); } @@ -636,17 +681,29 @@ public final WindowInsets onApplyWindowInsets(WindowInsets insets) { @SuppressWarnings("deprecation") protected boolean fitSystemWindows(Rect insets) { if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.KITKAT) { + // TODO(gspencergoog): Currently, there is only one screen, and it is always + // the same size as the window. This will change as screen support is added. + // See https://github.com/flutter/flutter/issues/60131 // Status bar, left/right system insets partially obscure content (padding). - mMetrics.physicalPaddingTop = insets.top; - mMetrics.physicalPaddingRight = insets.right; - mMetrics.physicalPaddingBottom = 0; - mMetrics.physicalPaddingLeft = insets.left; + mScreenMetrics.physicalPaddingTop = insets.top; + mScreenMetrics.physicalPaddingRight = insets.right; + mScreenMetrics.physicalPaddingBottom = 0; + mScreenMetrics.physicalPaddingLeft = insets.left; // Bottom system inset (keyboard) should adjust scrollable bottom edge (inset). - mMetrics.physicalViewInsetTop = 0; - mMetrics.physicalViewInsetRight = 0; - mMetrics.physicalViewInsetBottom = insets.bottom; - mMetrics.physicalViewInsetLeft = 0; + mScreenMetrics.physicalViewInsetTop = 0; + mScreenMetrics.physicalViewInsetRight = 0; + mScreenMetrics.physicalViewInsetBottom = insets.bottom; + mScreenMetrics.physicalViewInsetLeft = 0; + mMetrics.physicalPaddingTop = mScreenMetrics.physicalPaddingTop; + mMetrics.physicalPaddingRight = mScreenMetrics.physicalPaddingRight; + mMetrics.physicalPaddingBottom = mScreenMetrics.physicalPaddingBottom; + mMetrics.physicalPaddingLeft = mScreenMetrics.physicalPaddingLeft; + mMetrics.physicalViewInsetTop = mScreenMetrics.physicalViewInsetTop; + mMetrics.physicalViewInsetRight = mScreenMetrics.physicalViewInsetRight; + mMetrics.physicalViewInsetBottom = mScreenMetrics.physicalViewInsetBottom; + mMetrics.physicalViewInsetLeft = mScreenMetrics.physicalViewInsetLeft; + updateScreenMetrics(); updateViewportMetrics(); return true; } else { @@ -696,7 +753,10 @@ private void updateViewportMetrics() { mNativeView .getFlutterJNI() .setViewportMetrics( + mMetrics.viewId, mMetrics.devicePixelRatio, + mMetrics.physicalLeft, + mMetrics.physicalTop, mMetrics.physicalWidth, mMetrics.physicalHeight, mMetrics.physicalPaddingTop, @@ -713,6 +773,31 @@ private void updateViewportMetrics() { mMetrics.systemGestureInsetLeft); } + private void updateScreenMetrics() { + if (!isAttached()) return; + mNativeView + .getFlutterJNI() + .setScreenMetrics( + mScreenMetrics.screenId, + mScreenMetrics.devicePixelRatio, + mScreenMetrics.physicalLeft, + mScreenMetrics.physicalTop, + mScreenMetrics.physicalWidth, + mScreenMetrics.physicalHeight, + mScreenMetrics.physicalPaddingTop, + mScreenMetrics.physicalPaddingRight, + mScreenMetrics.physicalPaddingBottom, + mScreenMetrics.physicalPaddingLeft, + mScreenMetrics.physicalViewInsetTop, + mScreenMetrics.physicalViewInsetRight, + mScreenMetrics.physicalViewInsetBottom, + mScreenMetrics.physicalViewInsetLeft, + mScreenMetrics.systemGestureInsetTop, + mScreenMetrics.systemGestureInsetRight, + mScreenMetrics.systemGestureInsetBottom, + mScreenMetrics.systemGestureInsetLeft); + } + // Called by FlutterNativeView to notify first Flutter frame rendered. public void onFirstFrame() { didRenderFirstFrame = true; diff --git a/shell/platform/android/platform_view_android_jni_impl.cc b/shell/platform/android/platform_view_android_jni_impl.cc index 35c867bed400c..5b7c324afd84e 100644 --- a/shell/platform/android/platform_view_android_jni_impl.cc +++ b/shell/platform/android/platform_view_android_jni_impl.cc @@ -239,7 +239,10 @@ static jobject LookupCallbackInformation(JNIEnv* env, static void SetViewportMetrics(JNIEnv* env, jobject jcaller, jlong shell_holder, + jlong view_id, jfloat devicePixelRatio, + jint physicalLeft, + jint physicalTop, jint physicalWidth, jint physicalHeight, jint physicalPaddingTop, @@ -255,7 +258,10 @@ static void SetViewportMetrics(JNIEnv* env, jint systemGestureInsetBottom, jint systemGestureInsetLeft) { const flutter::ViewportMetrics metrics{ + static_cast(view_id), static_cast(devicePixelRatio), + static_cast(physicalLeft), + static_cast(physicalTop), static_cast(physicalWidth), static_cast(physicalHeight), static_cast(physicalPaddingTop), @@ -272,7 +278,52 @@ static void SetViewportMetrics(JNIEnv* env, static_cast(systemGestureInsetLeft), }; - ANDROID_SHELL_HOLDER->GetPlatformView()->SetViewportMetrics(metrics); + ANDROID_SHELL_HOLDER->GetPlatformView()->SetViewportMetrics({metrics}); +} + +static void SetScreenMetrics(JNIEnv* env, + jobject jcaller, + jlong shell_holder, + jlong screen_id, + jfloat devicePixelRatio, + jint physicalLeft, + jint physicalTop, + jint physicalWidth, + jint physicalHeight, + jint physicalPaddingTop, + jint physicalPaddingRight, + jint physicalPaddingBottom, + jint physicalPaddingLeft, + jint physicalViewInsetTop, + jint physicalViewInsetRight, + jint physicalViewInsetBottom, + jint physicalViewInsetLeft, + jint systemGestureInsetTop, + jint systemGestureInsetRight, + jint systemGestureInsetBottom, + jint systemGestureInsetLeft) { + const flutter::ScreenMetrics metrics{ + static_cast(screen_id), + static_cast(devicePixelRatio), + static_cast(physicalLeft), + static_cast(physicalTop), + static_cast(physicalWidth), + static_cast(physicalHeight), + static_cast(physicalPaddingTop), + static_cast(physicalPaddingRight), + static_cast(physicalPaddingBottom), + static_cast(physicalPaddingLeft), + static_cast(physicalViewInsetTop), + static_cast(physicalViewInsetRight), + static_cast(physicalViewInsetBottom), + static_cast(physicalViewInsetLeft), + static_cast(systemGestureInsetTop), + static_cast(systemGestureInsetRight), + static_cast(systemGestureInsetBottom), + static_cast(systemGestureInsetLeft), + }; + + ANDROID_SHELL_HOLDER->GetPlatformView()->SetScreenMetrics({metrics}); } static jobject GetBitmap(JNIEnv* env, jobject jcaller, jlong shell_holder) { @@ -582,9 +633,14 @@ bool RegisterApi(JNIEnv* env) { }, { .name = "nativeSetViewportMetrics", - .signature = "(JFIIIIIIIIIIIIII)V", + .signature = "(JJFIIIIIIIIIIIIIIII)V", .fnPtr = reinterpret_cast(&SetViewportMetrics), }, + { + .name = "nativeSetScreenMetrics", + .signature = "(JJFIIIIIIIIIIIIIIII)V", + .fnPtr = reinterpret_cast(&SetScreenMetrics), + }, { .name = "nativeDispatchPointerDataPacket", .signature = "(JLjava/nio/ByteBuffer;I)V", diff --git a/shell/platform/darwin/ios/framework/Source/FlutterEngine.mm b/shell/platform/darwin/ios/framework/Source/FlutterEngine.mm index 51a741fa4109f..e474abadbb303 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterEngine.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterEngine.mm @@ -11,6 +11,7 @@ #include "flutter/fml/message_loop.h" #include "flutter/fml/platform/darwin/platform_version.h" #include "flutter/fml/trace_event.h" +#include "flutter/lib/ui/window/screen_metrics.h" #include "flutter/shell/common/engine.h" #include "flutter/shell/common/platform_view.h" #include "flutter/shell/common/shell.h" @@ -185,6 +186,13 @@ - (void)dealloc { return _weakFactory->GetWeakPtr(); } +- (void)updateScreenMetrics:(flutter::ScreenMetrics)screenMetrics { + if (!self.platformView) { + return; + } + self.platformView->SetScreenMetrics(std::move(screenMetrics)); +} + - (void)updateViewportMetrics:(flutter::ViewportMetrics)viewportMetrics { if (!self.platformView) { return; diff --git a/shell/platform/darwin/ios/framework/Source/FlutterEngine_Internal.h b/shell/platform/darwin/ios/framework/Source/FlutterEngine_Internal.h index 52558eaf71ab3..5ee372c539698 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterEngine_Internal.h +++ b/shell/platform/darwin/ios/framework/Source/FlutterEngine_Internal.h @@ -12,6 +12,7 @@ #include "flutter/fml/memory/weak_ptr.h" #include "flutter/fml/task_runner.h" #include "flutter/lib/ui/window/pointer_data_packet.h" +#include "flutter/lib/ui/window/screen_metrics.h" #include "flutter/lib/ui/window/viewport_metrics.h" #include "flutter/shell/common/platform_view.h" #include "flutter/shell/common/rasterizer.h" @@ -28,6 +29,7 @@ - (flutter::Shell&)shell; +- (void)updateScreenMetrics:(flutter::ScreenMetrics)screenMetrics; - (void)updateViewportMetrics:(flutter::ViewportMetrics)viewportMetrics; - (void)dispatchPointerDataPacket:(std::unique_ptr)packet; diff --git a/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm b/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm index d788b461586f6..72384bc8aa53f 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm @@ -68,6 +68,7 @@ @implementation FlutterViewController { UIInterfaceOrientationMask _orientationPreferences; UIStatusBarStyle _statusBarStyle; flutter::ViewportMetrics _viewportMetrics; + flutter::ScreenMetrics _screenMetrics; BOOL _initialized; BOOL _viewOpaque; BOOL _engineNeedsLaunch; @@ -831,6 +832,10 @@ - (void)touchesCancelled:(NSSet*)touches withEvent:(UIEvent*)event { #pragma mark - Handle view resizing +- (void)updateScreenMetrics { + [_engine.get() updateScreenMetrics:_screenMetrics]; +} + - (void)updateViewportMetrics { [_engine.get() updateViewportMetrics:_viewportMetrics]; } @@ -845,19 +850,29 @@ - (CGFloat)statusBarPadding { } - (void)viewDidLayoutSubviews { - CGSize viewSize = self.view.bounds.size; - CGFloat scale = [UIScreen mainScreen].scale; + CGRect viewBounds = self.view.bounds; + CGRect screenBounds = self.view.window.screen.bounds; + CGFloat scale = self.view.window.screen.scale; // Purposefully place this not visible. - _scrollView.get().frame = CGRectMake(0.0, 0.0, viewSize.width, 0.0); + _scrollView.get().frame = CGRectMake(0.0, 0.0, viewBounds.size.width, 0.0); _scrollView.get().contentOffset = CGPointMake(kScrollViewContentSize, kScrollViewContentSize); // First time since creation that the dimensions of its view is known. bool firstViewBoundsUpdate = !_viewportMetrics.physical_width; + _screenMetrics.device_pixel_ratio = scale; + _screenMetrics.physical_left = screenBounds.origin.x; + _screenMetrics.physical_top = screenBounds.origin.y; + _screenMetrics.physical_width = screenBounds.size.width; + _screenMetrics.physical_height = screenBounds.size.height; _viewportMetrics.device_pixel_ratio = scale; - _viewportMetrics.physical_width = viewSize.width * scale; - _viewportMetrics.physical_height = viewSize.height * scale; + _viewportMetrics.physical_left = viewBounds.origin.x; + _viewportMetrics.physical_top = viewBounds.origin.y; + _viewportMetrics.physical_width = viewBounds.size.width * scale; + _viewportMetrics.physical_height = viewBounds.size.height * scale; + [self updateScreenPadding]; + [self updateScreenMetrics]; [self updateViewportPadding]; [self updateViewportMetrics]; @@ -888,11 +903,28 @@ - (void)viewDidLayoutSubviews { } - (void)viewSafeAreaInsetsDidChange { + [self updateScreenPadding]; + [self updateScreenMetrics]; [self updateViewportPadding]; [self updateViewportMetrics]; [super viewSafeAreaInsetsDidChange]; } +// Updates _screenMetrics physical padding. +// +// Screen padding represents the iOS safe area insets. +- (void)updateScreenPadding { + CGFloat scale = [UIScreen mainScreen].scale; + if (@available(iOS 11, *)) { + _screenMetrics.physical_padding_top = self.view.safeAreaInsets.top * scale; + _screenMetrics.physical_padding_left = self.view.safeAreaInsets.left * scale; + _screenMetrics.physical_padding_right = self.view.safeAreaInsets.right * scale; + _screenMetrics.physical_padding_bottom = self.view.safeAreaInsets.bottom * scale; + } else { + _screenMetrics.physical_padding_top = [self statusBarPadding] * scale; + } +} + // Updates _viewportMetrics physical padding. // // Viewport padding represents the iOS safe area insets. @@ -933,16 +965,21 @@ - (void)keyboardWillChangeFrame:(NSNotification*)notification { // The keyboard is treated as an inset since we want to effectively reduce the window size by // the keyboard height. The Dart side will compute a value accounting for the keyboard-consuming // bottom padding. - _viewportMetrics.physical_view_inset_bottom = bottom * scale; + _screenMetrics.physical_view_inset_bottom = bottom * scale; + _viewportMetrics.physical_view_inset_bottom = _screenMetrics.physical_view_inset_bottom; } else { + _screenMetrics.physical_view_inset_bottom = 0; _viewportMetrics.physical_view_inset_bottom = 0; } + [self updateScreenMetrics]; [self updateViewportMetrics]; } - (void)keyboardWillBeHidden:(NSNotification*)notification { + _screenMetrics.physical_view_inset_bottom = 0; _viewportMetrics.physical_view_inset_bottom = 0; + [self updateScreenMetrics]; [self updateViewportMetrics]; } diff --git a/shell/platform/darwin/ios/framework/Source/accessibility_bridge_test.mm b/shell/platform/darwin/ios/framework/Source/accessibility_bridge_test.mm index 47a0b0c0272b7..a4628a4c6910a 100644 --- a/shell/platform/darwin/ios/framework/Source/accessibility_bridge_test.mm +++ b/shell/platform/darwin/ios/framework/Source/accessibility_bridge_test.mm @@ -75,6 +75,7 @@ void OnPlatformViewCreated(std::unique_ptr surface) override {} void OnPlatformViewDestroyed() override {} void OnPlatformViewSetNextFrameCallback(const fml::closure& closure) override {} void OnPlatformViewSetViewportMetrics(const ViewportMetrics& metrics) override {} + void OnPlatformViewSetScreenMetrics(const ScreenMetrics& metrics) override {} void OnPlatformViewDispatchPlatformMessage(fml::RefPtr message) override {} void OnPlatformViewDispatchPointerDataPacket(std::unique_ptr packet) override { } diff --git a/shell/platform/darwin/macos/framework/Source/FlutterEngine.mm b/shell/platform/darwin/macos/framework/Source/FlutterEngine.mm index e16cb6efde866..7bdc5fc8c49f7 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterEngine.mm +++ b/shell/platform/darwin/macos/framework/Source/FlutterEngine.mm @@ -253,6 +253,7 @@ - (BOOL)runWithEntrypoint:(NSString*)entrypoint { return NO; } + [self updateScreenMetrics]; [self updateWindowMetrics]; return YES; } @@ -264,6 +265,7 @@ - (void)setViewController:(FlutterViewController*)controller { [self shutDownEngine]; _resourceContext = nil; } + [self updateScreenMetrics]; [self updateWindowMetrics]; } @@ -295,16 +297,43 @@ - (void)updateWindowMetrics { return; } NSView* view = _viewController.view; - CGSize scaledSize = [view convertRectToBacking:view.bounds].size; - double pixelRatio = view.bounds.size.width == 0 ? 1 : scaledSize.width / view.bounds.size.width; - - const FlutterWindowMetricsEvent event = { - .struct_size = sizeof(event), - .width = static_cast(scaledSize.width), - .height = static_cast(scaledSize.height), - .pixel_ratio = pixelRatio, + CGRect scaledBounds = [view convertRectToBacking:view.bounds]; + + const FlutterWindowMetricsEvent windowMetricsEvent = { + .struct_size = sizeof(windowMetricsEvent), + .width = static_cast(scaledBounds.size.width), + .height = static_cast(scaledBounds.size.height), + .pixel_ratio = static_cast(view.window.screen.backingScaleFactor), + .left = static_cast(scaledBounds.origin.x), + .top = static_cast(scaledBounds.origin.y), + .window_id = 0, }; - FlutterEngineSendWindowMetricsEvent(_engine, &event); + + // TODO(gspencergoog): Currently, there is only one window. This will change + // as multi-window support is added. See + // https://github.com/flutter/flutter/issues/60131 + FlutterEngineSendWindowMetricsEvent(_engine, &windowMetricsEvent, 1); +} + +- (void)updateScreenMetrics { + if (!_engine) { + return; + } + NSView* view = _viewController.view; + CGRect screenBounds = view.window.screen.frame; + + // TODO(gspencergoog): Currently, there is only one screen. This will change as + // screen support is added. See https://github.com/flutter/flutter/issues/60131 + const FlutterScreenMetricsEvent screenMetricsEvent = { + .struct_size = sizeof(screenMetricsEvent), + .screen_id = 0, + .left = static_cast(screenBounds.origin.x), + .top = static_cast(screenBounds.origin.y), + .width = static_cast(screenBounds.size.width), + .height = static_cast(screenBounds.size.height), + .pixel_ratio = static_cast(view.window.screen.backingScaleFactor), + }; + FlutterEngineSendScreenMetricsEvent(_engine, &screenMetricsEvent, 1); } - (void)sendPointerEvent:(const FlutterPointerEvent&)event { diff --git a/shell/platform/darwin/macos/framework/Source/FlutterEngine_Internal.h b/shell/platform/darwin/macos/framework/Source/FlutterEngine_Internal.h index 2a01586efa27e..973c3bd06965c 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterEngine_Internal.h +++ b/shell/platform/darwin/macos/framework/Source/FlutterEngine_Internal.h @@ -22,7 +22,12 @@ @property(nonatomic, readonly, nullable) NSOpenGLContext* resourceContext; /** - * Informs the engine that the associated view controller's view size has changed. + * Informs the engine that the associated view controller's screen metrics have changed. + */ +- (void)updateScreenMetrics; + +/** + * Informs the engine that the associated view controller's view metrics have changed. */ - (void)updateWindowMetrics; diff --git a/shell/platform/embedder/embedder.cc b/shell/platform/embedder/embedder.cc index c9b3589182e1f..ee1b09c72ca57 100644 --- a/shell/platform/embedder/embedder.cc +++ b/shell/platform/embedder/embedder.cc @@ -1112,30 +1112,115 @@ FlutterEngineResult FlutterEngineShutdown(FLUTTER_API_SYMBOL(FlutterEngine) return kSuccess; } -FlutterEngineResult FlutterEngineSendWindowMetricsEvent( +FlutterEngineResult FlutterEngineSendScreenMetricsEvent( FLUTTER_API_SYMBOL(FlutterEngine) engine, - const FlutterWindowMetricsEvent* flutter_metrics) { - if (engine == nullptr || flutter_metrics == nullptr) { + const FlutterScreenMetricsEvent* metrics_events, + size_t events_count) { + if (engine == nullptr) { return LOG_EMBEDDER_ERROR(kInvalidArguments, "Engine handle was invalid."); } + if (metrics_events == nullptr || events_count == 0) { + return LOG_EMBEDDER_ERROR(kInvalidArguments, + "Invalid screen metrics events."); + } - flutter::ViewportMetrics metrics; + const FlutterScreenMetricsEvent* current = metrics_events; + std::vector metrics_vector; + for (size_t i = 0; i < events_count; ++i) { + flutter::ScreenMetrics screen_metrics; - metrics.physical_width = SAFE_ACCESS(flutter_metrics, width, 0.0); - metrics.physical_height = SAFE_ACCESS(flutter_metrics, height, 0.0); - metrics.device_pixel_ratio = SAFE_ACCESS(flutter_metrics, pixel_ratio, 1.0); + screen_metrics.screen_id = SAFE_ACCESS(current, screen_id, 0); + screen_metrics.physical_left = SAFE_ACCESS(current, left, 0.0); + screen_metrics.physical_top = SAFE_ACCESS(current, top, 0.0); + screen_metrics.physical_width = SAFE_ACCESS(current, width, 0.0); + screen_metrics.physical_height = SAFE_ACCESS(current, height, 0.0); + screen_metrics.device_pixel_ratio = SAFE_ACCESS(current, pixel_ratio, 1.0); - if (metrics.device_pixel_ratio <= 0.0) { - return LOG_EMBEDDER_ERROR( - kInvalidArguments, - "Device pixel ratio was invalid. It must be greater than zero."); + if (screen_metrics.screen_id < 0) { + return LOG_EMBEDDER_ERROR( + kInvalidArguments, + "Window screen id must be set to a positive integer."); + } + if (screen_metrics.device_pixel_ratio <= 0.0) { + return LOG_EMBEDDER_ERROR( + kInvalidArguments, + "Device pixel ratio was invalid. It must be greater than zero."); + } + if (screen_metrics.physical_width < 0.0) { + return LOG_EMBEDDER_ERROR(kInvalidArguments, + "Device width was invalid. It must be greater " + "than or equal to zero."); + } + if (screen_metrics.physical_height < 0.0) { + return LOG_EMBEDDER_ERROR(kInvalidArguments, + "Device height was invalid. It must be greater " + "than or equal to zero."); + } + metrics_vector.push_back(std::move(screen_metrics)); + current = reinterpret_cast( + reinterpret_cast(current) + current->struct_size); + } + return reinterpret_cast(engine)->SetScreenMetrics( + std::move(metrics_vector)) + ? kSuccess + : LOG_EMBEDDER_ERROR(kInvalidArguments, + "Screen metrics were invalid."); +} + +FlutterEngineResult FlutterEngineSendWindowMetricsEvent( + FLUTTER_API_SYMBOL(FlutterEngine) engine, + const FlutterWindowMetricsEvent* metrics_events, + size_t events_count) { + if (engine == nullptr) { + return LOG_EMBEDDER_ERROR(kInvalidArguments, "Engine handle was invalid."); } + if (metrics_events == nullptr || events_count == 0) { + return LOG_EMBEDDER_ERROR(kInvalidArguments, + "Invalid screen metrics events."); + } + + const FlutterWindowMetricsEvent* current = metrics_events; + std::vector metrics_vector; + for (size_t i = 0; i < events_count; ++i) { + flutter::ViewportMetrics viewport_metrics; + + viewport_metrics.view_id = SAFE_ACCESS(current, window_id, 0); + viewport_metrics.physical_left = SAFE_ACCESS(current, left, 0.0); + viewport_metrics.physical_top = SAFE_ACCESS(current, top, 0.0); + viewport_metrics.physical_width = SAFE_ACCESS(current, width, 0.0); + viewport_metrics.physical_height = SAFE_ACCESS(current, height, 0.0); + viewport_metrics.device_pixel_ratio = + SAFE_ACCESS(current, pixel_ratio, 1.0); + if (viewport_metrics.view_id < 0) { + return LOG_EMBEDDER_ERROR( + kInvalidArguments, + "Window screen id must be set to a positive integer."); + } + if (viewport_metrics.device_pixel_ratio <= 0.0) { + return LOG_EMBEDDER_ERROR( + kInvalidArguments, + "Device pixel ratio was invalid. It must be greater than zero."); + } + if (viewport_metrics.physical_width < 0.0) { + return LOG_EMBEDDER_ERROR(kInvalidArguments, + "Device width was invalid. It must be greater " + "than or equal to zero."); + } + if (viewport_metrics.physical_height < 0.0) { + return LOG_EMBEDDER_ERROR(kInvalidArguments, + "Device height was invalid. It must be greater " + "than or equal to zero."); + } + metrics_vector.push_back(std::move(viewport_metrics)); + current = reinterpret_cast( + reinterpret_cast(current) + current->struct_size); + } return reinterpret_cast(engine)->SetViewportMetrics( - std::move(metrics)) + std::move(metrics_vector)) ? kSuccess : LOG_EMBEDDER_ERROR(kInvalidArguments, - "Viewport metrics were invalid."); + "Screen metrics were invalid."); } // Returns the flutter::PointerData::Change for the given FlutterPointerPhase. diff --git a/shell/platform/embedder/embedder.h b/shell/platform/embedder/embedder.h index 947d9d368025a..82cd29d605253 100644 --- a/shell/platform/embedder/embedder.h +++ b/shell/platform/embedder/embedder.h @@ -345,10 +345,36 @@ typedef struct { size_t width; /// Physical height of the window. size_t height; - /// Scale factor for the physical screen. + /// Pixel density scale factor for the window. double pixel_ratio; + /// Physical horizontal location of the left side of the window. + int64_t left; + /// Physical vertical location of the top of the window. + int64_t top; + /// The id for the window that corresponds to these metrics. + size_t window_id; } FlutterWindowMetricsEvent; +/// The order, type, and size of these struct members must remain the same, and +/// members should not be removed. This is to allow for forward and backward +/// compatibility between the engine and the embedder. +typedef struct { + /// The size of this struct. Must be sizeof(FlutterScreenMetricsEvent). + size_t struct_size; + /// The id for the screen that corresponds to these metrics. + size_t screen_id; + /// Physical horizontal location of the left side of the window. + int64_t left; + /// Physical vertical location of the top of the window. + int64_t top; + /// Physical width of the screen. + size_t width; + /// Physical height of the screen. + size_t height; + /// Pixel density scale factor for the physical screen. + double pixel_ratio; +} FlutterScreenMetricsEvent; + /// The phase of the pointer event. typedef enum { kCancel, @@ -1370,10 +1396,17 @@ FLUTTER_EXPORT FlutterEngineResult FlutterEngineRunInitialized( FLUTTER_API_SYMBOL(FlutterEngine) engine); +FLUTTER_EXPORT +FlutterEngineResult FlutterEngineSendScreenMetricsEvent( + FLUTTER_API_SYMBOL(FlutterEngine) engine, + const FlutterScreenMetricsEvent* metrics_events, + size_t events_count); + FLUTTER_EXPORT FlutterEngineResult FlutterEngineSendWindowMetricsEvent( FLUTTER_API_SYMBOL(FlutterEngine) engine, - const FlutterWindowMetricsEvent* event); + const FlutterWindowMetricsEvent* metrics_events, + size_t events_count); FLUTTER_EXPORT FlutterEngineResult FlutterEngineSendPointerEvent( diff --git a/shell/platform/embedder/embedder_engine.cc b/shell/platform/embedder/embedder_engine.cc index 7d6f2c5d788f1..79302bf0331c7 100644 --- a/shell/platform/embedder/embedder_engine.cc +++ b/shell/platform/embedder/embedder_engine.cc @@ -100,7 +100,8 @@ bool EmbedderEngine::NotifyDestroyed() { return true; } -bool EmbedderEngine::SetViewportMetrics(flutter::ViewportMetrics metrics) { +bool EmbedderEngine::SetViewportMetrics( + const std::vector& metrics) { if (!IsValid()) { return false; } @@ -113,6 +114,20 @@ bool EmbedderEngine::SetViewportMetrics(flutter::ViewportMetrics metrics) { return true; } +bool EmbedderEngine::SetScreenMetrics( + const std::vector& metrics) { + if (!IsValid()) { + return false; + } + + auto platform_view = shell_->GetPlatformView(); + if (!platform_view) { + return false; + } + platform_view->SetScreenMetrics(std::move(metrics)); + return true; +} + bool EmbedderEngine::DispatchPointerDataPacket( std::unique_ptr packet) { if (!IsValid() || !packet) { diff --git a/shell/platform/embedder/embedder_engine.h b/shell/platform/embedder/embedder_engine.h index 151b489bb9465..67a92c032655b 100644 --- a/shell/platform/embedder/embedder_engine.h +++ b/shell/platform/embedder/embedder_engine.h @@ -48,7 +48,9 @@ class EmbedderEngine { bool IsValid() const; - bool SetViewportMetrics(flutter::ViewportMetrics metrics); + bool SetViewportMetrics(const std::vector& metrics); + + bool SetScreenMetrics(const std::vector& metrics); bool DispatchPointerDataPacket( std::unique_ptr packet); diff --git a/shell/platform/embedder/tests/embedder_unittests.cc b/shell/platform/embedder/tests/embedder_unittests.cc index a3ece90e032cc..cf1567d4ac5f8 100644 --- a/shell/platform/embedder/tests/embedder_unittests.cc +++ b/shell/platform/embedder/tests/embedder_unittests.cc @@ -655,7 +655,7 @@ TEST_F(EmbedderTest, CompositorMustBeAbleToRenderToOpenGLFramebuffer) { event.width = 800; event.height = 600; event.pixel_ratio = 1.0; - ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event), + ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event, 1), kSuccess); ASSERT_TRUE(engine.is_valid()); @@ -748,7 +748,7 @@ TEST_F(EmbedderTest, RasterCacheDisabledWithPlatformViews) { event.width = 800; event.height = 600; event.pixel_ratio = 1.0; - ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event), + ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event, 1), kSuccess); ASSERT_TRUE(engine.is_valid()); @@ -820,7 +820,7 @@ TEST_F(EmbedderTest, RasterCacheEnabled) { event.width = 800; event.height = 600; event.pixel_ratio = 1.0; - ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event), + ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event, 1), kSuccess); ASSERT_TRUE(engine.is_valid()); @@ -921,7 +921,7 @@ TEST_F(EmbedderTest, CompositorMustBeAbleToRenderToOpenGLTexture) { event.width = 800; event.height = 600; event.pixel_ratio = 1.0; - ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event), + ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event, 1), kSuccess); ASSERT_TRUE(engine.is_valid()); @@ -1013,7 +1013,7 @@ TEST_F(EmbedderTest, CompositorMustBeAbleToRenderToSoftwareBuffer) { event.width = 800; event.height = 600; event.pixel_ratio = 1.0; - ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event), + ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event, 1), kSuccess); ASSERT_TRUE(engine.is_valid()); @@ -1306,7 +1306,7 @@ TEST_F(EmbedderTest, CompositorMustBeAbleToRenderKnownScene) { event.width = 800; event.height = 600; event.pixel_ratio = 1.0; - ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event), + ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event, 1), kSuccess); ASSERT_TRUE(engine.is_valid()); @@ -1480,7 +1480,7 @@ TEST_F(EmbedderTest, event.width = 800; event.height = 600; event.pixel_ratio = 1.0; - ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event), + ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event, 1), kSuccess); ASSERT_TRUE(engine.is_valid()); @@ -1601,7 +1601,7 @@ TEST_F(EmbedderTest, CustomCompositorMustWorkWithCustomTaskRunner) { event.width = 800; event.height = 600; event.pixel_ratio = 1.0; - ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event), + ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event, 1), kSuccess); ASSERT_TRUE(engine.is_valid()); sync_latch.Signal(); @@ -1675,7 +1675,7 @@ TEST_F(EmbedderTest, CompositorMustBeAbleToRenderWithRootLayerOnly) { event.width = 800; event.height = 600; event.pixel_ratio = 1.0; - ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event), + ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event, 1), kSuccess); ASSERT_TRUE(engine.is_valid()); @@ -1784,7 +1784,7 @@ TEST_F(EmbedderTest, CompositorMustBeAbleToRenderWithPlatformLayerOnBottom) { event.width = 800; event.height = 600; event.pixel_ratio = 1.0; - ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event), + ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event, 1), kSuccess); ASSERT_TRUE(engine.is_valid()); @@ -1964,7 +1964,7 @@ TEST_F(EmbedderTest, event.width = 800; event.height = 600; event.pixel_ratio = 1.0; - ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event), + ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event, 1), kSuccess); ASSERT_TRUE(engine.is_valid()); @@ -1993,7 +1993,7 @@ TEST_F(EmbedderTest, CanRenderSceneWithoutCustomCompositor) { event.width = 800; event.height = 600; event.pixel_ratio = 1.0; - ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event), + ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event, 1), kSuccess); ASSERT_TRUE(ImageMatchesFixture("scene_without_custom_compositor.png", @@ -2026,7 +2026,7 @@ TEST_F(EmbedderTest, CanRenderSceneWithoutCustomCompositorWithTransformation) { event.width = 800; event.height = 600; event.pixel_ratio = 1.0; - ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event), + ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event, 1), kSuccess); ASSERT_TRUE(ImageMatchesFixture( @@ -2052,7 +2052,7 @@ TEST_F(EmbedderTest, CanRenderGradientWithoutCompositor) { event.width = 800; event.height = 600; event.pixel_ratio = 1.0; - ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event), + ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event, 1), kSuccess); ASSERT_TRUE(ImageMatchesFixture("gradient.png", renderered_scene)); @@ -2085,7 +2085,7 @@ TEST_F(EmbedderTest, CanRenderGradientWithoutCompositorWithXform) { event.width = 800; event.height = 600; event.pixel_ratio = 1.0; - ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event), + ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event, 1), kSuccess); ASSERT_TRUE(ImageMatchesFixture("gradient_xform.png", renderered_scene)); @@ -2111,7 +2111,7 @@ TEST_F(EmbedderTest, CanRenderGradientWithCompositor) { event.width = 800; event.height = 600; event.pixel_ratio = 1.0; - ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event), + ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event, 1), kSuccess); ASSERT_TRUE(ImageMatchesFixture("gradient.png", renderered_scene)); @@ -2146,7 +2146,7 @@ TEST_F(EmbedderTest, CanRenderGradientWithCompositorWithXform) { event.width = 800; event.height = 600; event.pixel_ratio = 1.0; - ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event), + ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event, 1), kSuccess); ASSERT_TRUE(ImageMatchesFixture("gradient_xform.png", renderered_scene)); @@ -2248,7 +2248,7 @@ TEST_F(EmbedderTest, CanRenderGradientWithCompositorOnNonRootLayer) { event.width = 800; event.height = 600; event.pixel_ratio = 1.0; - ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event), + ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event, 1), kSuccess); ASSERT_TRUE(ImageMatchesFixture("gradient.png", renderered_scene)); @@ -2359,7 +2359,7 @@ TEST_F(EmbedderTest, CanRenderGradientWithCompositorOnNonRootLayerWithXform) { event.width = 800; event.height = 600; event.pixel_ratio = 1.0; - ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event), + ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event, 1), kSuccess); ASSERT_TRUE(ImageMatchesFixture("gradient_xform.png", renderered_scene)); @@ -2460,7 +2460,7 @@ TEST_F(EmbedderTest, VerifyB141980393) { event.width = flutter_application_rect.width(); event.height = flutter_application_rect.height(); event.pixel_ratio = 1.0; - ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event), + ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event, 1), kSuccess); ASSERT_TRUE(engine.is_valid()); @@ -2513,7 +2513,7 @@ TEST_F(EmbedderTest, CaDeinitializeAnEngine) { event.width = 800; event.height = 600; event.pixel_ratio = 1.0; - ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event), + ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event, 1), kInvalidArguments); engine.reset(); } @@ -2555,7 +2555,7 @@ TEST_F(EmbedderTest, CanCreateEmbedderWithCustomRenderTaskRunner) { event.width = 800; event.height = 600; event.pixel_ratio = 1.0; - ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event), + ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event, 1), kSuccess); task_latch.Wait(); ASSERT_TRUE(task_executed); @@ -2615,7 +2615,7 @@ TEST_F(EmbedderTest, event.width = 800; event.height = 600; event.pixel_ratio = 1.0; - ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event), + ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event, 1), kSuccess); }); @@ -2720,13 +2720,28 @@ TEST_F(EmbedderTest, auto engine = builder.LaunchEngine(); - // Send a window metrics events so frames may be scheduled. - FlutterWindowMetricsEvent event = {}; - event.struct_size = sizeof(event); - event.width = 400 * 2.0; - event.height = 300 * 2.0; - event.pixel_ratio = 2.0; - ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event), + // Send screen and window metrics events so frames may be scheduled. + FlutterScreenMetricsEvent screen_metrics_event = {}; + screen_metrics_event.struct_size = sizeof(screen_metrics_event); + screen_metrics_event.screen_id = 0; + screen_metrics_event.left = 0.0; + screen_metrics_event.top = 0.0; + screen_metrics_event.width = 400 * 2.0; + screen_metrics_event.height = 300 * 2.0; + screen_metrics_event.pixel_ratio = 2.0; + ASSERT_EQ(FlutterEngineSendScreenMetricsEvent(engine.get(), + &screen_metrics_event, 1), + kSuccess); + FlutterWindowMetricsEvent window_metrics_event = {}; + window_metrics_event.struct_size = sizeof(window_metrics_event); + window_metrics_event.window_id = 0; + window_metrics_event.left = 0.0; + window_metrics_event.top = 0.0; + window_metrics_event.width = 400 * 2.0; + window_metrics_event.height = 300 * 2.0; + window_metrics_event.pixel_ratio = 2.0; + ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), + &window_metrics_event, 1), kSuccess); ASSERT_TRUE(engine.is_valid()); @@ -2815,13 +2830,28 @@ TEST_F( auto engine = builder.LaunchEngine(); - // Send a window metrics events so frames may be scheduled. - FlutterWindowMetricsEvent event = {}; - event.struct_size = sizeof(event); - event.width = 400 * 2.0; - event.height = 300 * 2.0; - event.pixel_ratio = 2.0; - ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event), + // Send screen and window metrics events so frames may be scheduled. + FlutterScreenMetricsEvent screen_metrics_event = {}; + screen_metrics_event.struct_size = sizeof(screen_metrics_event); + screen_metrics_event.screen_id = 0; + screen_metrics_event.left = 0.0; + screen_metrics_event.top = 0.0; + screen_metrics_event.width = 400 * 2.0; + screen_metrics_event.height = 300 * 2.0; + screen_metrics_event.pixel_ratio = 2.0; + ASSERT_EQ(FlutterEngineSendScreenMetricsEvent(engine.get(), + &screen_metrics_event, 1), + kSuccess); + FlutterWindowMetricsEvent window_metrics_event = {}; + window_metrics_event.struct_size = sizeof(window_metrics_event); + window_metrics_event.window_id = 0; + window_metrics_event.left = 0.0; + window_metrics_event.top = 0.0; + window_metrics_event.width = 400 * 2.0; + window_metrics_event.height = 300 * 2.0; + window_metrics_event.pixel_ratio = 2.0; + ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), + &window_metrics_event, 1), kSuccess); ASSERT_TRUE(engine.is_valid()); @@ -2995,7 +3025,7 @@ TEST_F(EmbedderTest, VerifyB143464703WithSoftwareBackend) { event.width = 1024; event.height = 600; event.pixel_ratio = 1.0; - ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event), + ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event, 1), kSuccess); ASSERT_TRUE(engine.is_valid()); @@ -3037,7 +3067,7 @@ TEST_F(EmbedderTest, event.width = 1024; event.height = 600; event.pixel_ratio = 1.0; - ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event), + ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event, 1), kSuccess); ASSERT_TRUE(engine.is_valid()); @@ -3075,7 +3105,7 @@ TEST_F(EmbedderTest, event.width = 1024; event.height = 600; event.pixel_ratio = 1.0; - ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event), + ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event, 1), kSuccess); ASSERT_TRUE(engine.is_valid()); @@ -3181,7 +3211,7 @@ TEST_F(EmbedderTest, PlatformViewMutatorsAreValid) { event.width = 800; event.height = 600; event.pixel_ratio = 1.0; - ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event), + ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event, 1), kSuccess); ASSERT_TRUE(engine.is_valid()); @@ -3271,13 +3301,28 @@ TEST_F(EmbedderTest, PlatformViewMutatorsAreValidWithPixelRatio) { auto engine = builder.LaunchEngine(); - // Send a window metrics events so frames may be scheduled. - FlutterWindowMetricsEvent event = {}; - event.struct_size = sizeof(event); - event.width = 800; - event.height = 600; - event.pixel_ratio = 2.0; - ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event), + // Send screen and window metrics events so frames may be scheduled. + FlutterScreenMetricsEvent screen_metrics_event = {}; + screen_metrics_event.struct_size = sizeof(screen_metrics_event); + screen_metrics_event.screen_id = 0; + screen_metrics_event.left = 0.0; + screen_metrics_event.top = 0.0; + screen_metrics_event.width = 400 * 2.0; + screen_metrics_event.height = 300 * 2.0; + screen_metrics_event.pixel_ratio = 2.0; + ASSERT_EQ(FlutterEngineSendScreenMetricsEvent(engine.get(), + &screen_metrics_event, 1), + kSuccess); + FlutterWindowMetricsEvent window_metrics_event = {}; + window_metrics_event.struct_size = sizeof(window_metrics_event); + window_metrics_event.window_id = 0; + window_metrics_event.left = 0.0; + window_metrics_event.top = 0.0; + window_metrics_event.width = 400 * 2.0; + window_metrics_event.height = 300 * 2.0; + window_metrics_event.pixel_ratio = 2.0; + ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), + &window_metrics_event, 1), kSuccess); ASSERT_TRUE(engine.is_valid()); @@ -3374,13 +3419,28 @@ TEST_F(EmbedderTest, auto engine = builder.LaunchEngine(); - // Send a window metrics events so frames may be scheduled. - FlutterWindowMetricsEvent event = {}; - event.struct_size = sizeof(event); - event.width = 800; - event.height = 600; - event.pixel_ratio = 2.0; - ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event), + // Send screen and window metrics events so frames may be scheduled. + FlutterScreenMetricsEvent screen_metrics_event = {}; + screen_metrics_event.struct_size = sizeof(screen_metrics_event); + screen_metrics_event.screen_id = 0; + screen_metrics_event.left = 0.0; + screen_metrics_event.top = 0.0; + screen_metrics_event.width = 400 * 2.0; + screen_metrics_event.height = 300 * 2.0; + screen_metrics_event.pixel_ratio = 2.0; + ASSERT_EQ(FlutterEngineSendScreenMetricsEvent(engine.get(), + &screen_metrics_event, 1), + kSuccess); + FlutterWindowMetricsEvent window_metrics_event = {}; + window_metrics_event.struct_size = sizeof(window_metrics_event); + window_metrics_event.window_id = 0; + window_metrics_event.left = 0.0; + window_metrics_event.top = 0.0; + window_metrics_event.width = 400 * 2.0; + window_metrics_event.height = 300 * 2.0; + window_metrics_event.pixel_ratio = 2.0; + ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), + &window_metrics_event, 1), kSuccess); ASSERT_TRUE(engine.is_valid()); @@ -3408,7 +3468,7 @@ TEST_F(EmbedderTest, EmptySceneIsAcceptable) { event.width = 800; event.height = 600; event.pixel_ratio = 1.0; - ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event), + ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event, 1), kSuccess); latch.Wait(); } @@ -3434,7 +3494,7 @@ TEST_F(EmbedderTest, SceneWithNoRootContainerIsAcceptable) { event.width = 800; event.height = 600; event.pixel_ratio = 1.0; - ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event), + ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event, 1), kSuccess); latch.Wait(); } @@ -3467,7 +3527,7 @@ TEST_F(EmbedderTest, ArcEndCapsAreDrawnCorrectly) { event.width = 1024; event.height = 800; event.pixel_ratio = 1.0; - ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event), + ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event, 1), kSuccess); ASSERT_TRUE(ImageMatchesFixture("arc_end_caps.png", scene_image)); @@ -3591,7 +3651,7 @@ TEST_F(EmbedderTest, ClipsAreCorrectlyCalculated) { event.width = 400; event.height = 300; event.pixel_ratio = 1.0; - ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event), + ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event, 1), kSuccess); latch.Wait(); @@ -3673,7 +3733,7 @@ TEST_F(EmbedderTest, ComplexClipsAreCorrectlyCalculated) { event.width = 400; event.height = 300; event.pixel_ratio = 1.0; - ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event), + ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event, 1), kSuccess); latch.Wait(); @@ -4023,7 +4083,7 @@ TEST_F(EmbedderTest, CompositorCanPostZeroLayersForPresentation) { event.width = 300; event.height = 200; event.pixel_ratio = 1.0; - ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event), + ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event, 1), kSuccess); ASSERT_TRUE(engine.is_valid()); latch.Wait(); @@ -4086,7 +4146,7 @@ TEST_F(EmbedderTest, CompositorCanPostOnlyPlatformViews) { event.width = 300; event.height = 200; event.pixel_ratio = 1.0; - ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event), + ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event, 1), kSuccess); ASSERT_TRUE(engine.is_valid()); latch.Wait(); @@ -4125,7 +4185,7 @@ TEST_F(EmbedderTest, CompositorRenderTargetsAreRecycled) { event.width = 300; event.height = 200; event.pixel_ratio = 1.0; - ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event), + ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event, 1), kSuccess); latch.Wait(); @@ -4202,7 +4262,7 @@ TEST_F(EmbedderTest, CompositorRenderTargetsAreInStableOrder) { event.width = 300; event.height = 200; event.pixel_ratio = 1.0; - ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event), + ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event, 1), kSuccess); latch.Wait(); diff --git a/shell/platform/fuchsia/flutter/platform_view.cc b/shell/platform/fuchsia/flutter/platform_view.cc index df2b454336b1a..10f86f8fdbe49 100644 --- a/shell/platform/fuchsia/flutter/platform_view.cc +++ b/shell/platform/fuchsia/flutter/platform_view.cc @@ -11,6 +11,7 @@ #include "flutter/fml/logging.h" #include "flutter/lib/ui/compositing/scene_host.h" #include "flutter/lib/ui/window/pointer_data.h" +#include "flutter/lib/ui/window/screen_metrics.h" #include "flutter/lib/ui/window/window.h" #include "flutter_runner_product_configuration.h" #include "logging.h" @@ -191,23 +192,43 @@ void PlatformView::UpdateViewportMetrics( void PlatformView::FlushViewportMetrics() { const auto scale = metrics_.scale; const auto scale_z = metrics_.scale_z; - - SetViewportMetrics({ - scale, // device_pixel_ratio - metrics_.size.width * scale, // physical_width - metrics_.size.height * scale, // physical_height - metrics_.size.depth * scale_z, // physical_depth - metrics_.padding.top * scale, // physical_padding_top - metrics_.padding.right * scale, // physical_padding_right - metrics_.padding.bottom * scale, // physical_padding_bottom - metrics_.padding.left * scale, // physical_padding_left - metrics_.view_inset.front * scale_z, // physical_view_inset_front - metrics_.view_inset.back * scale_z, // physical_view_inset_back - metrics_.view_inset.top * scale, // physical_view_inset_top - metrics_.view_inset.right * scale, // physical_view_inset_right - metrics_.view_inset.bottom * scale, // physical_view_inset_bottom - metrics_.view_inset.left * scale // physical_view_inset_left - }); + // TODO(gspencergoog): Currently, there is only one screen. This will change + // as screen support is added. See + // https://github.com/flutter/flutter/issues/60131 + const flutter::ScreenMetrics screen_metrics{ + 0, // screen_id + scale, // device_pixel_ratio + 0.0, // physical_left + 0.0, // physical_top + metrics_.size.width * scale, // physical_width + metrics_.size.height * scale, // physical_height + metrics_.padding.top * scale, // physical_padding_top + metrics_.padding.right * scale, // physical_padding_right + metrics_.padding.bottom * scale, // physical_padding_bottom + metrics_.padding.left * scale, // physical_padding_left + metrics_.view_inset.top * scale, // physical_view_inset_top + metrics_.view_inset.right * scale, // physical_view_inset_right + metrics_.view_inset.bottom * scale, // physical_view_inset_bottom + metrics_.view_inset.left * scale // physical_view_inset_left + }; + SetScreenMetrics(screen_metrics); + SetViewportMetrics( + {0, // view_id + scale, // device_pixel_ratio + 0.0, // physical_left + 0.0, // physical_top + screen_metrics.physical_width, screen_metrics.physical_height, + metrics_.size.depth * scale_z, // physical_depth + screen_metrics.physical_padding_top, + screen_metrics.physical_padding_right, + screen_metrics.physical_padding_bottom, + screen_metrics.physical_padding_left, + metrics_.view_inset.front * scale_z, // physical_view_inset_front + metrics_.view_inset.back * scale_z, // physical_view_inset_back + screen_metrics.physical_view_inset_top, + screen_metrics.physical_view_inset_right, + screen_metrics.physical_view_inset_bottom, + screen_metrics.physical_view_inset_left}); } // |fuchsia::ui::input::InputMethodEditorClient| diff --git a/shell/platform/fuchsia/flutter/platform_view_unittest.cc b/shell/platform/fuchsia/flutter/platform_view_unittest.cc index 89a5658d8dd63..a83a56c02fc3c 100644 --- a/shell/platform/fuchsia/flutter/platform_view_unittest.cc +++ b/shell/platform/fuchsia/flutter/platform_view_unittest.cc @@ -52,6 +52,9 @@ class MockPlatformViewDelegate : public flutter::PlatformView::Delegate { // |flutter::PlatformView::Delegate| void OnPlatformViewSetNextFrameCallback(const fml::closure& closure) {} // |flutter::PlatformView::Delegate| + void OnPlatformViewSetScreenMetrics( + const std::vector& metrics) {} + // |flutter::PlatformView::Delegate| void OnPlatformViewSetViewportMetrics( const flutter::ViewportMetrics& metrics) {} // |flutter::PlatformView::Delegate| diff --git a/shell/platform/glfw/flutter_glfw.cc b/shell/platform/glfw/flutter_glfw.cc index 8658b31203372..cd0753fc54bde 100644 --- a/shell/platform/glfw/flutter_glfw.cc +++ b/shell/platform/glfw/flutter_glfw.cc @@ -196,6 +196,8 @@ static double GetScreenCoordinatesPerInch() { // Sends a window metrics update to the Flutter engine using the given // framebuffer size and the current window information in |state|. static void SendWindowMetrics(FlutterDesktopWindowControllerState* controller, + int left, + int top, int width, int height) { double dpi = controller->window_wrapper->pixels_per_screen_coordinate * @@ -203,6 +205,8 @@ static void SendWindowMetrics(FlutterDesktopWindowControllerState* controller, FlutterWindowMetricsEvent event = {}; event.struct_size = sizeof(event); + event.left = left; + event.top = top; event.width = width; event.height = height; if (controller->window_wrapper->pixel_ratio_override == 0.0) { @@ -213,8 +217,12 @@ static void SendWindowMetrics(FlutterDesktopWindowControllerState* controller, } else { event.pixel_ratio = controller->window_wrapper->pixel_ratio_override; } + + // TODO(gspencergoog): Currently, there is only one window. This will change + // as multi-window support is added. See + // https://github.com/flutter/flutter/issues/60131 FlutterEngineSendWindowMetricsEvent(controller->engine->flutter_engine, - &event); + &event, 1); } // Populates |task_runner| with a description that uses |engine_state|'s event @@ -240,13 +248,15 @@ static void ConfigurePlatformTaskRunner( static void GLFWFramebufferSizeCallback(GLFWwindow* window, int width_px, int height_px) { + int left_px, top_px; + glfwGetWindowPos(window, &left_px, &top_px); int width; glfwGetWindowSize(window, &width, nullptr); auto* controller = GetWindowController(window); controller->window_wrapper->pixels_per_screen_coordinate = width > 0 ? width_px / width : 1; - SendWindowMetrics(controller, width_px, height_px); + SendWindowMetrics(controller, left_px, top_px, width_px, height_px); controller->window_wrapper->skip_next_window_refresh = true; } @@ -259,10 +269,27 @@ void GLFWWindowRefreshCallback(GLFWwindow* window) { } // There's no engine API to request a redraw explicitly, so instead send a // window metrics event with the current size to trigger it. + int left_px, top_px; + glfwGetWindowPos(window, &left_px, &top_px); int width_px, height_px; glfwGetFramebufferSize(window, &width_px, &height_px); if (width_px > 0 && height_px > 0) { - SendWindowMetrics(controller, width_px, height_px); + SendWindowMetrics(controller, left_px, top_px, width_px, height_px); + } +} + +// Indicates that the window has moved. +void GLFWWindowPosCallback(GLFWwindow* window, int left_px, int top_px) { + auto* controller = GetWindowController(window); + int width_px, height_px; + glfwGetFramebufferSize(window, &width_px, &height_px); + + if (controller->window_wrapper->skip_next_window_refresh) { + controller->window_wrapper->skip_next_window_refresh = false; + return; + } + if (width_px > 0 && height_px > 0) { + SendWindowMetrics(controller, left_px, top_px, width_px, height_px); } } @@ -783,12 +810,16 @@ FlutterDesktopWindowControllerRef FlutterDesktopCreateWindow( // Trigger an initial size callback to send size information to Flutter. state->monitor_screen_coordinates_per_inch = GetScreenCoordinatesPerInch(); + int left_px, top_px; + glfwGetWindowPos(window, &left_px, &top_px); + GLFWWindowPosCallback(window, left_px, top_px); int width_px, height_px; glfwGetFramebufferSize(window, &width_px, &height_px); GLFWFramebufferSizeCallback(window, width_px, height_px); // Set up GLFW callbacks for the window. glfwSetFramebufferSizeCallback(window, GLFWFramebufferSizeCallback); + glfwSetWindowPosCallback(window, GLFWWindowPosCallback); glfwSetWindowRefreshCallback(window, GLFWWindowRefreshCallback); GLFWAssignEventCallbacks(window); @@ -878,9 +909,11 @@ void FlutterDesktopWindowSetPixelRatioOverride( // Send a metrics update using the new pixel ratio. int width_px, height_px; glfwGetFramebufferSize(flutter_window->window, &width_px, &height_px); + int left_px, top_px; + glfwGetWindowPos(flutter_window->window, &left_px, &top_px); if (width_px > 0 && height_px > 0) { auto* controller = GetWindowController(flutter_window->window); - SendWindowMetrics(controller, width_px, height_px); + SendWindowMetrics(controller, left_px, top_px, width_px, height_px); } } diff --git a/shell/platform/linux/fl_engine.cc b/shell/platform/linux/fl_engine.cc index 13e5c22088d7c..1e9e1e0935fed 100644 --- a/shell/platform/linux/fl_engine.cc +++ b/shell/platform/linux/fl_engine.cc @@ -5,6 +5,8 @@ #include "flutter/shell/platform/linux/public/flutter_linux/fl_engine.h" #include "flutter/shell/platform/linux/fl_engine_private.h" +#include + #include "flutter/shell/platform/linux/fl_binary_messenger_private.h" #include "flutter/shell/platform/linux/fl_plugin_registrar_private.h" #include "flutter/shell/platform/linux/fl_renderer.h" @@ -513,6 +515,9 @@ GBytes* fl_engine_send_platform_message_finish(FlEngine* self, } void fl_engine_send_window_metrics_event(FlEngine* self, + int64_t window_id, + size_t left, + size_t top, size_t width, size_t height, double pixel_ratio) { @@ -523,10 +528,43 @@ void fl_engine_send_window_metrics_event(FlEngine* self, FlutterWindowMetricsEvent event = {}; event.struct_size = sizeof(FlutterWindowMetricsEvent); + event.window_id = window_id; + event.left = left; + event.top = top; event.width = width; event.height = height; event.pixel_ratio = pixel_ratio; - FlutterEngineSendWindowMetricsEvent(self->engine, &event); + + // TODO(gspencergoog): Currently, there is only one window. This will change + // as multi-window support is added. See + // https://github.com/flutter/flutter/issues/60131 + FlutterEngineSendWindowMetricsEvent(self->engine, &event, 1); +} + +void fl_engine_update_screen_metrics(FlEngine* self, GdkDisplay* display) { + g_return_if_fail(FL_IS_ENGINE(self)); + g_return_if_fail(GDK_IS_DISPLAY(display)); + + size_t num_monitors = + static_cast(gdk_display_get_n_monitors(display)); + std::vector events(num_monitors); + for (size_t monitor_index = 0; monitor_index < num_monitors; + ++monitor_index) { + GdkMonitor* monitor = gdk_display_get_monitor(display, monitor_index); + GdkRectangle geometry; + gdk_monitor_get_geometry(monitor, &geometry); + events[monitor_index] = { + sizeof(FlutterScreenMetricsEvent), + monitor_index, + geometry.x, + geometry.y, + static_cast(geometry.width), + static_cast(geometry.height), + static_cast(gdk_monitor_get_scale_factor(monitor)), + }; + } + FlutterEngineSendScreenMetricsEvent(self->engine, events.data(), + events.size()); } void fl_engine_send_mouse_pointer_event(FlEngine* self, diff --git a/shell/platform/linux/fl_engine_private.h b/shell/platform/linux/fl_engine_private.h index 6c912979ba16c..f82634b1f84c8 100644 --- a/shell/platform/linux/fl_engine_private.h +++ b/shell/platform/linux/fl_engine_private.h @@ -90,17 +90,32 @@ gboolean fl_engine_start(FlEngine* engine, GError** error); /** * fl_engine_send_window_metrics_event: * @engine: an #FlEngine. + * @window_id: the window identifier for the window to be updated. + * @left: left edge of the window in pixels from the origin of the screen. + * @top: top edge of the window in pixels from the origin of the screen. * @width: width of the window in pixels. * @height: height of the window in pixels. - * @pixel_ratio: scale factor for window. + * @pixel_ratio: scale factor for the window. * * Sends a window metrics event to the engine. */ void fl_engine_send_window_metrics_event(FlEngine* engine, + int64_t window_id, + size_t left, + size_t top, size_t width, size_t height, double pixel_ratio); +/** + * fl_engine_update_screen_metrics: + * @engine: a #FlEngine + * + * Updates the screen metrics for all of the monitors attached to the display + * that this engine is running on. + */ +void fl_engine_update_screen_metrics(FlEngine* engine, GdkDisplay* display); + /** * fl_engine_send_mouse_pointer_event: * @engine: an #FlEngine. diff --git a/shell/platform/linux/fl_view.cc b/shell/platform/linux/fl_view.cc index 6b6fac67d46a8..c128042e7a6e7 100644 --- a/shell/platform/linux/fl_view.cc +++ b/shell/platform/linux/fl_view.cc @@ -4,6 +4,9 @@ #include "flutter/shell/platform/linux/public/flutter_linux/fl_view.h" +#include +#include + #include "flutter/shell/platform/linux/fl_engine_private.h" #include "flutter/shell/platform/linux/fl_key_event_plugin.h" #include "flutter/shell/platform/linux/fl_mouse_cursor_plugin.h" @@ -14,8 +17,6 @@ #include "flutter/shell/platform/linux/public/flutter_linux/fl_engine.h" #include "flutter/shell/platform/linux/public/flutter_linux/fl_plugin_registry.h" -#include - static constexpr int kMicrosecondsPerMillisecond = 1000; struct _FlView { @@ -33,6 +34,12 @@ struct _FlView { // Pointer button state recorded for sending status updates. int64_t button_state; + // The engine view id that this view has. + int64_t view_id; + + // Bounds given by the latest GtkConfigureEvent. + GdkRectangle current_bounds; + // Flutter system channel handlers. FlKeyEventPlugin* key_event_plugin; FlMouseCursorPlugin* mouse_cursor_plugin; @@ -101,12 +108,30 @@ static gboolean fl_view_send_pointer_button_event(FlView* self, // Updates the engine with the current window metrics. static void fl_view_send_window_metrics(FlView* self) { - GtkAllocation allocation; - gtk_widget_get_allocation(GTK_WIDGET(self), &allocation); gint scale_factor = gtk_widget_get_scale_factor(GTK_WIDGET(self)); fl_engine_send_window_metrics_event( - self->engine, allocation.width * scale_factor, - allocation.height * scale_factor, scale_factor); + self->engine, self->view_id, self->current_bounds.x * scale_factor, + self->current_bounds.y * scale_factor, + self->current_bounds.width * scale_factor, + self->current_bounds.height * scale_factor, scale_factor); +} + +static gboolean fl_view_configure_event(GtkWidget* widget, + GdkEventConfigure* configure, + gpointer userdata) { + FlView* self = FL_VIEW(userdata); + self->current_bounds.x = configure->x; + self->current_bounds.y = configure->y; + self->current_bounds.width = configure->width; + self->current_bounds.height = configure->height; + fl_view_send_window_metrics(self); + return false; +} + +static void fl_view_on_monitors_changed(GdkDisplay* display, + GdkMonitor* monitor, + gpointer userdata) { + fl_engine_update_screen_metrics(((FlView*)userdata)->engine, display); } // Implements FlPluginRegistry::get_registrar_for_plugin. @@ -235,15 +260,29 @@ static void fl_view_realize(GtkWidget* widget) { fl_renderer_x11_set_window( self->renderer, GDK_X11_WINDOW(gtk_widget_get_window(GTK_WIDGET(self)))); - if (!fl_engine_start(self->engine, &error)) + // TODO(gspencergoog): Currently, there is only one view (one window). This + // will change as multi-window support is added. See + // https://github.com/flutter/flutter/issues/60131 + self->view_id = 0; + self->current_bounds = {0, 0, 0, 0}; + if (!fl_engine_start(self->engine, &error)) { g_warning("Failed to start Flutter engine: %s", error->message); + } + + g_signal_connect(gtk_widget_get_toplevel(widget), "configure-event", + G_CALLBACK(fl_view_configure_event), (gpointer)self); + + GdkDisplay* display = gdk_window_get_display(window); + g_signal_connect(G_OBJECT(display), "monitor-added", + G_CALLBACK(fl_view_on_monitors_changed), (gpointer)self); + g_signal_connect(G_OBJECT(display), "monitor-removed", + G_CALLBACK(fl_view_on_monitors_changed), (gpointer)self); + fl_engine_update_screen_metrics(self->engine, display); } // Implements GtkWidget::size-allocate. static void fl_view_size_allocate(GtkWidget* widget, GtkAllocation* allocation) { - FlView* self = FL_VIEW(widget); - gtk_widget_set_allocation(widget, allocation); if (gtk_widget_get_realized(widget) && gtk_widget_get_has_window(widget)) { @@ -251,8 +290,6 @@ static void fl_view_size_allocate(GtkWidget* widget, allocation->y, allocation->width, allocation->height); } - - fl_view_send_window_metrics(self); } // Implements GtkWidget::button_press_event. diff --git a/shell/platform/linux/testing/mock_engine.cc b/shell/platform/linux/testing/mock_engine.cc index f82394bdd4ca3..ce0264ece39ce 100644 --- a/shell/platform/linux/testing/mock_engine.cc +++ b/shell/platform/linux/testing/mock_engine.cc @@ -194,9 +194,18 @@ FlutterEngineResult FlutterEngineRunInitialized( return kSuccess; } +FlutterEngineResult FlutterEngineSendScreenMetricsEvent( + FLUTTER_API_SYMBOL(FlutterEngine) engine, + const FlutterScreenMetricsEvent* events, + size_t num_events) { + EXPECT_TRUE(engine->running); + return kSuccess; +} + FlutterEngineResult FlutterEngineSendWindowMetricsEvent( FLUTTER_API_SYMBOL(FlutterEngine) engine, - const FlutterWindowMetricsEvent* event) { + const FlutterWindowMetricsEvent* event, + size_t events_count) { EXPECT_TRUE(engine->running); return kSuccess; } diff --git a/shell/platform/windows/flutter_windows_view.cc b/shell/platform/windows/flutter_windows_view.cc index db650a4e0ae7d..382b11d700329 100644 --- a/shell/platform/windows/flutter_windows_view.cc +++ b/shell/platform/windows/flutter_windows_view.cc @@ -1,6 +1,7 @@ #include "flutter/shell/platform/windows/flutter_windows_view.h" #include +#include "shell/platform/windows/window_binding_handler.h" namespace flutter { @@ -68,10 +69,7 @@ void FlutterWindowsView::SetState(FLUTTER_API_SYMBOL(FlutterEngine) eng) { cursor_handler_ = std::make_unique( internal_plugin_messenger, binding_handler_.get()); - PhysicalWindowBounds bounds = binding_handler_->GetPhysicalWindowBounds(); - - SendWindowMetrics(bounds.width, bounds.height, - binding_handler_->GetDpiScale()); + SendWindowMetrics(); } FlutterDesktopPluginRegistrarRef FlutterWindowsView::GetRegistrar() { @@ -107,9 +105,8 @@ void FlutterWindowsView::HandlePlatformMessage( message, [this] {}, [this] {}); } -void FlutterWindowsView::OnWindowSizeChanged(size_t width, - size_t height) const { - SendWindowMetrics(width, height, binding_handler_->GetDpiScale()); +void FlutterWindowsView::OnWindowBoundsChanged(PhysicalBounds bounds) const { + SendWindowMetrics(); } void FlutterWindowsView::OnPointerMove(double x, double y) { @@ -168,20 +165,42 @@ void FlutterWindowsView::OnFontChange() { FlutterEngineReloadSystemFonts(engine_); } -// Sends new size information to FlutterEngine. -void FlutterWindowsView::SendWindowMetrics(size_t width, - size_t height, - double dpiScale) const { +// Sends new window size information to FlutterEngine. +void FlutterWindowsView::SendWindowMetrics() const { if (engine_ == nullptr) { return; } + PhysicalBounds bounds = binding_handler_->GetWindowBounds(); + FlutterWindowMetricsEvent event = {}; event.struct_size = sizeof(event); - event.width = width; - event.height = height; - event.pixel_ratio = dpiScale; - auto result = FlutterEngineSendWindowMetricsEvent(engine_, &event); + event.window_id = 0; + event.left = bounds.left; + event.top = bounds.top; + event.width = bounds.width; + event.height = bounds.height; + event.pixel_ratio = binding_handler_->GetDpiScale(); + FlutterEngineSendWindowMetricsEvent(engine_, &event, 1); +} + +// Sends new screen size information to FlutterEngine. +void FlutterWindowsView::SendScreenMetrics() const { + if (engine_ == nullptr) { + return; + } + + PhysicalBounds bounds = binding_handler_->GetScreenBounds(); + + FlutterScreenMetricsEvent event = {}; + event.struct_size = sizeof(event); + event.screen_id = 0; + event.left = bounds.left; + event.top = bounds.top; + event.width = bounds.width; + event.height = bounds.height; + event.pixel_ratio = binding_handler_->GetDpiScale(); + FlutterEngineSendScreenMetricsEvent(engine_, &event, 1); } // Set's |event_data|'s phase to either kMove or kHover depending on the current diff --git a/shell/platform/windows/flutter_windows_view.h b/shell/platform/windows/flutter_windows_view.h index f19e9f97ac02a..82d94fc2a1c25 100644 --- a/shell/platform/windows/flutter_windows_view.h +++ b/shell/platform/windows/flutter_windows_view.h @@ -68,7 +68,7 @@ class FlutterWindowsView : public WindowBindingHandlerDelegate { bool SwapBuffers(); // |WindowBindingHandlerDelegate| - void OnWindowSizeChanged(size_t width, size_t height) const override; + void OnWindowBoundsChanged(PhysicalBounds bounds) const override; // |WindowBindingHandlerDelegate| void OnPointerMove(double x, double y) override; @@ -120,8 +120,12 @@ class FlutterWindowsView : public WindowBindingHandlerDelegate { }; // Sends a window metrics update to the Flutter engine using current window - // dimensions in physical - void SendWindowMetrics(size_t width, size_t height, double dpiscale) const; + // dimensions and location in physical coordinates. + void SendWindowMetrics() const; + + // Sends a screen metrics update to the Flutter engine using current screen + // dimensions and location in physical coordinates. + void SendScreenMetrics() const; // Reports a mouse movement to Flutter engine. void SendPointerMove(double x, double y); diff --git a/shell/platform/windows/testing/win32_flutter_window_test.cc b/shell/platform/windows/testing/win32_flutter_window_test.cc index bae1d9cd8d5b3..7317d796d232f 100644 --- a/shell/platform/windows/testing/win32_flutter_window_test.cc +++ b/shell/platform/windows/testing/win32_flutter_window_test.cc @@ -3,8 +3,11 @@ namespace flutter { namespace testing { -Win32FlutterWindowTest::Win32FlutterWindowTest(int width, int height) - : Win32FlutterWindow(width, height){}; +Win32FlutterWindowTest::Win32FlutterWindowTest(int left, + int top, + int width, + int height) + : Win32FlutterWindow(left, top, width, height){}; Win32FlutterWindowTest::~Win32FlutterWindowTest() = default; diff --git a/shell/platform/windows/testing/win32_flutter_window_test.h b/shell/platform/windows/testing/win32_flutter_window_test.h index 6da56d9383a5b..af93d09e1303e 100644 --- a/shell/platform/windows/testing/win32_flutter_window_test.h +++ b/shell/platform/windows/testing/win32_flutter_window_test.h @@ -12,7 +12,7 @@ namespace testing { /// Test class for Win32FlutterWindow. class Win32FlutterWindowTest : public Win32FlutterWindow { public: - Win32FlutterWindowTest(int width, int height); + Win32FlutterWindowTest(int left, int top, int width, int height); virtual ~Win32FlutterWindowTest(); // Prevent copying. diff --git a/shell/platform/windows/testing/win32_window_test.cc b/shell/platform/windows/testing/win32_window_test.cc index c7aaf6038bf9a..02ecfefe4be2b 100644 --- a/shell/platform/windows/testing/win32_window_test.cc +++ b/shell/platform/windows/testing/win32_window_test.cc @@ -11,6 +11,8 @@ void Win32WindowTest::OnDpiScale(unsigned int dpi){}; void Win32WindowTest::OnResize(unsigned int width, unsigned int height) {} +void Win32WindowTest::OnMove(unsigned int left, unsigned int top) {} + void Win32WindowTest::OnPointerMove(double x, double y) {} void Win32WindowTest::OnPointerDown(double x, double y, UINT button) {} diff --git a/shell/platform/windows/testing/win32_window_test.h b/shell/platform/windows/testing/win32_window_test.h index dade7a4061e69..99ca26f04d24d 100644 --- a/shell/platform/windows/testing/win32_window_test.h +++ b/shell/platform/windows/testing/win32_window_test.h @@ -29,6 +29,9 @@ class Win32WindowTest : public Win32Window { // |Win32Window| void OnResize(unsigned int width, unsigned int height) override; + // |Win32Window| + void OnMove(unsigned int left, unsigned int top) override; + // |Win32Window| void OnPointerMove(double x, double y) override; diff --git a/shell/platform/windows/win32_flutter_window.cc b/shell/platform/windows/win32_flutter_window.cc index 6fea467183870..9bdf5c78426a5 100644 --- a/shell/platform/windows/win32_flutter_window.cc +++ b/shell/platform/windows/win32_flutter_window.cc @@ -38,9 +38,9 @@ static HCURSOR GetCursorByName(const std::string& cursor_name) { } // namespace -Win32FlutterWindow::Win32FlutterWindow(int width, int height) +Win32FlutterWindow::Win32FlutterWindow(int left, int top, int width, int height) : binding_handler_delegate_(nullptr) { - Win32Window::InitializeChild("FLUTTERVIEW", width, height); + Win32Window::InitializeChild("FLUTTERVIEW", left, top, width, height); current_cursor_ = ::LoadCursor(nullptr, IDC_ARROW); } @@ -58,8 +58,12 @@ float Win32FlutterWindow::GetDpiScale() { return static_cast(GetCurrentDPI()) / static_cast(base_dpi); } -PhysicalWindowBounds Win32FlutterWindow::GetPhysicalWindowBounds() { - return {GetCurrentWidth(), GetCurrentHeight()}; +PhysicalBounds Win32FlutterWindow::GetWindowBounds() { + return GetCurrentWindowBounds(); +} + +PhysicalBounds Win32FlutterWindow::GetScreenBounds() { + return GetCurrentScreenBounds(); } void Win32FlutterWindow::UpdateFlutterCursor(const std::string& cursor_name) { @@ -97,6 +101,14 @@ void Win32FlutterWindow::OnResize(unsigned int width, unsigned int height) { } } +// When DesktopWindow notifies that a WM_Move message has come in +// lets FlutterEngine know about the new location. +void Win32FlutterWindow::OnMove(unsigned int left, unsigned int top) { + if (binding_handler_delegate_ != nullptr) { + binding_handler_delegate_->OnWindowLocationChanged(left, top); + } +} + void Win32FlutterWindow::OnPointerMove(double x, double y) { binding_handler_delegate_->OnPointerMove(x, y); } diff --git a/shell/platform/windows/win32_flutter_window.h b/shell/platform/windows/win32_flutter_window.h index b97d9b38b01ee..bfa9aab45dff4 100644 --- a/shell/platform/windows/win32_flutter_window.h +++ b/shell/platform/windows/win32_flutter_window.h @@ -20,12 +20,12 @@ namespace flutter { // A win32 flutter child window used as implementatin for flutter view. In the // future, there will likely be a CoreWindow-based FlutterWindow as well. At -// the point may make sense to dependency inject the native window rather than -// inherit. +// that point it may make sense to dependency inject the native window rather +// than inherit. class Win32FlutterWindow : public Win32Window, public WindowBindingHandler { public: // Create flutter Window for use as child window - Win32FlutterWindow(int width, int height); + Win32FlutterWindow(int left, int top, int width, int height); virtual ~Win32FlutterWindow(); @@ -35,6 +35,9 @@ class Win32FlutterWindow : public Win32Window, public WindowBindingHandler { // |Win32Window| void OnResize(unsigned int width, unsigned int height) override; + // |Win32Window| + void OnMove(unsigned int left, unsigned int top) override; + // |Win32Window| void OnPointerMove(double x, double y) override; @@ -72,7 +75,10 @@ class Win32FlutterWindow : public Win32Window, public WindowBindingHandler { float GetDpiScale() override; // |FlutterWindowBindingHandler| - PhysicalWindowBounds GetPhysicalWindowBounds() override; + PhysicalBounds GetWindowBounds() override; + + // |FlutterWindowBindingHandler| + PhysicalBounds GetScreenBounds() override; // |FlutterWindowBindingHandler| void UpdateFlutterCursor(const std::string& cursor_name) override; diff --git a/shell/platform/windows/win32_window.cc b/shell/platform/windows/win32_window.cc index 4f7f83405df4f..2c40585a933d1 100644 --- a/shell/platform/windows/win32_window.cc +++ b/shell/platform/windows/win32_window.cc @@ -4,6 +4,7 @@ #include "flutter/shell/platform/windows/win32_window.h" +#include "shell/platform/windows/window_binding_handler.h" #include "win32_dpi_utils.h" namespace flutter { @@ -27,6 +28,8 @@ Win32Window::~Win32Window() { } void Win32Window::InitializeChild(const char* title, + unsigned int left, + unsigned int top, unsigned int width, unsigned int height) { Destroy(); @@ -34,10 +37,10 @@ void Win32Window::InitializeChild(const char* title, WNDCLASS window_class = RegisterWindowClass(converted_title); - auto* result = CreateWindowEx( - 0, window_class.lpszClassName, converted_title.c_str(), - WS_CHILD | WS_VISIBLE, CW_DEFAULT, CW_DEFAULT, width, height, - HWND_MESSAGE, nullptr, window_class.hInstance, this); + auto* result = + CreateWindowEx(0, window_class.lpszClassName, converted_title.c_str(), + WS_CHILD | WS_VISIBLE, left, top, width, height, + HWND_MESSAGE, nullptr, window_class.hInstance, this); if (result == nullptr) { auto error = GetLastError(); @@ -113,7 +116,6 @@ Win32Window::MessageHandler(HWND hwnd, WPARAM const wparam, LPARAM const lparam) noexcept { int xPos = 0, yPos = 0; - UINT width = 0, height = 0; auto window = reinterpret_cast(GetWindowLongPtr(hwnd, GWLP_USERDATA)); UINT button_pressed = 0; @@ -121,16 +123,16 @@ Win32Window::MessageHandler(HWND hwnd, if (window != nullptr) { switch (message) { case kWmDpiChangedBeforeParent: - current_dpi_ = GetDpiForHWND(window_handle_); - window->OnDpiScale(current_dpi_); + window->HandleDpiChange(); return 0; case WM_SIZE: - width = LOWORD(lparam); - height = HIWORD(lparam); - - current_width_ = width; - current_height_ = height; - window->HandleResize(width, height); + window->HandleResize(LOWORD(lparam), HIWORD(lparam)); + break; + case WM_MOVE: + window->HandleMove(LOWORD(lparam), HIWORD(lparam)); + break; + case WM_DISPLAYCHANGE: + window->HandleDisplayChange(); break; case WM_FONTCHANGE: window->OnFontChange(); @@ -281,16 +283,16 @@ Win32Window::MessageHandler(HWND hwnd, return DefWindowProc(window_handle_, message, wparam, lparam); } -UINT Win32Window::GetCurrentDPI() { +UINT GetCurrentDPI() { return current_dpi_; } -UINT Win32Window::GetCurrentWidth() { - return current_width_; +PhysicalBounds Win32Window::GetCurrentWindowBounds() { + return window_bounds_; } -UINT Win32Window::GetCurrentHeight() { - return current_height_; +PhysicalBounds Win32Window::GetCurrentScreenBounds() { + return screen_bounds_; } HWND Win32Window::GetWindowHandle() { @@ -307,11 +309,35 @@ void Win32Window::Destroy() { } void Win32Window::HandleResize(UINT width, UINT height) { - current_width_ = width; - current_height_ = height; + window_bounds_.width = width; + window_bounds_.height = height; OnResize(width, height); } +void Win32Window::HandleMove(UINT left, UINT top) { + window_bounds_.left = left; + window_bounds_.top = top; + OnMove(left, top); +} + +void Win32Window::HandleDpiChange(UINT dpi) { + current_dpi_ = GetDpiForHWND(window_handle_); + window->OnDpiScale(current_dpi_); +} + +void HandleDisplayChange() { + HMONITOR monitor = + GetMonitorFromWindow(window_handle_, MONITOR_DEFAULTTONEAREST); + MONITORINFO info; + info.cbSize = sizeof(info); + if (GetMonitorInfo(monitor, &info)) { + screen_bounds_.left = info.rcMonitor.left; + screen_bounds_.top = info.rcMonitor.top; + screen_bounds_.width = info.rcMonitor.right - info.rcMonitor.left; + screen_bounds_.height = info.rcMonitor.bottom - info.rcMonitor.top; + } +} + Win32Window* Win32Window::GetThisFromHandle(HWND const window) noexcept { return reinterpret_cast( GetWindowLongPtr(window, GWLP_USERDATA)); diff --git a/shell/platform/windows/win32_window.h b/shell/platform/windows/win32_window.h index 61e3a4a338508..0c18e80c33f7e 100644 --- a/shell/platform/windows/win32_window.h +++ b/shell/platform/windows/win32_window.h @@ -10,6 +10,7 @@ #include #include +#include "shell/platform/windows/window_binding_handler.h" namespace flutter { @@ -24,7 +25,12 @@ class Win32Window { // Initializes as a child window with size using |width| and |height| and // |title| to identify the windowclass. Does not show window, window must be // parented into window hierarchy by caller. + // + // Use CW_USEDEFAULT for the left, top, width, and height values to allow the + // system to position and size the window with default values. void InitializeChild(const char* title, + unsigned int left, + unsigned int top, unsigned int width, unsigned int height); @@ -72,6 +78,9 @@ class Win32Window { // Called when a resize occurs. virtual void OnResize(UINT width, UINT height) = 0; + // Called when the window moves. + virtual void OnMove(UINT left, UINT top) = 0; + // Called when the pointer moves within the // window bounds. virtual void OnPointerMove(double x, double y) = 0; @@ -101,11 +110,12 @@ class Win32Window { // Called when the system font change. virtual void OnFontChange() = 0; + // Gets the current DPI value for the window. UINT GetCurrentDPI(); - UINT GetCurrentWidth(); + PhysicalBounds GetCurrentWindowBounds(); - UINT GetCurrentHeight(); + PhysicalBounds GetCurrentScreenBounds(); private: // Release OS resources asociated with window. @@ -117,11 +127,20 @@ class Win32Window { // Stores new width and height and calls |OnResize| to notify inheritors void HandleResize(UINT width, UINT height); + // Stores new location and calls |OnMove| to notify inheritors + void HandleMove(UINT left, UINT top); + + // Handles a change to the display information. + void HandleDisplayChange(); + + // Handles a change to the display information. + void HandleDpiChange(); + // Retrieves a class instance pointer for |window| static Win32Window* GetThisFromHandle(HWND const window) noexcept; - int current_dpi_ = 0; - int current_width_ = 0; - int current_height_ = 0; + + PhysicalBounds window_bounds_; + PhysicalBounds screen_bounds_; // WM_DPICHANGED_BEFOREPARENT defined in more recent Windows // SDK diff --git a/shell/platform/windows/window_binding_handler.h b/shell/platform/windows/window_binding_handler.h index 50eba0587765f..ff17d718b7227 100644 --- a/shell/platform/windows/window_binding_handler.h +++ b/shell/platform/windows/window_binding_handler.h @@ -17,9 +17,15 @@ namespace flutter { class FlutterWindowsView; -// Structure containing physical bounds of a Window -struct PhysicalWindowBounds { +// Structure containing physical bounds of a Window or Screen +struct PhysicalBounds { + /// Physical horizontal location of the left side of the window. + size_t left; + /// Physical vertical location of the top of the window. + size_t top; + /// Physical width of the window. size_t width; + /// Physical height of the window. size_t height; }; @@ -39,11 +45,12 @@ class WindowBindingHandler { // window. virtual WindowsRenderTarget GetRenderTarget() = 0; - // Returns the scale factor for the backing window. - virtual float GetDpiScale() = 0; + // Returns the metrics of the backing window in physical pixels. + virtual PhysicalBounds GetWindowBounds() = 0; - // Returns the bounds of the backing window in physical pixels. - virtual PhysicalWindowBounds GetPhysicalWindowBounds() = 0; + // Returns the metrics of the screen that this window is on, in physical + // pixels. + virtual PhysicalBounds GetScreenBounds() = 0; // Sets the cursor that should be used when the mouse is over the Flutter // content. See mouse_cursor.dart for the values and meanings of cursor_name. diff --git a/shell/platform/windows/window_binding_handler_delegate.h b/shell/platform/windows/window_binding_handler_delegate.h index 3ff8f7e889de5..42b06e25b8f70 100644 --- a/shell/platform/windows/window_binding_handler_delegate.h +++ b/shell/platform/windows/window_binding_handler_delegate.h @@ -6,14 +6,19 @@ #define FLUTTER_SHELL_PLATFORM_WINDOWS_WINDOW_BINDING_HANDLER_DELEGATE_H_ #include "flutter/shell/platform/embedder/embedder.h" +#include "shell/platform/windows/window_binding_handler.h" namespace flutter { class WindowBindingHandlerDelegate { public: - // Notifies delegate that backing window size has changed. - // Typically called by currently configured WindowBindingHandler - virtual void OnWindowSizeChanged(size_t width, size_t height) const = 0; + // Notifies delegate that backing window bounds have changed. + // Typically called by the currently configured WindowBindingHandler + virtual void OnWindowBoundsChanged(PhysicalBounds bounds) const = 0; + + // Notifies delegate that screen bounds for the current window have changed. + // Typically called by the currently configured WindowBindingHandler + virtual void OnScreenBoundsChanged(PhysicalBounds bounds) const = 0; // Notifies delegate that backing window mouse has moved. // Typically called by currently configured WindowBindingHandler diff --git a/shell/testing/tester_main.cc b/shell/testing/tester_main.cc index 7c5599127d8ed..28a4ed1d1aac0 100644 --- a/shell/testing/tester_main.cc +++ b/shell/testing/tester_main.cc @@ -235,7 +235,9 @@ int RunTester(const flutter::Settings& settings, }); // 800x600 at 3x resolution. - shell->GetPlatformView()->SetViewportMetrics({3.0, 2400, 1800}); + shell->GetPlatformView()->SetScreenMetrics({{0, 3.0, 0.0, 0.0, 2400, 1800}}); + shell->GetPlatformView()->SetViewportMetrics( + {{0, 3.0, 0.0, 0.0, 2400, 1800}}); // Run the message loop and wait for the script to do its thing. fml::MessageLoop::GetCurrent().Run(); From b1809d8c9e01aa6f54997d1ee99a0d9e2542b87a Mon Sep 17 00:00:00 2001 From: Greg Spencer Date: Tue, 14 Jul 2020 16:18:29 -0700 Subject: [PATCH 7/8] Fix macOS --- .../darwin/macos/framework/Source/FlutterEngine.mm | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/shell/platform/darwin/macos/framework/Source/FlutterEngine.mm b/shell/platform/darwin/macos/framework/Source/FlutterEngine.mm index 7bdc5fc8c49f7..00581842c2ab1 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterEngine.mm +++ b/shell/platform/darwin/macos/framework/Source/FlutterEngine.mm @@ -304,8 +304,8 @@ - (void)updateWindowMetrics { .width = static_cast(scaledBounds.size.width), .height = static_cast(scaledBounds.size.height), .pixel_ratio = static_cast(view.window.screen.backingScaleFactor), - .left = static_cast(scaledBounds.origin.x), - .top = static_cast(scaledBounds.origin.y), + .left = static_cast(scaledBounds.origin.x), + .top = static_cast(scaledBounds.origin.y), .window_id = 0, }; @@ -327,8 +327,8 @@ - (void)updateScreenMetrics { const FlutterScreenMetricsEvent screenMetricsEvent = { .struct_size = sizeof(screenMetricsEvent), .screen_id = 0, - .left = static_cast(screenBounds.origin.x), - .top = static_cast(screenBounds.origin.y), + .left = static_cast(screenBounds.origin.x), + .top = static_cast(screenBounds.origin.y), .width = static_cast(screenBounds.size.width), .height = static_cast(screenBounds.size.height), .pixel_ratio = static_cast(view.window.screen.backingScaleFactor), From b0e0e3601c1421ee929564197d8d4fc357da5078 Mon Sep 17 00:00:00 2001 From: Greg Spencer Date: Wed, 15 Jul 2020 14:48:49 -0700 Subject: [PATCH 8/8] Fix Windows compile, still not updating screen bounds --- lib/ui/hooks.dart | 164 ++++++++++-------- .../include/flutter/flutter_view_controller.h | 28 +-- .../platform/windows/flutter_windows_view.cc | 17 +- shell/platform/windows/flutter_windows_view.h | 9 +- .../testing/win32_flutter_window_test.cc | 7 +- .../testing/win32_flutter_window_test.h | 2 +- .../windows/testing/win32_window_test.cc | 2 + .../windows/testing/win32_window_test.h | 3 + .../platform/windows/win32_flutter_window.cc | 19 +- shell/platform/windows/win32_flutter_window.h | 18 +- shell/platform/windows/win32_window.cc | 44 +++-- shell/platform/windows/win32_window.h | 17 +- .../platform/windows/window_binding_handler.h | 14 +- .../windows/window_binding_handler_delegate.h | 10 +- .../.dart_tool/package_config.json | 33 ++-- tools/const_finder/.packages | 2 +- 16 files changed, 233 insertions(+), 156 deletions(-) diff --git a/lib/ui/hooks.dart b/lib/ui/hooks.dart index 4513f96865228..384b1aa80fbb3 100644 --- a/lib/ui/hooks.dart +++ b/lib/ui/hooks.dart @@ -69,25 +69,33 @@ void _removeWindows(List removedIds) { @pragma('vm:entry-point') // ignore: unused_element void _updateScreenMetrics( - Object screenId, - double left, - double top, - double width, - double height, - double devicePixelRatio, - double viewPaddingTop, - double viewPaddingRight, - double viewPaddingBottom, - double viewPaddingLeft, - double viewInsetTop, - double viewInsetRight, - double viewInsetBottom, - double viewInsetLeft, - double systemGestureInsetTop, - double systemGestureInsetRight, - double systemGestureInsetBottom, - double systemGestureInsetLeft, - ) { + Object screenId, + double left, + double top, + double width, + double height, + double devicePixelRatio, + double viewPaddingTop, + double viewPaddingRight, + double viewPaddingBottom, + double viewPaddingLeft, + double viewInsetTop, + double viewInsetRight, + double viewInsetBottom, + double viewInsetLeft, + double systemGestureInsetTop, + double systemGestureInsetRight, + double systemGestureInsetBottom, + double systemGestureInsetLeft, +) { + print(''' + Updating screen metrics for ($screenId): + left: $left + top: $top + width: $width + height: $height + devicePixelRatio: $devicePixelRatio + '''); // TODO(gspencergoog): Once dart:ui understands screens, set their metrics // here. See https://github.com/flutter/flutter/issues/60131 } @@ -136,7 +144,8 @@ void _updateLocales(List locales) { @pragma('vm:entry-point') // ignore: unused_element void _updateUserSettingsData(String jsonData) { - final Map data = json.decode(jsonData) as Map; + final Map data = + json.decode(jsonData) as Map; if (data.isEmpty) { return; } @@ -154,10 +163,10 @@ void _updateLifecycleState(String state) { window._initialLifecycleState = state; } - void _updateTextScaleFactor(double textScaleFactor) { window._textScaleFactor = textScaleFactor; - _invoke(window.onTextScaleFactorChanged, window._onTextScaleFactorChangedZone); + _invoke( + window.onTextScaleFactorChanged, window._onTextScaleFactorChangedZone); } void _updateAlwaysUse24HourFormat(bool alwaysUse24HourFormat) { @@ -165,25 +174,28 @@ void _updateAlwaysUse24HourFormat(bool alwaysUse24HourFormat) { } void _updatePlatformBrightness(String brightnessName) { - window._platformBrightness = brightnessName == 'dark' ? Brightness.dark : Brightness.light; - _invoke(window.onPlatformBrightnessChanged, window._onPlatformBrightnessChangedZone); + window._platformBrightness = + brightnessName == 'dark' ? Brightness.dark : Brightness.light; + _invoke(window.onPlatformBrightnessChanged, + window._onPlatformBrightnessChangedZone); } @pragma('vm:entry-point') // ignore: unused_element void _updateSemanticsEnabled(bool enabled) { window._semanticsEnabled = enabled; - _invoke(window.onSemanticsEnabledChanged, window._onSemanticsEnabledChangedZone); + _invoke( + window.onSemanticsEnabledChanged, window._onSemanticsEnabledChangedZone); } @pragma('vm:entry-point') // ignore: unused_element void _updateAccessibilityFeatures(int values) { final AccessibilityFeatures newFeatures = AccessibilityFeatures._(values); - if (newFeatures == window._accessibilityFeatures) - return; + if (newFeatures == window._accessibilityFeatures) return; window._accessibilityFeatures = newFeatures; - _invoke(window.onAccessibilityFeaturesChanged, window._onAccessibilityFeaturesChangedZone); + _invoke(window.onAccessibilityFeaturesChanged, + window._onAccessibilityFeaturesChangedZone); } @pragma('vm:entry-point') @@ -218,7 +230,8 @@ void _dispatchPlatformMessage(String name, ByteData? data, int responseId) { // ignore: unused_element void _dispatchPointerDataPacket(ByteData packet) { if (window.onPointerDataPacket != null) - _invoke1(window.onPointerDataPacket, window._onPointerDataPacketZone, _unpackPointerDataPacket(packet)); + _invoke1(window.onPointerDataPacket, + window._onPointerDataPacketZone, _unpackPointerDataPacket(packet)); } @pragma('vm:entry-point') @@ -236,7 +249,8 @@ void _dispatchSemanticsAction(int id, int action, ByteData? args) { @pragma('vm:entry-point') // ignore: unused_element void _beginFrame(int microseconds) { - _invoke1(window.onBeginFrame, window._onBeginFrameZone, Duration(microseconds: microseconds)); + _invoke1(window.onBeginFrame, window._onBeginFrameZone, + Duration(microseconds: microseconds)); } @pragma('vm:entry-point') @@ -245,7 +259,8 @@ void _reportTimings(List timings) { assert(timings.length % FramePhase.values.length == 0); final List frameTimings = []; for (int i = 0; i < timings.length; i += FramePhase.values.length) { - frameTimings.add(FrameTiming(timings.sublist(i, i + FramePhase.values.length))); + frameTimings + .add(FrameTiming(timings.sublist(i, i + FramePhase.values.length))); } _invoke1(window.onReportTimings, window._onReportTimingsZone, frameTimings); } @@ -263,10 +278,9 @@ typedef _BinaryFunction(Null args, Null message); @pragma('vm:entry-point') // ignore: unused_element -void _runMainZoned(Function startMainIsolateFunction, - Function userMainFunction, - List args) { - startMainIsolateFunction((){ +void _runMainZoned(Function startMainIsolateFunction, Function userMainFunction, + List args) { + startMainIsolateFunction(() { runZonedGuarded(() { if (userMainFunction is _BinaryFunction) { // This seems to be undocumented but supported by the command line VM. @@ -283,12 +297,12 @@ void _runMainZoned(Function startMainIsolateFunction, }, null); } -void _reportUnhandledException(String error, String stackTrace) native 'PlatformConfiguration_reportUnhandledException'; +void _reportUnhandledException(String error, String stackTrace) + native 'PlatformConfiguration_reportUnhandledException'; /// Invokes [callback] inside the given [zone]. void _invoke(void callback()?, Zone zone) { - if (callback == null) - return; + if (callback == null) return; assert(zone != null); // ignore: unnecessary_null_comparison @@ -301,8 +315,7 @@ void _invoke(void callback()?, Zone zone) { /// Invokes [callback] inside the given [zone] passing it [arg]. void _invoke1(void callback(A a)?, Zone zone, A arg) { - if (callback == null) - return; + if (callback == null) return; assert(zone != null); // ignore: unnecessary_null_comparison @@ -314,9 +327,9 @@ void _invoke1(void callback(A a)?, Zone zone, A arg) { } /// Invokes [callback] inside the given [zone] passing it [arg1], [arg2], and [arg3]. -void _invoke3(void callback(A1 a1, A2 a2, A3 a3)?, Zone zone, A1 arg1, A2 arg2, A3 arg3) { - if (callback == null) - return; +void _invoke3( + void callback(A1 a1, A2 a2, A3 a3)?, Zone zone, A1 arg1, A2 arg2, A3 arg3) { + if (callback == null) return; assert(zone != null); // ignore: unnecessary_null_comparison @@ -345,36 +358,41 @@ PointerDataPacket _unpackPointerDataPacket(ByteData packet) { for (int i = 0; i < length; ++i) { int offset = i * _kPointerDataFieldCount; data.add(PointerData( - embedderId: packet.getInt64(kStride * offset++, _kFakeHostEndian), - timeStamp: Duration(microseconds: packet.getInt64(kStride * offset++, _kFakeHostEndian)), - change: PointerChange.values[packet.getInt64(kStride * offset++, _kFakeHostEndian)], - kind: PointerDeviceKind.values[packet.getInt64(kStride * offset++, _kFakeHostEndian)], - signalKind: PointerSignalKind.values[packet.getInt64(kStride * offset++, _kFakeHostEndian)], - device: packet.getInt64(kStride * offset++, _kFakeHostEndian), - pointerIdentifier: packet.getInt64(kStride * offset++, _kFakeHostEndian), - physicalX: packet.getFloat64(kStride * offset++, _kFakeHostEndian), - physicalY: packet.getFloat64(kStride * offset++, _kFakeHostEndian), - physicalDeltaX: packet.getFloat64(kStride * offset++, _kFakeHostEndian), - physicalDeltaY: packet.getFloat64(kStride * offset++, _kFakeHostEndian), - buttons: packet.getInt64(kStride * offset++, _kFakeHostEndian), - obscured: packet.getInt64(kStride * offset++, _kFakeHostEndian) != 0, - synthesized: packet.getInt64(kStride * offset++, _kFakeHostEndian) != 0, - pressure: packet.getFloat64(kStride * offset++, _kFakeHostEndian), - pressureMin: packet.getFloat64(kStride * offset++, _kFakeHostEndian), - pressureMax: packet.getFloat64(kStride * offset++, _kFakeHostEndian), - distance: packet.getFloat64(kStride * offset++, _kFakeHostEndian), - distanceMax: packet.getFloat64(kStride * offset++, _kFakeHostEndian), - size: packet.getFloat64(kStride * offset++, _kFakeHostEndian), - radiusMajor: packet.getFloat64(kStride * offset++, _kFakeHostEndian), - radiusMinor: packet.getFloat64(kStride * offset++, _kFakeHostEndian), - radiusMin: packet.getFloat64(kStride * offset++, _kFakeHostEndian), - radiusMax: packet.getFloat64(kStride * offset++, _kFakeHostEndian), - orientation: packet.getFloat64(kStride * offset++, _kFakeHostEndian), - tilt: packet.getFloat64(kStride * offset++, _kFakeHostEndian), - platformData: packet.getInt64(kStride * offset++, _kFakeHostEndian), - scrollDeltaX: packet.getFloat64(kStride * offset++, _kFakeHostEndian), - scrollDeltaY: packet.getFloat64(kStride * offset++, _kFakeHostEndian) - )); + embedderId: packet.getInt64(kStride * offset++, _kFakeHostEndian), + timeStamp: Duration( + microseconds: + packet.getInt64(kStride * offset++, _kFakeHostEndian)), + change: PointerChange + .values[packet.getInt64(kStride * offset++, _kFakeHostEndian)], + kind: PointerDeviceKind + .values[packet.getInt64(kStride * offset++, _kFakeHostEndian)], + signalKind: PointerSignalKind + .values[packet.getInt64(kStride * offset++, _kFakeHostEndian)], + device: packet.getInt64(kStride * offset++, _kFakeHostEndian), + pointerIdentifier: + packet.getInt64(kStride * offset++, _kFakeHostEndian), + physicalX: packet.getFloat64(kStride * offset++, _kFakeHostEndian), + physicalY: packet.getFloat64(kStride * offset++, _kFakeHostEndian), + physicalDeltaX: packet.getFloat64(kStride * offset++, _kFakeHostEndian), + physicalDeltaY: packet.getFloat64(kStride * offset++, _kFakeHostEndian), + buttons: packet.getInt64(kStride * offset++, _kFakeHostEndian), + obscured: packet.getInt64(kStride * offset++, _kFakeHostEndian) != 0, + synthesized: packet.getInt64(kStride * offset++, _kFakeHostEndian) != 0, + pressure: packet.getFloat64(kStride * offset++, _kFakeHostEndian), + pressureMin: packet.getFloat64(kStride * offset++, _kFakeHostEndian), + pressureMax: packet.getFloat64(kStride * offset++, _kFakeHostEndian), + distance: packet.getFloat64(kStride * offset++, _kFakeHostEndian), + distanceMax: packet.getFloat64(kStride * offset++, _kFakeHostEndian), + size: packet.getFloat64(kStride * offset++, _kFakeHostEndian), + radiusMajor: packet.getFloat64(kStride * offset++, _kFakeHostEndian), + radiusMinor: packet.getFloat64(kStride * offset++, _kFakeHostEndian), + radiusMin: packet.getFloat64(kStride * offset++, _kFakeHostEndian), + radiusMax: packet.getFloat64(kStride * offset++, _kFakeHostEndian), + orientation: packet.getFloat64(kStride * offset++, _kFakeHostEndian), + tilt: packet.getFloat64(kStride * offset++, _kFakeHostEndian), + platformData: packet.getInt64(kStride * offset++, _kFakeHostEndian), + scrollDeltaX: packet.getFloat64(kStride * offset++, _kFakeHostEndian), + scrollDeltaY: packet.getFloat64(kStride * offset++, _kFakeHostEndian))); assert(offset == (i + 1) * _kPointerDataFieldCount); } return PointerDataPacket(data: data); diff --git a/shell/platform/windows/client_wrapper/include/flutter/flutter_view_controller.h b/shell/platform/windows/client_wrapper/include/flutter/flutter_view_controller.h index 607e01a72f247..a87ff9bb052fc 100644 --- a/shell/platform/windows/client_wrapper/include/flutter/flutter_view_controller.h +++ b/shell/platform/windows/client_wrapper/include/flutter/flutter_view_controller.h @@ -25,20 +25,20 @@ namespace flutter { // methods in the C API directly, as this class will do that internally. class FlutterViewController : public PluginRegistry { public: - // Creates a FlutterView that can be parented into a Windows View hierarchy - // either using HWNDs or in the future into a CoreWindow, or using compositor. - // - // |dart_project| will be used to configure the engine backing this view. - explicit FlutterViewController(int width, - int height, - const DartProject& project); - - // DEPRECATED. Will be removed soon; use the version above. - explicit FlutterViewController(const std::string& icu_data_path, - int width, - int height, - const std::string& assets_path, - const std::vector& arguments); + // Creates a FlutterView that can be parented into a Windows View hierarchy + // either using HWNDs or in the future into a CoreWindow, or using compositor. + // + // |dart_project| will be used to configure the engine backing this view. + FlutterViewController(int width, + int height, + const DartProject& project); + + // DEPRECATED. Will be removed soon; use the version above. + FlutterViewController(const std::string& icu_data_path, + int width, + int height, + const std::string& assets_path, + const std::vector& arguments); virtual ~FlutterViewController(); diff --git a/shell/platform/windows/flutter_windows_view.cc b/shell/platform/windows/flutter_windows_view.cc index 382b11d700329..0e678432bb7ca 100644 --- a/shell/platform/windows/flutter_windows_view.cc +++ b/shell/platform/windows/flutter_windows_view.cc @@ -1,7 +1,6 @@ #include "flutter/shell/platform/windows/flutter_windows_view.h" #include -#include "shell/platform/windows/window_binding_handler.h" namespace flutter { @@ -165,6 +164,16 @@ void FlutterWindowsView::OnFontChange() { FlutterEngineReloadSystemFonts(engine_); } +void FlutterWindowsView::OnDisplayChange() { + if (engine_ == nullptr) { + return; + } + std::vector screen_bounds = binding_handler_->GetScreenBounds(); + for (int64_t i = 0; i < screen_bounds.size() ; ++i) { + SendScreenMetrics(i, screen_bounds[i]); + } +} + // Sends new window size information to FlutterEngine. void FlutterWindowsView::SendWindowMetrics() const { if (engine_ == nullptr) { @@ -185,16 +194,14 @@ void FlutterWindowsView::SendWindowMetrics() const { } // Sends new screen size information to FlutterEngine. -void FlutterWindowsView::SendScreenMetrics() const { +void FlutterWindowsView::SendScreenMetrics(int64_t screen_id, PhysicalBounds bounds) const { if (engine_ == nullptr) { return; } - PhysicalBounds bounds = binding_handler_->GetScreenBounds(); - FlutterScreenMetricsEvent event = {}; event.struct_size = sizeof(event); - event.screen_id = 0; + event.screen_id = screen_id; event.left = bounds.left; event.top = bounds.top; event.width = bounds.width; diff --git a/shell/platform/windows/flutter_windows_view.h b/shell/platform/windows/flutter_windows_view.h index 82d94fc2a1c25..773f13eb3217d 100644 --- a/shell/platform/windows/flutter_windows_view.h +++ b/shell/platform/windows/flutter_windows_view.h @@ -26,8 +26,8 @@ namespace flutter { -// An OS-windowing neutral abstration for flutter -// view that works with win32 hwnds and Windows::UI::Composition visuals. +// An OS-windowing neutral abstraction for a Flutter view that works +// with win32 HWNDs and Windows::UI::Composition visuals. class FlutterWindowsView : public WindowBindingHandlerDelegate { public: FlutterWindowsView(); @@ -102,6 +102,9 @@ class FlutterWindowsView : public WindowBindingHandlerDelegate { // |WindowBindingHandlerDelegate| void OnFontChange() override; + // |WindowBindingHandlerDelegate| + void OnDisplayChange() override; + private: // Struct holding the mouse state. The engine doesn't keep track of which // mouse buttons have been pressed, so it's the embedding's responsibility. @@ -125,7 +128,7 @@ class FlutterWindowsView : public WindowBindingHandlerDelegate { // Sends a screen metrics update to the Flutter engine using current screen // dimensions and location in physical coordinates. - void SendScreenMetrics() const; + void SendScreenMetrics(int64_t screen_id, PhysicalBounds bounds) const; // Reports a mouse movement to Flutter engine. void SendPointerMove(double x, double y); diff --git a/shell/platform/windows/testing/win32_flutter_window_test.cc b/shell/platform/windows/testing/win32_flutter_window_test.cc index 7317d796d232f..bae1d9cd8d5b3 100644 --- a/shell/platform/windows/testing/win32_flutter_window_test.cc +++ b/shell/platform/windows/testing/win32_flutter_window_test.cc @@ -3,11 +3,8 @@ namespace flutter { namespace testing { -Win32FlutterWindowTest::Win32FlutterWindowTest(int left, - int top, - int width, - int height) - : Win32FlutterWindow(left, top, width, height){}; +Win32FlutterWindowTest::Win32FlutterWindowTest(int width, int height) + : Win32FlutterWindow(width, height){}; Win32FlutterWindowTest::~Win32FlutterWindowTest() = default; diff --git a/shell/platform/windows/testing/win32_flutter_window_test.h b/shell/platform/windows/testing/win32_flutter_window_test.h index af93d09e1303e..6da56d9383a5b 100644 --- a/shell/platform/windows/testing/win32_flutter_window_test.h +++ b/shell/platform/windows/testing/win32_flutter_window_test.h @@ -12,7 +12,7 @@ namespace testing { /// Test class for Win32FlutterWindow. class Win32FlutterWindowTest : public Win32FlutterWindow { public: - Win32FlutterWindowTest(int left, int top, int width, int height); + Win32FlutterWindowTest(int width, int height); virtual ~Win32FlutterWindowTest(); // Prevent copying. diff --git a/shell/platform/windows/testing/win32_window_test.cc b/shell/platform/windows/testing/win32_window_test.cc index 02ecfefe4be2b..510bfd0612e90 100644 --- a/shell/platform/windows/testing/win32_window_test.cc +++ b/shell/platform/windows/testing/win32_window_test.cc @@ -34,6 +34,8 @@ void Win32WindowTest::OnScroll(double delta_x, double delta_y) {} void Win32WindowTest::OnFontChange() {} +void Win32WindowTest::OnDisplayChange() {} + UINT Win32WindowTest::GetDpi() { return GetCurrentDPI(); } diff --git a/shell/platform/windows/testing/win32_window_test.h b/shell/platform/windows/testing/win32_window_test.h index 99ca26f04d24d..3829426fa321f 100644 --- a/shell/platform/windows/testing/win32_window_test.h +++ b/shell/platform/windows/testing/win32_window_test.h @@ -58,6 +58,9 @@ class Win32WindowTest : public Win32Window { // |Win32Window| void OnFontChange() override; + + // |Win32Window| + void OnDisplayChange() override; }; } // namespace testing diff --git a/shell/platform/windows/win32_flutter_window.cc b/shell/platform/windows/win32_flutter_window.cc index 9bdf5c78426a5..e51e2145dff91 100644 --- a/shell/platform/windows/win32_flutter_window.cc +++ b/shell/platform/windows/win32_flutter_window.cc @@ -44,6 +44,9 @@ Win32FlutterWindow::Win32FlutterWindow(int left, int top, int width, int height) current_cursor_ = ::LoadCursor(nullptr, IDC_ARROW); } +Win32FlutterWindow::Win32FlutterWindow(int width, int height) + : Win32FlutterWindow(CW_USEDEFAULT, CW_USEDEFAULT, width, height) {} + Win32FlutterWindow::~Win32FlutterWindow() {} void Win32FlutterWindow::SetView(WindowBindingHandlerDelegate* window) { @@ -62,7 +65,7 @@ PhysicalBounds Win32FlutterWindow::GetWindowBounds() { return GetCurrentWindowBounds(); } -PhysicalBounds Win32FlutterWindow::GetScreenBounds() { +std::vector Win32FlutterWindow::GetScreenBounds() { return GetCurrentScreenBounds(); } @@ -97,7 +100,10 @@ void Win32FlutterWindow::OnDpiScale(unsigned int dpi){}; // lets FlutterEngine know about the new size. void Win32FlutterWindow::OnResize(unsigned int width, unsigned int height) { if (binding_handler_delegate_ != nullptr) { - binding_handler_delegate_->OnWindowSizeChanged(width, height); + PhysicalBounds bounds = GetWindowBounds(); + bounds.width = width; + bounds.height = height; + binding_handler_delegate_->OnWindowBoundsChanged(bounds); } } @@ -105,7 +111,10 @@ void Win32FlutterWindow::OnResize(unsigned int width, unsigned int height) { // lets FlutterEngine know about the new location. void Win32FlutterWindow::OnMove(unsigned int left, unsigned int top) { if (binding_handler_delegate_ != nullptr) { - binding_handler_delegate_->OnWindowLocationChanged(left, top); + PhysicalBounds bounds = GetWindowBounds(); + bounds.left = left; + bounds.top = top; + binding_handler_delegate_->OnWindowBoundsChanged(bounds); } } @@ -161,4 +170,8 @@ void Win32FlutterWindow::OnFontChange() { binding_handler_delegate_->OnFontChange(); } +void Win32FlutterWindow::OnDisplayChange() { + binding_handler_delegate_->OnDisplayChange(); +} + } // namespace flutter diff --git a/shell/platform/windows/win32_flutter_window.h b/shell/platform/windows/win32_flutter_window.h index bfa9aab45dff4..ca234e18da2e3 100644 --- a/shell/platform/windows/win32_flutter_window.h +++ b/shell/platform/windows/win32_flutter_window.h @@ -18,15 +18,18 @@ namespace flutter { -// A win32 flutter child window used as implementatin for flutter view. In the -// future, there will likely be a CoreWindow-based FlutterWindow as well. At -// that point it may make sense to dependency inject the native window rather -// than inherit. +// A win32 flutter child window which is used as the implementation for flutter +// view. In the future, there will likely be a CoreWindow-based FlutterWindow +// as well. At that point it may make sense to dependency inject the native +// window rather than inherit. class Win32FlutterWindow : public Win32Window, public WindowBindingHandler { public: - // Create flutter Window for use as child window + // Create a Flutter Window at a specified location. Win32FlutterWindow(int left, int top, int width, int height); + // Create a Flutter Window of a particular size for use as child window. + Win32FlutterWindow(int width, int height); + virtual ~Win32FlutterWindow(); // |Win32Window| @@ -65,6 +68,9 @@ class Win32FlutterWindow : public Win32Window, public WindowBindingHandler { // |Win32Window| void OnFontChange() override; + // |Win32Window| + void OnDisplayChange() override; + // |FlutterWindowBindingHandler| void SetView(WindowBindingHandlerDelegate* view) override; @@ -78,7 +84,7 @@ class Win32FlutterWindow : public Win32Window, public WindowBindingHandler { PhysicalBounds GetWindowBounds() override; // |FlutterWindowBindingHandler| - PhysicalBounds GetScreenBounds() override; + std::vector GetScreenBounds() override; // |FlutterWindowBindingHandler| void UpdateFlutterCursor(const std::string& cursor_name) override; diff --git a/shell/platform/windows/win32_window.cc b/shell/platform/windows/win32_window.cc index 2c40585a933d1..987844867a48e 100644 --- a/shell/platform/windows/win32_window.cc +++ b/shell/platform/windows/win32_window.cc @@ -4,7 +4,8 @@ #include "flutter/shell/platform/windows/win32_window.h" -#include "shell/platform/windows/window_binding_handler.h" +#include + #include "win32_dpi_utils.h" namespace flutter { @@ -14,6 +15,24 @@ char32_t CodePointFromSurrogatePair(wchar_t high, wchar_t low) { return 0x10000 + ((static_cast(high) & 0x000003FF) << 10) + (low & 0x3FF); } + +// Called by Windows when enumerating monitors. +BOOL MonitorEnumerationCallback( + HMONITOR monitor_handle, + HDC monitor_hdc, + LPRECT monitor_rect, + LPARAM user_data +) { + std::vector* bounds = (std::vector*)user_data; + assert(monitor_rect->right >= monitor_rect->left); + assert(monitor_rect->bottom >= monitor_rect->top); + bounds->push_back({ + static_cast(monitor_rect->left), + static_cast(monitor_rect->top), + static_cast(monitor_rect->right - monitor_rect->left), + static_cast(monitor_rect->bottom - monitor_rect->top)}); + return TRUE; +} } // namespace Win32Window::Win32Window() { @@ -283,7 +302,7 @@ Win32Window::MessageHandler(HWND hwnd, return DefWindowProc(window_handle_, message, wparam, lparam); } -UINT GetCurrentDPI() { +UINT Win32Window::GetCurrentDPI() { return current_dpi_; } @@ -291,7 +310,7 @@ PhysicalBounds Win32Window::GetCurrentWindowBounds() { return window_bounds_; } -PhysicalBounds Win32Window::GetCurrentScreenBounds() { +std::vector Win32Window::GetCurrentScreenBounds() { return screen_bounds_; } @@ -320,22 +339,17 @@ void Win32Window::HandleMove(UINT left, UINT top) { OnMove(left, top); } -void Win32Window::HandleDpiChange(UINT dpi) { +void Win32Window::HandleDpiChange() { current_dpi_ = GetDpiForHWND(window_handle_); - window->OnDpiScale(current_dpi_); + OnDpiScale(current_dpi_); } -void HandleDisplayChange() { - HMONITOR monitor = - GetMonitorFromWindow(window_handle_, MONITOR_DEFAULTTONEAREST); - MONITORINFO info; - info.cbSize = sizeof(info); - if (GetMonitorInfo(monitor, &info)) { - screen_bounds_.left = info.rcMonitor.left; - screen_bounds_.top = info.rcMonitor.top; - screen_bounds_.width = info.rcMonitor.right - info.rcMonitor.left; - screen_bounds_.height = info.rcMonitor.bottom - info.rcMonitor.top; +void Win32Window::HandleDisplayChange() { + std::vector new_bounds; + if (!EnumDisplayMonitors(NULL, NULL, MonitorEnumerationCallback, (LPARAM)&new_bounds)) { + return; } + screen_bounds_.swap(new_bounds); } Win32Window* Win32Window::GetThisFromHandle(HWND const window) noexcept { diff --git a/shell/platform/windows/win32_window.h b/shell/platform/windows/win32_window.h index 0c18e80c33f7e..f2a6b14380cb7 100644 --- a/shell/platform/windows/win32_window.h +++ b/shell/platform/windows/win32_window.h @@ -10,7 +10,9 @@ #include #include -#include "shell/platform/windows/window_binding_handler.h" +#include + +#include "flutter/shell/platform/windows/window_binding_handler.h" namespace flutter { @@ -107,15 +109,20 @@ class Win32Window { // Called when mouse scrollwheel input occurs. virtual void OnScroll(double delta_x, double delta_y) = 0; - // Called when the system font change. + // Called when the system font changes. virtual void OnFontChange() = 0; + // Called when the displays (monitors) on the device change. + virtual void OnDisplayChange() = 0; + // Gets the current DPI value for the window. UINT GetCurrentDPI(); + // Gets the bounds of the window in physical pixels. PhysicalBounds GetCurrentWindowBounds(); - PhysicalBounds GetCurrentScreenBounds(); + // Gets the bounds of all attached screens in physical pixels. + std::vector GetCurrentScreenBounds(); private: // Release OS resources asociated with window. @@ -138,9 +145,9 @@ class Win32Window { // Retrieves a class instance pointer for |window| static Win32Window* GetThisFromHandle(HWND const window) noexcept; - + UINT current_dpi_ = 0; PhysicalBounds window_bounds_; - PhysicalBounds screen_bounds_; + std::vector screen_bounds_; // WM_DPICHANGED_BEFOREPARENT defined in more recent Windows // SDK diff --git a/shell/platform/windows/window_binding_handler.h b/shell/platform/windows/window_binding_handler.h index ff17d718b7227..6614e914e6c88 100644 --- a/shell/platform/windows/window_binding_handler.h +++ b/shell/platform/windows/window_binding_handler.h @@ -9,20 +9,21 @@ #include #include +#include #include "flutter/shell/platform/windows/public/flutter_windows.h" -#include "flutter/shell/platform/windows/window_binding_handler_delegate.h" namespace flutter { +class WindowBindingHandlerDelegate; class FlutterWindowsView; // Structure containing physical bounds of a Window or Screen struct PhysicalBounds { /// Physical horizontal location of the left side of the window. - size_t left; + int64_t left; /// Physical vertical location of the top of the window. - size_t top; + int64_t top; /// Physical width of the window. size_t width; /// Physical height of the window. @@ -45,12 +46,15 @@ class WindowBindingHandler { // window. virtual WindowsRenderTarget GetRenderTarget() = 0; + // Gets the current DPI value for the window. + virtual float GetDpiScale() = 0; + // Returns the metrics of the backing window in physical pixels. virtual PhysicalBounds GetWindowBounds() = 0; - // Returns the metrics of the screen that this window is on, in physical + // Returns the metrics of all the screens connected to the device, in physical // pixels. - virtual PhysicalBounds GetScreenBounds() = 0; + virtual std::vector GetScreenBounds() = 0; // Sets the cursor that should be used when the mouse is over the Flutter // content. See mouse_cursor.dart for the values and meanings of cursor_name. diff --git a/shell/platform/windows/window_binding_handler_delegate.h b/shell/platform/windows/window_binding_handler_delegate.h index 42b06e25b8f70..c6a0a1dce9340 100644 --- a/shell/platform/windows/window_binding_handler_delegate.h +++ b/shell/platform/windows/window_binding_handler_delegate.h @@ -6,7 +6,7 @@ #define FLUTTER_SHELL_PLATFORM_WINDOWS_WINDOW_BINDING_HANDLER_DELEGATE_H_ #include "flutter/shell/platform/embedder/embedder.h" -#include "shell/platform/windows/window_binding_handler.h" +#include "flutter/shell/platform/windows/window_binding_handler.h" namespace flutter { @@ -16,10 +16,6 @@ class WindowBindingHandlerDelegate { // Typically called by the currently configured WindowBindingHandler virtual void OnWindowBoundsChanged(PhysicalBounds bounds) const = 0; - // Notifies delegate that screen bounds for the current window have changed. - // Typically called by the currently configured WindowBindingHandler - virtual void OnScreenBoundsChanged(PhysicalBounds bounds) const = 0; - // Notifies delegate that backing window mouse has moved. // Typically called by currently configured WindowBindingHandler virtual void OnPointerMove(double x, double y) = 0; @@ -59,6 +55,10 @@ class WindowBindingHandlerDelegate { // Notifies delegate that backing window size has had system font change. // Typically called by currently configured WindowBindingHandler virtual void OnFontChange() = 0; + + // Notifies delegate that the display configuration has changed. + // Typically called by currently configured WindowBindingHandler. + virtual void OnDisplayChange() = 0; }; } // namespace flutter diff --git a/tools/const_finder/.dart_tool/package_config.json b/tools/const_finder/.dart_tool/package_config.json index c0548411d61fd..473d36864ee2b 100644 --- a/tools/const_finder/.dart_tool/package_config.json +++ b/tools/const_finder/.dart_tool/package_config.json @@ -2,34 +2,37 @@ "configVersion": 2, "packages": [ { - "name": "const_finder", - "rootUri": "../", - "packageUri": "lib", - "languageVersion": "2.4" + "name": "args", + "rootUri": "../../../../third_party/dart/third_party/pkg/args", + "packageUri": "lib/", + "languageVersion": "2.3" }, { "name": "kernel", "rootUri": "../../../../third_party/dart/pkg/kernel", - "packageUri": "lib", + "packageUri": "lib/", "languageVersion": "2.2" }, { "name": "meta", "rootUri": "../../../../third_party/dart/pkg/meta", - "packageUri": "lib", + "packageUri": "lib/", "languageVersion": "2.9" }, - { - "name": "args", - "rootUri": "../../../../third_party/dart/third_party/pkg/args", - "packageUri": "lib", - "languageVersion": "2.3" - }, { "name": "path", "rootUri": "../../../../third_party/dart/third_party/pkg/path", - "packageUri": "lib", + "packageUri": "lib/", "languageVersion": "2.0" + }, + { + "name": "const_finder", + "rootUri": "../", + "packageUri": "lib/", + "languageVersion": "2.4" } - ] -} \ No newline at end of file + ], + "generated": "2020-07-15T21:39:09.035792Z", + "generator": "pub", + "generatorVersion": "2.9.0-21.0.dev.flutter-06cb010247" +} diff --git a/tools/const_finder/.packages b/tools/const_finder/.packages index 2a698fd32e89e..db45ecc8eba7f 100644 --- a/tools/const_finder/.packages +++ b/tools/const_finder/.packages @@ -1,4 +1,4 @@ -# Generated by pub on 2020-01-16 11:11:54.947929. +# Generated by pub on 2020-07-15 14:39:09.019790. args:../../../third_party/dart/third_party/pkg/args/lib/ kernel:../../../third_party/dart/pkg/kernel/lib/ meta:../../../third_party/dart/pkg/meta/lib/