diff --git a/dev/devicelab/bin/tasks/module_test_ios.dart b/dev/devicelab/bin/tasks/module_test_ios.dart index 9264ab8cecb..192d722cf19 100644 --- a/dev/devicelab/bin/tasks/module_test_ios.dart +++ b/dev/devicelab/bin/tasks/module_test_ios.dart @@ -54,9 +54,6 @@ Future main() async { final File marquee = File(path.join(flutterModuleLibSource.path, 'marquee')); marquee.copySync(path.join(flutterModuleLibDestination.path, 'marquee.dart')); - final File resize = File(path.join(flutterModuleLibSource.path, 'resize')); - resize.copySync(path.join(flutterModuleLibDestination.path, 'resize.dart')); - section('Create package with native assets'); const String ffiPackageName = 'ffi_package'; diff --git a/dev/integration_tests/ios_host_app/FlutterUITests/FlutterUITests.m b/dev/integration_tests/ios_host_app/FlutterUITests/FlutterUITests.m index cf45751408c..91f9cc890cd 100644 --- a/dev/integration_tests/ios_host_app/FlutterUITests/FlutterUITests.m +++ b/dev/integration_tests/ios_host_app/FlutterUITests/FlutterUITests.m @@ -126,30 +126,6 @@ static const CGFloat kStandardTimeOut = 60.0; XCTAssertTrue([app.navigationBars[@"Flutter iOS Demos Home"] waitForExistenceWithTimeout:kStandardTimeOut]); } -- (void)testResize { - XCUIApplication *app = self.app; - - [self waitForAndTapElement:app.buttons[@"Dynamic Content Resizing"]]; - XCUIElement *flutterView = app.otherElements[@"flutter_view"]; - - CGRect flutterViewFrame = flutterView.frame; - CGSize flutterViewSize = flutterViewFrame.size; - - XCTAssertTrue(flutterViewSize.height == 100); - - [self waitForAndTapElement: app.otherElements[@"flutter_view"]]; - - XCUIElement *flutterViewPostClick = app.otherElements[@"flutter_view"]; - CGRect flutterViewFramePostClick = flutterViewPostClick.frame; - CGSize flutterViewSizePostClick = flutterViewFramePostClick.size; - - XCTAssertTrue(flutterViewSizePostClick.height == 200); - - // Back navigation. - [app.navigationBars[@"Dynamic Content Resizing"].buttons[@"Flutter iOS Demos Home"] tap]; - XCTAssertTrue([app.navigationBars[@"Flutter iOS Demos Home"] waitForExistenceWithTimeout:kStandardTimeOut]); -} - - (void)waitForAndTapElement:(XCUIElement *)element { NSPredicate *hittable = [NSPredicate predicateWithFormat:@"exists == YES AND hittable == YES"]; [self expectationForPredicate:hittable evaluatedWithObject:element handler:nil]; diff --git a/dev/integration_tests/ios_host_app/Host.xcodeproj/project.pbxproj b/dev/integration_tests/ios_host_app/Host.xcodeproj/project.pbxproj index bf390e4896f..f782c3aa32a 100644 --- a/dev/integration_tests/ios_host_app/Host.xcodeproj/project.pbxproj +++ b/dev/integration_tests/ios_host_app/Host.xcodeproj/project.pbxproj @@ -13,7 +13,6 @@ 74F97871215AB9E9005A0F04 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 74F9786F215AB9E9005A0F04 /* LaunchScreen.storyboard */; }; 74F97874215AB9E9005A0F04 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 74F97873215AB9E9005A0F04 /* main.m */; }; 7E06ECD9FAEFCA4A0ED04D6E /* libPods-FlutterUITests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 327E8CC22A494E7D7155FB58 /* libPods-FlutterUITests.a */; }; - F2D997DE2EA8BCB0002FC7EC /* DynamicResizingViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = F2D997DD2EA8BCB0002FC7EC /* DynamicResizingViewController.m */; }; F7C2661424AC18D00085742D /* DualFlutterViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = F7C2660E24AC18D00085742D /* DualFlutterViewController.m */; }; F7C2661524AC18D00085742D /* FullScreenViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = F7C2660F24AC18D00085742D /* FullScreenViewController.m */; }; F7C2661624AC18D00085742D /* HybridViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = F7C2661124AC18D00085742D /* HybridViewController.m */; }; @@ -46,8 +45,6 @@ 8E6751F293967EE3DFF4178A /* Pods-FlutterUITests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-FlutterUITests.release.xcconfig"; path = "Pods/Target Support Files/Pods-FlutterUITests/Pods-FlutterUITests.release.xcconfig"; sourceTree = ""; }; 91B7D4263BFD246A27391225 /* Pods-Host.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Host.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Host/Pods-Host.debug.xcconfig"; sourceTree = ""; }; E20960BD8B505D605FE82853 /* libPods-Host.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Host.a"; sourceTree = BUILT_PRODUCTS_DIR; }; - F2D997DC2EA8BCB0002FC7EC /* DynamicResizingViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DynamicResizingViewController.h; sourceTree = ""; }; - F2D997DD2EA8BCB0002FC7EC /* DynamicResizingViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = DynamicResizingViewController.m; sourceTree = ""; }; F7C2660E24AC18D00085742D /* DualFlutterViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DualFlutterViewController.m; sourceTree = ""; }; F7C2660F24AC18D00085742D /* FullScreenViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FullScreenViewController.m; sourceTree = ""; }; F7C2661024AC18D00085742D /* HybridViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HybridViewController.h; sourceTree = ""; }; @@ -106,8 +103,6 @@ 74F97863215AB9E8005A0F04 /* Host */ = { isa = PBXGroup; children = ( - F2D997DC2EA8BCB0002FC7EC /* DynamicResizingViewController.h */, - F2D997DD2EA8BCB0002FC7EC /* DynamicResizingViewController.m */, F7C2661724AC18DD0085742D /* MainViewController.h */, F7C2661A24AC18DD0085742D /* MainViewController.m */, F7C2661924AC18DD0085742D /* NativeViewController.h */, @@ -289,14 +284,10 @@ inputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-FlutterUITests/Pods-FlutterUITests-frameworks-${CONFIGURATION}-input-files.xcfilelist", ); - inputPaths = ( - ); name = "[CP] Embed Pods Frameworks"; outputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-FlutterUITests/Pods-FlutterUITests-frameworks-${CONFIGURATION}-output-files.xcfilelist", ); - outputPaths = ( - ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-FlutterUITests/Pods-FlutterUITests-frameworks.sh\"\n"; @@ -314,8 +305,6 @@ "${SRCROOT}/../hello/.ios/Flutter/flutter_export_environment.sh", ); name = "[CP-User] Run Flutter Build hello Script"; - outputPaths = ( - ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "set -e\nset -u\nsource \"${SRCROOT}/../hello/.ios/Flutter/flutter_export_environment.sh\"\n\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/xcode_backend.sh build"; @@ -328,14 +317,10 @@ inputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-Host/Pods-Host-frameworks-${CONFIGURATION}-input-files.xcfilelist", ); - inputPaths = ( - ); name = "[CP] Embed Pods Frameworks"; outputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-Host/Pods-Host-frameworks-${CONFIGURATION}-output-files.xcfilelist", ); - outputPaths = ( - ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Host/Pods-Host-frameworks.sh\"\n"; @@ -353,8 +338,6 @@ "${SRCROOT}/../hello/.ios/Flutter/flutter_export_environment.sh", ); name = "[CP-User] Run Flutter Build hello Script"; - outputPaths = ( - ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "set -e\nset -u\nsource \"${SRCROOT}/../hello/.ios/Flutter/flutter_export_environment.sh\"\n\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/xcode_backend.sh build"; @@ -389,7 +372,6 @@ buildActionMask = 2147483647; files = ( F7C2661524AC18D00085742D /* FullScreenViewController.m in Sources */, - F2D997DE2EA8BCB0002FC7EC /* DynamicResizingViewController.m in Sources */, F7C2661424AC18D00085742D /* DualFlutterViewController.m in Sources */, F7C2661C24AC18DD0085742D /* MainViewController.m in Sources */, 74F97874215AB9E9005A0F04 /* main.m in Sources */, diff --git a/dev/integration_tests/ios_host_app/Host/DynamicResizingViewController.h b/dev/integration_tests/ios_host_app/Host/DynamicResizingViewController.h deleted file mode 100644 index 3e02dd71208..00000000000 --- a/dev/integration_tests/ios_host_app/Host/DynamicResizingViewController.h +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright 2014 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. - -#import -#import - -NS_ASSUME_NONNULL_BEGIN - -@interface DynamicResizingViewController : UIViewController - -@property (readonly, strong, nonatomic) FlutterViewController* flutterViewController; - -@end - -NS_ASSUME_NONNULL_END diff --git a/dev/integration_tests/ios_host_app/Host/DynamicResizingViewController.m b/dev/integration_tests/ios_host_app/Host/DynamicResizingViewController.m deleted file mode 100644 index 5e5a20418a1..00000000000 --- a/dev/integration_tests/ios_host_app/Host/DynamicResizingViewController.m +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright 2014 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. - -#import - -#import "DynamicResizingViewController.h" - -@interface DynamicResizingViewController () - -@end - -@implementation DynamicResizingViewController { - FlutterBasicMessageChannel *_messageChannel; -} - -- (void)viewDidLoad { - [super viewDidLoad]; - - self.view.backgroundColor = [UIColor systemBackgroundColor]; - self.title = @"Dynamic Content Resizing"; - - UIScrollView *scrollView = [[UIScrollView alloc] init]; - scrollView.translatesAutoresizingMaskIntoConstraints = NO; - [self.view addSubview:scrollView]; - - UIStackView *stackView = [[UIStackView alloc] init]; - stackView.translatesAutoresizingMaskIntoConstraints = NO; - stackView.axis = UILayoutConstraintAxisVertical; - stackView.spacing = 10; - [scrollView addSubview:stackView]; - - [NSLayoutConstraint activateConstraints:@[ - [scrollView.topAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.topAnchor], - [scrollView.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor], - [scrollView.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor], - [scrollView.bottomAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.bottomAnchor] - ]]; - - [NSLayoutConstraint activateConstraints:@[ - [stackView.topAnchor constraintEqualToAnchor:scrollView.contentLayoutGuide.topAnchor], - [stackView.leadingAnchor constraintEqualToAnchor:scrollView.contentLayoutGuide.leadingAnchor], - [stackView.trailingAnchor constraintEqualToAnchor:scrollView.contentLayoutGuide.trailingAnchor], - [stackView.bottomAnchor constraintEqualToAnchor:scrollView.contentLayoutGuide.bottomAnchor], - - [stackView.widthAnchor constraintEqualToAnchor:scrollView.frameLayoutGuide.widthAnchor] - ]]; - - for (int index = 1; index <= 50; index++) { - if (index == 10) { - _flutterViewController = [[FlutterViewController alloc] init]; - [_flutterViewController setInitialRoute:@"resize"]; - _flutterViewController.autoResizable = true; - [self addChildViewController:_flutterViewController]; - [stackView addArrangedSubview:_flutterViewController.view]; - _flutterViewController.view.translatesAutoresizingMaskIntoConstraints = NO; - _flutterViewController.view.accessibilityIdentifier = @"flutter_view"; - [_flutterViewController didMoveToParentViewController:self]; - } else { - UILabel *label = [[UILabel alloc] init]; - label.text = [NSString stringWithFormat:@" Hello from iOS %d ", index]; - label.backgroundColor = (index % 2 == 0) ? [UIColor systemGray5Color] : [UIColor systemGray3Color]; - label.translatesAutoresizingMaskIntoConstraints = NO; - - [label.heightAnchor constraintEqualToConstant:44].active = YES; - - [stackView addArrangedSubview:label]; - } - } -} - -@end diff --git a/dev/integration_tests/ios_host_app/Host/MainViewController.m b/dev/integration_tests/ios_host_app/Host/MainViewController.m index 2f5796de3c6..f2c1c66096b 100644 --- a/dev/integration_tests/ios_host_app/Host/MainViewController.m +++ b/dev/integration_tests/ios_host_app/Host/MainViewController.m @@ -9,7 +9,6 @@ #import "FullScreenViewController.h" #import "HybridViewController.h" #import "NativeViewController.h" -#import "DynamicResizingViewController.h" @interface MainViewController () @@ -45,7 +44,6 @@ self.flutterViewWarmButton = [self addButton:@"Flutter View (Warm)" action:@selector(showFlutterViewWarm)]; [self addButton:@"Hybrid View (Warm)" action:@selector(showHybridView)]; [self addButton:@"Dual Flutter View (Cold)" action:@selector(showDualView)]; - [self addButton:@"Dynamic Content Resizing" action:@selector(showContentResizingView)]; } - (FlutterEngine *)engine { @@ -76,13 +74,6 @@ animated:YES]; } -- (void)showContentResizingView { - DynamicResizingViewController *resizingViewController = - [[DynamicResizingViewController alloc] init]; - [self.navigationController pushViewController:resizingViewController - animated:NO]; -} - - (void)showFullScreenCold { FullScreenViewController *flutterViewController = [[FullScreenViewController alloc] init]; diff --git a/dev/integration_tests/ios_host_app/flutterapp/lib/main b/dev/integration_tests/ios_host_app/flutterapp/lib/main index 066ce1c0e3e..87557d41728 100644 --- a/dev/integration_tests/ios_host_app/flutterapp/lib/main +++ b/dev/integration_tests/ios_host_app/flutterapp/lib/main @@ -10,7 +10,6 @@ import 'package:flutter/services.dart'; import 'package:ffi_package/ffi_package.dart'; import 'marquee.dart'; -import 'resize.dart'; /// Route names. (See [main] for more details.) /// @@ -19,7 +18,6 @@ const String greenMarqueeRouteName = 'marquee_green'; const String purpleMarqueeRouteName = 'marquee_purple'; const String fullscreenRouteName = 'full'; const String hybridRouteName = 'hybrid'; -const String resizeRouteName = 'resize'; /// Channel used to let the Flutter app know to reset the app to a specific /// route. See the [run] method. @@ -57,9 +55,6 @@ Future run(String? name) async { case purpleMarqueeRouteName: runApp(Marquee(color: Colors.purple[400])); break; - case resizeRouteName: - runApp(ResizeApp()); - break; case fullscreenRouteName: case hybridRouteName: default: diff --git a/dev/integration_tests/ios_host_app/flutterapp/lib/resize b/dev/integration_tests/ios_host_app/flutterapp/lib/resize deleted file mode 100644 index 4b54bd39088..00000000000 --- a/dev/integration_tests/ios_host_app/flutterapp/lib/resize +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright 2014 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. - -import 'package:flutter/material.dart'; - -class ResizeApp extends StatefulWidget { - /// Creates the [ResizeApp]. - const ResizeApp({super.key}); - - @override - State createState() => _ResizeAppState(); -} - -class _ResizeAppState extends State { - int _listSize = 1; - void _addToList() { - setState(() { - _listSize++; - }); - } - - @override - Widget build(BuildContext context) { - return GestureDetector( - onTap: _addToList, // The tap anywhere logic - child: Center( - heightFactor: 1, - child: Directionality( - textDirection: TextDirection.ltr, - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - for (int i = 0; i < _listSize; i++) - Container(color: HSVColor.fromAHSV(1, (10.0 * i), 1, 1).toColor(), height: 100), - ], - ), - ), - ), - ); - } -} \ No newline at end of file diff --git a/engine/src/flutter/fml/task_runner.cc b/engine/src/flutter/fml/task_runner.cc index 1e869243e14..8920a8f73ab 100644 --- a/engine/src/flutter/fml/task_runner.cc +++ b/engine/src/flutter/fml/task_runner.cc @@ -13,7 +13,6 @@ #include "flutter/fml/message_loop.h" #include "flutter/fml/message_loop_impl.h" #include "flutter/fml/message_loop_task_queues.h" -#include "flutter/fml/synchronization/waitable_event.h" namespace fml { diff --git a/engine/src/flutter/shell/platform/darwin/ios/framework/Headers/FlutterViewController.h b/engine/src/flutter/shell/platform/darwin/ios/framework/Headers/FlutterViewController.h index a92b8402272..19fe17d0ce9 100644 --- a/engine/src/flutter/shell/platform/darwin/ios/framework/Headers/FlutterViewController.h +++ b/engine/src/flutter/shell/platform/darwin/ios/framework/Headers/FlutterViewController.h @@ -254,19 +254,6 @@ FLUTTER_DARWIN_EXPORT */ @property(nonatomic, readonly) BOOL engineAllowHeadlessExecution; -/** - * Controls whether the created view can be sized based on its content. - * When set to `YES`, the FlutterView will be the same size as the outermost widget. - * Cannot be used with unbounded height widgets, such as Scaffold. - * This property is intended to be used with Add-to-App scenarios. - * - * Once auto resizing is enabled, the FlutterView will rely on custom constraints from then on. - * Avoid disabling it after enabling, as behaviour will then be undefined. - * - * Default is `NO`. - */ -@property(nonatomic, getter=isAutoResizable) BOOL autoResizable; - @end NS_ASSUME_NONNULL_END diff --git a/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterMetalLayer.mm b/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterMetalLayer.mm index 00c0e807b28..a291fda8c71 100644 --- a/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterMetalLayer.mm +++ b/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterMetalLayer.mm @@ -404,14 +404,6 @@ extern CFTimeInterval display_link_target; } - (void)presentOnMainThread:(FlutterTexture*)texture { - if (texture.texture.width != _drawableSize.width || - texture.texture.height != _drawableSize.height) { - // This texture was created with an old size, but the view has since been - // resized. Do not present this stale frame to avoid distortion. The texture - // will be correctly recycled on the next frame. - return; - } - // This is needed otherwise frame gets skipped on touch begin / end. Go figure. // Might also be placebo [self setNeedsDisplay]; diff --git a/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterPlatformViewsController.mm b/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterPlatformViewsController.mm index 931b804401b..8fdaf2fb76c 100644 --- a/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterPlatformViewsController.mm +++ b/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterPlatformViewsController.mm @@ -665,19 +665,8 @@ static CGRect GetCGRectFromDlRect(const DlRect& clipDlRect) { withIosContext:(const std::shared_ptr&)iosContext { TRACE_EVENT0("flutter", "PlatformViewsController::SubmitFrame"); - // No platform views to render. + // No platform views to render; we're done. if (self.flutterView == nil || (self.compositionOrder.empty() && !self.hadPlatformViews)) { - // No platform views to render but the FlutterView may need to be resized. - if (self.flutterView != nil) { - if (self.platformTaskRunner->RunsTasksOnCurrentThread()) { - [self performResize:self.frameSize]; - } else { - PostTaskSync(self.platformTaskRunner, [self, frameSize = self.frameSize]() mutable { - [self performResize:frameSize]; - }); - } - } - self.hadPlatformViews = NO; return background_frame->Submit(); } @@ -763,13 +752,15 @@ static CGRect GetCGRectFromDlRect(const DlRect& clipDlRect) { std::vector> unusedLayers = self.layerPool->RemoveUnusedLayers(); self.layerPool->RecycleLayers(); + auto task = [self, // platformViewLayers = std::move(platformViewLayers), // currentCompositionParams = self.currentCompositionParams, // viewsToRecomposite = self.viewsToRecomposite, // compositionOrder = self.compositionOrder, // unusedLayers = std::move(unusedLayers), // - surfaceFrames = std::move(surfaceFrames)]() mutable { + surfaceFrames = std::move(surfaceFrames) // + ]() mutable { [self performSubmit:platformViewLayers currentCompositionParams:currentCompositionParams viewsToRecomposite:viewsToRecomposite @@ -779,6 +770,7 @@ static CGRect GetCGRectFromDlRect(const DlRect& clipDlRect) { }; fml::TaskRunner::RunNowOrPostTask(self.platformTaskRunner, fml::MakeCopyable(std::move(task))); + return didEncode; } @@ -807,16 +799,6 @@ static CGRect GetCGRectFromDlRect(const DlRect& clipDlRect) { } } -- (void)performResize:(const flutter::DlISize&)frameSize { - TRACE_EVENT0("flutter", "PlatformViewsController::PerformResize"); - FML_DCHECK([[NSThread currentThread] isMainThread]); - - if (self.flutterView != nil) { - [(FlutterView*)self.flutterView - setIntrinsicContentSize:CGSizeMake(frameSize.width, frameSize.height)]; - } -} - - (void)performSubmit:(const LayersMap&)platformViewLayers currentCompositionParams: (std::unordered_map&)currentCompositionParams @@ -1019,18 +1001,4 @@ static CGRect GetCGRectFromDlRect(const DlRect& clipDlRect) { return _previousCompositionOrder; } -namespace { -void PostTaskSync(const fml::RefPtr& task_runner, fml::closure task) { - FML_DCHECK(!task_runner->RunsTasksOnCurrentThread()); - fml::AutoResetWaitableEvent latch; - task_runner->PostTask([&latch, task = std::move(task)]() { - if (task) { - task(); - } - latch.Signal(); - }); - latch.Wait(); -} -} // namespace - @end diff --git a/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterView.h b/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterView.h index fdaf8b9e266..7f3a32ed63f 100644 --- a/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterView.h +++ b/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterView.h @@ -29,23 +29,6 @@ - (void)flutterViewAccessibilityDidCall; @end -/** - * A custom NSLayoutConstraint subclass for autoresizing the FlutterView. - * This class is a special NSLayoutConstraint used internally to - * manage the dynamic resizing of a FlutterView based on its content. - * - * In native, `intrinsicContentSize` is a public property that determines the preferred - * sized of an UIView, based on it's internal content. Given a position and layout constraints, - * this allows the UIView to size itself. - * However, the mechanism in which this sizing occurs based on`intrinsicContentSize` - * and the layout constraints is private. - * - * This custom NSLayoutConstraint allows us to replicate this mechanizm without needing to rely - * on private APIs. - */ -@interface FlutterAutoResizeLayoutConstraint : NSLayoutConstraint -@end - @interface FlutterView : UIView - (instancetype)init NS_UNAVAILABLE; @@ -60,19 +43,6 @@ - (UIScreen*)screen; - (MTLPixelFormat)pixelFormat; -/** - * A method that sets the instrinsic content size - * This is used when autoResizable is enabled. - */ -- (void)setIntrinsicContentSize:(CGSize)size; - -/** - * A method that resets and recalculates the instrinsic content size - * Currently called when the device orientation changes. - */ -- (void)resetIntrinsicContentSize; -@property(nonatomic, assign, readwrite) BOOL autoResizable; - @end #endif // FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_SOURCE_FLUTTERVIEW_H_ diff --git a/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterView.mm b/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterView.mm index 19b815a51c9..76ee723f924 100644 --- a/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterView.mm +++ b/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterView.mm @@ -16,12 +16,8 @@ FLUTTER_ASSERT_ARC @property(nonatomic, weak) UIWindowScene* previousScene; @end -@implementation FlutterAutoResizeLayoutConstraint -@end - @implementation FlutterView { BOOL _isWideGamutEnabled; - CGSize _intrinsicSize; } - (instancetype)init { @@ -43,70 +39,6 @@ FLUTTER_ASSERT_ARC return self.window.windowScene.screen; } -// iOS has a concept of "intrinsicContentSize", which indicates the size a view would like to be -// based on its content. When an intrinsicContentSize is set, iOS will automatically add Auto Layout -// constraints for the width and/or height. However, the constraints use a private API. There are -// situations where we may want to filter these constraints. To avoid using a private API, Flutter -// creates a custom constraint called FlutterAutoResizeLayoutConstraint to add a width/height -// constraint that reflects the intrinsicContentSize. -- (void)setIntrinsicContentSize:(CGSize)size { - if (!self.autoResizable) { - return; - } - - CGFloat scale = self.window.windowScene.screen.scale; - CGSize scaledSize = CGSizeMake(size.width / scale, size.height / scale); - - CGSize roundedScaleSize = CGSizeMake(roundf(scaledSize.width), roundf(scaledSize.height)); - CGSize roundedIntrinsicSize = - CGSizeMake(roundf(_intrinsicSize.width), roundf(_intrinsicSize.height)); - - // If the size has not changed, don't update constraints. - if (CGSizeEqualToSize(roundedIntrinsicSize, roundedScaleSize)) { - return; - } - _intrinsicSize = scaledSize; - - self.translatesAutoresizingMaskIntoConstraints = false; - - // Remove any existing FlutterAutoResizeLayoutConstraint - [self removeAutoResizeLayoutConstraints]; - - FlutterAutoResizeLayoutConstraint* widthConstraint = - [FlutterAutoResizeLayoutConstraint constraintWithItem:self - attribute:NSLayoutAttributeWidth - relatedBy:NSLayoutRelationEqual - toItem:nil - attribute:NSLayoutAttributeNotAnAttribute - multiplier:1.0 - constant:scaledSize.width]; - - FlutterAutoResizeLayoutConstraint* heightConstraint = - [FlutterAutoResizeLayoutConstraint constraintWithItem:self - attribute:NSLayoutAttributeHeight - relatedBy:NSLayoutRelationEqual - toItem:nil - attribute:NSLayoutAttributeNotAnAttribute - multiplier:1.0 - constant:scaledSize.height]; - - [NSLayoutConstraint activateConstraints:@[ widthConstraint, heightConstraint ]]; - [self setNeedsLayout]; -} - -- (void)resetIntrinsicContentSize { - _intrinsicSize = CGSizeMake(UIViewNoIntrinsicMetric, UIViewNoIntrinsicMetric); - [self removeAutoResizeLayoutConstraints]; -} - -- (void)removeAutoResizeLayoutConstraints { - for (NSLayoutConstraint* constraint in self.constraints) { - if ([constraint isKindOfClass:[FlutterAutoResizeLayoutConstraint class]]) { - constraint.active = NO; - } - } -} - - (MTLPixelFormat)pixelFormat { if ([self.layer isKindOfClass:[CAMetalLayer class]]) { // It is a known Apple bug that CAMetalLayer incorrectly reports its supported @@ -147,8 +79,6 @@ FLUTTER_ASSERT_ARC _delegate = delegate; _isWideGamutEnabled = isWideGamutEnabled; self.layer.opaque = opaque; - _autoResizable = NO; - _intrinsicSize = CGSizeMake(UIViewNoIntrinsicMetric, UIViewNoIntrinsicMetric); } return self; 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 48480ec61cd..371611319d9 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 @@ -101,6 +101,7 @@ typedef struct MouseState { * Whether we should ignore viewport metrics updates during rotation transition. */ @property(nonatomic, assign) BOOL shouldIgnoreViewportMetricsUpdatesDuringRotation; + /** * Keyboard animation properties */ @@ -130,10 +131,6 @@ typedef struct MouseState { /// the same with frame rate of rendering. @property(nonatomic, strong) VSyncClient* touchRateCorrectionVSyncClient; -/// The size of the FlutterView's frame, as determined by auto-layout, -/// before Flutter's custom auto-resizing constraints are applied. -@property(nonatomic, assign) CGSize sizeBeforeAutoResized; - /* * Mouse and trackpad gesture recognizers */ @@ -1461,7 +1458,6 @@ static flutter::PointerData::DeviceKind DeviceKindFromTouchType(UITouch* touch) bool firstViewBoundsUpdate = !_viewportMetrics.physical_width; _viewportMetrics.device_pixel_ratio = scale; [self setViewportMetricsSize]; - [self checkAndUpdateAutoResizeConstraints]; [self setViewportMetricsPaddings]; [self updateViewportMetricsIfNeeded]; @@ -1490,89 +1486,6 @@ static flutter::PointerData::DeviceKind DeviceKindFromTouchType(UITouch* touch) } } -- (BOOL)isAutoResizable { - return self.flutterView.autoResizable; -} - -- (void)setAutoResizable:(BOOL)value { - self.flutterView.autoResizable = value; - self.flutterView.contentMode = UIViewContentModeCenter; -} - -- (void)checkAndUpdateAutoResizeConstraints { - if (!self.isAutoResizable) { - return; - } - - [self updateAutoResizeConstraints]; -} - -/** - * Updates the FlutterAutoResizeLayoutConstraints based on the view's - * current frame. - * - * This method is invoked during viewDidLayoutSubviews, at which point the - * view has completed its subview layout and applied any existing Auto Layout - * constraints. - * - * Initially, the view's frame is used to determine the maximum size allowed - * by the native layout system. This size is then used to establish the viewport - * constraints for the Flutter engine. - * - * A critical consideration is that this initial frame-based sizing is only - * applicable if FlutterAutoResizeLayoutConstraints have not yet been applied - * by Flutter. Once Flutter applies its own FlutterAutoResizeLayoutConstraints, - * these constraints will subsequently dictate the view's frame. - * - * This interaction imposes a limitation: native layout constraints that are - * updated after Flutter has applied its auto-resize constraints may not - * function as expected or properly influence the FlutterView's size. - */ -- (void)updateAutoResizeConstraints { - BOOL hasBeenAutoResized = NO; - for (NSLayoutConstraint* constraint in self.view.constraints) { - if ([constraint isKindOfClass:[FlutterAutoResizeLayoutConstraint class]]) { - hasBeenAutoResized = YES; - break; - } - } - if (!hasBeenAutoResized) { - self.sizeBeforeAutoResized = self.view.frame.size; - } - - CGFloat maxWidth = self.sizeBeforeAutoResized.width; - CGFloat maxHeight = self.sizeBeforeAutoResized.height; - CGFloat minWidth = self.sizeBeforeAutoResized.width; - CGFloat minHeight = self.sizeBeforeAutoResized.height; - - // maxWidth or maxHeight may be 0 when the width/height are ambiguous, eg. for - // unsized widgets - if (maxWidth == 0) { - maxWidth = CGFLOAT_MAX; - [FlutterLogger - logWarning: - @"Warning: The outermost widget in the autoresizable Flutter view is unsized or has " - @"ambiguous dimensions, causing the host native view's width to be 0. The autoresizing " - @"logic is setting the viewport constraint to unbounded DBL_MAX to prevent " - @"rendering failure. Please ensure your top-level Flutter widget has explicit " - @"constraints (e.g., using SizedBox or Container)."]; - } - if (maxHeight == 0) { - maxHeight = CGFLOAT_MAX; - [FlutterLogger - logWarning: - @"Warning: The outermost widget in the autoresizable Flutter view is unsized or has " - @"ambiguous dimensions, causing the host native view's width to be 0. The autoresizing " - @"logic is setting the viewport constraint to unbounded DBL_MAX to prevent " - @"rendering failure. Please ensure your top-level Flutter widget has explicit " - @"constraints (e.g., using SizedBox or Container)."]; - } - _viewportMetrics.physical_min_width_constraint = minWidth * _viewportMetrics.device_pixel_ratio; - _viewportMetrics.physical_max_width_constraint = maxWidth * _viewportMetrics.device_pixel_ratio; - _viewportMetrics.physical_min_height_constraint = minHeight * _viewportMetrics.device_pixel_ratio; - _viewportMetrics.physical_max_height_constraint = maxHeight * _viewportMetrics.device_pixel_ratio; -} - - (void)viewSafeAreaInsetsDidChange { [self setViewportMetricsPaddings]; [self updateViewportMetricsIfNeeded]; @@ -2282,12 +2195,6 @@ static flutter::PointerData::DeviceKind DeviceKindFromTouchType(UITouch* touch) - (void)traitCollectionDidChange:(UITraitCollection*)previousTraitCollection { [super traitCollectionDidChange:previousTraitCollection]; [self onUserSettingsChanged:nil]; - - // Since this method can get triggered by changes in device orientation, reset and recalculate the - // instrinsic size. - if (self.isAutoResizable) { - [self.flutterView resetIntrinsicContentSize]; - } } - (void)onUserSettingsChanged:(NSNotification*)notification { diff --git a/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterViewControllerTest.mm b/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterViewControllerTest.mm index 66614c12163..97d105f4422 100644 --- a/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterViewControllerTest.mm +++ b/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterViewControllerTest.mm @@ -142,8 +142,6 @@ extern NSNotificationName const FlutterViewControllerWillDealloc; nextAction:(void (^)())next API_AVAILABLE(ios(13.4)); - (void)discreteScrollEvent:(UIPanGestureRecognizer*)recognizer; - (void)updateViewportMetricsIfNeeded; -- (void)updateAutoResizeConstraints; -- (void)checkAndUpdateAutoResizeConstraints; - (void)onUserSettingsChanged:(NSNotification*)notification; - (void)applicationWillTerminate:(NSNotification*)notification; - (void)goToApplicationLifecycle:(nonnull NSString*)state; @@ -999,44 +997,6 @@ extern NSNotificationName const FlutterViewControllerWillDealloc; OCMVerifyAll(mockEngine); } -- (void)testUpdatedViewportMetricsDoesResizeFlutterViewWhenAutoResizable { - FlutterEngine* mockEngine = OCMPartialMock([[FlutterEngine alloc] init]); - [mockEngine createShell:@"" libraryURI:@"" initialRoute:nil]; - - FlutterViewController* realVC = [[FlutterViewController alloc] initWithEngine:mockEngine - nibName:nil - bundle:nil]; - id mockVC = OCMPartialMock(realVC); - mockEngine.viewController = mockVC; - - OCMExpect([mockVC updateAutoResizeConstraints]); - - [mockVC setAutoResizable:YES]; - - [mockVC viewDidLayoutSubviews]; - - OCMVerifyAll(mockVC); -} - -- (void)testUpdatedViewportMetricsDoesNotResizeFlutterViewWhenNotAutoResizable { - FlutterEngine* mockEngine = OCMPartialMock([[FlutterEngine alloc] init]); - [mockEngine createShell:@"" libraryURI:@"" initialRoute:nil]; - - FlutterViewController* realVC = [[FlutterViewController alloc] initWithEngine:mockEngine - nibName:nil - bundle:nil]; - id mockVC = OCMPartialMock(realVC); - mockEngine.viewController = mockVC; - - OCMReject([mockVC updateAutoResizeConstraints]); - - [mockVC setAutoResizable:NO]; - - [mockVC viewDidLayoutSubviews]; - - OCMVerifyAll(mockVC); -} - - (void)testUpdateViewportMetricsIfNeeded_DoesNotInvokeEngineWhenShouldBeIgnoredDuringRotation { FlutterEngine* mockEngine = OCMPartialMock([[FlutterEngine alloc] init]); [mockEngine createShell:@"" libraryURI:@"" initialRoute:nil]; @@ -1319,36 +1279,6 @@ extern NSNotificationName const FlutterViewControllerWillDealloc; return mockTraitCollection; } -- (void)testTraitCollectionDidChangeCallsResetIntrinsicContentSizeWhenAutoResizable { - // Setup test. - id mockEngine = OCMPartialMock([[FlutterEngine alloc] init]); - [mockEngine createShell:@"" libraryURI:@"" initialRoute:nil]; - - FlutterViewController* realVC = [[FlutterViewController alloc] initWithEngine:mockEngine - nibName:nil - bundle:nil]; - id partialMockVC = OCMPartialMock(realVC); - - id mockFlutterView = OCMClassMock([FlutterView class]); - OCMStub([partialMockVC flutterView]).andReturn(mockFlutterView); - - // Ensure isAutoResizable is YES - OCMStub([partialMockVC isAutoResizable]).andReturn(YES); - - // Expect resetIntrinsicContentSize to be called on mockFlutterView - OCMExpect([mockFlutterView resetIntrinsicContentSize]); - - // Exercise behavior under test. - [partialMockVC traitCollectionDidChange:nil]; - - // Verify behavior. - OCMVerifyAll(mockFlutterView); - - // Clean up mocks - [partialMockVC stopMocking]; - [mockFlutterView stopMocking]; -} - #pragma mark - Platform Contrast - (void)testItReportsNormalPlatformContrastByDefault {