Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.
Closed
Show file tree
Hide file tree
Changes from 1 commit
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
Prev Previous commit
Next Next commit
Create FlutterPlatformViewController
  • Loading branch information
RichardJCai committed Jan 18, 2021
commit f049b8b78d4e3a9b0f0f7413cce82f4a10e6244b
2 changes: 2 additions & 0 deletions ci/licenses_golden/licenses_flutter
Original file line number Diff line number Diff line change
Expand Up @@ -1094,6 +1094,8 @@ FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterMouse
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterOpenGLRenderer.h
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterOpenGLRenderer.mm
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterOpenGLRendererTest.mm
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterPlatformViewController.h
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterPlatformViewController.mm
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterPlatformViews.h
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterRenderer.h
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterResizableBackingStoreProvider.h
Expand Down
2 changes: 2 additions & 0 deletions shell/platform/darwin/macos/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ source_set("flutter_framework_source") {
"framework/Source/FlutterMouseCursorPlugin.mm",
"framework/Source/FlutterOpenGLRenderer.h",
"framework/Source/FlutterOpenGLRenderer.mm",
"framework/Source/FlutterPlatformViewController.mm",
"framework/Source/FlutterPlatformViewController_Internal.h",
"framework/Source/FlutterPlatformViews.h",
"framework/Source/FlutterRenderer.h",
"framework/Source/FlutterResizableBackingStoreProvider.h",
Expand Down
80 changes: 80 additions & 0 deletions shell/platform/darwin/macos/framework/Source/FlutterEngine.mm
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterMetalRenderer.h"
#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterOpenGLRenderer.h"
#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterViewController_Internal.h"
#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterPlatformViewController_Internal.h"
#import "flutter/shell/platform/embedder/embedder.h"

/**
Expand Down Expand Up @@ -141,6 +142,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 @@ -248,6 +256,9 @@ - (BOOL)runWithEntrypoint:(NSString*)entrypoint {
flutterArguments.aot_data = _aotData;
}

[self setupPlatformViewChannel];
[self createPlatformViewController];

flutterArguments.compositor = [self createFlutterCompositor];

FlutterRendererConfig rendererConfig = [_renderer createRendererConfig];
Expand Down Expand Up @@ -428,6 +439,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 @@ -504,6 +519,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 @@ -6,6 +6,7 @@

#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 Down Expand Up @@ -51,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 @@ -76,9 +78,6 @@ class FlutterGLCompositor {
// Set frame_started_ to true and reset all layer state.
void StartFrame();

// Remove platform views that are specified for deletion.
void DisposePlatformViews();

// Creates a CALayer and adds it to ca_layer_map_ and increments
// ca_layer_count_; Returns the key value (size_t) for the layer in
// ca_layer_map_.
Expand Down
36 changes: 15 additions & 21 deletions shell/platform/darwin/macos/framework/Source/FlutterGLCompositor.mm
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,11 @@
NSOpenGLContext* opengl_context)
: open_gl_context_(opengl_context) {
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 @@ -75,7 +79,7 @@
}

bool FlutterGLCompositor::Present(const FlutterLayer** layers, size_t layers_count) {
DisposePlatformViews();
[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);
Expand All @@ -89,9 +93,15 @@
break;
}
case kFlutterLayerContentTypePlatformView:
FML_CHECK([[NSThread currentThread] isMainThread])
FML_DCHECK([[NSThread currentThread] isMainThread])
<< "Must be on the main thread to handle presenting platform views";
NSView* platform_view = view_controller_.platformViews[layer->platform_view->identifier];

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);
Expand All @@ -112,15 +122,15 @@
void FlutterGLCompositor::PresentBackingStoreContent(
FlutterBackingStoreData* flutter_backing_store_data,
size_t layer_position) {
FML_CHECK([[NSThread currentThread] isMainThread])
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_CHECK(content_layer) << "Unable to find a content layer with layer id " << 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;
Expand Down Expand Up @@ -162,20 +172,4 @@
return ca_layer_count_++;
}

void FlutterGLCompositor::DisposePlatformViews() {
auto views_to_dispose = view_controller_.platformViewsToDispose;
if (views_to_dispose.empty()) {
return;
}

for (int64_t viewId : views_to_dispose) {
FML_CHECK([[NSThread currentThread] isMainThread])
<< "Must be on the main thread to handle disposing platform views";
NSView* view = view_controller_.platformViews[viewId];
[view removeFromSuperview];
view_controller_.platformViews.erase(viewId);
}
views_to_dispose.clear();
}

} // namespace flutter
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, nullptr);
std::make_unique<FlutterGLCompositor>(mockViewController, platformViewController);

bool flag = false;
macos_compositor->SetPresentCallback([f = &flag]() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
// 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.

#include "flutter/fml/logging.h"

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

@implementation FlutterPlatformViewController

- (instancetype)init {
self = [super init];

self->_platformViewFactories = [[NSMutableDictionary alloc] init];
return self;
}

- (void)onCreateWithViewId:(int64_t)viewId
viewType:(nonnull NSString*)viewType
result:(nonnull FlutterResult)result {
if (_platformViews.count(viewId) != 0) {
result([FlutterError errorWithCode:@"recreating_view"
message:@"trying to create an already created view"
details:[NSString stringWithFormat:@"view id: '%lld'", viewId]]);
}

NSObject<FlutterPlatformViewFactory>* factory = _platformViewFactories[viewType];
if (factory == nil) {
result([FlutterError
errorWithCode:@"unregistered_view_type"
message:@"trying to create a view with an unregistered type"
details:[NSString stringWithFormat:@"unregistered view type: '%@'", viewType]]);
return;
}

NSObject<FlutterPlatformView>* platform_view = [factory createWithFrame:CGRectZero
viewIdentifier:viewId
arguments:nil];
Copy link
Contributor

Choose a reason for hiding this comment

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

Why is this always nil?


_platformViews[viewId] = [platform_view view];
result(nil);
}

- (void)onDisposeWithViewId:(int64_t)viewId result:(nonnull FlutterResult)result {
if (_platformViews.count(viewId) == 0) {
result([FlutterError errorWithCode:@"unknown_view"
message:@"trying to dispose an unknown"
details:[NSString stringWithFormat:@"view id: '%lld'", viewId]]);
return;
}

// The following disposePlatformViews call will dispose the views.
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm not sure what "the following [...] call" is referring to here. Do you mean "The next call to"?

_platformViewsToDispose.insert(viewId);
Copy link
Contributor

Choose a reason for hiding this comment

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

Given that you're already doing a lookup to see if it's present anyway, why not insert the view itself here to avoid a second lookup later (and to make the structure match its name; it sounds like it contains views, but currently doesn't).

result(nil);
}

- (void)registerViewFactory:(nonnull NSObject<FlutterPlatformViewFactory>*)factory
withId:(nonnull NSString*)factoryId {
_platformViewFactories[factoryId] = factory;
}

- (void)handleMethodCall:(nonnull FlutterMethodCall*)call result:(nonnull FlutterResult)result {
if ([[call method] isEqualToString:@"create"]) {
NSMutableDictionary<NSString*, id>* args = [call arguments];
int64_t viewId = [args[@"id"] longValue];
NSString* viewType = [NSString stringWithUTF8String:([args[@"viewType"] UTF8String])];
Copy link
Contributor

Choose a reason for hiding this comment

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

Why are you round-tripping through a C string here?

[self onCreateWithViewId:viewId viewType:viewType result:result];
} else if ([[call method] isEqualToString:@"dispose"]) {
NSNumber* arg = [call arguments];
int64_t viewId = [arg longLongValue];
[self onDisposeWithViewId:viewId result:result];
} else {
result(FlutterMethodNotImplemented);
}
}

- (void)disposePlatformViews {
if (_platformViewsToDispose.empty()) {
return;
}

FML_DCHECK([[NSThread currentThread] isMainThread])
<< "Must be on the main thread to handle disposing platform views";
for (int64_t viewId : _platformViewsToDispose) {
NSView* view = _platformViews[viewId];
[view removeFromSuperview];
_platformViews.erase(viewId);
}
_platformViewsToDispose.clear();
}

@end
Loading