mirror of
https://github.com/Tencent/Hippy.git
synced 2026-10-28 05:07:51 +08:00
326 lines
9.6 KiB
Dart
326 lines
9.6 KiB
Dart
//
|
|
// Tencent is pleased to support the open source community by making
|
|
// Hippy available.
|
|
//
|
|
// Copyright (C) 2022 THL A29 Limited, a Tencent company.
|
|
// All rights reserved.
|
|
//
|
|
// 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 'dart:convert';
|
|
import 'dart:ffi';
|
|
|
|
import 'package:ffi/ffi.dart';
|
|
import 'package:flutter/services.dart';
|
|
import 'package:voltron_ffi/voltron_ffi.dart';
|
|
|
|
import '../style.dart';
|
|
import '../util.dart';
|
|
import 'render_bridge.dart';
|
|
import 'render_bridge_define.dart';
|
|
|
|
/// 管理dart to c++方法调用以及c++ to dart方法注册逻辑
|
|
class _RenderBridgeFFIManager {
|
|
static final _RenderBridgeFFIManager _instance = _RenderBridgeFFIManager._internal();
|
|
static const String _kRenderRegisterHeader = 'voltron_renderer_register';
|
|
|
|
factory _RenderBridgeFFIManager() => _instance;
|
|
|
|
static _RenderBridgeFFIManager get instance => _instance;
|
|
|
|
final _library = FfiManager().library;
|
|
|
|
// 调用c++ dom相关方法
|
|
late CallNativeFunctionFfiDartType callNativeFunction;
|
|
|
|
// 调用c++ dom相关的事件
|
|
late CallNativeEventFfiDartType callNativeEvent;
|
|
|
|
// 更新节点宽高
|
|
late UpdateNodeSizeFfiDartType updateNodeSize;
|
|
|
|
// 创建voltron native render manager
|
|
late CreateVoltronRenderDartType createNativeRender;
|
|
|
|
// 销毁voltron native render manager
|
|
late DestroyVoltronRenderDartType destroyNativeRender;
|
|
|
|
// 向native注册或者删除rootView
|
|
late AddRootFfiDartType addRoot;
|
|
late RemoveRootFfiDartType removeRoot;
|
|
|
|
late CreateDomFfiDartType createDom;
|
|
late DestroyDomFfiDartType destroyDom;
|
|
|
|
_RenderBridgeFFIManager._internal() {
|
|
createNativeRender =
|
|
_library.lookupFunction<CreateVoltronRenderNativeType, CreateVoltronRenderDartType>(
|
|
'CreateVoltronRenderProvider',
|
|
);
|
|
|
|
destroyNativeRender =
|
|
_library.lookupFunction<DestroyVoltronRenderNativeType, DestroyVoltronRenderDartType>(
|
|
'DestroyVoltronRenderProvider',
|
|
);
|
|
|
|
createDom = _library.lookupFunction<CreateDomFfiNativeType, CreateDomFfiDartType>(
|
|
'CreateDomInstance',
|
|
);
|
|
|
|
destroyDom = _library.lookupFunction<DestroyDomFfiNativeType, DestroyDomFfiDartType>(
|
|
'DestroyDomInstance',
|
|
);
|
|
|
|
addRoot = _library.lookupFunction<AddRootFfiNativeType, AddRootFfiDartType>(
|
|
'AddRoot',
|
|
);
|
|
removeRoot = _library.lookupFunction<RemoveRootFfiNativeType, RemoveRootFfiDartType>(
|
|
'RemoveRoot',
|
|
);
|
|
|
|
callNativeFunction =
|
|
_library.lookupFunction<CallNativeFunctionFfiNativeType, CallNativeFunctionFfiDartType>(
|
|
"CallNativeFunctionFFI",
|
|
);
|
|
|
|
callNativeEvent =
|
|
_library.lookupFunction<CallNativeEventFfiNativeType, CallNativeEventFfiDartType>(
|
|
"CallNativeEventFFI",
|
|
);
|
|
|
|
updateNodeSize =
|
|
_library.lookupFunction<UpdateNodeSizeFfiNativeType, UpdateNodeSizeFfiDartType>(
|
|
'UpdateNodeSize',
|
|
);
|
|
}
|
|
}
|
|
|
|
/// 封装dart to c++的api调用,处理各种中间数据
|
|
class VoltronRenderApi {
|
|
static bool _isInit = false;
|
|
|
|
static void init() {
|
|
if (!_isInit) {
|
|
_RenderBridgeFFIManager();
|
|
initBridge();
|
|
_isInit = true;
|
|
}
|
|
}
|
|
|
|
static int createNativeRender(double density) {
|
|
return _RenderBridgeFFIManager.instance.createNativeRender(density);
|
|
}
|
|
|
|
static Future destroyNativeRender(int nativeRenderId) async {
|
|
_RenderBridgeFFIManager.instance.destroyNativeRender(nativeRenderId);
|
|
}
|
|
|
|
static int createDomInstance() {
|
|
return _RenderBridgeFFIManager.instance.createDom();
|
|
}
|
|
|
|
static void destroyDomInstance(int domInstanceId) {
|
|
_RenderBridgeFFIManager.instance.destroyDom(domInstanceId);
|
|
}
|
|
|
|
static void addRoot(int domInstanceId, int rootId) {
|
|
_RenderBridgeFFIManager.instance.addRoot(domInstanceId, rootId);
|
|
}
|
|
|
|
static void removeRoot(int domInstanceId, int rootId) {
|
|
_RenderBridgeFFIManager.instance.removeRoot(domInstanceId, rootId);
|
|
}
|
|
|
|
static Future updateNodeSize(
|
|
int renderManagerId,
|
|
int rootId,
|
|
int nodeId,
|
|
double width,
|
|
double height,
|
|
) async {
|
|
var stopwatch = Stopwatch();
|
|
stopwatch.start();
|
|
_RenderBridgeFFIManager.instance.updateNodeSize(renderManagerId, rootId, nodeId, width, height);
|
|
stopwatch.stop();
|
|
LogUtils.profile("update node size cost", stopwatch.elapsedMilliseconds);
|
|
}
|
|
|
|
static Pointer<Utf16> strByteDataToPointer(ByteData data) {
|
|
var units = data.buffer.asUint8List(data.offsetInBytes, data.lengthInBytes);
|
|
var result = utf8.decode(units);
|
|
return result.toNativeUtf16();
|
|
}
|
|
|
|
static Future<dynamic> callNativeFunction(
|
|
int engineId,
|
|
int renderManagerId,
|
|
String callId,
|
|
Object params,
|
|
bool keep,
|
|
) async {
|
|
var stopwatch = Stopwatch();
|
|
stopwatch.start();
|
|
var callIdU16 = callId.toNativeUtf16();
|
|
var encodeParamsByteData = const StandardMessageCodec().encodeMessage(params);
|
|
if (encodeParamsByteData != null) {
|
|
var length = encodeParamsByteData.lengthInBytes;
|
|
final result = malloc<Uint8>(length);
|
|
final nativeParams = result.asTypedList(length);
|
|
nativeParams.setRange(
|
|
0,
|
|
length,
|
|
encodeParamsByteData.buffer.asUint8List(),
|
|
);
|
|
_RenderBridgeFFIManager.instance.callNativeFunction(
|
|
engineId,
|
|
renderManagerId,
|
|
callIdU16,
|
|
result,
|
|
length,
|
|
keep ? 1 : 0,
|
|
);
|
|
free(result);
|
|
stopwatch.stop();
|
|
LogUtils.profile("callNativeFunction", stopwatch.elapsedMilliseconds);
|
|
} else {
|
|
LogUtils.e(
|
|
'Voltron::Bridge',
|
|
'call native function error, invalid params',
|
|
);
|
|
}
|
|
|
|
free(callIdU16);
|
|
}
|
|
|
|
static Future callNativeEvent(
|
|
int renderManagerId,
|
|
int rootId,
|
|
int nodeId,
|
|
String eventName,
|
|
bool useCapture,
|
|
bool useBubble,
|
|
Object params,
|
|
) async {
|
|
var stopwatch = Stopwatch();
|
|
stopwatch.start();
|
|
var eventU16 = eventName.toNativeUtf16();
|
|
LogUtils.i('Voltron::Bridge', 'ID:$nodeId, call native event $eventName');
|
|
var encodeParamsByteData = const StandardMessageCodec().encodeMessage(params);
|
|
if (encodeParamsByteData != null) {
|
|
var length = encodeParamsByteData.lengthInBytes;
|
|
final result = malloc<Uint8>(length);
|
|
final nativeParams = result.asTypedList(length);
|
|
nativeParams.setRange(
|
|
0,
|
|
length,
|
|
encodeParamsByteData.buffer.asUint8List(),
|
|
);
|
|
_RenderBridgeFFIManager.instance.callNativeEvent(
|
|
renderManagerId,
|
|
rootId,
|
|
nodeId,
|
|
eventU16,
|
|
useCapture,
|
|
useBubble,
|
|
result,
|
|
length,
|
|
);
|
|
free(result);
|
|
stopwatch.stop();
|
|
LogUtils.profile("callNativeEvent", stopwatch.elapsedMilliseconds);
|
|
} else {
|
|
LogUtils.e('Voltron::Bridge', 'call native event error, invalid params');
|
|
}
|
|
|
|
free(eventU16);
|
|
}
|
|
|
|
// ------------------ dart call native方法 end ---------------------
|
|
|
|
// 初始化bridge层
|
|
static void initBridge() async {
|
|
// 添加postRenderOp回调
|
|
var postRenderRegisterFunc = FfiManager().library.lookupFunction<
|
|
AddCallFuncNativeType<PostRenderOpNativeType>,
|
|
AddCallFuncDartType<PostRenderOpNativeType>>(FfiManager().registerFuncName);
|
|
|
|
var postRenderOpFunc = Pointer.fromFunction<PostRenderOpNativeType>(postRenderOp);
|
|
FfiManager().addRegisterFunc(
|
|
_RenderBridgeFFIManager._kRenderRegisterHeader,
|
|
RenderFuncType.postRenderOp.index,
|
|
postRenderOpFunc,
|
|
postRenderRegisterFunc,
|
|
);
|
|
|
|
// 添加layout回调
|
|
var calculateNodeLayoutRegisterFunc = FfiManager().library.lookupFunction<
|
|
AddCallFuncNativeType<CalculateNodeLayoutNativeType>,
|
|
AddCallFuncDartType<CalculateNodeLayoutNativeType>>(FfiManager().registerFuncName);
|
|
var calculateNodeLayoutFunc =
|
|
Pointer.fromFunction<CalculateNodeLayoutNativeType>(calculateNodeLayout);
|
|
FfiManager().addRegisterFunc(
|
|
_RenderBridgeFFIManager._kRenderRegisterHeader,
|
|
RenderFuncType.calculateNodeLayout.index,
|
|
calculateNodeLayoutFunc,
|
|
calculateNodeLayoutRegisterFunc,
|
|
);
|
|
}
|
|
}
|
|
|
|
// ------------------ native call dart方法 start ---------------------
|
|
|
|
void postRenderOp(
|
|
int engineId,
|
|
int rootId,
|
|
Pointer<Void> data,
|
|
int len,
|
|
) {
|
|
var dataList = data.cast<Uint8>().asTypedList(len);
|
|
if (dataList.isNotEmpty) {
|
|
var renderOpList = const StandardMessageCodec().decodeMessage(dataList.buffer.asByteData());
|
|
final bridge = VoltronRenderBridgeManager.bridgeMap[engineId];
|
|
if (bridge != null) {
|
|
bridge.postRenderOp(rootId, renderOpList);
|
|
}
|
|
}
|
|
}
|
|
|
|
Pointer<Int64> calculateNodeLayout(
|
|
int engineId,
|
|
int rootId,
|
|
int nodeId,
|
|
double width,
|
|
int widthMode,
|
|
double height,
|
|
int heightMode,
|
|
) {
|
|
try {
|
|
final bridge = VoltronRenderBridgeManager.bridgeMap[engineId];
|
|
var layoutParams = FlexLayoutParams(width, height, widthMode, heightMode);
|
|
var result = layoutParams.defaultOutput();
|
|
if (bridge != null) {
|
|
result = bridge.calculateNodeLayout(rootId, nodeId, layoutParams);
|
|
}
|
|
|
|
final resultPtr = malloc<Int64>(1);
|
|
resultPtr.asTypedList(1)[0] = result;
|
|
return resultPtr;
|
|
} catch (err) {
|
|
LogUtils.d('calculateNodeLayout', err.toString());
|
|
}
|
|
return Pointer.fromAddress(0);
|
|
}
|
|
|
|
// ------------------ native call dart方法 end ---------------------
|