From cd25486f13b43e0a5d43f136d95cc0d4d486acbe Mon Sep 17 00:00:00 2001 From: Alex Wallen Date: Fri, 28 Oct 2022 09:24:08 -1000 Subject: [PATCH] [macOS] Make the default background color black. (flutter/engine#36906) --- .../framework/Headers/FlutterViewController.h | 44 +++++++++++++ .../framework/Source/FlutterEngineTest.mm | 61 +++++++++++++++++++ .../macos/framework/Source/FlutterView.h | 9 +++ .../macos/framework/Source/FlutterView.mm | 6 ++ .../framework/Source/FlutterViewController.mm | 14 +++++ .../Source/fixtures/flutter_desktop_test.dart | 6 ++ 6 files changed, 140 insertions(+) diff --git a/engine/src/flutter/shell/platform/darwin/macos/framework/Headers/FlutterViewController.h b/engine/src/flutter/shell/platform/darwin/macos/framework/Headers/FlutterViewController.h index 038db1f322..53e26fbad4 100644 --- a/engine/src/flutter/shell/platform/darwin/macos/framework/Headers/FlutterViewController.h +++ b/engine/src/flutter/shell/platform/darwin/macos/framework/Headers/FlutterViewController.h @@ -73,4 +73,48 @@ FLUTTER_DARWIN_EXPORT */ - (void)onPreEngineRestart; +/** + * The contentView (FlutterView)'s background color is set to black during + * its instantiation. + * + * The containing layer's color can be set to the NSColor provided to this method. + * + * For example, the background may be set after the FlutterViewController + * is instantiated in MainFlutterWindow.swift in the Flutter project. + * ```swift + * import Cocoa + * import FlutterMacOS + * + * class MainFlutterWindow: NSWindow { + * override func awakeFromNib() { + * let flutterViewController = FlutterViewController.init() + * + * // The background color of the window and `FlutterViewController` + * // are retained separately. + * // + * // In this example, both the MainFlutterWindow and FlutterViewController's + * // FlutterView's backgroundColor are set to clear to achieve a fully + * // transparent effect. + * // + * // If the window's background color is not set, it will use the system + * // default. + * // + * // If the `FlutterView`'s color is not set via `FlutterViewController.setBackgroundColor` + * // it's default will be black. + * self.backgroundColor = NSColor.clear + * flutterViewController.backgroundColor = NSColor.clear + * + * let windowFrame = self.frame + * self.contentViewController = flutterViewController + * self.setFrame(windowFrame, display: true) + * + * RegisterGeneratedPlugins(registry: flutterViewController) + * + * super.awakeFromNib() + * } + * } + * ``` + */ +@property(readwrite, nonatomic, nullable) NSColor* backgroundColor; + @end diff --git a/engine/src/flutter/shell/platform/darwin/macos/framework/Source/FlutterEngineTest.mm b/engine/src/flutter/shell/platform/darwin/macos/framework/Source/FlutterEngineTest.mm index 439519575e..f6ac4a37a1 100644 --- a/engine/src/flutter/shell/platform/darwin/macos/framework/Source/FlutterEngineTest.mm +++ b/engine/src/flutter/shell/platform/darwin/macos/framework/Source/FlutterEngineTest.mm @@ -101,6 +101,67 @@ TEST_F(FlutterEngineTest, CanLogToStdout) { EXPECT_TRUE(logs.find("Hello logging") != std::string::npos); } +TEST_F(FlutterEngineTest, BackgroundIsBlack) { + // Launch the test entrypoint. + FlutterEngine* engine = GetFlutterEngine(); + EXPECT_TRUE([engine runWithEntrypoint:@"backgroundTest"]); + EXPECT_TRUE(engine.running); + + NSString* fixtures = @(flutter::testing::GetFixturesPath()); + FlutterDartProject* project = [[FlutterDartProject alloc] + initWithAssetsPath:fixtures + ICUDataPath:[fixtures stringByAppendingString:@"/icudtl.dat"]]; + FlutterViewController* viewController = [[FlutterViewController alloc] initWithProject:project]; + [viewController loadView]; + viewController.flutterView.frame = CGRectMake(0, 0, 800, 600); + [engine setViewController:viewController]; + + // Latch to ensure the entire layer tree has been generated and presented. + fml::AutoResetWaitableEvent latch; + AddNativeCallback("SignalNativeTest", CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) { + CALayer* rootLayer = engine.viewController.flutterView.layer; + EXPECT_TRUE(rootLayer.backgroundColor != nil); + if (rootLayer.backgroundColor != nil) { + NSColor* actualBackgroundColor = + [NSColor colorWithCGColor:rootLayer.backgroundColor]; + EXPECT_EQ(actualBackgroundColor, [NSColor blackColor]); + } + latch.Signal(); + })); + latch.Wait(); +} + +TEST_F(FlutterEngineTest, CanOverrideBackgroundColor) { + // Launch the test entrypoint. + FlutterEngine* engine = GetFlutterEngine(); + EXPECT_TRUE([engine runWithEntrypoint:@"backgroundTest"]); + EXPECT_TRUE(engine.running); + + NSString* fixtures = @(flutter::testing::GetFixturesPath()); + FlutterDartProject* project = [[FlutterDartProject alloc] + initWithAssetsPath:fixtures + ICUDataPath:[fixtures stringByAppendingString:@"/icudtl.dat"]]; + FlutterViewController* viewController = [[FlutterViewController alloc] initWithProject:project]; + [viewController loadView]; + viewController.flutterView.frame = CGRectMake(0, 0, 800, 600); + [engine setViewController:viewController]; + viewController.flutterView.backgroundColor = [NSColor whiteColor]; + + // Latch to ensure the entire layer tree has been generated and presented. + fml::AutoResetWaitableEvent latch; + AddNativeCallback("SignalNativeTest", CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) { + CALayer* rootLayer = engine.viewController.flutterView.layer; + EXPECT_TRUE(rootLayer.backgroundColor != nil); + if (rootLayer.backgroundColor != nil) { + NSColor* actualBackgroundColor = + [NSColor colorWithCGColor:rootLayer.backgroundColor]; + EXPECT_EQ(actualBackgroundColor, [NSColor whiteColor]); + } + latch.Signal(); + })); + latch.Wait(); +} + TEST_F(FlutterEngineTest, CanToggleAccessibility) { FlutterEngine* engine = GetFlutterEngine(); // Capture the update callbacks before the embedder API initializes. diff --git a/engine/src/flutter/shell/platform/darwin/macos/framework/Source/FlutterView.h b/engine/src/flutter/shell/platform/darwin/macos/framework/Source/FlutterView.h index 8aed110e70..6dd21830b2 100644 --- a/engine/src/flutter/shell/platform/darwin/macos/framework/Source/FlutterView.h +++ b/engine/src/flutter/shell/platform/darwin/macos/framework/Source/FlutterView.h @@ -68,4 +68,13 @@ */ - (void)shutdown; +/** + * By default, the `FlutterSurfaceManager` creates two layers to manage Flutter + * content, the content layer and containing layer. To set the native background + * color, onto which the Flutter content is drawn, call this method with the + * NSColor which you would like to override the default, black background color + * with. + */ +- (void)setBackgroundColor:(nonnull NSColor*)color; + @end diff --git a/engine/src/flutter/shell/platform/darwin/macos/framework/Source/FlutterView.mm b/engine/src/flutter/shell/platform/darwin/macos/framework/Source/FlutterView.mm index 30c0a4495a..b2c85efba3 100644 --- a/engine/src/flutter/shell/platform/darwin/macos/framework/Source/FlutterView.mm +++ b/engine/src/flutter/shell/platform/darwin/macos/framework/Source/FlutterView.mm @@ -28,6 +28,7 @@ self = [super initWithFrame:NSZeroRect]; if (self) { [self setWantsLayer:YES]; + [self setBackgroundColor:[NSColor blackColor]]; [self setLayerContentsRedrawPolicy:NSViewLayerContentsRedrawDuringViewResize]; _reshapeListener = reshapeListener; _resizableBackingStoreProvider = @@ -51,6 +52,7 @@ self = [super initWithFrame:frame]; if (self) { [self setWantsLayer:YES]; + [self setBackgroundColor:[NSColor blackColor]]; _reshapeListener = reshapeListener; _resizableBackingStoreProvider = [[FlutterOpenGLResizableBackingStoreProvider alloc] initWithMainContext:mainContext @@ -84,6 +86,10 @@ }]; } +- (void)setBackgroundColor:(NSColor*)color { + self.layer.backgroundColor = color.CGColor; +} + #pragma mark - NSView overrides - (void)setFrameSize:(NSSize)newSize { diff --git a/engine/src/flutter/shell/platform/darwin/macos/framework/Source/FlutterViewController.mm b/engine/src/flutter/shell/platform/darwin/macos/framework/Source/FlutterViewController.mm index cb47201840..d78c3941aa 100644 --- a/engine/src/flutter/shell/platform/darwin/macos/framework/Source/FlutterViewController.mm +++ b/engine/src/flutter/shell/platform/darwin/macos/framework/Source/FlutterViewController.mm @@ -159,6 +159,8 @@ NSData* currentKeyboardLayoutData() { */ @interface FlutterViewWrapper : NSView +- (void)setBackgroundColor:(NSColor*)color; + @end /** @@ -266,6 +268,10 @@ void OnKeyboardLayoutChanged(CFNotificationCenterRef center, return self; } +- (void)setBackgroundColor:(NSColor*)color { + [_flutterView setBackgroundColor:color]; +} + - (NSArray*)accessibilityChildren { return @[ _flutterView ]; } @@ -376,6 +382,9 @@ static void CommonInit(FlutterViewController* controller) { } flutterView = [[FlutterView alloc] initWithMainContext:mainContext reshapeListener:self]; } + if (_backgroundColor != nil) { + [flutterView setBackgroundColor:_backgroundColor]; + } FlutterViewWrapper* wrapperView = [[FlutterViewWrapper alloc] initWithFlutterView:flutterView]; self.view = wrapperView; _flutterView = flutterView; @@ -418,6 +427,11 @@ static void CommonInit(FlutterViewController* controller) { [self configureTrackingArea]; } +- (void)setBackgroundColor:(NSColor*)color { + _backgroundColor = color; + [_flutterView setBackgroundColor:_backgroundColor]; +} + - (void)onPreEngineRestart { [self initializeKeyboard]; } diff --git a/engine/src/flutter/shell/platform/darwin/macos/framework/Source/fixtures/flutter_desktop_test.dart b/engine/src/flutter/shell/platform/darwin/macos/framework/Source/fixtures/flutter_desktop_test.dart index 50c31f3adc..afdc3275e9 100644 --- a/engine/src/flutter/shell/platform/darwin/macos/framework/Source/fixtures/flutter_desktop_test.dart +++ b/engine/src/flutter/shell/platform/darwin/macos/framework/Source/fixtures/flutter_desktop_test.dart @@ -57,3 +57,9 @@ Picture _createSimplePicture() { void nativeCallback() { signalNativeTest(); } + +@pragma('vm:entry-point') +void backgroundTest() { + PlatformDispatcher.instance.views.first.render(SceneBuilder().build()); + signalNativeTest(); // should look black +}