diff --git a/engine/src/flutter/BUILD.gn b/engine/src/flutter/BUILD.gn index f5ace7c3531..ec7b55d24f1 100644 --- a/engine/src/flutter/BUILD.gn +++ b/engine/src/flutter/BUILD.gn @@ -213,6 +213,7 @@ group("unittests") { "//flutter/runtime:no_dart_plugin_registrant_unittests", "//flutter/runtime:runtime_unittests", "//flutter/shell/common:shell_unittests", + "//flutter/shell/geometry:geometry_unittests", "//flutter/shell/platform/embedder:embedder_a11y_unittests", "//flutter/shell/platform/embedder:embedder_proctable_unittests", "//flutter/shell/platform/embedder:embedder_unittests", diff --git a/engine/src/flutter/lib/ui/fixtures/ui_test.dart b/engine/src/flutter/lib/ui/fixtures/ui_test.dart index 4f0b4a3bfe0..44e17a36322 100644 --- a/engine/src/flutter/lib/ui/fixtures/ui_test.dart +++ b/engine/src/flutter/lib/ui/fixtures/ui_test.dart @@ -730,7 +730,7 @@ void hooksTests() async { window.onMetricsChanged!(); _callHook( '_updateWindowMetrics', - 21, + 25, 0, // window Id 0.1234, // device pixel ratio 0.0, // width @@ -752,6 +752,10 @@ void hooksTests() async { [], // display features types [], // display features states 0, // Display ID + 0.0, // minWidth + 0.0, // maxWidth + 0.0, // minHeight + 0.0, // maxHeight ); expectIdentical(originalZone, callbackZone); @@ -844,7 +848,7 @@ void hooksTests() async { await test('View padding/insets/viewPadding/systemGestureInsets', () { _callHook( '_updateWindowMetrics', - 21, + 25, 0, // window Id 1.0, // devicePixelRatio 800.0, // width @@ -866,6 +870,10 @@ void hooksTests() async { [], // display features types [], // display features states 0, // Display ID + 0.0, // minWidth + 1000.0, // maxWidth + 0.0, // minHeight + 1000.0, // maxHeight ); expectEquals(window.viewInsets.bottom, 0.0); @@ -875,7 +883,7 @@ void hooksTests() async { _callHook( '_updateWindowMetrics', - 21, + 25, 0, // window Id 1.0, // devicePixelRatio 800.0, // width @@ -897,6 +905,10 @@ void hooksTests() async { [], // display features types [], // display features states 0, // Display ID + 0.0, // minWidth + 0.0, // maxWidth + 0.0, // minHeight + 0.0, // maxHeight ); expectEquals(window.viewInsets.bottom, 400.0); @@ -908,7 +920,7 @@ void hooksTests() async { await test('Window physical touch slop', () { _callHook( '_updateWindowMetrics', - 21, + 25, 0, // window Id 1.0, // devicePixelRatio 800.0, // width @@ -930,13 +942,17 @@ void hooksTests() async { [], // display features types [], // display features states 0, // Display ID + 0.0, // minWidth + 0.0, // maxWidth + 0.0, // minHeight + 0.0, // maxHeight ); expectEquals(window.gestureSettings, GestureSettings(physicalTouchSlop: 11.0)); _callHook( '_updateWindowMetrics', - 21, + 25, 0, // window Id 1.0, // devicePixelRatio 800.0, // width @@ -958,13 +974,17 @@ void hooksTests() async { [], // display features types [], // display features states 0, // Display ID + 0.0, // minWidth + 0.0, // maxWidth + 0.0, // minHeight + 0.0, // maxHeight ); expectEquals(window.gestureSettings, GestureSettings(physicalTouchSlop: null)); _callHook( '_updateWindowMetrics', - 21, + 25, 0, // window Id 1.0, // devicePixelRatio 800.0, // width @@ -986,6 +1006,10 @@ void hooksTests() async { [], // display features types [], // display features states 0, // Display ID + 0.0, // minWidth + 0.0, // maxWidth + 0.0, // minHeight + 0.0, // maxHeight ); expectEquals(window.gestureSettings, GestureSettings(physicalTouchSlop: 22.0)); @@ -1382,4 +1406,8 @@ external void _callHook( Object? arg19, Object? arg20, Object? arg21, + Object? arg22, + Object? arg23, + Object? arg24, + Object? arg25, ]); diff --git a/engine/src/flutter/lib/ui/hooks.dart b/engine/src/flutter/lib/ui/hooks.dart index d9965953940..602f520b1e2 100644 --- a/engine/src/flutter/lib/ui/hooks.dart +++ b/engine/src/flutter/lib/ui/hooks.dart @@ -27,6 +27,10 @@ void _addView( List displayFeaturesType, List displayFeaturesState, int displayId, + double minWidth, + double maxWidth, + double minHeight, + double maxHeight, ) { final _ViewConfiguration viewConfiguration = _buildViewConfiguration( devicePixelRatio, @@ -49,6 +53,10 @@ void _addView( displayFeaturesType, displayFeaturesState, displayId, + minWidth, + maxWidth, + minHeight, + maxHeight, ); PlatformDispatcher.instance._addView(viewId, viewConfiguration); } @@ -151,6 +159,10 @@ _ViewConfiguration _buildViewConfiguration( List displayFeaturesType, List displayFeaturesState, int displayId, + double minWidth, + double maxWidth, + double minHeight, + double maxHeight, ) { return _ViewConfiguration( devicePixelRatio: devicePixelRatio, @@ -189,6 +201,12 @@ _ViewConfiguration _buildViewConfiguration( devicePixelRatio: devicePixelRatio, ), displayId: displayId, + viewConstraints: ViewConstraints( + minWidth: minWidth, + maxWidth: maxWidth, + minHeight: minHeight, + maxHeight: maxHeight, + ), ); } @@ -215,6 +233,10 @@ void _updateWindowMetrics( List displayFeaturesType, List displayFeaturesState, int displayId, + double minWidth, + double maxWidth, + double minHeight, + double maxHeight, ) { final _ViewConfiguration viewConfiguration = _buildViewConfiguration( devicePixelRatio, @@ -237,6 +259,10 @@ void _updateWindowMetrics( displayFeaturesType, displayFeaturesState, displayId, + minWidth, + maxWidth, + minHeight, + maxHeight, ); PlatformDispatcher.instance._updateWindowMetrics(viewId, viewConfiguration); } diff --git a/engine/src/flutter/lib/ui/platform_dispatcher.dart b/engine/src/flutter/lib/ui/platform_dispatcher.dart index c2aa5419a05..ff5a56e0b4e 100644 --- a/engine/src/flutter/lib/ui/platform_dispatcher.dart +++ b/engine/src/flutter/lib/ui/platform_dispatcher.dart @@ -1886,12 +1886,16 @@ class _ViewConfiguration { this.gestureSettings = const GestureSettings(), this.displayFeatures = const [], this.displayId = 0, + this.viewConstraints = const ViewConstraints(maxWidth: 0, maxHeight: 0), }); /// The identifier for a display for this view, in /// [PlatformDispatcher._displays]. final int displayId; + /// The sizing constraints for this view in physical pixels. + final ViewConstraints viewConstraints; + /// The pixel density of the output surface. final double devicePixelRatio; diff --git a/engine/src/flutter/lib/ui/window.dart b/engine/src/flutter/lib/ui/window.dart index ef8551c892e..3af4bb9af81 100644 --- a/engine/src/flutter/lib/ui/window.dart +++ b/engine/src/flutter/lib/ui/window.dart @@ -145,7 +145,7 @@ class FlutterView { /// /// The view can take on any [Size] that fulfills these constraints. These /// constraints are typically used by an UI framework as the input for its - /// layout algorithm to determine an approrpiate size for the view. To size + /// layout algorithm to determine an appropriate size for the view. To size /// the view, the selected size must be provided to the [render] method and it /// must satisfy the constraints. /// @@ -164,10 +164,7 @@ class FlutterView { /// See also: /// /// * [physicalSize], which returns the current size of the view. - // TODO(goderbauer): Wire this up so embedders can configure it. This will - // also require to message the size provided to the render call back to the - // embedder. - ViewConstraints get physicalConstraints => ViewConstraints.tight(physicalSize); + ViewConstraints get physicalConstraints => _viewConfiguration.viewConstraints; /// The current dimensions of the rectangle as last reported by the platform /// into which scenes rendered in this view are drawn. diff --git a/engine/src/flutter/lib/ui/window/platform_configuration.cc b/engine/src/flutter/lib/ui/window/platform_configuration.cc index 46b0d745a59..2edeb2cf598 100644 --- a/engine/src/flutter/lib/ui/window/platform_configuration.cc +++ b/engine/src/flutter/lib/ui/window/platform_configuration.cc @@ -126,6 +126,10 @@ bool PlatformConfiguration::AddView(int64_t view_id, tonic::ToDart(view_metrics.physical_display_features_type), tonic::ToDart(view_metrics.physical_display_features_state), tonic::ToDart(view_metrics.display_id), + tonic::ToDart(view_metrics.physical_min_width_constraint), + tonic::ToDart(view_metrics.physical_max_width_constraint), + tonic::ToDart(view_metrics.physical_min_height_constraint), + tonic::ToDart(view_metrics.physical_max_height_constraint), })); return true; } @@ -224,6 +228,10 @@ bool PlatformConfiguration::UpdateViewMetrics( tonic::ToDart(view_metrics.physical_display_features_type), tonic::ToDart(view_metrics.physical_display_features_state), tonic::ToDart(view_metrics.display_id), + tonic::ToDart(view_metrics.physical_min_width_constraint), + tonic::ToDart(view_metrics.physical_max_width_constraint), + tonic::ToDart(view_metrics.physical_min_height_constraint), + tonic::ToDart(view_metrics.physical_max_height_constraint), })); return true; } diff --git a/engine/src/flutter/lib/ui/window/viewport_metrics.cc b/engine/src/flutter/lib/ui/window/viewport_metrics.cc index 05d01c47c8e..14919d94367 100644 --- a/engine/src/flutter/lib/ui/window/viewport_metrics.cc +++ b/engine/src/flutter/lib/ui/window/viewport_metrics.cc @@ -18,13 +18,20 @@ ViewportMetrics::ViewportMetrics(double p_device_pixel_ratio, : device_pixel_ratio(p_device_pixel_ratio), physical_width(p_physical_width), physical_height(p_physical_height), + physical_min_width_constraint(p_physical_width), + physical_max_width_constraint(p_physical_width), + physical_min_height_constraint(p_physical_height), + physical_max_height_constraint(p_physical_height), physical_touch_slop(p_physical_touch_slop), display_id(p_display_id) {} - ViewportMetrics::ViewportMetrics( double p_device_pixel_ratio, double p_physical_width, double p_physical_height, + double p_physical_min_width_constraint, + double p_physical_max_width_constraint, + double p_physical_min_height_constraint, + double p_physical_max_height_constraint, double p_physical_padding_top, double p_physical_padding_right, double p_physical_padding_bottom, @@ -45,6 +52,10 @@ ViewportMetrics::ViewportMetrics( : device_pixel_ratio(p_device_pixel_ratio), physical_width(p_physical_width), physical_height(p_physical_height), + physical_min_width_constraint(p_physical_min_width_constraint), + physical_max_width_constraint(p_physical_max_width_constraint), + physical_min_height_constraint(p_physical_min_height_constraint), + physical_max_height_constraint(p_physical_max_height_constraint), physical_padding_top(p_physical_padding_top), physical_padding_right(p_physical_padding_right), physical_padding_bottom(p_physical_padding_bottom), @@ -69,6 +80,10 @@ bool operator==(const ViewportMetrics& a, const ViewportMetrics& b) { return a.device_pixel_ratio == b.device_pixel_ratio && a.physical_width == b.physical_width && a.physical_height == b.physical_height && + a.physical_min_width_constraint == b.physical_min_width_constraint && + a.physical_max_width_constraint == b.physical_max_width_constraint && + a.physical_min_height_constraint == b.physical_min_height_constraint && + a.physical_max_height_constraint == b.physical_max_height_constraint && a.physical_padding_top == b.physical_padding_top && a.physical_padding_right == b.physical_padding_right && a.physical_padding_bottom == b.physical_padding_bottom && @@ -99,6 +114,10 @@ std::ostream& operator<<(std::ostream& os, const ViewportMetrics& a) { << "W " << a.physical_height << "H] " << "Padding: [" << a.physical_padding_top << "T " << a.physical_padding_right << "R " << a.physical_padding_bottom << "B " << a.physical_padding_left << "L] " + << "View Constraints: [" << a.physical_min_width_constraint << "-" + << a.physical_max_width_constraint << "W " + << a.physical_min_height_constraint << "-" + << a.physical_max_height_constraint << "H] " << "Insets: [" << a.physical_view_inset_top << "T " << a.physical_view_inset_right << "R " << a.physical_view_inset_bottom << "B " << a.physical_view_inset_left << "L] " << "Gesture Insets: [" diff --git a/engine/src/flutter/lib/ui/window/viewport_metrics.h b/engine/src/flutter/lib/ui/window/viewport_metrics.h index 13a0dee9439..2ec2aaeff61 100644 --- a/engine/src/flutter/lib/ui/window/viewport_metrics.h +++ b/engine/src/flutter/lib/ui/window/viewport_metrics.h @@ -20,6 +20,10 @@ struct ViewportMetrics { ViewportMetrics(double p_device_pixel_ratio, double p_physical_width, double p_physical_height, + double p_physical_min_width_constraint, + double p_physical_max_width_constraint, + double p_physical_min_height_constraint, + double p_physical_max_height_constraint, double p_physical_padding_top, double p_physical_padding_right, double p_physical_padding_bottom, @@ -37,10 +41,13 @@ struct ViewportMetrics { const std::vector& p_physical_display_features_type, const std::vector& p_physical_display_features_state, size_t p_display_id); - double device_pixel_ratio = 1.0; double physical_width = 0; double physical_height = 0; + double physical_min_width_constraint = 0; + double physical_max_width_constraint = 0; + double physical_min_height_constraint = 0; + double physical_max_height_constraint = 0; double physical_padding_top = 0; double physical_padding_right = 0; double physical_padding_bottom = 0; diff --git a/engine/src/flutter/shell/common/BUILD.gn b/engine/src/flutter/shell/common/BUILD.gn index c3ffd57d5c4..d577e322877 100644 --- a/engine/src/flutter/shell/common/BUILD.gn +++ b/engine/src/flutter/shell/common/BUILD.gn @@ -148,6 +148,7 @@ source_set("common") { "//flutter/lib/ui", "//flutter/runtime", "//flutter/shell/common:base64", + "//flutter/shell/geometry", "//flutter/shell/profiling", "//flutter/skia", ] diff --git a/engine/src/flutter/shell/common/shell.cc b/engine/src/flutter/shell/common/shell.cc index 226e35932f0..c8e9154a7a5 100644 --- a/engine/src/flutter/shell/common/shell.cc +++ b/engine/src/flutter/shell/common/shell.cc @@ -149,6 +149,56 @@ void PerformInitializationTasks(Settings& settings) { #endif // !SLIMPELLER } +bool ValidateViewportMetrics(const ViewportMetrics& metrics) { + // Pixel ratio cannot be zero. + if (metrics.device_pixel_ratio <= 0) { + return false; + } + + // If negative values are passed in. + if (metrics.physical_width < 0 || metrics.physical_height < 0 || + metrics.physical_min_width_constraint < 0 || + metrics.physical_max_width_constraint < 0 || + metrics.physical_min_height_constraint < 0 || + metrics.physical_max_height_constraint < 0) { + return false; + } + + // If width is zero and the constraints are tight. + if (metrics.physical_width == 0 && + metrics.physical_min_width_constraint == + metrics.physical_max_width_constraint) { + return false; + } + + // If not tight constraints, check the width fits in the constraints. + if (metrics.physical_min_width_constraint != + metrics.physical_max_width_constraint) { + if (metrics.physical_min_width_constraint > metrics.physical_width || + metrics.physical_width > metrics.physical_max_width_constraint) { + return false; + } + } + + // If height is zero and the constraints are tight. + if (metrics.physical_height == 0 && + metrics.physical_min_height_constraint == + metrics.physical_max_height_constraint) { + return false; + } + + // If not tight constraints, check the height fits in the constraints. + if (metrics.physical_min_height_constraint != + metrics.physical_max_height_constraint) { + if (metrics.physical_min_height_constraint > metrics.physical_height || + metrics.physical_height > metrics.physical_max_height_constraint) { + return false; + } + } + + return true; +} + } // namespace std::pair> @@ -1078,8 +1128,7 @@ void Shell::OnPlatformViewSetViewportMetrics(int64_t view_id, FML_DCHECK(is_set_up_); FML_DCHECK(task_runners_.GetPlatformTaskRunner()->RunsTasksOnCurrentThread()); - if (metrics.device_pixel_ratio <= 0 || metrics.physical_width <= 0 || - metrics.physical_height <= 0) { + if (!ValidateViewportMetrics(metrics)) { // Ignore invalid view-port metrics. return; } @@ -1107,8 +1156,12 @@ void Shell::OnPlatformViewSetViewportMetrics(int64_t view_id, { std::scoped_lock lock(resize_mutex_); - expected_frame_sizes_[view_id] = - DlISize(metrics.physical_width, metrics.physical_height); + + expected_frame_constraints_[view_id] = + BoxConstraints(Size(metrics.physical_min_width_constraint, + metrics.physical_min_height_constraint), + Size(metrics.physical_max_width_constraint, + metrics.physical_max_height_constraint)); device_pixel_ratio_ = metrics.device_pixel_ratio; } } @@ -1756,9 +1809,9 @@ fml::TimePoint Shell::GetLatestFrameTargetTime() const { bool Shell::ShouldDiscardLayerTree(int64_t view_id, const flutter::LayerTree& tree) { std::scoped_lock lock(resize_mutex_); - auto expected_frame_size = ExpectedFrameSize(view_id); - return !expected_frame_size.IsEmpty() && - tree.frame_size() != expected_frame_size; + auto expected_frame_constraints = ExpectedFrameConstraints(view_id); + return !expected_frame_constraints.IsSatisfiedBy( + Size(tree.frame_size().width, tree.frame_size().height)); } // |ServiceProtocol::Handler| @@ -2169,8 +2222,10 @@ void Shell::OnPlatformViewRemoveView(int64_t view_id, FML_DCHECK(view_id != kFlutterImplicitViewId) << "Unexpected request to remove the implicit view #" << kFlutterImplicitViewId << ". This view should never be removed."; - - expected_frame_sizes_.erase(view_id); + { + std::scoped_lock lock(resize_mutex_); + expected_frame_constraints_.erase(view_id); + } task_runners_.GetUITaskRunner()->RunNowOrPostTask( task_runners_.GetUITaskRunner(), [&task_runners = task_runners_, // @@ -2363,11 +2418,13 @@ Shell::GetConcurrentWorkerTaskRunner() const { return vm_->GetConcurrentWorkerTaskRunner(); } -DlISize Shell::ExpectedFrameSize(int64_t view_id) { - auto found = expected_frame_sizes_.find(view_id); - if (found == expected_frame_sizes_.end()) { - return DlISize(); +BoxConstraints Shell::ExpectedFrameConstraints(int64_t view_id) { + auto found = expected_frame_constraints_.find(view_id); + + if (found == expected_frame_constraints_.end()) { + return {}; } + return found->second; } diff --git a/engine/src/flutter/shell/common/shell.h b/engine/src/flutter/shell/common/shell.h index 41ae6e263fb..a98c3a2aaed 100644 --- a/engine/src/flutter/shell/common/shell.h +++ b/engine/src/flutter/shell/common/shell.h @@ -39,6 +39,7 @@ #include "flutter/shell/common/rasterizer.h" #include "flutter/shell/common/resource_cache_limit_calculator.h" #include "flutter/shell/common/shell_io_manager.h" +#include "flutter/shell/geometry/geometry.h" #include "impeller/core/runtime_types.h" #include "impeller/renderer/context.h" #include "impeller/runtime_stage/runtime_stage.h" @@ -511,13 +512,13 @@ class Shell final : public PlatformView::Delegate, /// any of the threads. std::unique_ptr display_manager_; - // protects expected_frame_size_ which is set on platform thread and read on - // raster thread + // Protects expected_frame_constraints_ which is set on platform thread and + // read on raster thread. std::mutex resize_mutex_; - // used to discard wrong size layer tree produced during interactive - // resizing - std::unordered_map expected_frame_sizes_; + // Used to discard wrong size layer tree produced during interactive + // resizing. + std::unordered_map expected_frame_constraints_; // Used to communicate the right frame bounds via service protocol. double device_pixel_ratio_ = 0.0; @@ -804,7 +805,7 @@ class Shell final : public PlatformView::Delegate, // directory. std::unique_ptr RestoreOriginalAssetResolver(); - DlISize ExpectedFrameSize(int64_t view_id); + BoxConstraints ExpectedFrameConstraints(int64_t view_id); // For accessing the Shell via the raster thread, necessary for various // rasterizer callbacks. diff --git a/engine/src/flutter/shell/common/shell_test.cc b/engine/src/flutter/shell/common/shell_test.cc index 24ce62e7a7b..71086a6b201 100644 --- a/engine/src/flutter/shell/common/shell_test.cc +++ b/engine/src/flutter/shell/common/shell_test.cc @@ -165,6 +165,10 @@ void ShellTest::SetViewportMetrics(Shell* shell, double width, double height) { 1, // device pixel ratio width, // physical width height, // physical height + 0, // min width constraint + 0, // max width constraint + 0, // min height constraint + 0, // max height constraint 0, // padding top 0, // padding right 0, // padding bottom @@ -425,5 +429,11 @@ void ShellTest::TurnOffGPU(Shell* shell, bool value) { shell->is_gpu_disabled_sync_switch_->SetSwitch(value); } +bool ShellTest::ShouldDiscardLayerTree(Shell* shell, + int64_t view_id, + const flutter::LayerTree& tree) { + return shell->ShouldDiscardLayerTree(view_id, tree); +} + } // namespace testing } // namespace flutter diff --git a/engine/src/flutter/shell/common/shell_test.h b/engine/src/flutter/shell/common/shell_test.h index 0fd729f5a67..0034ecf816a 100644 --- a/engine/src/flutter/shell/common/shell_test.h +++ b/engine/src/flutter/shell/common/shell_test.h @@ -163,6 +163,10 @@ class ShellTest : public FixtureTest { static void TurnOffGPU(Shell* shell, bool value); + static bool ShouldDiscardLayerTree(Shell* shell, + int64_t view_id, + const flutter::LayerTree& tree); + private: ThreadHost thread_host_; diff --git a/engine/src/flutter/shell/common/shell_unittests.cc b/engine/src/flutter/shell/common/shell_unittests.cc index b0b5bfb5ea2..bb57adc49e4 100644 --- a/engine/src/flutter/shell/common/shell_unittests.cc +++ b/engine/src/flutter/shell/common/shell_unittests.cc @@ -24,6 +24,7 @@ #include "flutter/flow/layers/clip_rect_layer.h" #include "flutter/flow/layers/display_list_layer.h" #include "flutter/flow/layers/layer_raster_cache_item.h" +#include "flutter/flow/layers/layer_tree.h" #include "flutter/flow/layers/platform_view_layer.h" #include "flutter/flow/layers/transform_layer.h" #include "flutter/fml/backtrace.h" @@ -5040,6 +5041,72 @@ TEST_F(ShellTest, ReleaseResourceContextWhenIOManagerIsDeleted) { ASSERT_TRUE(called_release_resource_context); } +TEST_F(ShellTest, ShoulDiscardLayerTreeIfFrameIsSizedIncorrectly) { + Settings settings = CreateSettingsForFixture(); + auto task_runner = CreateNewThread(); + TaskRunners task_runners("test", task_runner, task_runner, task_runner, + task_runner); + std::unique_ptr shell = CreateShell(settings, task_runners); + + fml::TaskRunner::RunNowOrPostTask( + shell->GetTaskRunners().GetPlatformTaskRunner(), [&shell]() { + shell->GetPlatformView()->SetViewportMetrics( + kImplicitViewId, + { + 1.0, // p_device_pixel_ratio + 500, // p_physical_width + 800, // p_physical_height + 1, // p_min_width_constraint, + 1000, // p_max_width_constraint, + 1, // p_min_height_constraint, + 1000, // p_max_height_constraint, + 0, // p_physical_padding_top + 0, // p_physical_padding_right + 0, // p_physical_padding_bottom + 0, // p_physical_padding_left + 0, // p_physical_view_inset_top, + 0, // p_physical_view_inset_right, + 0, // p_physical_view_inset_bottom, + 0, // p_physical_view_inset_left, + 0, // p_physical_system_gesture_inset_top, + 0, // p_physical_system_gesture_inset_right, + 0, // p_physical_system_gesture_inset_bottom, + 0, // p_physical_system_gesture_inset_left, + 22, // p_physical_touch_slop, + {}, // p_physical_display_features_bounds, + {}, // p_physical_display_features_type, + {}, // p_physical_display_features_state, + 0 // p_display_id + }); + }); + PumpOneFrame(shell.get()); + + auto layer_tree = + std::make_unique(/*root_layer=*/nullptr, + /*frame_size=*/DlISize(100, 100)); + ASSERT_FALSE(ShellTest::ShouldDiscardLayerTree(shell.get(), kImplicitViewId, + *layer_tree)); + auto over_width = + std::make_unique(/*root_layer=*/nullptr, + /*frame_size=*/DlISize(1010, 100)); + ASSERT_TRUE(ShellTest::ShouldDiscardLayerTree(shell.get(), kImplicitViewId, + *over_width)); + auto over_height = + std::make_unique(/*root_layer=*/nullptr, + /*frame_size=*/DlISize(100, 1010)); + ASSERT_TRUE(ShellTest::ShouldDiscardLayerTree(shell.get(), kImplicitViewId, + *over_height)); + auto min_width = std::make_unique(/*root_layer=*/nullptr, + /*frame_size=*/DlISize(0, 100)); + ASSERT_TRUE(ShellTest::ShouldDiscardLayerTree(shell.get(), kImplicitViewId, + *min_width)); + auto min_height = std::make_unique(/*root_layer=*/nullptr, + /*frame_size=*/DlISize(100, 0)); + ASSERT_TRUE(ShellTest::ShouldDiscardLayerTree(shell.get(), kImplicitViewId, + *min_height)); + DestroyShell(std::move(shell), task_runners); +} + } // namespace testing } // namespace flutter diff --git a/engine/src/flutter/shell/geometry/BUILD.gn b/engine/src/flutter/shell/geometry/BUILD.gn new file mode 100644 index 00000000000..0d65bb739d5 --- /dev/null +++ b/engine/src/flutter/shell/geometry/BUILD.gn @@ -0,0 +1,31 @@ +import("//flutter/common/config.gni") +import("//flutter/testing/testing.gni") + +source_set("geometry") { + visibility = [ + ":geometry_unittests", + "//flutter/shell/common:*", + "//flutter/shell/platform/common:*", + "//flutter/shell/platform/windows:*", + ] + + sources = [ "geometry.h" ] +} + +if (enable_unittests) { + test_fixtures("geometry_fixtures") { + fixtures = [] + } + + executable("geometry_unittests") { + testonly = true + + sources = [ "geometry_unittests.cc" ] + + deps = [ + ":geometry", + ":geometry_fixtures", + "//flutter/testing", + ] + } +} diff --git a/engine/src/flutter/shell/platform/common/geometry.h b/engine/src/flutter/shell/geometry/geometry.h similarity index 88% rename from engine/src/flutter/shell/platform/common/geometry.h rename to engine/src/flutter/shell/geometry/geometry.h index eabe4d685ce..e5572e924c9 100644 --- a/engine/src/flutter/shell/platform/common/geometry.h +++ b/engine/src/flutter/shell/geometry/geometry.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_SHELL_PLATFORM_COMMON_GEOMETRY_H_ -#define FLUTTER_SHELL_PLATFORM_COMMON_GEOMETRY_H_ +#ifndef FLUTTER_SHELL_GEOMETRY_GEOMETRY_H_ +#define FLUTTER_SHELL_GEOMETRY_GEOMETRY_H_ #include #include @@ -93,6 +93,13 @@ class BoxConstraints { Size biggest() const { return biggest_; } Size smallest() const { return smallest_; } + bool IsSatisfiedBy(Size size) { + return smallest().width() <= size.width() && + size.width() <= biggest().width() && + smallest().height() <= size.height() && + size.height() <= biggest().height(); + } + private: Size smallest_ = Size(0, 0); Size biggest_ = Size(std::numeric_limits::infinity(), @@ -101,4 +108,4 @@ class BoxConstraints { } // namespace flutter -#endif // FLUTTER_SHELL_PLATFORM_COMMON_GEOMETRY_H_ +#endif // FLUTTER_SHELL_GEOMETRY_GEOMETRY_H_ diff --git a/engine/src/flutter/shell/platform/common/geometry_unittests.cc b/engine/src/flutter/shell/geometry/geometry_unittests.cc similarity index 96% rename from engine/src/flutter/shell/platform/common/geometry_unittests.cc rename to engine/src/flutter/shell/geometry/geometry_unittests.cc index c8645028be9..4be46ae696d 100644 --- a/engine/src/flutter/shell/platform/common/geometry_unittests.cc +++ b/engine/src/flutter/shell/geometry/geometry_unittests.cc @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "flutter/shell/platform/common/geometry.h" +#include "flutter/shell/geometry/geometry.h" #include "gtest/gtest.h" diff --git a/engine/src/flutter/shell/platform/android/platform_view_android_jni_impl.cc b/engine/src/flutter/shell/platform/android/platform_view_android_jni_impl.cc index b2ed47f64f2..80dcf7458f3 100644 --- a/engine/src/flutter/shell/platform/android/platform_view_android_jni_impl.cc +++ b/engine/src/flutter/shell/platform/android/platform_view_android_jni_impl.cc @@ -367,27 +367,38 @@ static void SetViewportMetrics(JNIEnv* env, env->GetIntArrayRegion(javaDisplayFeaturesState, 0, stateSize, &displayFeaturesState[0]); + // TODO(boetger): update for https://github.com/flutter/flutter/issues/149033 const flutter::ViewportMetrics metrics{ - static_cast(devicePixelRatio), - 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), - static_cast(physicalTouchSlop), - displayFeaturesBounds, - displayFeaturesType, - displayFeaturesState, - 0, // Display ID + static_cast(devicePixelRatio), // p_device_pixel_ratio + static_cast(physicalWidth), // p_physical_width + static_cast(physicalHeight), // p_physical_height + static_cast(physicalWidth), // p_physical_min_width_constraint + static_cast(physicalWidth), // p_physical_max_width_constraint + static_cast(physicalHeight), // p_physical_min_height_constraint + static_cast(physicalHeight), // p_physical_max_height_constraint + static_cast(physicalPaddingTop), // p_physical_padding_top + static_cast(physicalPaddingRight), // p_physical_padding_right + static_cast(physicalPaddingBottom), // p_physical_padding_bottom + static_cast(physicalPaddingLeft), // p_physical_padding_left + static_cast(physicalViewInsetTop), // p_physical_view_inset_top + static_cast( + physicalViewInsetRight), // p_physical_view_inset_right + static_cast( + physicalViewInsetBottom), // p_physical_view_inset_bottom + static_cast(physicalViewInsetLeft), // p_physical_view_inset_left + static_cast( + systemGestureInsetTop), // p_physical_system_gesture_inset_top + static_cast( + systemGestureInsetRight), // p_physical_system_gesture_inset_right + static_cast( + systemGestureInsetBottom), // p_physical_system_gesture_inset_bottom + static_cast( + systemGestureInsetLeft), // p_physical_system_gesture_inset_left + static_cast(physicalTouchSlop), // p_physical_touch_slop + displayFeaturesBounds, // p_physical_display_features_bounds + displayFeaturesType, // p_physical_display_features_type + displayFeaturesState, // p_physical_display_features_state + 0, // p_display_id }; ANDROID_SHELL_HOLDER->GetPlatformView()->SetViewportMetrics( diff --git a/engine/src/flutter/shell/platform/common/BUILD.gn b/engine/src/flutter/shell/platform/common/BUILD.gn index b27be6bfa03..e7cc8609551 100644 --- a/engine/src/flutter/shell/platform/common/BUILD.gn +++ b/engine/src/flutter/shell/platform/common/BUILD.gn @@ -150,7 +150,6 @@ source_set("common_cpp") { # API surface there will be. source_set("common_cpp_core") { public = [ - "geometry.h", "path_utils.h", "windowing.h", ] @@ -159,7 +158,10 @@ source_set("common_cpp_core") { public_configs = [ "//flutter:config" ] - deps = [ "//flutter/fml:fml" ] + deps = [ + "//flutter/fml:fml", + "//flutter/shell/geometry:geometry", + ] } if (enable_unittests) { @@ -191,7 +193,6 @@ if (enable_unittests) { sources = [ "engine_switches_unittests.cc", - "geometry_unittests.cc", "incoming_message_dispatcher_unittests.cc", "json_message_codec_unittests.cc", "json_method_codec_unittests.cc", diff --git a/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm b/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm index 1e5aa0a4489..f7fd6cd518d 100644 --- a/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm +++ b/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm @@ -1478,6 +1478,11 @@ static flutter::PointerData::DeviceKind DeviceKindFromTouchType(UITouch* touch) CGFloat scale = screen.scale; _viewportMetrics.physical_width = self.view.bounds.size.width * scale; _viewportMetrics.physical_height = self.view.bounds.size.height * scale; + // TODO(louisehsu): update for https://github.com/flutter/flutter/issues/169147 + _viewportMetrics.physical_min_width_constraint = _viewportMetrics.physical_width; + _viewportMetrics.physical_max_width_constraint = _viewportMetrics.physical_width; + _viewportMetrics.physical_min_height_constraint = _viewportMetrics.physical_height; + _viewportMetrics.physical_max_height_constraint = _viewportMetrics.physical_height; } // Set _viewportMetrics physical paddings. diff --git a/engine/src/flutter/shell/platform/embedder/embedder.cc b/engine/src/flutter/shell/platform/embedder/embedder.cc index d3434052663..a2e5b51086d 100644 --- a/engine/src/flutter/shell/platform/embedder/embedder.cc +++ b/engine/src/flutter/shell/platform/embedder/embedder.cc @@ -1649,6 +1649,11 @@ MakeViewportMetricsFromWindowMetrics( "physical height or width."; } + metrics.physical_min_width_constraint = metrics.physical_width; + metrics.physical_max_width_constraint = metrics.physical_width; + metrics.physical_min_height_constraint = metrics.physical_height; + metrics.physical_max_height_constraint = metrics.physical_height; + return metrics; } diff --git a/engine/src/flutter/shell/platform/fuchsia/flutter/platform_view.cc b/engine/src/flutter/shell/platform/fuchsia/flutter/platform_view.cc index 35147128eef..b2c15e3021b 100644 --- a/engine/src/flutter/shell/platform/fuchsia/flutter/platform_view.cc +++ b/engine/src/flutter/shell/platform/fuchsia/flutter/platform_view.cc @@ -342,6 +342,14 @@ void PlatformView::OnGetLayout(fuchsia::ui::composition::LayoutInfo info) { pixel_ratio), // physical_width std::round(view_logical_size_.value()[1] * pixel_ratio), // physical_height + std::round(view_logical_size_.value()[0] * + pixel_ratio), // physical_min_width_constraint + std::round(view_logical_size_.value()[0] * + pixel_ratio), // physical_max_width_constraint + std::round(view_logical_size_.value()[1] * + pixel_ratio), // physical_min_height_constraint + std::round(view_logical_size_.value()[1] * + pixel_ratio), // physical_max_height_constraint 0.0f, // physical_padding_top 0.0f, // physical_padding_right 0.0f, // physical_padding_bottom diff --git a/engine/src/flutter/shell/platform/windows/BUILD.gn b/engine/src/flutter/shell/platform/windows/BUILD.gn index 4f49f5dc600..600fa110d68 100644 --- a/engine/src/flutter/shell/platform/windows/BUILD.gn +++ b/engine/src/flutter/shell/platform/windows/BUILD.gn @@ -165,6 +165,7 @@ source_set("flutter_windows_source") { ":flutter_windows_headers", "//flutter/fml:fml", "//flutter/impeller/renderer/backend/gles", + "//flutter/shell/geometry:geometry", "//flutter/shell/platform/common:common_cpp", "//flutter/shell/platform/common:common_cpp_input", "//flutter/shell/platform/common:common_cpp_isolate_scope", diff --git a/engine/src/flutter/shell/platform/windows/flutter_window.h b/engine/src/flutter/shell/platform/windows/flutter_window.h index d1b20f17181..d0c206aa963 100644 --- a/engine/src/flutter/shell/platform/windows/flutter_window.h +++ b/engine/src/flutter/shell/platform/windows/flutter_window.h @@ -9,8 +9,8 @@ #include #include "flutter/fml/macros.h" +#include "flutter/shell/geometry/geometry.h" #include "flutter/shell/platform/common/alert_platform_node_delegate.h" -#include "flutter/shell/platform/common/geometry.h" #include "flutter/shell/platform/embedder/embedder.h" #include "flutter/shell/platform/windows/direct_manipulation.h" #include "flutter/shell/platform/windows/flutter_windows_view.h" diff --git a/engine/src/flutter/shell/platform/windows/flutter_windows_view.h b/engine/src/flutter/shell/platform/windows/flutter_windows_view.h index 66ab0f0f0a4..738b37dbeff 100644 --- a/engine/src/flutter/shell/platform/windows/flutter_windows_view.h +++ b/engine/src/flutter/shell/platform/windows/flutter_windows_view.h @@ -13,8 +13,8 @@ #include #include "flutter/fml/macros.h" +#include "flutter/shell/geometry/geometry.h" #include "flutter/shell/platform/common/client_wrapper/include/flutter/plugin_registrar.h" -#include "flutter/shell/platform/common/geometry.h" #include "flutter/shell/platform/embedder/embedder.h" #include "flutter/shell/platform/windows/accessibility_bridge_windows.h" #include "flutter/shell/platform/windows/flutter_windows_engine.h" diff --git a/engine/src/flutter/shell/platform/windows/host_window.h b/engine/src/flutter/shell/platform/windows/host_window.h index e3773d65ec5..77e28aa00dc 100644 --- a/engine/src/flutter/shell/platform/windows/host_window.h +++ b/engine/src/flutter/shell/platform/windows/host_window.h @@ -12,7 +12,7 @@ #include #include "flutter/fml/macros.h" -#include "flutter/shell/platform/common/geometry.h" +#include "flutter/shell/geometry/geometry.h" #include "flutter/shell/platform/common/windowing.h" #include "flutter/shell/platform/windows/window_manager.h" diff --git a/engine/src/flutter/shell/platform/windows/text_input_manager.h b/engine/src/flutter/shell/platform/windows/text_input_manager.h index 4e1c262fa31..d6e7d6866c4 100644 --- a/engine/src/flutter/shell/platform/windows/text_input_manager.h +++ b/engine/src/flutter/shell/platform/windows/text_input_manager.h @@ -12,7 +12,7 @@ #include #include "flutter/fml/macros.h" -#include "flutter/shell/platform/common/geometry.h" +#include "flutter/shell/geometry/geometry.h" namespace flutter { diff --git a/engine/src/flutter/shell/platform/windows/text_input_plugin.h b/engine/src/flutter/shell/platform/windows/text_input_plugin.h index 1a836f9db83..1ef228a3144 100644 --- a/engine/src/flutter/shell/platform/windows/text_input_plugin.h +++ b/engine/src/flutter/shell/platform/windows/text_input_plugin.h @@ -10,9 +10,9 @@ #include #include "flutter/fml/macros.h" +#include "flutter/shell/geometry/geometry.h" #include "flutter/shell/platform/common/client_wrapper/include/flutter/binary_messenger.h" #include "flutter/shell/platform/common/client_wrapper/include/flutter/method_channel.h" -#include "flutter/shell/platform/common/geometry.h" #include "flutter/shell/platform/common/json_method_codec.h" #include "flutter/shell/platform/common/text_editing_delta.h" #include "flutter/shell/platform/common/text_input_model.h" diff --git a/engine/src/flutter/shell/platform/windows/window_binding_handler.h b/engine/src/flutter/shell/platform/windows/window_binding_handler.h index 6585567b287..a9f9c320082 100644 --- a/engine/src/flutter/shell/platform/windows/window_binding_handler.h +++ b/engine/src/flutter/shell/platform/windows/window_binding_handler.h @@ -10,8 +10,8 @@ #include #include +#include "flutter/shell/geometry/geometry.h" #include "flutter/shell/platform/common/alert_platform_node_delegate.h" -#include "flutter/shell/platform/common/geometry.h" #include "flutter/shell/platform/embedder/embedder.h" #include "flutter/shell/platform/windows/public/flutter_windows.h" #include "flutter/shell/platform/windows/window_binding_handler_delegate.h" diff --git a/engine/src/flutter/shell/platform/windows/window_binding_handler_delegate.h b/engine/src/flutter/shell/platform/windows/window_binding_handler_delegate.h index 0245a742286..7a755b1018b 100644 --- a/engine/src/flutter/shell/platform/windows/window_binding_handler_delegate.h +++ b/engine/src/flutter/shell/platform/windows/window_binding_handler_delegate.h @@ -7,7 +7,7 @@ #include -#include "flutter/shell/platform/common/geometry.h" +#include "flutter/shell/geometry/geometry.h" #include "flutter/shell/platform/embedder/embedder.h" #include "flutter/shell/platform/windows/windows_lifecycle_manager.h" #include "flutter/third_party/accessibility/ax/platform/ax_fragment_root_delegate_win.h" diff --git a/engine/src/flutter/shell/testing/tester_main.cc b/engine/src/flutter/shell/testing/tester_main.cc index d3e65d720be..4640b0d40d1 100644 --- a/engine/src/flutter/shell/testing/tester_main.cc +++ b/engine/src/flutter/shell/testing/tester_main.cc @@ -140,6 +140,10 @@ static void ConfigureShell(Shell* shell) { metrics.physical_width = physical_width; metrics.physical_height = physical_height; metrics.display_id = 0; + metrics.physical_min_width_constraint = physical_width; + metrics.physical_max_width_constraint = physical_width; + metrics.physical_min_height_constraint = physical_height; + metrics.physical_max_height_constraint = physical_height; shell->GetPlatformView()->SetViewportMetrics(kImplicitViewId, metrics); } diff --git a/engine/src/flutter/testing/run_tests.py b/engine/src/flutter/testing/run_tests.py index 97676a9c0ff..bfd58723746 100755 --- a/engine/src/flutter/testing/run_tests.py +++ b/engine/src/flutter/testing/run_tests.py @@ -431,6 +431,7 @@ def run_cc_tests(build_dir, executable_filter, coverage, capture_core_dump): make_test('embedder_proctable_unittests'), make_test('embedder_unittests'), make_test('fml_unittests'), + make_test('geometry_unittests'), make_test('no_dart_plugin_registrant_unittests'), make_test('runtime_unittests'), make_test('testing_unittests'),