diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index 02e8ce98e055c..831528cd9d698 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -2519,6 +2519,9 @@ ORIGIN: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterTextI ORIGIN: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterTextInputPlugin.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterTextInputPlugin.mm + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterTextInputPluginTest.mm + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterTextureRegistryRelay.h + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterTextureRegistryRelay.mm + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterTextureRegistryRelayTest.mm + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterUIPressProxy.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterUIPressProxy.mm + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterUmbrellaImport.m + ../../../flutter/LICENSE @@ -5000,6 +5003,9 @@ FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterTextInp FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterTextInputPlugin.h FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterTextInputPlugin.mm FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterTextInputPluginTest.mm +FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterTextureRegistryRelay.h +FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterTextureRegistryRelay.mm +FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterTextureRegistryRelayTest.mm FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterUIPressProxy.h FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterUIPressProxy.mm FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterUmbrellaImport.m diff --git a/shell/platform/darwin/ios/BUILD.gn b/shell/platform/darwin/ios/BUILD.gn index 63ca777abfbd9..8492a1475e517 100644 --- a/shell/platform/darwin/ios/BUILD.gn +++ b/shell/platform/darwin/ios/BUILD.gn @@ -106,6 +106,8 @@ source_set("flutter_framework_source") { "framework/Source/FlutterSemanticsScrollView.mm", "framework/Source/FlutterSpellCheckPlugin.h", "framework/Source/FlutterSpellCheckPlugin.mm", + "framework/Source/FlutterTextureRegistryRelay.h", + "framework/Source/FlutterTextureRegistryRelay.mm", "framework/Source/FlutterUIPressProxy.h", "framework/Source/FlutterUIPressProxy.mm", "framework/Source/FlutterUndoManagerDelegate.h", @@ -282,6 +284,7 @@ shared_library("ios_test_flutter") { "framework/Source/FlutterRestorationPluginTest.mm", "framework/Source/FlutterSpellCheckPluginTest.mm", "framework/Source/FlutterTextInputPluginTest.mm", + "framework/Source/FlutterTextureRegistryRelayTest.mm", "framework/Source/FlutterUndoManagerPluginTest.mm", "framework/Source/FlutterViewControllerTest.mm", "framework/Source/SemanticsObjectTest.mm", diff --git a/shell/platform/darwin/ios/framework/Headers/FlutterEngine.h b/shell/platform/darwin/ios/framework/Headers/FlutterEngine.h index 5867ea36aa6c6..57ac4c22d34bf 100644 --- a/shell/platform/darwin/ios/framework/Headers/FlutterEngine.h +++ b/shell/platform/darwin/ios/framework/Headers/FlutterEngine.h @@ -56,7 +56,7 @@ extern NSString* const FlutterDefaultInitialRoute; * One of these methods must be invoked before calling `-setViewController:`. */ FLUTTER_DARWIN_EXPORT -@interface FlutterEngine : NSObject +@interface FlutterEngine : NSObject /** * Default initializer for a FlutterEngine. @@ -424,6 +424,11 @@ FLUTTER_DARWIN_EXPORT */ @property(nonatomic, readonly) NSObject* binaryMessenger; +/** + * The `FlutterTextureRegistry` associated with this FlutterEngine (used to register textures). + */ +@property(nonatomic, readonly) NSObject* textureRegistry; + /** * The UI Isolate ID of the engine. * diff --git a/shell/platform/darwin/ios/framework/Source/FlutterEngine.mm b/shell/platform/darwin/ios/framework/Source/FlutterEngine.mm index 9a0352a360604..480b284678614 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterEngine.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterEngine.mm @@ -26,6 +26,7 @@ #import "flutter/shell/platform/darwin/ios/framework/Source/FlutterPlatformPlugin.h" #import "flutter/shell/platform/darwin/ios/framework/Source/FlutterSpellCheckPlugin.h" #import "flutter/shell/platform/darwin/ios/framework/Source/FlutterTextInputDelegate.h" +#import "flutter/shell/platform/darwin/ios/framework/Source/FlutterTextureRegistryRelay.h" #import "flutter/shell/platform/darwin/ios/framework/Source/FlutterUndoManagerDelegate.h" #import "flutter/shell/platform/darwin/ios/framework/Source/FlutterUndoManagerPlugin.h" #import "flutter/shell/platform/darwin/ios/framework/Source/FlutterViewController_Internal.h" @@ -87,7 +88,8 @@ - (instancetype)initWithPlugin:(NSString*)pluginKey flutterEngine:(FlutterEngine @interface FlutterEngine () + FlutterBinaryMessenger, + FlutterTextureRegistry> // Maintains a dictionary of plugin names that have registered with the engine. Used by // FlutterEngineRegistrar to implement a FlutterPluginRegistrar. @property(nonatomic, readonly) NSMutableDictionary* pluginPublications; @@ -138,6 +140,7 @@ @implementation FlutterEngine { BOOL _allowHeadlessExecution; BOOL _restorationEnabled; FlutterBinaryMessengerRelay* _binaryMessenger; + FlutterTextureRegistryRelay* _textureRegistry; std::unique_ptr _connections; } @@ -197,6 +200,7 @@ - (instancetype)initWithName:(NSString*)labelPrefix [self recreatePlatformViewController]; _binaryMessenger = [[FlutterBinaryMessengerRelay alloc] initWithParent:self]; + _textureRegistry = [[FlutterTextureRegistryRelay alloc] initWithParent:self]; _connections.reset(new flutter::ConnectionCollection()); NSNotificationCenter* center = [NSNotificationCenter defaultCenter]; @@ -261,7 +265,10 @@ - (void)dealloc { [_pluginPublications release]; [_registrars release]; _binaryMessenger.parent = nil; + _textureRegistry.parent = nil; [_binaryMessenger release]; + [_textureRegistry release]; + _textureRegistry = nil; [_isolateId release]; NSNotificationCenter* center = [NSNotificationCenter defaultCenter]; @@ -1073,6 +1080,10 @@ - (void)flutterViewAccessibilityDidCall { return _binaryMessenger; } +- (NSObject*)textureRegistry { + return _textureRegistry; +} + // For test only. Ideally we should create a dependency injector for all dependencies and // remove this. - (void)setBinaryMessenger:(FlutterBinaryMessengerRelay*)binaryMessenger { @@ -1333,7 +1344,7 @@ - (void)dealloc { } - (NSObject*)textures { - return _flutterEngine; + return _flutterEngine.textureRegistry; } - (void)publish:(NSObject*)value { diff --git a/shell/platform/darwin/ios/framework/Source/FlutterTextureRegistryRelay.h b/shell/platform/darwin/ios/framework/Source/FlutterTextureRegistryRelay.h new file mode 100644 index 0000000000000..adbcc5986901a --- /dev/null +++ b/shell/platform/darwin/ios/framework/Source/FlutterTextureRegistryRelay.h @@ -0,0 +1,24 @@ +// 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. + +#import "flutter/shell/platform/darwin/common/framework/Headers/FlutterMacros.h" +#import "flutter/shell/platform/darwin/common/framework/Headers/FlutterTexture.h" + +#if FLUTTER_RUNTIME_MODE == FLUTTER_RUNTIME_MODE_DEBUG +FLUTTER_DARWIN_EXPORT +#endif + +/** + * Wrapper around a weakly held collection of registered textures. + * + * Avoids a retain cycle between plugins and the engine. + */ +@interface FlutterTextureRegistryRelay : NSObject + +/** + * A weak reference to a FlutterEngine that will be passed texture registration. + */ +@property(nonatomic, assign) NSObject* parent; +- (instancetype)initWithParent:(NSObject*)parent; +@end diff --git a/shell/platform/darwin/ios/framework/Source/FlutterTextureRegistryRelay.mm b/shell/platform/darwin/ios/framework/Source/FlutterTextureRegistryRelay.mm new file mode 100644 index 0000000000000..89377f0b4b561 --- /dev/null +++ b/shell/platform/darwin/ios/framework/Source/FlutterTextureRegistryRelay.mm @@ -0,0 +1,42 @@ +// 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. + +#import "flutter/shell/platform/darwin/ios/framework/Source/FlutterTextureRegistryRelay.h" + +#include "flutter/fml/logging.h" + +@implementation FlutterTextureRegistryRelay : NSObject + +#pragma mark - FlutterTextureRegistry + +- (instancetype)initWithParent:(NSObject*)parent { + if (self = [super init]) { + _parent = parent; + } + return self; +} + +- (int64_t)registerTexture:(NSObject*)texture { + if (!self.parent) { + FML_LOG(WARNING) << "Using on an empty registry."; + return 0; + } + return [self.parent registerTexture:texture]; +} + +- (void)textureFrameAvailable:(int64_t)textureId { + if (!self.parent) { + FML_LOG(WARNING) << "Using on an empty registry."; + } + return [self.parent textureFrameAvailable:textureId]; +} + +- (void)unregisterTexture:(int64_t)textureId { + if (!self.parent) { + FML_LOG(WARNING) << "Using on an empty registry."; + } + return [self.parent unregisterTexture:textureId]; +} + +@end diff --git a/shell/platform/darwin/ios/framework/Source/FlutterTextureRegistryRelayTest.mm b/shell/platform/darwin/ios/framework/Source/FlutterTextureRegistryRelayTest.mm new file mode 100644 index 0000000000000..c80cba66decfd --- /dev/null +++ b/shell/platform/darwin/ios/framework/Source/FlutterTextureRegistryRelayTest.mm @@ -0,0 +1,66 @@ +// 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. + +#import "flutter/shell/platform/darwin/ios/framework/Headers/FlutterEngine.h" +#import "flutter/shell/platform/darwin/ios/framework/Source/FlutterTextureRegistryRelay.h" + +#import +#import + +#import "flutter/shell/platform/darwin/common/framework/Headers/FlutterMacros.h" +#import "flutter/shell/platform/darwin/common/framework/Headers/FlutterTexture.h" + +FLUTTER_ASSERT_ARC + +@interface FlutterTextureRegistryRelayTest : XCTestCase +@end + +@implementation FlutterTextureRegistryRelayTest + +- (void)testCreate { + id textureRegistry = OCMProtocolMock(@protocol(FlutterTextureRegistry)); + FlutterTextureRegistryRelay* relay = + [[FlutterTextureRegistryRelay alloc] initWithParent:textureRegistry]; + XCTAssertNotNil(relay); + XCTAssertEqual(textureRegistry, relay.parent); +} + +- (void)testRegisterTexture { + id textureRegistry = OCMProtocolMock(@protocol(FlutterTextureRegistry)); + FlutterTextureRegistryRelay* relay = + [[FlutterTextureRegistryRelay alloc] initWithParent:textureRegistry]; + id texture = OCMProtocolMock(@protocol(FlutterTexture)); + [relay registerTexture:texture]; + OCMVerify([textureRegistry registerTexture:texture]); +} + +- (void)testTextureFrameAvailable { + id textureRegistry = OCMProtocolMock(@protocol(FlutterTextureRegistry)); + FlutterTextureRegistryRelay* relay = + [[FlutterTextureRegistryRelay alloc] initWithParent:textureRegistry]; + [relay textureFrameAvailable:0]; + OCMVerify([textureRegistry textureFrameAvailable:0]); +} + +- (void)testUnregisterTexture { + id textureRegistry = OCMProtocolMock(@protocol(FlutterTextureRegistry)); + FlutterTextureRegistryRelay* relay = + [[FlutterTextureRegistryRelay alloc] initWithParent:textureRegistry]; + [relay unregisterTexture:0]; + OCMVerify([textureRegistry unregisterTexture:0]); +} + +- (void)testRetainCycle { + __weak FlutterEngine* weakEngine; + NSObject* strongRelay; + @autoreleasepool { + id project = OCMClassMock([FlutterDartProject class]); + FlutterEngine* engine = [[FlutterEngine alloc] initWithName:@"foobar" project:project]; + strongRelay = [engine textureRegistry]; + weakEngine = engine; + } + XCTAssertNil(weakEngine); +} + +@end diff --git a/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm b/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm index 7a80c937366cf..d9ffc2c26d5bd 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm @@ -2022,15 +2022,15 @@ - (void)cleanUpConnection:(FlutterBinaryMessengerConnection)connection { #pragma mark - FlutterTextureRegistry - (int64_t)registerTexture:(NSObject*)texture { - return [_engine.get() registerTexture:texture]; + return [_engine.get().textureRegistry registerTexture:texture]; } - (void)unregisterTexture:(int64_t)textureId { - [_engine.get() unregisterTexture:textureId]; + [_engine.get().textureRegistry unregisterTexture:textureId]; } - (void)textureFrameAvailable:(int64_t)textureId { - [_engine.get() textureFrameAvailable:textureId]; + [_engine.get().textureRegistry textureFrameAvailable:textureId]; } - (NSString*)lookupKeyForAsset:(NSString*)asset {