From 1794616b35c9413096a3b3c64d5cd14580d653be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B9=96=E5=8C=97=E6=8D=B7=E6=99=BA=E4=BA=91=E6=8A=80?= =?UTF-8?q?=E6=9C=AF=E6=9C=89=E9=99=90=E5=85=AC=E5=8F=B8?= Date: Mon, 17 Dec 2018 11:43:35 +0800 Subject: [PATCH 01/12] [macos] Add FLEEventChannel --- library/macos/FLEEventChannel.h | 98 +++++++++++++++++++ library/macos/FLEEventChannel.m | 97 ++++++++++++++++++ .../project.pbxproj | 8 ++ 3 files changed, 203 insertions(+) create mode 100644 library/macos/FLEEventChannel.h create mode 100644 library/macos/FLEEventChannel.m diff --git a/library/macos/FLEEventChannel.h b/library/macos/FLEEventChannel.h new file mode 100644 index 000000000..8c127443c --- /dev/null +++ b/library/macos/FLEEventChannel.h @@ -0,0 +1,98 @@ +// Copyright 2018 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +#import "FLEBinaryMessenger.h" +#import "FLEMethodCodec.h" + +/** + * An event sink callback. + * + * @param event The event. + */ +typedef void (^FLEEventSink)(id _Nullable event); +/** + * A constant used with `FLEEventChannel` to indicate end of stream. + */ +extern NSObject const* FLEEndOfEventStream; +/** + * A strategy for exposing an event stream to the Flutter side. + */ +@protocol FLEStreamHandler +/** + * Sets up an event stream and begin emitting events. + * + * Invoked when the first listener is registered with the Stream associated to + * this channel on the Flutter side. + * + * @param arguments Arguments for the stream. + * @param events A callback to asynchronously emit events. Invoke the + * callback with a `FLEMethodError` to emit an error event. Invoke the + * callback with `FLEEndOfEventStream` to indicate that no more + * events will be emitted. Any other value, including `nil` are emitted as + * successful events. + * @return A FLEMethodError instance, if setup fails. + */ +- (FLEMethodError* _Nullable)onListenWithArguments:(id _Nullable)arguments + eventSink:(FLEEventSink)events; +/** + * Tears down an event stream. + * + * Invoked when the last listener is deregistered from the Stream associated to + * this channel on the Flutter side. + * + * The channel implementation may call this method with `nil` arguments + * to separate a pair of two consecutive set up requests. Such request pairs + * may occur during Flutter hot restart. + * + * @param arguments Arguments for the stream. + * @return A FLEMethodError instance, if teardown fails. + */ +- (FLEMethodError* _Nullable)onCancelWithArguments:(id _Nullable)arguments; +@end +/** + * A channel for communicating with the Flutter side using event streams. + */ +@interface FLEEventChannel : NSObject +/** + * Creates a `FLEEventChannel` with the specified name and binary messenger. + * + * The channel name logically identifies the channel; identically named channels + * interfere with each other's communication. + * + * The binary messenger is a facility for sending raw, binary messages to the + * Flutter side. This protocol is implemented by `FLEViewController`. + * + * The channel uses `FLEMethodCodec` to decode stream setup and + * teardown requests, and to encode event envelopes. + * + * @param name The channel name. + * @param messenger The binary messenger. + * @param codec The method codec. + */ ++ (instancetype)eventChannelWithName:(nonnull NSString *)name + binaryMessenger:(nonnull id)messenger + codec:(nonnull id)codec; +/** + * Registers a handler for stream setup requests from the Flutter side. + * + * Replaces any existing handler. Use a `nil` handler for unregistering the + * existing handler. + * + * @param handler The stream handler. + */ +- (void)setStreamHandler:(nullable id)handler; +@end + diff --git a/library/macos/FLEEventChannel.m b/library/macos/FLEEventChannel.m new file mode 100644 index 000000000..19bcec07e --- /dev/null +++ b/library/macos/FLEEventChannel.m @@ -0,0 +1,97 @@ +// Copyright 2018 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "FLEEventChannel.h" + +NSObject const* FLEEndOfEventStream = @"EndOfEventStream"; + +@implementation FLEEventChannel { + NSString* _name; + __weak id _messenger; + id _codec; +} + ++ (instancetype)eventChannelWithName:(nonnull NSString*)name + binaryMessenger:(nonnull id)messenger + codec:(nonnull id)codec { + return [[FLEEventChannel alloc] initWithName:name binaryMessenger:messenger codec:codec]; +} + +- (instancetype)initWithName:(nonnull NSString*)name + binaryMessenger:(nonnull id)messenger + codec:(nonnull id)codec { + self = [super init]; + NSAssert(self, @"Super init cannot be nil"); + _name = name; + _messenger = messenger; + _codec = codec; + + return self; +} + +- (void)setStreamHandler:(NSObject*)handler { + if (!handler) { + [_messenger setMessageHandlerOnChannel:_name binaryMessageHandler:nil]; + return; + } + + id codec = _codec; + __weak id messenger = _messenger; + NSString *channelName = _name; + + __block FLEEventSink currentSink = nil; + FLEBinaryMessageHandler messageHandler = ^(NSData* message, FLEBinaryReply callback) { + FLEMethodCall* call = [codec decodeMethodCall:message]; + if ([call.methodName isEqual:@"listen"]) { + if (currentSink) { + FLEMethodError* error = [handler onCancelWithArguments:nil]; + if (error) + NSLog(@"Failed to cancel existing stream: %@. %@ (%@)", error.code, error.message, + error.details); + } + currentSink = ^(id event) { + if (event == FLEEndOfEventStream) + [messenger sendOnChannel:channelName message:nil]; + else if ([event isKindOfClass:[FLEMethodError class]]) + [messenger sendOnChannel:channelName + message:[codec encodeErrorEnvelope:(FLEMethodError*)event]]; + else + [messenger sendOnChannel:channelName message:[codec encodeSuccessEnvelope:event]]; + }; + FLEMethodError* error = [handler onListenWithArguments:call.arguments eventSink:currentSink]; + if (error) + callback([codec encodeErrorEnvelope:error]); + else + callback([codec encodeSuccessEnvelope:nil]); + } else if ([call.methodName isEqual:@"cancel"]) { + if (!currentSink) { + callback( + [codec encodeErrorEnvelope:[[FLEMethodError alloc] initWithCode:@"error" + message:@"No active stream to cancel" + details:nil]]); + return; + } + currentSink = nil; + FLEMethodError* error = [handler onCancelWithArguments:call.arguments]; + if (error) + callback([codec encodeErrorEnvelope:error]); + else + callback([codec encodeSuccessEnvelope:nil]); + } else { + callback(nil); + } + }; + [_messenger setMessageHandlerOnChannel:_name binaryMessageHandler:messageHandler]; +} +@end diff --git a/library/macos/FlutterEmbedderMac.xcodeproj/project.pbxproj b/library/macos/FlutterEmbedderMac.xcodeproj/project.pbxproj index 0b730ac53..2b1896191 100644 --- a/library/macos/FlutterEmbedderMac.xcodeproj/project.pbxproj +++ b/library/macos/FlutterEmbedderMac.xcodeproj/project.pbxproj @@ -30,6 +30,8 @@ 1E2492411FCF50BE00DD3BBB /* FlutterEmbedderMac.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E2492371FCF50BE00DD3BBB /* FlutterEmbedderMac.h */; settings = {ATTRIBUTES = (Public, ); }; }; 1EEF8E071FD1F0C300DD563C /* FLEView.h in Headers */ = {isa = PBXBuildFile; fileRef = 1EEF8E051FD1F0C300DD563C /* FLEView.h */; settings = {ATTRIBUTES = (Public, ); }; }; 1EEF8E081FD1F0C300DD563C /* FLEView.m in Sources */ = {isa = PBXBuildFile; fileRef = 1EEF8E061FD1F0C300DD563C /* FLEView.m */; }; + 2CCADF9A21C74690001B4026 /* FLEEventChannel.m in Sources */ = {isa = PBXBuildFile; fileRef = 2CCADF9821C74690001B4026 /* FLEEventChannel.m */; }; + 2CCADF9B21C74690001B4026 /* FLEEventChannel.h in Headers */ = {isa = PBXBuildFile; fileRef = 2CCADF9921C74690001B4026 /* FLEEventChannel.h */; settings = {ATTRIBUTES = (Public, ); }; }; 3389A6872159359200A27898 /* FLEBinaryMessenger.h in Headers */ = {isa = PBXBuildFile; fileRef = 3389A6862159359200A27898 /* FLEBinaryMessenger.h */; settings = {ATTRIBUTES = (Public, ); }; }; 3389A68D215949CB00A27898 /* FLEMethodError.m in Sources */ = {isa = PBXBuildFile; fileRef = 3389A68C215949CB00A27898 /* FLEMethodError.m */; }; 3389A68F215949D600A27898 /* FLEMethodError.h in Headers */ = {isa = PBXBuildFile; fileRef = 3389A68E215949D600A27898 /* FLEMethodError.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -91,6 +93,8 @@ 1E2492381FCF50BE00DD3BBB /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist; path = Info.plist; sourceTree = ""; }; 1EEF8E051FD1F0C300DD563C /* FLEView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FLEView.h; sourceTree = ""; }; 1EEF8E061FD1F0C300DD563C /* FLEView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FLEView.m; sourceTree = ""; }; + 2CCADF9821C74690001B4026 /* FLEEventChannel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FLEEventChannel.m; sourceTree = ""; }; + 2CCADF9921C74690001B4026 /* FLEEventChannel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FLEEventChannel.h; sourceTree = ""; }; 3389A6862159359200A27898 /* FLEBinaryMessenger.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FLEBinaryMessenger.h; sourceTree = ""; }; 3389A68C215949CB00A27898 /* FLEMethodError.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FLEMethodError.m; sourceTree = ""; }; 3389A68E215949D600A27898 /* FLEMethodError.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FLEMethodError.h; sourceTree = ""; }; @@ -134,6 +138,7 @@ 1E2492371FCF50BE00DD3BBB /* FlutterEmbedderMac.h */, 1E2492451FCF536200DD3BBB /* Public */, 33C0FA1821B845EF008F8959 /* FLEBasicMessageChannel.m */, + 2CCADF9821C74690001B4026 /* FLEEventChannel.m */, 33C0FA1C21B84810008F8959 /* FLEJSONMessageCodec.m */, 33A87EB520F6BCDB0086D21D /* FLEJSONMethodCodec.m */, 64C76C2620D7BDFB00B16256 /* FLEKeyEventPlugin.h */, @@ -167,6 +172,7 @@ children = ( 33C0FA1921B845F0008F8959 /* FLEBasicMessageChannel.h */, 3389A6862159359200A27898 /* FLEBinaryMessenger.h */, + 2CCADF9921C74690001B4026 /* FLEEventChannel.h */, 33C0FA1E21B84810008F8959 /* FLEJSONMessageCodec.h */, 33C0FA1D21B84810008F8959 /* FLEJSONMethodCodec.h */, 33C0FA1F21B84810008F8959 /* FLEMessageCodec.h */, @@ -201,6 +207,7 @@ 33E202A6212BC0ED00337F48 /* FLEKeyEventPlugin.h in Headers */, 33C0FA2621B84AA4008F8959 /* FLEMethodCall.h in Headers */, 1E24923B1FCF50BE00DD3BBB /* FLEPlugin.h in Headers */, + 2CCADF9B21C74690001B4026 /* FLEEventChannel.h in Headers */, 3389A6872159359200A27898 /* FLEBinaryMessenger.h in Headers */, 33D7B59920A4F54400296EFC /* FLEMethodChannel.h in Headers */, 1E24923F1FCF50BE00DD3BBB /* FLEViewController.h in Headers */, @@ -321,6 +328,7 @@ 1E24923E1FCF50BE00DD3BBB /* FLETextInputPlugin.m in Sources */, 1EEF8E081FD1F0C300DD563C /* FLEView.m in Sources */, 33A87EB720F6BCDB0086D21D /* FLEJSONMethodCodec.m in Sources */, + 2CCADF9A21C74690001B4026 /* FLEEventChannel.m in Sources */, AA8AE8BA1FD948BA00B6FB31 /* FLETextInputModel.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; From acfa9f793c9e76914cb6ac4c899ea1b4ceffb531 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B9=96=E5=8C=97=E6=8D=B7=E6=99=BA=E4=BA=91=E6=8A=80?= =?UTF-8?q?=E6=9C=AF=E6=9C=89=E9=99=90=E5=85=AC=E5=8F=B8?= Date: Fri, 4 Jan 2019 17:07:57 +0800 Subject: [PATCH 02/12] Fixed code styles. --- library/macos/FLEEventChannel.h | 24 +++++++++++++------- library/macos/FLEEventChannel.m | 39 +++++++++++++++++---------------- 2 files changed, 36 insertions(+), 27 deletions(-) diff --git a/library/macos/FLEEventChannel.h b/library/macos/FLEEventChannel.h index 8c127443c..e5aaf7e69 100644 --- a/library/macos/FLEEventChannel.h +++ b/library/macos/FLEEventChannel.h @@ -23,14 +23,17 @@ * @param event The event. */ typedef void (^FLEEventSink)(id _Nullable event); + /** * A constant used with `FLEEventChannel` to indicate end of stream. */ -extern NSObject const* FLEEndOfEventStream; +extern NSString const *_Nonnull FLEEndOfEventStream; + /** * A strategy for exposing an event stream to the Flutter side. */ @protocol FLEStreamHandler + /** * Sets up an event stream and begin emitting events. * @@ -45,8 +48,9 @@ extern NSObject const* FLEEndOfEventStream; * successful events. * @return A FLEMethodError instance, if setup fails. */ -- (FLEMethodError* _Nullable)onListenWithArguments:(id _Nullable)arguments - eventSink:(FLEEventSink)events; +- (FLEMethodError *_Nonnull)onListenWithArguments:(id _Nullable)arguments + eventSink:(FLEEventSink)events; + /** * Tears down an event stream. * @@ -60,12 +64,14 @@ extern NSObject const* FLEEndOfEventStream; * @param arguments Arguments for the stream. * @return A FLEMethodError instance, if teardown fails. */ -- (FLEMethodError* _Nullable)onCancelWithArguments:(id _Nullable)arguments; +- (FLEMethodError *_Nonnull)onCancelWithArguments:(id _Nullable)arguments; @end + /** * A channel for communicating with the Flutter side using event streams. */ @interface FLEEventChannel : NSObject + /** * Creates a `FLEEventChannel` with the specified name and binary messenger. * @@ -81,10 +87,12 @@ extern NSObject const* FLEEndOfEventStream; * @param name The channel name. * @param messenger The binary messenger. * @param codec The method codec. + * @return A new channel. */ -+ (instancetype)eventChannelWithName:(nonnull NSString *)name - binaryMessenger:(nonnull id)messenger - codec:(nonnull id)codec; ++ (nonnull instancetype)eventChannelWithName:(nonnull NSString *)name + binaryMessenger:(nonnull id)messenger + codec:(nonnull id)codec; + /** * Registers a handler for stream setup requests from the Flutter side. * @@ -94,5 +102,5 @@ extern NSObject const* FLEEndOfEventStream; * @param handler The stream handler. */ - (void)setStreamHandler:(nullable id)handler; -@end +@end diff --git a/library/macos/FLEEventChannel.m b/library/macos/FLEEventChannel.m index 19bcec07e..61076f645 100644 --- a/library/macos/FLEEventChannel.m +++ b/library/macos/FLEEventChannel.m @@ -14,33 +14,33 @@ #import "FLEEventChannel.h" -NSObject const* FLEEndOfEventStream = @"EndOfEventStream"; +NSString const *FLEEndOfEventStream = @"EndOfEventStream"; @implementation FLEEventChannel { - NSString* _name; + NSString *_name; __weak id _messenger; id _codec; } -+ (instancetype)eventChannelWithName:(nonnull NSString*)name - binaryMessenger:(nonnull id)messenger - codec:(nonnull id)codec { - return [[FLEEventChannel alloc] initWithName:name binaryMessenger:messenger codec:codec]; ++ (instancetype)eventChannelWithName:(NSString *)name + binaryMessenger:(id)messenger + codec:(id)codec { + return [[[self class] alloc] initWithName:name binaryMessenger:messenger codec:codec]; } -- (instancetype)initWithName:(nonnull NSString*)name - binaryMessenger:(nonnull id)messenger - codec:(nonnull id)codec { +- (instancetype)initWithName:(NSString *)name + binaryMessenger:(id)messenger + codec:(id)codec { self = [super init]; - NSAssert(self, @"Super init cannot be nil"); - _name = name; - _messenger = messenger; - _codec = codec; - + if (self) { + _name = [name copy]; + _messenger = messenger; + _codec = codec; + } return self; } -- (void)setStreamHandler:(NSObject*)handler { +- (void)setStreamHandler:(NSObject *)handler { if (!handler) { [_messenger setMessageHandlerOnChannel:_name binaryMessageHandler:nil]; return; @@ -51,7 +51,7 @@ - (void)setStreamHandler:(NSObject*)handler { NSString *channelName = _name; __block FLEEventSink currentSink = nil; - FLEBinaryMessageHandler messageHandler = ^(NSData* message, FLEBinaryReply callback) { + FLEBinaryMessageHandler messageHandler = ^(NSData *message, FLEBinaryReply callback) { FLEMethodCall* call = [codec decodeMethodCall:message]; if ([call.methodName isEqual:@"listen"]) { if (currentSink) { @@ -65,11 +65,11 @@ - (void)setStreamHandler:(NSObject*)handler { [messenger sendOnChannel:channelName message:nil]; else if ([event isKindOfClass:[FLEMethodError class]]) [messenger sendOnChannel:channelName - message:[codec encodeErrorEnvelope:(FLEMethodError*)event]]; + message:[codec encodeErrorEnvelope:(FLEMethodError *)event]]; else [messenger sendOnChannel:channelName message:[codec encodeSuccessEnvelope:event]]; }; - FLEMethodError* error = [handler onListenWithArguments:call.arguments eventSink:currentSink]; + FLEMethodError *error = [handler onListenWithArguments:call.arguments eventSink:currentSink]; if (error) callback([codec encodeErrorEnvelope:error]); else @@ -83,7 +83,7 @@ - (void)setStreamHandler:(NSObject*)handler { return; } currentSink = nil; - FLEMethodError* error = [handler onCancelWithArguments:call.arguments]; + FLEMethodError *error = [handler onCancelWithArguments:call.arguments]; if (error) callback([codec encodeErrorEnvelope:error]); else @@ -94,4 +94,5 @@ - (void)setStreamHandler:(NSObject*)handler { }; [_messenger setMessageHandlerOnChannel:_name binaryMessageHandler:messageHandler]; } + @end From 413b8434f5bbaddb975181ae554d170d58723cdf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B9=96=E5=8C=97=E6=8D=B7=E6=99=BA=E4=BA=91=E6=8A=80?= =?UTF-8?q?=E6=9C=AF=E6=9C=89=E9=99=90=E5=85=AC=E5=8F=B8?= Date: Fri, 4 Jan 2019 18:21:18 +0800 Subject: [PATCH 03/12] Update. --- library/macos/FLEEventChannel.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/library/macos/FLEEventChannel.h b/library/macos/FLEEventChannel.h index e5aaf7e69..a1b5f1080 100644 --- a/library/macos/FLEEventChannel.h +++ b/library/macos/FLEEventChannel.h @@ -48,7 +48,7 @@ extern NSString const *_Nonnull FLEEndOfEventStream; * successful events. * @return A FLEMethodError instance, if setup fails. */ -- (FLEMethodError *_Nonnull)onListenWithArguments:(id _Nullable)arguments +- (nullable FLEMethodError *)onListenWithArguments:(id _Nullable)arguments eventSink:(FLEEventSink)events; /** @@ -64,7 +64,8 @@ extern NSString const *_Nonnull FLEEndOfEventStream; * @param arguments Arguments for the stream. * @return A FLEMethodError instance, if teardown fails. */ -- (FLEMethodError *_Nonnull)onCancelWithArguments:(id _Nullable)arguments; +- (nullable FLEMethodError *)onCancelWithArguments:(id _Nullable)arguments; + @end /** From 713fd8282598a64761af983be0ed4467b67550ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B9=96=E5=8C=97=E6=8D=B7=E6=99=BA=E4=BA=91=E6=8A=80?= =?UTF-8?q?=E6=9C=AF=E6=9C=89=E9=99=90=E5=85=AC=E5=8F=B8?= Date: Fri, 4 Jan 2019 19:03:41 +0800 Subject: [PATCH 04/12] Remove unnecessary comments. --- library/macos/FLEEventChannel.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/macos/FLEEventChannel.h b/library/macos/FLEEventChannel.h index a1b5f1080..6d98fcb52 100644 --- a/library/macos/FLEEventChannel.h +++ b/library/macos/FLEEventChannel.h @@ -80,7 +80,7 @@ extern NSString const *_Nonnull FLEEndOfEventStream; * interfere with each other's communication. * * The binary messenger is a facility for sending raw, binary messages to the - * Flutter side. This protocol is implemented by `FLEViewController`. + * Flutter side. * * The channel uses `FLEMethodCodec` to decode stream setup and * teardown requests, and to encode event envelopes. From a33f8e3b04e4da34bdf8bd12912b5366e291a2b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B9=96=E5=8C=97=E6=8D=B7=E6=99=BA=E4=BA=91=E6=8A=80?= =?UTF-8?q?=E6=9C=AF=E6=9C=89=E9=99=90=E5=85=AC=E5=8F=B8?= Date: Fri, 4 Jan 2019 19:15:04 +0800 Subject: [PATCH 05/12] Move the EventSink block to the outside. --- library/macos/FLEEventChannel.m | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/library/macos/FLEEventChannel.m b/library/macos/FLEEventChannel.m index 61076f645..f722ea021 100644 --- a/library/macos/FLEEventChannel.m +++ b/library/macos/FLEEventChannel.m @@ -48,8 +48,17 @@ - (void)setStreamHandler:(NSObject *)handler { id codec = _codec; __weak id messenger = _messenger; - NSString *channelName = _name; - + NSString *name = _name; + FLEEventSink eventSink = ^(id event) { + if (event == FLEEndOfEventStream) + [messenger sendOnChannel:name message:nil]; + else if ([event isKindOfClass:[FLEMethodError class]]) + [messenger sendOnChannel:name + message:[codec encodeErrorEnvelope:(FLEMethodError *)event]]; + else + [messenger sendOnChannel:name message:[codec encodeSuccessEnvelope:event]]; + }; + __block FLEEventSink currentSink = nil; FLEBinaryMessageHandler messageHandler = ^(NSData *message, FLEBinaryReply callback) { FLEMethodCall* call = [codec decodeMethodCall:message]; @@ -60,15 +69,7 @@ - (void)setStreamHandler:(NSObject *)handler { NSLog(@"Failed to cancel existing stream: %@. %@ (%@)", error.code, error.message, error.details); } - currentSink = ^(id event) { - if (event == FLEEndOfEventStream) - [messenger sendOnChannel:channelName message:nil]; - else if ([event isKindOfClass:[FLEMethodError class]]) - [messenger sendOnChannel:channelName - message:[codec encodeErrorEnvelope:(FLEMethodError *)event]]; - else - [messenger sendOnChannel:channelName message:[codec encodeSuccessEnvelope:event]]; - }; + currentSink = eventSink; FLEMethodError *error = [handler onListenWithArguments:call.arguments eventSink:currentSink]; if (error) callback([codec encodeErrorEnvelope:error]); From b2fc8b9989374c6210c1209c1bd27883c57e0da3 Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Tue, 8 Jan 2019 15:37:24 -0800 Subject: [PATCH 06/12] Minor adjustments - Add a missing nullability specifier. - Use simplified nullability annotations when possible. - clang-format using project style file. - Add braces to conditionals to match project style. - Add new header to umbrella header. --- library/macos/FLEEventChannel.h | 8 +- library/macos/FLEEventChannel.m | 125 +++++++++++++++-------------- library/macos/FlutterEmbedderMac.h | 1 + 3 files changed, 69 insertions(+), 65 deletions(-) diff --git a/library/macos/FLEEventChannel.h b/library/macos/FLEEventChannel.h index 6d98fcb52..7dac85821 100644 --- a/library/macos/FLEEventChannel.h +++ b/library/macos/FLEEventChannel.h @@ -35,7 +35,7 @@ extern NSString const *_Nonnull FLEEndOfEventStream; @protocol FLEStreamHandler /** - * Sets up an event stream and begin emitting events. + * Sets up an event stream and begins emitting events. * * Invoked when the first listener is registered with the Stream associated to * this channel on the Flutter side. @@ -48,8 +48,8 @@ extern NSString const *_Nonnull FLEEndOfEventStream; * successful events. * @return A FLEMethodError instance, if setup fails. */ -- (nullable FLEMethodError *)onListenWithArguments:(id _Nullable)arguments - eventSink:(FLEEventSink)events; +- (nullable FLEMethodError *)onListenWithArguments:(nullable id)arguments + eventSink:(FLEEventSink _Nonnull)events; /** * Tears down an event stream. @@ -64,7 +64,7 @@ extern NSString const *_Nonnull FLEEndOfEventStream; * @param arguments Arguments for the stream. * @return A FLEMethodError instance, if teardown fails. */ -- (nullable FLEMethodError *)onCancelWithArguments:(id _Nullable)arguments; +- (nullable FLEMethodError *)onCancelWithArguments:(nullable id)arguments; @end diff --git a/library/macos/FLEEventChannel.m b/library/macos/FLEEventChannel.m index f722ea021..931e4929e 100644 --- a/library/macos/FLEEventChannel.m +++ b/library/macos/FLEEventChannel.m @@ -17,83 +17,86 @@ NSString const *FLEEndOfEventStream = @"EndOfEventStream"; @implementation FLEEventChannel { - NSString *_name; - __weak id _messenger; - id _codec; + NSString *_name; + __weak id _messenger; + id _codec; } + (instancetype)eventChannelWithName:(NSString *)name binaryMessenger:(id)messenger codec:(id)codec { - return [[[self class] alloc] initWithName:name binaryMessenger:messenger codec:codec]; + return [[[self class] alloc] initWithName:name binaryMessenger:messenger codec:codec]; } - (instancetype)initWithName:(NSString *)name binaryMessenger:(id)messenger codec:(id)codec { - self = [super init]; - if (self) { - _name = [name copy]; - _messenger = messenger; - _codec = codec; - } - return self; + self = [super init]; + if (self) { + _name = [name copy]; + _messenger = messenger; + _codec = codec; + } + return self; } - (void)setStreamHandler:(NSObject *)handler { - if (!handler) { - [_messenger setMessageHandlerOnChannel:_name binaryMessageHandler:nil]; - return; - } + if (!handler) { + [_messenger setMessageHandlerOnChannel:_name binaryMessageHandler:nil]; + return; + } - id codec = _codec; - __weak id messenger = _messenger; - NSString *name = _name; - FLEEventSink eventSink = ^(id event) { - if (event == FLEEndOfEventStream) - [messenger sendOnChannel:name message:nil]; - else if ([event isKindOfClass:[FLEMethodError class]]) - [messenger sendOnChannel:name - message:[codec encodeErrorEnvelope:(FLEMethodError *)event]]; - else - [messenger sendOnChannel:name message:[codec encodeSuccessEnvelope:event]]; - }; + id codec = _codec; + __weak id messenger = _messenger; + NSString *name = _name; + FLEEventSink eventSink = ^(id event) { + if (event == FLEEndOfEventStream) { + [messenger sendOnChannel:name message:nil]; + } else if ([event isKindOfClass:[FLEMethodError class]]) { + [messenger sendOnChannel:name message:[codec encodeErrorEnvelope:(FLEMethodError *)event]]; + } else { + [messenger sendOnChannel:name message:[codec encodeSuccessEnvelope:event]]; + } + }; - __block FLEEventSink currentSink = nil; - FLEBinaryMessageHandler messageHandler = ^(NSData *message, FLEBinaryReply callback) { - FLEMethodCall* call = [codec decodeMethodCall:message]; - if ([call.methodName isEqual:@"listen"]) { - if (currentSink) { - FLEMethodError* error = [handler onCancelWithArguments:nil]; - if (error) - NSLog(@"Failed to cancel existing stream: %@. %@ (%@)", error.code, error.message, - error.details); - } - currentSink = eventSink; - FLEMethodError *error = [handler onListenWithArguments:call.arguments eventSink:currentSink]; - if (error) - callback([codec encodeErrorEnvelope:error]); - else - callback([codec encodeSuccessEnvelope:nil]); - } else if ([call.methodName isEqual:@"cancel"]) { - if (!currentSink) { - callback( - [codec encodeErrorEnvelope:[[FLEMethodError alloc] initWithCode:@"error" - message:@"No active stream to cancel" - details:nil]]); - return; - } - currentSink = nil; - FLEMethodError *error = [handler onCancelWithArguments:call.arguments]; - if (error) - callback([codec encodeErrorEnvelope:error]); - else - callback([codec encodeSuccessEnvelope:nil]); - } else { - callback(nil); + __block FLEEventSink currentSink = nil; + FLEBinaryMessageHandler messageHandler = ^(NSData *message, FLEBinaryReply callback) { + FLEMethodCall *call = [codec decodeMethodCall:message]; + if ([call.methodName isEqual:@"listen"]) { + if (currentSink) { + FLEMethodError *error = [handler onCancelWithArguments:nil]; + if (error) { + NSLog(@"Failed to cancel existing stream: %@. %@ (%@)", error.code, error.message, + error.details); } - }; - [_messenger setMessageHandlerOnChannel:_name binaryMessageHandler:messageHandler]; + } + currentSink = eventSink; + FLEMethodError *error = [handler onListenWithArguments:call.arguments eventSink:currentSink]; + if (error) { + callback([codec encodeErrorEnvelope:error]); + } else { + callback([codec encodeSuccessEnvelope:nil]); + } + } else if ([call.methodName isEqual:@"cancel"]) { + if (!currentSink) { + callback([codec + encodeErrorEnvelope:[[FLEMethodError alloc] initWithCode:@"error" + message:@"No active stream to cancel" + details:nil]]); + return; + } + currentSink = nil; + FLEMethodError *error = [handler onCancelWithArguments:call.arguments]; + if (error) { + callback([codec encodeErrorEnvelope:error]); + } else { + callback([codec encodeSuccessEnvelope:nil]); + } + } else { + callback(nil); + } + }; + [_messenger setMessageHandlerOnChannel:_name binaryMessageHandler:messageHandler]; } @end diff --git a/library/macos/FlutterEmbedderMac.h b/library/macos/FlutterEmbedderMac.h index 18ccefa39..4416dfd45 100644 --- a/library/macos/FlutterEmbedderMac.h +++ b/library/macos/FlutterEmbedderMac.h @@ -14,6 +14,7 @@ #import "FLEBasicMessageChannel.h" #import "FLEBinaryMessenger.h" +#import "FLEEventChannel.h" #import "FLEJSONMessageCodec.h" #import "FLEJSONMethodCodec.h" #import "FLEMessageCodec.h" From 1f147f32900c15cb34db0b5e549006877fe3b3af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B9=96=E5=8C=97=E6=8D=B7=E6=99=BA=E4=BA=91=E6=8A=80?= =?UTF-8?q?=E6=9C=AF=E6=9C=89=E9=99=90=E5=85=AC=E5=8F=B8?= Date: Thu, 31 Jan 2019 23:29:33 +0800 Subject: [PATCH 07/12] Add Texture for FLE. --- library/macos/FLEExternalTexture.h | 36 ++++++++ library/macos/FLEExternalTexture.m | 92 +++++++++++++++++++ library/macos/FLETexture.h | 32 +++++++ library/macos/FLEViewController.h | 3 +- library/macos/FLEViewController.mm | 38 ++++++++ .../project.pbxproj | 12 +++ 6 files changed, 212 insertions(+), 1 deletion(-) create mode 100644 library/macos/FLEExternalTexture.h create mode 100644 library/macos/FLEExternalTexture.m create mode 100644 library/macos/FLETexture.h diff --git a/library/macos/FLEExternalTexture.h b/library/macos/FLEExternalTexture.h new file mode 100644 index 000000000..13838e9db --- /dev/null +++ b/library/macos/FLEExternalTexture.h @@ -0,0 +1,36 @@ +// Copyright 2018 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import +#import + +#import "FLETexture.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FLEExternalTexture : NSObject + +-(nonnull instancetype)initExternalTexture:(id)external_texture; + +-(BOOL)populateTextureWidth:(size_t)width + height:(size_t)height + texture:(FlutterOpenGLTexture *)texture; + +-(int64_t)textureId; + +@property(nullable, weak) id external_texture; + +@end + +NS_ASSUME_NONNULL_END diff --git a/library/macos/FLEExternalTexture.m b/library/macos/FLEExternalTexture.m new file mode 100644 index 000000000..7ed2b88f5 --- /dev/null +++ b/library/macos/FLEExternalTexture.m @@ -0,0 +1,92 @@ +// Copyright 2018 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "FLEExternalTexture.h" + +#import +#import +#import +#import + +@implementation FLEExternalTexture { + CVOpenGLTextureCacheRef _textureCache; + CVPixelBufferRef _pixelBuffer; +} + +@synthesize external_texture; + +-(instancetype) initExternalTexture:(id)external_texture { + self = [super init]; + + if (self) { + self.external_texture = external_texture; + } + + return self; +} + +static void OnGLTextureRelease(CVPixelBufferRef pixelBuffer) { + CVPixelBufferRelease(pixelBuffer); +} + +-(int64_t)textureId { + return (NSInteger)(self); +} + +-(BOOL)populateTextureWidth:(size_t)width + height:(size_t)height + texture:(FlutterOpenGLTexture *)texture{ + + if(_pixelBuffer == NULL || external_texture == NULL){ + return NO; + } + + // Copy image buffer from external texture. + _pixelBuffer = [external_texture copyPixelBuffer]; + + // Create the texture cache if necessary. + if (_textureCache == NULL) { + CGLContextObj context = [NSOpenGLContext currentContext].CGLContextObj; + CGLPixelFormatObj format = CGLGetPixelFormat(context); + if (CVOpenGLTextureCacheCreate(kCFAllocatorDefault, NULL, context, format, NULL, &_textureCache) != kCVReturnSuccess) { + NSLog(@"Could not create texture cache."); + CVPixelBufferRelease(_pixelBuffer); + return NO; + } + } + + // Try to clear the cache of OpenGL textures to save memory. + CVOpenGLTextureCacheFlush(_textureCache, 0); + + CVOpenGLTextureRef openGLTexture = NULL; + if (CVOpenGLTextureCacheCreateTextureFromImage(kCFAllocatorDefault, _textureCache, _pixelBuffer, NULL, &openGLTexture) != kCVReturnSuccess) { + CVPixelBufferRelease(_pixelBuffer); + return NO; + } + + texture->target = CVOpenGLTextureGetTarget(openGLTexture); + texture->name = CVOpenGLTextureGetName(openGLTexture); + texture->format = GL_RGBA8; + texture->destruction_callback = (VoidCallback)&OnGLTextureRelease; + texture->user_data = openGLTexture; + + CVPixelBufferRelease(_pixelBuffer); + return YES; +} + +-(void) dealloc { + CVOpenGLTextureCacheRelease(_textureCache); +} + +@end diff --git a/library/macos/FLETexture.h b/library/macos/FLETexture.h new file mode 100644 index 000000000..c16b8f510 --- /dev/null +++ b/library/macos/FLETexture.h @@ -0,0 +1,32 @@ +// Copyright 2018 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import +#import + +@protocol FLETexture + +- (nullable CVPixelBufferRef)copyPixelBuffer; + +@end + +@protocol FLETextureRegistrar + +- (int64_t)registerTexture:(nonnull id)texture; + +- (void)textureFrameAvailable:(int64_t)textureId; + +- (void)unregisterTexture:(int64_t)textureId; + +@end diff --git a/library/macos/FLEViewController.h b/library/macos/FLEViewController.h index 10eb0ea5b..5d2af4d64 100644 --- a/library/macos/FLEViewController.h +++ b/library/macos/FLEViewController.h @@ -20,6 +20,7 @@ #import "FLEPlugin.h" #import "FLEPluginRegistrar.h" #import "FLEReshapeListener.h" +#import "FLETexture.h" /** * Controls embedder plugins and communication with the underlying Flutter engine, managing a view @@ -29,7 +30,7 @@ * Flutter engine in non-interactive mode, or with a drawable Flutter canvas. */ @interface FLEViewController - : NSViewController + : NSViewController /** * The view this controller manages when launched in interactive mode (headless set to false). Must diff --git a/library/macos/FLEViewController.mm b/library/macos/FLEViewController.mm index 254e82294..ba3ad520d 100644 --- a/library/macos/FLEViewController.mm +++ b/library/macos/FLEViewController.mm @@ -22,6 +22,7 @@ #import "FLEReshapeListener.h" #import "FLETextInputPlugin.h" #import "FLEView.h" +#import "FLEExternalTexture.h" static NSString *const kXcodeExtraArgumentOne = @"-NSDocumentRevisionsDebugMode"; static NSString *const kXcodeExtraArgumentTwo = @"YES"; @@ -95,6 +96,10 @@ - (void)dispatchMouseEvent:(nonnull NSEvent *)event phase:(FlutterPointerPhase)p */ - (void)dispatchKeyEvent:(NSEvent *)event ofType:(NSString *)type; +-(BOOL) populateTextureWithIdentifier:(int64_t)texture_identifier + width:(size_t)width + height:(size_t)height + texture:(FlutterOpenGLTexture *)texture; @end #pragma mark - Static methods provided to engine configuration @@ -144,6 +149,14 @@ static bool OnMakeResourceCurrent(FLEViewController *controller) { return true; } +static bool OnAcquireExternalTexture(FLEViewController *controller, + int64_t texture_identifier, + size_t width, + size_t height, + FlutterOpenGLTexture *texture) { + return [controller populateTextureWithIdentifier:texture_identifier width:width height:height texture:texture]; +} + #pragma mark Static methods provided for headless engine configuration static bool HeadlessOnMakeCurrent(FLEViewController *controller) { return false; } @@ -173,6 +186,9 @@ @implementation FLEViewController { // A message channel for passing key events to the Flutter engine. This should be replaced with // an embedding API; see Issue #47. FLEBasicMessageChannel *_keyEventChannel; + + // A mapping of external textures. + NSMutableDictionary *_textures; } @dynamic view; @@ -183,6 +199,7 @@ @implementation FLEViewController { static void CommonInit(FLEViewController *controller) { controller->_messageHandlers = [[NSMutableDictionary alloc] init]; controller->_additionalKeyResponders = [[NSMutableOrderedSet alloc] init]; + controller->_textures = [[NSMutableDictionary alloc] init]; } - (instancetype)initWithCoder:(NSCoder *)coder { @@ -342,6 +359,27 @@ - (void)makeResourceContextCurrent { [_resourceContext makeCurrentContext]; } +-(BOOL) populateTextureWithIdentifier:(int64_t) textureId width:(size_t) width height:(size_t) height texture:(FlutterOpenGLTexture *) texture { + return [_textures[@(textureId)] populateTextureWidth:width height:height texture:texture]; +} + +- (int64_t)registerTexture:(NSObject*)texture { + FLEExternalTexture *fleTexture = [[FLEExternalTexture alloc] initExternalTexture:texture]; + int64_t textureId = [fleTexture textureId]; + FlutterEngineRegisterExternalTexture(_engine, textureId); + _textures[@(textureId)] = fleTexture; + return textureId; +} + +- (void)textureFrameAvailable:(int64_t)textureId { + FlutterEngineMarkExternalTextureFrameAvailable(_engine, textureId); +} + +- (void)unregisterTexture:(int64_t)textureId { + FlutterEngineUnregisterExternalTexture(_engine, textureId); + [_textures removeObjectForKey:@(textureId)]; +} + - (void)handlePlatformMessage:(const FlutterPlatformMessage *)message { NSData *messageData = [NSData dataWithBytesNoCopy:(void *)message->message length:message->message_size diff --git a/library/macos/FlutterEmbedderMac.xcodeproj/project.pbxproj b/library/macos/FlutterEmbedderMac.xcodeproj/project.pbxproj index bbc1a68f4..c842660ee 100644 --- a/library/macos/FlutterEmbedderMac.xcodeproj/project.pbxproj +++ b/library/macos/FlutterEmbedderMac.xcodeproj/project.pbxproj @@ -30,6 +30,9 @@ 1E2492411FCF50BE00DD3BBB /* FlutterEmbedderMac.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E2492371FCF50BE00DD3BBB /* FlutterEmbedderMac.h */; settings = {ATTRIBUTES = (Public, ); }; }; 1EEF8E071FD1F0C300DD563C /* FLEView.h in Headers */ = {isa = PBXBuildFile; fileRef = 1EEF8E051FD1F0C300DD563C /* FLEView.h */; settings = {ATTRIBUTES = (Public, ); }; }; 1EEF8E081FD1F0C300DD563C /* FLEView.m in Sources */ = {isa = PBXBuildFile; fileRef = 1EEF8E061FD1F0C300DD563C /* FLEView.m */; }; + 2CC5E74022033D53000EF5F5 /* FLETexture.h in Headers */ = {isa = PBXBuildFile; fileRef = 2CC5E73F22033D53000EF5F5 /* FLETexture.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 2CC5E7432203444A000EF5F5 /* FLEExternalTexture.h in Headers */ = {isa = PBXBuildFile; fileRef = 2CC5E7412203444A000EF5F5 /* FLEExternalTexture.h */; }; + 2CC5E7442203444A000EF5F5 /* FLEExternalTexture.m in Sources */ = {isa = PBXBuildFile; fileRef = 2CC5E7422203444A000EF5F5 /* FLEExternalTexture.m */; }; 2CCADF9A21C74690001B4026 /* FLEEventChannel.m in Sources */ = {isa = PBXBuildFile; fileRef = 2CCADF9821C74690001B4026 /* FLEEventChannel.m */; }; 2CCADF9B21C74690001B4026 /* FLEEventChannel.h in Headers */ = {isa = PBXBuildFile; fileRef = 2CCADF9921C74690001B4026 /* FLEEventChannel.h */; settings = {ATTRIBUTES = (Public, ); }; }; 3389A6872159359200A27898 /* FLEBinaryMessenger.h in Headers */ = {isa = PBXBuildFile; fileRef = 3389A6862159359200A27898 /* FLEBinaryMessenger.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -92,6 +95,9 @@ 1E2492381FCF50BE00DD3BBB /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist; path = Info.plist; sourceTree = ""; }; 1EEF8E051FD1F0C300DD563C /* FLEView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FLEView.h; sourceTree = ""; }; 1EEF8E061FD1F0C300DD563C /* FLEView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FLEView.m; sourceTree = ""; }; + 2CC5E73F22033D53000EF5F5 /* FLETexture.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FLETexture.h; sourceTree = ""; }; + 2CC5E7412203444A000EF5F5 /* FLEExternalTexture.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FLEExternalTexture.h; sourceTree = ""; }; + 2CC5E7422203444A000EF5F5 /* FLEExternalTexture.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FLEExternalTexture.m; sourceTree = ""; }; 2CCADF9821C74690001B4026 /* FLEEventChannel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FLEEventChannel.m; sourceTree = ""; }; 2CCADF9921C74690001B4026 /* FLEEventChannel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FLEEventChannel.h; sourceTree = ""; }; 3389A6862159359200A27898 /* FLEBinaryMessenger.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FLEBinaryMessenger.h; sourceTree = ""; }; @@ -132,6 +138,8 @@ 1E24921A1FCF504200DD3BBB = { isa = PBXGroup; children = ( + 2CC5E7412203444A000EF5F5 /* FLEExternalTexture.h */, + 2CC5E7422203444A000EF5F5 /* FLEExternalTexture.m */, C4C1FE431FD74F6400691968 /* FlutterEmbedder.framework */, 1E2492371FCF50BE00DD3BBB /* FlutterEmbedderMac.h */, 1E2492451FCF536200DD3BBB /* Public */, @@ -169,6 +177,7 @@ 33C0FA1921B845F0008F8959 /* FLEBasicMessageChannel.h */, 3389A6862159359200A27898 /* FLEBinaryMessenger.h */, 2CCADF9921C74690001B4026 /* FLEEventChannel.h */, + 2CC5E73F22033D53000EF5F5 /* FLETexture.h */, 33C0FA1E21B84810008F8959 /* FLEJSONMessageCodec.h */, 33C0FA1D21B84810008F8959 /* FLEJSONMethodCodec.h */, 33C0FA1F21B84810008F8959 /* FLEMessageCodec.h */, @@ -202,8 +211,10 @@ buildActionMask = 2147483647; files = ( 33C0FA2621B84AA4008F8959 /* FLEMethodCall.h in Headers */, + 2CC5E7432203444A000EF5F5 /* FLEExternalTexture.h in Headers */, 1E24923B1FCF50BE00DD3BBB /* FLEPlugin.h in Headers */, 2CCADF9B21C74690001B4026 /* FLEEventChannel.h in Headers */, + 2CC5E74022033D53000EF5F5 /* FLETexture.h in Headers */, 3389A6872159359200A27898 /* FLEBinaryMessenger.h in Headers */, 33D7B59920A4F54400296EFC /* FLEMethodChannel.h in Headers */, 1E24923F1FCF50BE00DD3BBB /* FLEViewController.h in Headers */, @@ -325,6 +336,7 @@ 1EEF8E081FD1F0C300DD563C /* FLEView.m in Sources */, 33A87EB720F6BCDB0086D21D /* FLEJSONMethodCodec.m in Sources */, 2CCADF9A21C74690001B4026 /* FLEEventChannel.m in Sources */, + 2CC5E7442203444A000EF5F5 /* FLEExternalTexture.m in Sources */, AA8AE8BA1FD948BA00B6FB31 /* FLETextInputModel.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; From 96230c114220fb90064fe08c3ab77206c4b583f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B9=96=E5=8C=97=E6=8D=B7=E6=99=BA=E4=BA=91=E6=8A=80?= =?UTF-8?q?=E6=9C=AF=E6=9C=89=E9=99=90=E5=85=AC=E5=8F=B8?= Date: Thu, 31 Jan 2019 23:37:30 +0800 Subject: [PATCH 08/12] Add missing callback parameters for RendererConfig. --- library/macos/FLEViewController.mm | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/macos/FLEViewController.mm b/library/macos/FLEViewController.mm index ba3ad520d..a0ddac991 100644 --- a/library/macos/FLEViewController.mm +++ b/library/macos/FLEViewController.mm @@ -344,7 +344,8 @@ + (FlutterRendererConfig)createRenderConfigHeadless:(BOOL)headless { .open_gl.clear_current = (BoolCallback)OnClearCurrent, .open_gl.present = (BoolCallback)OnPresent, .open_gl.fbo_callback = (UIntCallback)OnFBO, - .open_gl.make_resource_current = (BoolCallback)OnMakeResourceCurrent}; + .open_gl.make_resource_current = (BoolCallback)OnMakeResourceCurrent, + .open_gl.gl_external_texture_frame_callback = (TextureFrameCallback)OnAcquireExternalTexture}; return config; } } From 8862833ba498cc54dc2f78606caefb4842aab630 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B9=96=E5=8C=97=E6=8D=B7=E6=99=BA=E4=BA=91=E6=8A=80?= =?UTF-8?q?=E6=9C=AF=E6=9C=89=E9=99=90=E5=85=AC=E5=8F=B8?= Date: Thu, 31 Jan 2019 23:43:03 +0800 Subject: [PATCH 09/12] Add FLETexture.h include to FlutterEmbedderMac.h. --- library/macos/FlutterEmbedderMac.h | 1 + 1 file changed, 1 insertion(+) diff --git a/library/macos/FlutterEmbedderMac.h b/library/macos/FlutterEmbedderMac.h index 8d5ed477b..7fc61f091 100644 --- a/library/macos/FlutterEmbedderMac.h +++ b/library/macos/FlutterEmbedderMac.h @@ -26,5 +26,6 @@ #import "FLEPlugin.h" #import "FLEPluginRegistrar.h" #import "FLEReshapeListener.h" +#import "FLETexture.h" #import "FLEView.h" #import "FLEViewController.h" From c2f6f6f583ac361ff4033ef371ccc1d6963371dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B9=96=E5=8C=97=E6=8D=B7=E6=99=BA=E4=BA=91=E6=8A=80?= =?UTF-8?q?=E6=9C=AF=E6=9C=89=E9=99=90=E5=85=AC=E5=8F=B8?= Date: Fri, 1 Feb 2019 11:26:46 +0800 Subject: [PATCH 10/12] Add the necessary comments and code style changes for FLETexture. --- library/macos/FLEExternalTexture.h | 24 +++++--- library/macos/FLEExternalTexture.m | 96 +++++++++++++++--------------- library/macos/FLETexture.h | 20 +++++++ library/macos/FLEViewController.mm | 27 +++++---- 4 files changed, 100 insertions(+), 67 deletions(-) diff --git a/library/macos/FLEExternalTexture.h b/library/macos/FLEExternalTexture.h index 13838e9db..43de560be 100644 --- a/library/macos/FLEExternalTexture.h +++ b/library/macos/FLEExternalTexture.h @@ -17,20 +17,30 @@ #import "FLETexture.h" -NS_ASSUME_NONNULL_BEGIN - +/** + * Used to bridge external FLETexture objects, + * so the implementer only needs to return the CVPixelBufferRef object, + * which will make the interface consistent with the FlutterTexture. + */ @interface FLEExternalTexture : NSObject --(nonnull instancetype)initExternalTexture:(id)external_texture; +/** + * + */ +- (nonnull instancetype)initWithExternalTexture:(id)external_texture; --(BOOL)populateTextureWidth:(size_t)width +/** + * Accept texture rendering notifications from the flutter engine. + */ +- (BOOL)populateTextureWidth:(size_t)width height:(size_t)height texture:(FlutterOpenGLTexture *)texture; --(int64_t)textureId; +/** + * + */ +- (int64_t)textureId; @property(nullable, weak) id external_texture; @end - -NS_ASSUME_NONNULL_END diff --git a/library/macos/FLEExternalTexture.m b/library/macos/FLEExternalTexture.m index 7ed2b88f5..35b3b9c3d 100644 --- a/library/macos/FLEExternalTexture.m +++ b/library/macos/FLEExternalTexture.m @@ -20,73 +20,73 @@ #import @implementation FLEExternalTexture { - CVOpenGLTextureCacheRef _textureCache; - CVPixelBufferRef _pixelBuffer; + CVOpenGLTextureCacheRef _textureCache; + CVPixelBufferRef _pixelBuffer; } @synthesize external_texture; --(instancetype) initExternalTexture:(id)external_texture { - self = [super init]; +- (instancetype)initWithExternalTexture:(id)external_texture { + self = [super init]; - if (self) { - self.external_texture = external_texture; - } + if (self) { + self.external_texture = external_texture; + } - return self; + return self; } static void OnGLTextureRelease(CVPixelBufferRef pixelBuffer) { - CVPixelBufferRelease(pixelBuffer); + CVPixelBufferRelease(pixelBuffer); } --(int64_t)textureId { - return (NSInteger)(self); +- (int64_t)textureId { + return (NSInteger)(self); } --(BOOL)populateTextureWidth:(size_t)width - height:(size_t)height - texture:(FlutterOpenGLTexture *)texture{ - - if(_pixelBuffer == NULL || external_texture == NULL){ - return NO; - } - - // Copy image buffer from external texture. - _pixelBuffer = [external_texture copyPixelBuffer]; - - // Create the texture cache if necessary. - if (_textureCache == NULL) { - CGLContextObj context = [NSOpenGLContext currentContext].CGLContextObj; - CGLPixelFormatObj format = CGLGetPixelFormat(context); - if (CVOpenGLTextureCacheCreate(kCFAllocatorDefault, NULL, context, format, NULL, &_textureCache) != kCVReturnSuccess) { - NSLog(@"Could not create texture cache."); - CVPixelBufferRelease(_pixelBuffer); - return NO; - } +- (BOOL)populateTextureWidth:(size_t)width + height:(size_t)height + texture:(FlutterOpenGLTexture *)texture { + + if(_pixelBuffer == NULL || external_texture == NULL){ + return NO; + } + + // Copy image buffer from external texture. + _pixelBuffer = [external_texture copyPixelBuffer]; + + // Create the texture cache if necessary. + if (_textureCache == NULL) { + CGLContextObj context = [NSOpenGLContext currentContext].CGLContextObj; + CGLPixelFormatObj format = CGLGetPixelFormat(context); + if (CVOpenGLTextureCacheCreate(kCFAllocatorDefault, NULL, context, format, NULL, &_textureCache) != kCVReturnSuccess) { + NSLog(@"Could not create texture cache."); + CVPixelBufferRelease(_pixelBuffer); + return NO; } + } - // Try to clear the cache of OpenGL textures to save memory. - CVOpenGLTextureCacheFlush(_textureCache, 0); - - CVOpenGLTextureRef openGLTexture = NULL; - if (CVOpenGLTextureCacheCreateTextureFromImage(kCFAllocatorDefault, _textureCache, _pixelBuffer, NULL, &openGLTexture) != kCVReturnSuccess) { - CVPixelBufferRelease(_pixelBuffer); - return NO; - } + // Try to clear the cache of OpenGL textures to save memory. + CVOpenGLTextureCacheFlush(_textureCache, 0); + + CVOpenGLTextureRef openGLTexture = NULL; + if (CVOpenGLTextureCacheCreateTextureFromImage(kCFAllocatorDefault, _textureCache, _pixelBuffer, NULL, &openGLTexture) != kCVReturnSuccess) { + CVPixelBufferRelease(_pixelBuffer); + return NO; + } - texture->target = CVOpenGLTextureGetTarget(openGLTexture); - texture->name = CVOpenGLTextureGetName(openGLTexture); - texture->format = GL_RGBA8; - texture->destruction_callback = (VoidCallback)&OnGLTextureRelease; - texture->user_data = openGLTexture; + texture->target = CVOpenGLTextureGetTarget(openGLTexture); + texture->name = CVOpenGLTextureGetName(openGLTexture); + texture->format = GL_RGBA8; + texture->destruction_callback = (VoidCallback)&OnGLTextureRelease; + texture->user_data = openGLTexture; - CVPixelBufferRelease(_pixelBuffer); - return YES; + CVPixelBufferRelease(_pixelBuffer); + return YES; } --(void) dealloc { - CVOpenGLTextureCacheRelease(_textureCache); +- (void)dealloc { + CVOpenGLTextureCacheRelease(_textureCache); } @end diff --git a/library/macos/FLETexture.h b/library/macos/FLETexture.h index c16b8f510..5808c86a3 100644 --- a/library/macos/FLETexture.h +++ b/library/macos/FLETexture.h @@ -15,18 +15,38 @@ #import #import +/** + * Implement a texture object for the FLE plugin side. + */ @protocol FLETexture +/** + * When the texture on the platform side is ready, + * the flutter engine will copy the texture buffer + * using copyPixelBuffer. + */ - (nullable CVPixelBufferRef)copyPixelBuffer; @end +/** + * The protocol for an object managing registration for texture. + */ @protocol FLETextureRegistrar +/** + * Register a |texture| object and return a textureId. + */ - (int64_t)registerTexture:(nonnull id)texture; +/** + * Mark a texture buffer is ready. + */ - (void)textureFrameAvailable:(int64_t)textureId; +/** + * Unregister an existing Texture object. + */ - (void)unregisterTexture:(int64_t)textureId; @end diff --git a/library/macos/FLEViewController.mm b/library/macos/FLEViewController.mm index a0ddac991..b0bed74d5 100644 --- a/library/macos/FLEViewController.mm +++ b/library/macos/FLEViewController.mm @@ -154,7 +154,7 @@ static bool OnAcquireExternalTexture(FLEViewController *controller, size_t width, size_t height, FlutterOpenGLTexture *texture) { - return [controller populateTextureWithIdentifier:texture_identifier width:width height:height texture:texture]; + return [controller populateTextureWithIdentifier:texture_identifier width:width height:height texture:texture]; } #pragma mark Static methods provided for headless engine configuration @@ -360,25 +360,28 @@ - (void)makeResourceContextCurrent { [_resourceContext makeCurrentContext]; } --(BOOL) populateTextureWithIdentifier:(int64_t) textureId width:(size_t) width height:(size_t) height texture:(FlutterOpenGLTexture *) texture { - return [_textures[@(textureId)] populateTextureWidth:width height:height texture:texture]; +- (BOOL)populateTextureWithIdentifier:(int64_t)textureId + width:(size_t)width + height:(size_t) height + texture:(FlutterOpenGLTexture *)texture { + return [_textures[@(textureId)] populateTextureWidth:width height:height texture:texture]; } -- (int64_t)registerTexture:(NSObject*)texture { - FLEExternalTexture *fleTexture = [[FLEExternalTexture alloc] initExternalTexture:texture]; - int64_t textureId = [fleTexture textureId]; - FlutterEngineRegisterExternalTexture(_engine, textureId); - _textures[@(textureId)] = fleTexture; - return textureId; +- (int64_t)registerTexture:(id)texture { + FLEExternalTexture *fleTexture = [[FLEExternalTexture alloc] initWithExternalTexture:texture]; + int64_t textureId = [fleTexture textureId]; + FlutterEngineRegisterExternalTexture(_engine, textureId); + _textures[@(textureId)] = fleTexture; + return textureId; } - (void)textureFrameAvailable:(int64_t)textureId { - FlutterEngineMarkExternalTextureFrameAvailable(_engine, textureId); + FlutterEngineMarkExternalTextureFrameAvailable(_engine, textureId); } - (void)unregisterTexture:(int64_t)textureId { - FlutterEngineUnregisterExternalTexture(_engine, textureId); - [_textures removeObjectForKey:@(textureId)]; + FlutterEngineUnregisterExternalTexture(_engine, textureId); + [_textures removeObjectForKey:@(textureId)]; } - (void)handlePlatformMessage:(const FlutterPlatformMessage *)message { From ae5c364dd46eb2e5dbdcb62363b924b469e3eafc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B9=96=E5=8C=97=E6=8D=B7=E6=99=BA=E4=BA=91=E6=8A=80?= =?UTF-8?q?=E6=9C=AF=E6=9C=89=E9=99=90=E5=85=AC=E5=8F=B8?= Date: Fri, 1 Feb 2019 18:03:38 +0800 Subject: [PATCH 11/12] Export the texture registrar declaration from FLEPluginRegistrar. --- library/macos/FLEExternalTexture.m | 6 +++++- library/macos/FLEPluginRegistrar.h | 6 ++++++ library/macos/FLEViewController.mm | 4 ++++ 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/library/macos/FLEExternalTexture.m b/library/macos/FLEExternalTexture.m index 35b3b9c3d..6d9cca26f 100644 --- a/library/macos/FLEExternalTexture.m +++ b/library/macos/FLEExternalTexture.m @@ -48,13 +48,17 @@ - (BOOL)populateTextureWidth:(size_t)width height:(size_t)height texture:(FlutterOpenGLTexture *)texture { - if(_pixelBuffer == NULL || external_texture == NULL){ + if(external_texture == NULL) { return NO; } // Copy image buffer from external texture. _pixelBuffer = [external_texture copyPixelBuffer]; + if(_pixelBuffer == NULL) { + return NO; + } + // Create the texture cache if necessary. if (_textureCache == NULL) { CGLContextObj context = [NSOpenGLContext currentContext].CGLContextObj; diff --git a/library/macos/FLEPluginRegistrar.h b/library/macos/FLEPluginRegistrar.h index 20401863e..f5660549d 100644 --- a/library/macos/FLEPluginRegistrar.h +++ b/library/macos/FLEPluginRegistrar.h @@ -16,6 +16,7 @@ #import "FLEBinaryMessenger.h" #import "FLEMethodChannel.h" +#import "FLETexture.h" /** * The protocol for an object managing registration for a plugin. It provides access to application @@ -31,6 +32,11 @@ */ @property(nonnull, readonly) id messenger; +/** + * Returns a `FLETextureRegistry` for registering textures provided by the plugin. + */ +@property(nonnull, readonly) id textures; + /** * The view displaying Flutter content. * diff --git a/library/macos/FLEViewController.mm b/library/macos/FLEViewController.mm index b0bed74d5..7c909ed5a 100644 --- a/library/macos/FLEViewController.mm +++ b/library/macos/FLEViewController.mm @@ -482,6 +482,10 @@ - (void)setMessageHandlerOnChannel:(nonnull NSString *)channel return self; } +- (id)textures { + return self; +} + - (void)addMethodCallDelegate:(nonnull id)delegate channel:(nonnull FLEMethodChannel *)channel { [channel setMethodCallHandler:^(FLEMethodCall *call, FLEMethodResult result) { From 93225f29fa011c436e610210451191c42b82ded3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B9=96=E5=8C=97=E6=8D=B7=E6=99=BA=E4=BA=91=E6=8A=80?= =?UTF-8?q?=E6=9C=AF=E6=9C=89=E9=99=90=E5=85=AC=E5=8F=B8?= Date: Fri, 1 Feb 2019 21:31:07 +0800 Subject: [PATCH 12/12] Update FLEExternalTexture.h --- library/macos/FLEExternalTexture.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/macos/FLEExternalTexture.h b/library/macos/FLEExternalTexture.h index 43de560be..ceaa25e97 100644 --- a/library/macos/FLEExternalTexture.h +++ b/library/macos/FLEExternalTexture.h @@ -27,7 +27,7 @@ /** * */ -- (nonnull instancetype)initWithExternalTexture:(id)external_texture; +- (nonnull instancetype)initWithExternalTexture:(nonnull id)external_texture; /** * Accept texture rendering notifications from the flutter engine.