Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Add an Info.plist flag to enable MacOS platform views preview support #22929

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions ci/licenses_golden/licenses_flutter
Original file line number Diff line number Diff line change
Expand Up @@ -1056,6 +1056,7 @@ FILE: ../../../flutter/shell/platform/darwin/macos/framework/Info.plist
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterAppDelegate.mm
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterBackingStoreData.h
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterBackingStoreData.mm
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterConstants.h
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterDartProject.mm
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterDartProject_Internal.h
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterEngine.mm
Expand All @@ -1072,6 +1073,12 @@ FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterIOSur
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterIOSurfaceHolder.mm
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterMouseCursorPlugin.h
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterMouseCursorPlugin.mm
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterPlatformViewController.mm
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterPlatformViewControllerTest.mm
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterPlatformViewController_Internal.h
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterPlatformViewMock.h
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterPlatformViewMock.mm
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterPlatformViews.h
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterResizeSynchronizer.h
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterResizeSynchronizer.mm
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterSurfaceManager.h
Expand Down
6 changes: 6 additions & 0 deletions shell/platform/darwin/macos/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,9 @@ source_set("flutter_framework_source") {
"framework/Source/FlutterIOSurfaceHolder.mm",
"framework/Source/FlutterMouseCursorPlugin.h",
"framework/Source/FlutterMouseCursorPlugin.mm",
"framework/Source/FlutterPlatformViewController.mm",
"framework/Source/FlutterPlatformViewController_Internal.h",
"framework/Source/FlutterPlatformViews.h",
"framework/Source/FlutterResizeSynchronizer.h",
"framework/Source/FlutterResizeSynchronizer.mm",
"framework/Source/FlutterSurfaceManager.h",
Expand Down Expand Up @@ -127,6 +130,9 @@ executable("flutter_desktop_darwin_unittests") {
sources = [
"framework/Source/FlutterEngineTest.mm",
"framework/Source/FlutterGLCompositorUnittests.mm",
"framework/Source/FlutterPlatformViewControllerTest.mm",
"framework/Source/FlutterPlatformViewMock.h",
"framework/Source/FlutterPlatformViewMock.mm",
"framework/Source/FlutterViewControllerTest.mm",
"framework/Source/FlutterViewControllerTestUtils.h",
"framework/Source/FlutterViewControllerTestUtils.mm",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// 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.

// The name of the Info.plist flag to enable the embedded MacOS views preview.
const char* const kEmbeddedViewsPreview = "io.flutter_embedded_views_preview";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't need the constant in a separate file, can move it to FlutterPlatformViewController.mm

137 changes: 88 additions & 49 deletions shell/platform/darwin/macos/framework/Source/FlutterEngine.mm
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterDartProject_Internal.h"
#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterExternalTextureGL.h"
#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterGLCompositor.h"
#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterPlatformViewController_Internal.h"
#import "flutter/shell/platform/embedder/embedder.h"

/**
Expand Down Expand Up @@ -204,6 +205,13 @@ @implementation FlutterEngine {

// FlutterCompositor is copied and used in embedder.cc.
FlutterCompositor _compositor;

// A method channel for platform view functionality.
FlutterMethodChannel* _platformViewsChannel;

// Used to support creation and deletion of platform views and
// registering platform view factories.
FlutterPlatformViewController* _platformViewController;
}

- (instancetype)initWithName:(NSString*)labelPrefix project:(FlutterDartProject*)project {
Expand Down Expand Up @@ -302,17 +310,27 @@ - (BOOL)runWithEntrypoint:(NSString*)entrypoint {
},
.identifier = ++sTaskRunnerIdentifiers,
};

bool embedded_views_preview_enabled = [FlutterPlatformViewController embeddedViewsEnabled];

const FlutterCustomTaskRunners custom_task_runners = {
.struct_size = sizeof(FlutterCustomTaskRunners),
.platform_task_runner = &cocoa_task_runner_description,
};
// If platform views are enabled, set the render thread to the platform thread.
// Otherwise the render thread is created separately in embedder_thread_host.cc.
.render_task_runner =
embedded_views_preview_enabled ? &cocoa_task_runner_description : nullptr};

flutterArguments.custom_task_runners = &custom_task_runners;

[self loadAOTData:_project.assetsPath];
if (_aotData) {
flutterArguments.aot_data = _aotData;
}

[self setupPlatformViewChannel];
[self createPlatformViewController];

flutterArguments.compositor = [self createFlutterCompositor];

FlutterEngineResult result = _embedderAPI.Initialize(
Expand Down Expand Up @@ -369,54 +387,6 @@ - (void)setViewController:(FlutterViewController*)controller {
}
}

- (FlutterCompositor*)createFlutterCompositor {
// TODO(richardjcai): Add support for creating a FlutterGLCompositor
// with a nil _viewController for headless engines.
// https://github.com/flutter/flutter/issues/71606
if (_viewController == nullptr) {
return nullptr;
}

[_mainOpenGLContext makeCurrentContext];

_macOSGLCompositor = std::make_unique<flutter::FlutterGLCompositor>(_viewController);

_compositor = {};
_compositor.struct_size = sizeof(FlutterCompositor);
_compositor.user_data = _macOSGLCompositor.get();

_compositor.create_backing_store_callback = [](const FlutterBackingStoreConfig* config, //
FlutterBackingStore* backing_store_out, //
void* user_data //
) {
return reinterpret_cast<flutter::FlutterGLCompositor*>(user_data)->CreateBackingStore(
config, backing_store_out);
};

_compositor.collect_backing_store_callback = [](const FlutterBackingStore* backing_store, //
void* user_data //
) {
return reinterpret_cast<flutter::FlutterGLCompositor*>(user_data)->CollectBackingStore(
backing_store);
};

_compositor.present_layers_callback = [](const FlutterLayer** layers, //
size_t layers_count, //
void* user_data //
) {
return reinterpret_cast<flutter::FlutterGLCompositor*>(user_data)->Present(layers,
layers_count);
};

__weak FlutterEngine* weak_self = self;
_macOSGLCompositor->SetPresentCallback(
[weak_self]() { return [weak_self engineCallbackOnPresent]; });

_compositor.avoid_backing_store_cache = true;

return &_compositor;
}

- (id<FlutterBinaryMessenger>)binaryMessenger {
// TODO(stuartmorgan): Switch to FlutterBinaryMessengerRelay to avoid plugins
// keeping the engine alive.
Expand Down Expand Up @@ -493,6 +463,10 @@ - (void)sendPointerEvent:(const FlutterPointerEvent&)event {
_embedderAPI.SendPointerEvent(_engine, &event, 1);
}

- (FlutterPlatformViewController*)platformViewController {
return _platformViewController;
}

#pragma mark - Private methods

- (void)sendUserLocales {
Expand Down Expand Up @@ -600,6 +574,71 @@ - (void)shutDownEngine {
_engine = nullptr;
}

- (FlutterCompositor*)createFlutterCompositor {
// TODO(richardjcai): Add support for creating a FlutterGLCompositor
// with a nil _viewController for headless engines.
// https://github.com/flutter/flutter/issues/71606
if (_viewController == nullptr) {
return nullptr;
}

[_mainOpenGLContext makeCurrentContext];

_macOSGLCompositor =
std::make_unique<flutter::FlutterGLCompositor>(_viewController, _platformViewController);

_compositor = {};
_compositor.struct_size = sizeof(FlutterCompositor);
_compositor.user_data = _macOSGLCompositor.get();

_compositor.create_backing_store_callback = [](const FlutterBackingStoreConfig* config, //
FlutterBackingStore* backing_store_out, //
void* user_data //
) {
return reinterpret_cast<flutter::FlutterGLCompositor*>(user_data)->CreateBackingStore(
config, backing_store_out);
};

_compositor.collect_backing_store_callback = [](const FlutterBackingStore* backing_store, //
void* user_data //
) {
return reinterpret_cast<flutter::FlutterGLCompositor*>(user_data)->CollectBackingStore(
backing_store);
};

_compositor.present_layers_callback = [](const FlutterLayer** layers, //
size_t layers_count, //
void* user_data //
) {
return reinterpret_cast<flutter::FlutterGLCompositor*>(user_data)->Present(layers,
layers_count);
};

__weak FlutterEngine* weak_self = self;
_macOSGLCompositor->SetPresentCallback(
[weak_self]() { return [weak_self engineCallbackOnPresent]; });

_compositor.avoid_backing_store_cache = true;

return &_compositor;
}

- (void)createPlatformViewController {
_platformViewController = [[FlutterPlatformViewController alloc] init];
}

- (void)setupPlatformViewChannel {
_platformViewsChannel =
[FlutterMethodChannel methodChannelWithName:@"flutter/platform_views"
binaryMessenger:self.binaryMessenger
codec:[FlutterStandardMethodCodec sharedInstance]];

__weak FlutterEngine* weak_self = self;
[_platformViewsChannel setMethodCallHandler:^(FlutterMethodCall* call, FlutterResult result) {
[[weak_self platformViewController] handleMethodCall:call result:result];
}];
}

#pragma mark - FlutterBinaryMessenger

- (void)sendOnChannel:(nonnull NSString*)channel message:(nullable NSData*)message {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
#include <map>

#include "flutter/fml/macros.h"
#include "flutter/shell/platform/darwin/macos/framework/Source/FlutterBackingStoreData.h"
#include "flutter/shell/platform/darwin/macos/framework/Source/FlutterPlatformViewController_Internal.h"
#include "flutter/shell/platform/darwin/macos/framework/Source/FlutterSurfaceManager.h"
#include "flutter/shell/platform/darwin/macos/framework/Source/FlutterViewController_Internal.h"
#include "flutter/shell/platform/embedder/embedder.h"
Expand All @@ -18,7 +20,8 @@ namespace flutter {
// FlutterGLCompositor is created and destroyed by FlutterEngine.
class FlutterGLCompositor {
public:
FlutterGLCompositor(FlutterViewController* view_controller);
FlutterGLCompositor(FlutterViewController* view_controller,
FlutterPlatformViewController* platform_view_controller);

// Creates a BackingStore and saves updates the backing_store_out
// data with the new BackingStore data.
Expand Down Expand Up @@ -49,6 +52,7 @@ class FlutterGLCompositor {

private:
const FlutterViewController* view_controller_;
const FlutterPlatformViewController* platform_view_controller_;
const NSOpenGLContext* open_gl_context_;
PresentCallback present_callback_;

Expand All @@ -66,6 +70,11 @@ class FlutterGLCompositor {
// created for the frame.
bool frame_started_ = false;

// Update the backing CALayer using the backing store's specifications.
void PresentBackingStoreContent(
FlutterBackingStoreData* flutter_backing_store_data,
size_t layer_position);

// Set frame_started_ to true and reset all layer state.
void StartFrame();

Expand Down
68 changes: 49 additions & 19 deletions shell/platform/darwin/macos/framework/Source/FlutterGLCompositor.mm
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,15 @@

namespace flutter {

FlutterGLCompositor::FlutterGLCompositor(FlutterViewController* view_controller)
FlutterGLCompositor::FlutterGLCompositor(FlutterViewController* view_controller,
FlutterPlatformViewController* platform_view_controller)
: open_gl_context_(view_controller.flutterView.openGLContext) {
FML_CHECK(view_controller != nullptr) << "FlutterViewController* cannot be nullptr";
FML_CHECK(platform_view_controller != nullptr)
<< "FlutterPlatformViewController* cannot be nullptr";

view_controller_ = view_controller;
platform_view_controller_ = platform_view_controller;
}

bool FlutterGLCompositor::CreateBackingStore(const FlutterBackingStoreConfig* config,
Expand Down Expand Up @@ -71,35 +76,37 @@
}

bool FlutterGLCompositor::Present(const FlutterLayer** layers, size_t layers_count) {
[platform_view_controller_ disposePlatformViews];
for (size_t i = 0; i < layers_count; ++i) {
const auto* layer = layers[i];
FlutterBackingStore* backing_store = const_cast<FlutterBackingStore*>(layer->backing_store);
switch (layer->type) {
case kFlutterLayerContentTypeBackingStore: {
if (backing_store->open_gl.framebuffer.user_data) {
FlutterBackingStoreData* backing_store_data =
FlutterBackingStoreData* flutter_backing_store_data =
(__bridge FlutterBackingStoreData*)backing_store->open_gl.framebuffer.user_data;

FlutterIOSurfaceHolder* io_surface_holder = [backing_store_data ioSurfaceHolder];
size_t layer_id = [backing_store_data layerId];

CALayer* content_layer = ca_layer_map_[layer_id];

FML_CHECK(content_layer) << "Unable to find a content layer with layer id " << layer_id;

content_layer.frame = content_layer.superlayer.bounds;

// The surface is an OpenGL texture, which means it has origin in bottom left corner
// and needs to be flipped vertically
content_layer.transform = CATransform3DMakeScale(1, -1, 1);
IOSurfaceRef io_surface_contents = [io_surface_holder ioSurface];
[content_layer setContents:(__bridge id)io_surface_contents];
PresentBackingStoreContent(flutter_backing_store_data, i);
}
break;
}
case kFlutterLayerContentTypePlatformView:
// Add functionality in follow up PR.
FML_LOG(WARNING) << "Presenting PlatformViews not yet supported";
FML_DCHECK([[NSThread currentThread] isMainThread])
<< "Must be on the main thread to handle presenting platform views";

FML_DCHECK(platform_view_controller_.platformViews.count(layer->platform_view->identifier))
<< "Platform view not found for id: " << layer->platform_view->identifier;

NSView* platform_view =
platform_view_controller_.platformViews[layer->platform_view->identifier];

CGFloat scale = [[NSScreen mainScreen] backingScaleFactor];
platform_view.frame = CGRectMake(layer->offset.x / scale, layer->offset.y / scale,
layer->size.width / scale, layer->size.height / scale);
if (platform_view.superview == nil) {
[view_controller_.flutterView addSubview:platform_view];
} else {
platform_view.layer.zPosition = i;
}
break;
};
}
Expand All @@ -109,6 +116,29 @@
return present_callback_();
}

void FlutterGLCompositor::PresentBackingStoreContent(
FlutterBackingStoreData* flutter_backing_store_data,
size_t layer_position) {
FML_DCHECK([[NSThread currentThread] isMainThread])
<< "Must be on the main thread to update CALayer contents";

FlutterIOSurfaceHolder* io_surface_holder = [flutter_backing_store_data ioSurfaceHolder];
size_t layer_id = [flutter_backing_store_data layerId];

CALayer* content_layer = ca_layer_map_[layer_id];

FML_DCHECK(content_layer) << "Unable to find a content layer with layer id " << layer_id;

content_layer.frame = content_layer.superlayer.bounds;
content_layer.zPosition = layer_position;

// The surface is an OpenGL texture, which means it has origin in bottom left corner
// and needs to be flipped vertically
content_layer.transform = CATransform3DMakeScale(1, -1, 1);
IOSurfaceRef io_surface_contents = [io_surface_holder ioSurface];
[content_layer setContents:(__bridge id)io_surface_contents];
}

void FlutterGLCompositor::SetPresentCallback(
const FlutterGLCompositor::PresentCallback& present_callback) {
present_callback_ = present_callback;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,19 @@
#import <Foundation/Foundation.h>

#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterGLCompositor.h"
#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterPlatformViewController_Internal.h"
#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterViewControllerTestUtils.h"
#import "flutter/testing/testing.h"

namespace flutter::testing {

TEST(FlutterGLCompositorTest, TestPresent) {
id mockViewController = CreateMockViewController(nil);
FlutterPlatformViewController* platformViewController =
[[FlutterPlatformViewController alloc] init];

std::unique_ptr<flutter::FlutterGLCompositor> macos_compositor =
std::make_unique<FlutterGLCompositor>(mockViewController);
std::make_unique<FlutterGLCompositor>(mockViewController, platformViewController);

bool flag = false;
macos_compositor->SetPresentCallback([f = &flag]() {
Expand Down
Loading