diff --git a/bridge/core/api/executing_context.cc b/bridge/core/api/executing_context.cc index 36416e2382..50de6d9789 100644 --- a/bridge/core/api/executing_context.cc +++ b/bridge/core/api/executing_context.cc @@ -9,6 +9,8 @@ #include "core/executing_context.h" #include "core/frame/window.h" #include "core/frame/window_or_worker_global_scope.h" +#include "core/frame/module_manager.h" +#include "foundation/native_value_converter.h" namespace webf { @@ -32,6 +34,72 @@ void ExecutingContextWebFMethods::FinishRecordingUIOperations(webf::ExecutingCon context->uiCommandBuffer()->AddCommand(UICommand::kFinishRecordingCommand, nullptr, nullptr, nullptr, false); } +NativeValue ExecutingContextWebFMethods::WebFInvokeModule(ExecutingContext* context, + const char* module_name, + const char* method, + SharedExceptionState* shared_exception_state) { + AtomicString module_name_atomic = AtomicString(context->ctx(), module_name); + AtomicString method_atomic = webf::AtomicString(context->ctx(), method); + + ScriptValue result = ModuleManager::__webf_invoke_module__(context, module_name_atomic, method_atomic, shared_exception_state->exception_state); + NativeValue return_result = result.ToNative(context->ctx(), shared_exception_state->exception_state); + + if (shared_exception_state->exception_state.HasException()) { + return Native_NewNull(); + } + + return return_result; +} + +NativeValue ExecutingContextWebFMethods::WebFInvokeModuleWithParams(ExecutingContext* context, + const char* module_name, + const char* method, + NativeValue* params, + SharedExceptionState* shared_exception_state) { + AtomicString module_name_atomic = AtomicString(context->ctx(), module_name); + AtomicString method_atomic = webf::AtomicString(context->ctx(), method); + + if (params->tag == NativeTag::TAG_LIST) { + NativeValue* ptr = static_cast(params->u.ptr); + auto value_xxx = NativeValueConverter::FromNativeValue(*ptr); + WEBF_LOG(VERBOSE) << "Value: " << value_xxx; + } + + ScriptValue params_value = ScriptValue(context->ctx(), *params); + + ScriptValue result = ModuleManager::__webf_invoke_module__(context, module_name_atomic, method_atomic, params_value, shared_exception_state->exception_state); + NativeValue return_result = result.ToNative(context->ctx(), shared_exception_state->exception_state); + + if (shared_exception_state->exception_state.HasException()) { + return Native_NewNull(); + } + + return return_result; +} + +NativeValue ExecutingContextWebFMethods::WebFInvokeModuleWithParamsAndCallback(ExecutingContext* context, + const char* module_name, + const char* method, + NativeValue* params, + WebFNativeFunctionContext* callback_context, + SharedExceptionState* shared_exception_state) { + AtomicString module_name_atomic = AtomicString(context->ctx(), module_name); + AtomicString method_atomic = webf::AtomicString(context->ctx(), method); + + ScriptValue params_value = ScriptValue(context->ctx(), *params); + + auto callback_impl = WebFNativeFunction::Create(callback_context, shared_exception_state); + + ScriptValue result = ModuleManager::__webf_invoke_module__(context, module_name_atomic, method_atomic, params_value, callback_impl, shared_exception_state->exception_state); + NativeValue return_result = result.ToNative(context->ctx(), shared_exception_state->exception_state); + + if (shared_exception_state->exception_state.HasException()) { + return Native_NewNull(); + } + + return return_result; +} + int32_t ExecutingContextWebFMethods::SetTimeout(ExecutingContext* context, WebFNativeFunctionContext* callback_context, int32_t timeout, diff --git a/bridge/core/frame/module_callback.cc b/bridge/core/frame/module_callback.cc index c05b11d52a..0557e90e21 100644 --- a/bridge/core/frame/module_callback.cc +++ b/bridge/core/frame/module_callback.cc @@ -1,21 +1,21 @@ -/* - * Copyright (C) 2019-2022 The Kraken authors. All rights reserved. - * Copyright (C) 2022-present The WebF authors. All rights reserved. - */ -#include "module_callback.h" - -#include - -namespace webf { - -std::shared_ptr ModuleCallback::Create(const std::shared_ptr& function) { - return std::make_shared(function); -} - -ModuleCallback::ModuleCallback(std::shared_ptr function) : function_(std::move(function)) {} - -std::shared_ptr ModuleCallback::value() { - return function_; -} - -} // namespace webf +/* + * Copyright (C) 2019-2022 The Kraken authors. All rights reserved. + * Copyright (C) 2022-present The WebF authors. All rights reserved. + */ +#include "module_callback.h" + +#include + +namespace webf { + +std::shared_ptr ModuleCallback::Create(const std::shared_ptr& function) { + return std::make_shared(function); +} + +ModuleCallback::ModuleCallback(std::shared_ptr function) : function_(std::move(function)) {} + +std::shared_ptr ModuleCallback::value() { + return function_; +} + +} // namespace webf diff --git a/bridge/core/frame/module_callback.h b/bridge/core/frame/module_callback.h index 7e7fbc4d7a..20e6e1e771 100644 --- a/bridge/core/frame/module_callback.h +++ b/bridge/core/frame/module_callback.h @@ -1,29 +1,29 @@ -/* - * Copyright (C) 2019-2022 The Kraken authors. All rights reserved. - * Copyright (C) 2022-present The WebF authors. All rights reserved. - */ -#ifndef BRIDGE_MODULE_CALLBACK_H -#define BRIDGE_MODULE_CALLBACK_H - -#include -#include "bindings/qjs/qjs_function.h" - -namespace webf { - -// ModuleCallback is an asynchronous callback function, usually from the 4th parameter of `webf.invokeModule` -// function. When the asynchronous operation on the Dart side ends, the callback is will called and to return to the JS -// executing environment. -class ModuleCallback { - public: - static std::shared_ptr Create(const std::shared_ptr& function); - explicit ModuleCallback(std::shared_ptr function); - - std::shared_ptr value(); - - private: - std::shared_ptr function_{nullptr}; -}; - -} // namespace webf - -#endif // BRIDGE_MODULE_CALLBACK_H +/* + * Copyright (C) 2019-2022 The Kraken authors. All rights reserved. + * Copyright (C) 2022-present The WebF authors. All rights reserved. + */ +#ifndef BRIDGE_MODULE_CALLBACK_H +#define BRIDGE_MODULE_CALLBACK_H + +#include +#include "bindings/qjs/qjs_function.h" + +namespace webf { + +// ModuleCallback is an asynchronous callback function, usually from the 4th parameter of `webf.invokeModule` +// function. When the asynchronous operation on the Dart side ends, the callback is will called and to return to the JS +// executing environment. +class ModuleCallback { + public: + static std::shared_ptr Create(const std::shared_ptr& function); + explicit ModuleCallback(std::shared_ptr function); + + std::shared_ptr value(); + + private: + std::shared_ptr function_{nullptr}; +}; + +} // namespace webf + +#endif // BRIDGE_MODULE_CALLBACK_H diff --git a/bridge/core/frame/module_listener.cc b/bridge/core/frame/module_listener.cc index 7ac104e7a6..570cf03bae 100644 --- a/bridge/core/frame/module_listener.cc +++ b/bridge/core/frame/module_listener.cc @@ -1,21 +1,21 @@ -/* - * Copyright (C) 2019-2022 The Kraken authors. All rights reserved. - * Copyright (C) 2022-present The WebF authors. All rights reserved. - */ -#include "module_listener.h" - -#include - -namespace webf { - -std::shared_ptr ModuleListener::Create(const std::shared_ptr& function) { - return std::make_shared(function); -} - -ModuleListener::ModuleListener(std::shared_ptr function) : function_(std::move(function)) {} - -const std::shared_ptr& ModuleListener::value() { - return function_; -} - -} // namespace webf +/* + * Copyright (C) 2019-2022 The Kraken authors. All rights reserved. + * Copyright (C) 2022-present The WebF authors. All rights reserved. + */ +#include "module_listener.h" + +#include + +namespace webf { + +std::shared_ptr ModuleListener::Create(const std::shared_ptr& function) { + return std::make_shared(function); +} + +ModuleListener::ModuleListener(std::shared_ptr function) : function_(std::move(function)) {} + +const std::shared_ptr& ModuleListener::value() { + return function_; +} + +} // namespace webf diff --git a/bridge/core/frame/module_listener.h b/bridge/core/frame/module_listener.h index d4e2afa15b..53b0de14eb 100644 --- a/bridge/core/frame/module_listener.h +++ b/bridge/core/frame/module_listener.h @@ -1,34 +1,34 @@ -/* - * Copyright (C) 2019-2022 The Kraken authors. All rights reserved. - * Copyright (C) 2022-present The WebF authors. All rights reserved. - */ -#ifndef BRIDGE_MODULE_LISTENER_H -#define BRIDGE_MODULE_LISTENER_H - -#include "bindings/qjs/qjs_function.h" - -namespace webf { - -class ModuleContextCoordinator; -class ModuleListenerContainer; - -// ModuleListener is an persistent callback function. Registered from user with `webf.addModuleListener` method. -// When module event triggered at dart side, All module listener will be invoked and let user to dispatch further -// operations. -class ModuleListener { - public: - static std::shared_ptr Create(const std::shared_ptr& function); - explicit ModuleListener(std::shared_ptr function); - - const std::shared_ptr& value(); - - private: - std::shared_ptr function_{nullptr}; - - friend ModuleListenerContainer; - friend ModuleContextCoordinator; -}; - -} // namespace webf - -#endif // BRIDGE_MODULE_LISTENER_H +/* + * Copyright (C) 2019-2022 The Kraken authors. All rights reserved. + * Copyright (C) 2022-present The WebF authors. All rights reserved. + */ +#ifndef BRIDGE_MODULE_LISTENER_H +#define BRIDGE_MODULE_LISTENER_H + +#include "bindings/qjs/qjs_function.h" + +namespace webf { + +class ModuleContextCoordinator; +class ModuleListenerContainer; + +// ModuleListener is an persistent callback function. Registered from user with `webf.addModuleListener` method. +// When module event triggered at dart side, All module listener will be invoked and let user to dispatch further +// operations. +class ModuleListener { + public: + static std::shared_ptr Create(const std::shared_ptr& function); + explicit ModuleListener(std::shared_ptr function); + + const std::shared_ptr& value(); + + private: + std::shared_ptr function_{nullptr}; + + friend ModuleListenerContainer; + friend ModuleContextCoordinator; +}; + +} // namespace webf + +#endif // BRIDGE_MODULE_LISTENER_H diff --git a/bridge/core/frame/module_manager.cc b/bridge/core/frame/module_manager.cc index 24036f0221..af73275a3f 100644 --- a/bridge/core/frame/module_manager.cc +++ b/bridge/core/frame/module_manager.cc @@ -33,42 +33,57 @@ NativeValue* handleInvokeModuleTransientCallback(void* ptr, if (ctx == nullptr) return nullptr; - context->dartIsolateContext()->profiler()->StartTrackAsyncEvaluation(); - context->dartIsolateContext()->profiler()->StartTrackSteps("handleInvokeModuleTransientCallback"); - - ExceptionState exception_state; - - NativeValue* return_value = nullptr; - if (errmsg != nullptr) { - ScriptValue error_object = ScriptValue::CreateErrorObject(ctx, errmsg); - ScriptValue arguments[] = {error_object}; - ScriptValue result = moduleContext->callback->value()->Invoke(ctx, ScriptValue::Empty(ctx), 1, arguments); - if (result.IsException()) { - context->HandleException(&result); + auto callback_value = moduleContext->callback->value(); + + if (auto* callback = DynamicTo(callback_value.get())) { + context->dartIsolateContext()->profiler()->StartTrackAsyncEvaluation(); + context->dartIsolateContext()->profiler()->StartTrackSteps("handleInvokeModuleTransientCallback"); + + ExceptionState exception_state; + + NativeValue* return_value = nullptr; + if (errmsg != nullptr) { + ScriptValue error_object = ScriptValue::CreateErrorObject(ctx, errmsg); + ScriptValue arguments[] = {error_object}; + ScriptValue result = callback->Invoke(ctx, ScriptValue::Empty(ctx), 1, arguments); + if (result.IsException()) { + context->HandleException(&result); + } + NativeValue native_result = result.ToNative(ctx, exception_state); + return_value = static_cast(malloc(sizeof(NativeValue))); + memcpy(return_value, &native_result, sizeof(NativeValue)); + } else { + ScriptValue arguments[] = {ScriptValue::Empty(ctx), ScriptValue(ctx, *extra_data)}; + ScriptValue result = callback->Invoke(ctx, ScriptValue::Empty(ctx), 2, arguments); + if (result.IsException()) { + context->HandleException(&result); + } + NativeValue native_result = result.ToNative(ctx, exception_state); + return_value = static_cast(malloc(sizeof(NativeValue))); + memcpy(return_value, &native_result, sizeof(NativeValue)); } - NativeValue native_result = result.ToNative(ctx, exception_state); - return_value = static_cast(malloc(sizeof(NativeValue))); - memcpy(return_value, &native_result, sizeof(NativeValue)); - } else { - ScriptValue arguments[] = {ScriptValue::Empty(ctx), ScriptValue(ctx, *extra_data)}; - ScriptValue result = moduleContext->callback->value()->Invoke(ctx, ScriptValue::Empty(ctx), 2, arguments); - if (result.IsException()) { - context->HandleException(&result); - } - NativeValue native_result = result.ToNative(ctx, exception_state); - return_value = static_cast(malloc(sizeof(NativeValue))); - memcpy(return_value, &native_result, sizeof(NativeValue)); - } - context->dartIsolateContext()->profiler()->FinishTrackSteps(); - context->dartIsolateContext()->profiler()->FinishTrackAsyncEvaluation(); + context->dartIsolateContext()->profiler()->FinishTrackSteps(); + context->dartIsolateContext()->profiler()->FinishTrackAsyncEvaluation(); - if (exception_state.HasException()) { - context->HandleException(exception_state); - return nullptr; + if (exception_state.HasException()) { + context->HandleException(exception_state); + return nullptr; + } + + return return_value; + } else if (auto* callback = DynamicTo(callback_value.get())) { + if (errmsg != nullptr) { + NativeValue error_object = Native_NewCString(errmsg); + callback->Invoke(context, 1, &error_object); + } else { + NativeValue* params = new NativeValue[2]; + params[0] = Native_NewNull(); + params[1] = *extra_data; + callback->Invoke(context, 2, params); + } } - return return_value; } static void ReturnResultToDart(Dart_PersistentHandle persistent_handle, @@ -134,7 +149,7 @@ ScriptValue ModuleManager::__webf_invoke_module__(ExecutingContext* context, const AtomicString& module_name, const AtomicString& method, ScriptValue& params_value, - const std::shared_ptr& callback, + const std::shared_ptr& callback, ExceptionState& exception) { NativeValue params = params_value.ToNative(context->ctx(), exception); @@ -175,7 +190,7 @@ ScriptValue ModuleManager::__webf_invoke_module__(ExecutingContext* context, void ModuleManager::__webf_add_module_listener__(ExecutingContext* context, const AtomicString& module_name, - const std::shared_ptr& handler, + const std::shared_ptr& handler, ExceptionState& exception) { auto listener = ModuleListener::Create(handler); context->ModuleListeners()->AddModuleListener(module_name, listener); diff --git a/bridge/core/frame/module_manager.h b/bridge/core/frame/module_manager.h index 06d8e8ebb0..332a582eb2 100644 --- a/bridge/core/frame/module_manager.h +++ b/bridge/core/frame/module_manager.h @@ -1,52 +1,52 @@ -/* - * Copyright (C) 2019-2022 The Kraken authors. All rights reserved. - * Copyright (C) 2022-present The WebF authors. All rights reserved. - */ -#ifndef BRIDGE_MODULE_MANAGER_H -#define BRIDGE_MODULE_MANAGER_H - -#include "bindings/qjs/atomic_string.h" -#include "bindings/qjs/exception_state.h" -#include "bindings/qjs/qjs_function.h" -#include "module_callback.h" - -namespace webf { - -class ModuleContext { - public: - ModuleContext(ExecutingContext* context, const std::shared_ptr& callback) - : context(context), callback(callback) {} - ExecutingContext* context; - std::shared_ptr callback; -}; - -class ModuleManager { - public: - static ScriptValue __webf_invoke_module__(ExecutingContext* context, - const AtomicString& module_name, - const AtomicString& method, - ExceptionState& exception); - static ScriptValue __webf_invoke_module__(ExecutingContext* context, - const AtomicString& module_name, - const AtomicString& method, - ScriptValue& params_value, - ExceptionState& exception); - static ScriptValue __webf_invoke_module__(ExecutingContext* context, - const AtomicString& module_name, - const AtomicString& method, - ScriptValue& params_value, - const std::shared_ptr& callback, - ExceptionState& exception); - static void __webf_add_module_listener__(ExecutingContext* context, - const AtomicString& module_name, - const std::shared_ptr& handler, - ExceptionState& exception); - static void __webf_remove_module_listener__(ExecutingContext* context, - const AtomicString& module_name, - ExceptionState& exception_state); - static void __webf_clear_module_listener__(ExecutingContext* context, ExceptionState& exception_state); -}; - -} // namespace webf - -#endif // BRIDGE_MODULE_MANAGER_H +/* + * Copyright (C) 2019-2022 The Kraken authors. All rights reserved. + * Copyright (C) 2022-present The WebF authors. All rights reserved. + */ +#ifndef BRIDGE_MODULE_MANAGER_H +#define BRIDGE_MODULE_MANAGER_H + +#include "bindings/qjs/atomic_string.h" +#include "bindings/qjs/exception_state.h" +#include "foundation/function.h" +#include "module_callback.h" + +namespace webf { + +class ModuleContext { + public: + ModuleContext(ExecutingContext* context, const std::shared_ptr& callback) + : context(context), callback(callback) {} + ExecutingContext* context; + std::shared_ptr callback; +}; + +class ModuleManager { + public: + static ScriptValue __webf_invoke_module__(ExecutingContext* context, + const AtomicString& module_name, + const AtomicString& method, + ExceptionState& exception); + static ScriptValue __webf_invoke_module__(ExecutingContext* context, + const AtomicString& module_name, + const AtomicString& method, + ScriptValue& params_value, + ExceptionState& exception); + static ScriptValue __webf_invoke_module__(ExecutingContext* context, + const AtomicString& module_name, + const AtomicString& method, + ScriptValue& params_value, + const std::shared_ptr& callback, + ExceptionState& exception); + static void __webf_add_module_listener__(ExecutingContext* context, + const AtomicString& module_name, + const std::shared_ptr& handler, + ExceptionState& exception); + static void __webf_remove_module_listener__(ExecutingContext* context, + const AtomicString& module_name, + ExceptionState& exception_state); + static void __webf_clear_module_listener__(ExecutingContext* context, ExceptionState& exception_state); +}; + +} // namespace webf + +#endif // BRIDGE_MODULE_MANAGER_H diff --git a/bridge/core/page.cc b/bridge/core/page.cc index 6d04460dfd..f99fc30963 100644 --- a/bridge/core/page.cc +++ b/bridge/core/page.cc @@ -1,300 +1,319 @@ -/* - * Copyright (C) 2019-2022 The Kraken authors. All rights reserved. - * Copyright (C) 2022-present The WebF authors. All rights reserved. - */ -#include -#include - -#include "bindings/qjs/atomic_string.h" -#include "bindings/qjs/binding_initializer.h" -#include "core/dart_methods.h" -#include "core/dom/document.h" -#include "core/frame/window.h" -#include "core/html/html_html_element.h" -#include "core/html/parser/html_parser.h" -#include "event_factory.h" -#include "foundation/logging.h" -#include "foundation/native_value_converter.h" -#include "page.h" -#include "polyfill.h" - -namespace webf { - -ConsoleMessageHandler WebFPage::consoleMessageHandler{nullptr}; - -WebFPage::WebFPage(DartIsolateContext* dart_isolate_context, - bool is_dedicated, - size_t sync_buffer_size, - double context_id, - const JSExceptionHandler& handler) - : ownerThreadId(std::this_thread::get_id()), dart_isolate_context_(dart_isolate_context) { - context_ = new ExecutingContext( - dart_isolate_context, is_dedicated, sync_buffer_size, context_id, - [](ExecutingContext* context, const char* message) { - WEBF_LOG(ERROR) << message << std::endl; - if (context->IsContextValid()) { - context->dartMethodPtr()->onJSError(context->isDedicated(), context->contextId(), message); - } - }, - this); -} - -bool WebFPage::parseHTML(const char* code, size_t length) { - if (!context_->IsContextValid()) - return false; - - { - MemberMutationScope scope{context_}; - - auto document_element = context_->document()->documentElement(); - if (!document_element) { - return false; +/* + * Copyright (C) 2019-2022 The Kraken authors. All rights reserved. + * Copyright (C) 2022-present The WebF authors. All rights reserved. + */ +#include +#include + +#include "bindings/qjs/atomic_string.h" +#include "bindings/qjs/binding_initializer.h" +#include "core/dart_methods.h" +#include "core/dom/document.h" +#include "core/frame/window.h" +#include "core/html/html_html_element.h" +#include "core/html/parser/html_parser.h" +#include "event_factory.h" +#include "foundation/logging.h" +#include "foundation/native_value_converter.h" +#include "page.h" +#include "polyfill.h" + +namespace webf { + +ConsoleMessageHandler WebFPage::consoleMessageHandler{nullptr}; + +WebFPage::WebFPage(DartIsolateContext* dart_isolate_context, + bool is_dedicated, + size_t sync_buffer_size, + double context_id, + const JSExceptionHandler& handler) + : ownerThreadId(std::this_thread::get_id()), dart_isolate_context_(dart_isolate_context) { + context_ = new ExecutingContext( + dart_isolate_context, is_dedicated, sync_buffer_size, context_id, + [](ExecutingContext* context, const char* message) { + WEBF_LOG(ERROR) << message << std::endl; + if (context->IsContextValid()) { + context->dartMethodPtr()->onJSError(context->isDedicated(), context->contextId(), message); + } + }, + this); +} + +bool WebFPage::parseHTML(const char* code, size_t length) { + if (!context_->IsContextValid()) + return false; + + { + MemberMutationScope scope{context_}; + + auto document_element = context_->document()->documentElement(); + if (!document_element) { + return false; + } + + context_->dartIsolateContext()->profiler()->StartTrackSteps("HTMLParser::parseHTML"); + HTMLParser::parseHTML(code, length, context_->document()->documentElement()); + context_->dartIsolateContext()->profiler()->FinishTrackSteps(); + } + + context_->uiCommandBuffer()->AddCommand(UICommand::kFinishRecordingCommand, nullptr, nullptr, nullptr); + + return true; +} + +NativeValue* WebFPage::invokeModuleEvent(SharedNativeString* native_module_name, + const char* eventType, + void* ptr, + NativeValue* extra) { + if (!context_->IsContextValid()) + return nullptr; + + MemberMutationScope scope{context_}; + + JSContext* ctx = context_->ctx(); + Event* event = nullptr; + if (ptr != nullptr) { + std::string type = std::string(eventType); + auto* raw_event = static_cast(ptr); + event = EventFactory::Create(context_, AtomicString(ctx, type), raw_event); + delete raw_event; + } + + ScriptValue extraObject = ScriptValue(ctx, const_cast(*extra)); + AtomicString module_name = AtomicString( + ctx, std::unique_ptr(reinterpret_cast(native_module_name))); + auto listener = context_->ModuleListeners()->listener(module_name); + + if (listener == nullptr) { + return nullptr; + } + + auto callback_value = listener->value(); + if (auto* callback = DynamicTo(callback_value.get())) { + ScriptValue arguments[] = {event != nullptr ? event->ToValue() : ScriptValue::Empty(ctx), extraObject}; + ScriptValue result = callback->Invoke(ctx, ScriptValue::Empty(ctx), 2, arguments); + if (result.IsException()) { + context_->HandleException(&result); + return nullptr; + } + + ExceptionState exception_state; + auto* return_value = static_cast(malloc(sizeof(NativeValue))); + NativeValue tmp = result.ToNative(ctx, exception_state); + if (exception_state.HasException()) { + context_->HandleException(exception_state); + return nullptr; + } + + memcpy(return_value, &tmp, sizeof(NativeValue)); + return return_value; + } else if (auto* callback = DynamicTo(callback_value.get())) { + NativeValue* params = new NativeValue[2]; + + ExceptionState exception_state; + ScriptValue eventValue = event != nullptr ? event->ToValue() : ScriptValue::Empty(ctx); + params[0] = eventValue.ToNative(ctx, exception_state); + params[1] = *extra; + + + if (exception_state.HasException()) { + context_->HandleException(exception_state); + return nullptr; } - - context_->dartIsolateContext()->profiler()->StartTrackSteps("HTMLParser::parseHTML"); - HTMLParser::parseHTML(code, length, context_->document()->documentElement()); - context_->dartIsolateContext()->profiler()->FinishTrackSteps(); + + callback->Invoke(context_, 2, params); + return nullptr; } - - context_->uiCommandBuffer()->AddCommand(UICommand::kFinishRecordingCommand, nullptr, nullptr, nullptr); - - return true; -} - -NativeValue* WebFPage::invokeModuleEvent(SharedNativeString* native_module_name, - const char* eventType, - void* ptr, - NativeValue* extra) { - if (!context_->IsContextValid()) - return nullptr; - - MemberMutationScope scope{context_}; - - JSContext* ctx = context_->ctx(); - Event* event = nullptr; - if (ptr != nullptr) { - std::string type = std::string(eventType); - auto* raw_event = static_cast(ptr); - event = EventFactory::Create(context_, AtomicString(ctx, type), raw_event); - delete raw_event; - } - - ScriptValue extraObject = ScriptValue(ctx, const_cast(*extra)); - AtomicString module_name = AtomicString( - ctx, std::unique_ptr(reinterpret_cast(native_module_name))); - auto listener = context_->ModuleListeners()->listener(module_name); - - if (listener == nullptr) { - return nullptr; - } - - ScriptValue arguments[] = {event != nullptr ? event->ToValue() : ScriptValue::Empty(ctx), extraObject}; - ScriptValue result = listener->value()->Invoke(ctx, ScriptValue::Empty(ctx), 2, arguments); - if (result.IsException()) { - context_->HandleException(&result); - return nullptr; - } - - ExceptionState exception_state; - auto* return_value = static_cast(malloc(sizeof(NativeValue))); - NativeValue tmp = result.ToNative(ctx, exception_state); - if (exception_state.HasException()) { - context_->HandleException(exception_state); - return nullptr; - } - - memcpy(return_value, &tmp, sizeof(NativeValue)); - return return_value; -} - -bool WebFPage::evaluateScript(const char* script, - uint64_t script_len, - uint8_t** parsed_bytecodes, - uint64_t* bytecode_len, - const char* url, - int startLine) { - if (!context_->IsContextValid()) - return false; - return context_->EvaluateJavaScript(script, script_len, parsed_bytecodes, bytecode_len, url, startLine); -} - -void WebFPage::evaluateScript(const char* script, size_t length, const char* url, int startLine) { - if (!context_->IsContextValid()) - return; - context_->EvaluateJavaScript(script, length, url, startLine); -} - -uint8_t* WebFPage::dumpByteCode(const char* script, size_t length, const char* url, uint64_t* byteLength) { - if (!context_->IsContextValid()) - return nullptr; - return context_->DumpByteCode(script, static_cast(length), url, byteLength); -} - -bool WebFPage::evaluateByteCode(uint8_t* bytes, size_t byteLength) { - if (!context_->IsContextValid()) - return false; - return context_->EvaluateByteCode(bytes, byteLength); -} - -std::thread::id WebFPage::currentThread() const { - return ownerThreadId; -} - -WebFPage::~WebFPage() { -#if IS_TEST - if (disposeCallback != nullptr) { - disposeCallback(this); - } -#endif - delete context_; -} - -void WebFPage::reportError(const char* errmsg) { - handler_(context_, errmsg); -} - -static void ReturnEvaluateScriptsInternal(Dart_PersistentHandle persistent_handle, - EvaluateQuickjsByteCodeCallback result_callback, - bool is_success) { - Dart_Handle handle = Dart_HandleFromPersistent_DL(persistent_handle); - result_callback(handle, is_success ? 1 : 0); - Dart_DeletePersistentHandle_DL(persistent_handle); -} - -void WebFPage::EvaluateScriptsInternal(void* page_, - const char* code, - uint64_t code_len, - uint8_t** parsed_bytecodes, - uint64_t* bytecode_len, - const char* bundleFilename, - int32_t startLine, - int64_t profile_id, - Dart_Handle persistent_handle, - EvaluateScriptsCallback result_callback) { - auto page = reinterpret_cast(page_); - assert(std::this_thread::get_id() == page->currentThread()); - - page->dartIsolateContext()->profiler()->StartTrackEvaluation(profile_id); - - bool is_success = page->evaluateScript(code, code_len, parsed_bytecodes, bytecode_len, bundleFilename, startLine); - - page->dartIsolateContext()->profiler()->FinishTrackEvaluation(profile_id); - - page->dartIsolateContext()->dispatcher()->PostToDart(page->isDedicated(), ReturnEvaluateScriptsInternal, - persistent_handle, result_callback, is_success); -} - -static void ReturnEvaluateQuickjsByteCodeResultToDart(Dart_PersistentHandle persistent_handle, - EvaluateQuickjsByteCodeCallback result_callback, - bool is_success) { - Dart_Handle handle = Dart_HandleFromPersistent_DL(persistent_handle); - result_callback(handle, is_success ? 1 : 0); - Dart_DeletePersistentHandle_DL(persistent_handle); -} - -void WebFPage::EvaluateQuickjsByteCodeInternal(void* page_, - uint8_t* bytes, - int32_t byteLen, - int64_t profile_id, - Dart_PersistentHandle persistent_handle, - EvaluateQuickjsByteCodeCallback result_callback) { - auto page = reinterpret_cast(page_); - assert(std::this_thread::get_id() == page->currentThread()); - - page->dartIsolateContext()->profiler()->StartTrackEvaluation(profile_id); - - bool is_success = page->evaluateByteCode(bytes, byteLen); - - page->dartIsolateContext()->profiler()->FinishTrackEvaluation(profile_id); - - page->dartIsolateContext()->dispatcher()->PostToDart(page->isDedicated(), ReturnEvaluateQuickjsByteCodeResultToDart, - persistent_handle, result_callback, is_success); -} - -static void ReturnParseHTMLToDart(Dart_PersistentHandle persistent_handle, ParseHTMLCallback result_callback) { - Dart_Handle handle = Dart_HandleFromPersistent_DL(persistent_handle); - result_callback(handle); - Dart_DeletePersistentHandle_DL(persistent_handle); -} - -void WebFPage::ParseHTMLInternal(void* page_, - char* code, - int32_t length, - int64_t profile_id, - Dart_PersistentHandle dart_handle, - ParseHTMLCallback result_callback) { - auto page = reinterpret_cast(page_); - assert(std::this_thread::get_id() == page->currentThread()); - - page->dartIsolateContext()->profiler()->StartTrackEvaluation(profile_id); - - page->parseHTML(code, length); - dart_free(code); - - page->dartIsolateContext()->profiler()->FinishTrackEvaluation(profile_id); - - page->dartIsolateContext()->dispatcher()->PostToDart(page->isDedicated(), ReturnParseHTMLToDart, dart_handle, - result_callback); -} - -static void ReturnInvokeEventResultToDart(Dart_Handle persistent_handle, - InvokeModuleEventCallback result_callback, - webf::NativeValue* result) { - Dart_Handle handle = Dart_HandleFromPersistent_DL(persistent_handle); - result_callback(handle, result); - Dart_DeletePersistentHandle_DL(persistent_handle); -} - -void WebFPage::InvokeModuleEventInternal(void* page_, - void* module_name, - const char* eventType, - void* event, - void* extra, - Dart_Handle persistent_handle, - InvokeModuleEventCallback result_callback) { - auto page = reinterpret_cast(page_); - auto dart_isolate_context = page->executingContext()->dartIsolateContext(); - assert(std::this_thread::get_id() == page->currentThread()); - - page->dartIsolateContext()->profiler()->StartTrackAsyncEvaluation(); - - auto* result = page->invokeModuleEvent(reinterpret_cast(module_name), eventType, event, - reinterpret_cast(extra)); - - page->dartIsolateContext()->profiler()->FinishTrackAsyncEvaluation(); - - dart_isolate_context->dispatcher()->PostToDart(page->isDedicated(), ReturnInvokeEventResultToDart, persistent_handle, - result_callback, result); -} - -static void ReturnDumpByteCodeResultToDart(Dart_Handle persistent_handle, DumpQuickjsByteCodeCallback result_callback) { - Dart_Handle handle = Dart_HandleFromPersistent_DL(persistent_handle); - result_callback(handle); - Dart_DeletePersistentHandle_DL(persistent_handle); -} - -void WebFPage::DumpQuickJsByteCodeInternal(void* page_, - int64_t profile_id, - const char* code, - int32_t code_len, - uint8_t** parsed_bytecodes, - uint64_t* bytecode_len, - const char* url, - Dart_PersistentHandle persistent_handle, - DumpQuickjsByteCodeCallback result_callback) { - auto page = reinterpret_cast(page_); - auto dart_isolate_context = page->executingContext()->dartIsolateContext(); - - dart_isolate_context->profiler()->StartTrackEvaluation(profile_id); - - assert(std::this_thread::get_id() == page->currentThread()); - uint8_t* bytes = page->dumpByteCode(code, code_len, url, bytecode_len); - *parsed_bytecodes = bytes; - - dart_isolate_context->profiler()->FinishTrackEvaluation(profile_id); - - dart_isolate_context->dispatcher()->PostToDart(page->isDedicated(), ReturnDumpByteCodeResultToDart, persistent_handle, - result_callback); -} - -} // namespace webf +} + +bool WebFPage::evaluateScript(const char* script, + uint64_t script_len, + uint8_t** parsed_bytecodes, + uint64_t* bytecode_len, + const char* url, + int startLine) { + if (!context_->IsContextValid()) + return false; + return context_->EvaluateJavaScript(script, script_len, parsed_bytecodes, bytecode_len, url, startLine); +} + +void WebFPage::evaluateScript(const char* script, size_t length, const char* url, int startLine) { + if (!context_->IsContextValid()) + return; + context_->EvaluateJavaScript(script, length, url, startLine); +} + +uint8_t* WebFPage::dumpByteCode(const char* script, size_t length, const char* url, uint64_t* byteLength) { + if (!context_->IsContextValid()) + return nullptr; + return context_->DumpByteCode(script, static_cast(length), url, byteLength); +} + +bool WebFPage::evaluateByteCode(uint8_t* bytes, size_t byteLength) { + if (!context_->IsContextValid()) + return false; + return context_->EvaluateByteCode(bytes, byteLength); +} + +std::thread::id WebFPage::currentThread() const { + return ownerThreadId; +} + +WebFPage::~WebFPage() { +#if IS_TEST + if (disposeCallback != nullptr) { + disposeCallback(this); + } +#endif + delete context_; +} + +void WebFPage::reportError(const char* errmsg) { + handler_(context_, errmsg); +} + +static void ReturnEvaluateScriptsInternal(Dart_PersistentHandle persistent_handle, + EvaluateQuickjsByteCodeCallback result_callback, + bool is_success) { + Dart_Handle handle = Dart_HandleFromPersistent_DL(persistent_handle); + result_callback(handle, is_success ? 1 : 0); + Dart_DeletePersistentHandle_DL(persistent_handle); +} + +void WebFPage::EvaluateScriptsInternal(void* page_, + const char* code, + uint64_t code_len, + uint8_t** parsed_bytecodes, + uint64_t* bytecode_len, + const char* bundleFilename, + int32_t startLine, + int64_t profile_id, + Dart_Handle persistent_handle, + EvaluateScriptsCallback result_callback) { + auto page = reinterpret_cast(page_); + assert(std::this_thread::get_id() == page->currentThread()); + + page->dartIsolateContext()->profiler()->StartTrackEvaluation(profile_id); + + bool is_success = page->evaluateScript(code, code_len, parsed_bytecodes, bytecode_len, bundleFilename, startLine); + + page->dartIsolateContext()->profiler()->FinishTrackEvaluation(profile_id); + + page->dartIsolateContext()->dispatcher()->PostToDart(page->isDedicated(), ReturnEvaluateScriptsInternal, + persistent_handle, result_callback, is_success); +} + +static void ReturnEvaluateQuickjsByteCodeResultToDart(Dart_PersistentHandle persistent_handle, + EvaluateQuickjsByteCodeCallback result_callback, + bool is_success) { + Dart_Handle handle = Dart_HandleFromPersistent_DL(persistent_handle); + result_callback(handle, is_success ? 1 : 0); + Dart_DeletePersistentHandle_DL(persistent_handle); +} + +void WebFPage::EvaluateQuickjsByteCodeInternal(void* page_, + uint8_t* bytes, + int32_t byteLen, + int64_t profile_id, + Dart_PersistentHandle persistent_handle, + EvaluateQuickjsByteCodeCallback result_callback) { + auto page = reinterpret_cast(page_); + assert(std::this_thread::get_id() == page->currentThread()); + + page->dartIsolateContext()->profiler()->StartTrackEvaluation(profile_id); + + bool is_success = page->evaluateByteCode(bytes, byteLen); + + page->dartIsolateContext()->profiler()->FinishTrackEvaluation(profile_id); + + page->dartIsolateContext()->dispatcher()->PostToDart(page->isDedicated(), ReturnEvaluateQuickjsByteCodeResultToDart, + persistent_handle, result_callback, is_success); +} + +static void ReturnParseHTMLToDart(Dart_PersistentHandle persistent_handle, ParseHTMLCallback result_callback) { + Dart_Handle handle = Dart_HandleFromPersistent_DL(persistent_handle); + result_callback(handle); + Dart_DeletePersistentHandle_DL(persistent_handle); +} + +void WebFPage::ParseHTMLInternal(void* page_, + char* code, + int32_t length, + int64_t profile_id, + Dart_PersistentHandle dart_handle, + ParseHTMLCallback result_callback) { + auto page = reinterpret_cast(page_); + assert(std::this_thread::get_id() == page->currentThread()); + + page->dartIsolateContext()->profiler()->StartTrackEvaluation(profile_id); + + page->parseHTML(code, length); + dart_free(code); + + page->dartIsolateContext()->profiler()->FinishTrackEvaluation(profile_id); + + page->dartIsolateContext()->dispatcher()->PostToDart(page->isDedicated(), ReturnParseHTMLToDart, dart_handle, + result_callback); +} + +static void ReturnInvokeEventResultToDart(Dart_Handle persistent_handle, + InvokeModuleEventCallback result_callback, + webf::NativeValue* result) { + Dart_Handle handle = Dart_HandleFromPersistent_DL(persistent_handle); + result_callback(handle, result); + Dart_DeletePersistentHandle_DL(persistent_handle); +} + +void WebFPage::InvokeModuleEventInternal(void* page_, + void* module_name, + const char* eventType, + void* event, + void* extra, + Dart_Handle persistent_handle, + InvokeModuleEventCallback result_callback) { + auto page = reinterpret_cast(page_); + auto dart_isolate_context = page->executingContext()->dartIsolateContext(); + assert(std::this_thread::get_id() == page->currentThread()); + + page->dartIsolateContext()->profiler()->StartTrackAsyncEvaluation(); + + auto* result = page->invokeModuleEvent(reinterpret_cast(module_name), eventType, event, + reinterpret_cast(extra)); + + page->dartIsolateContext()->profiler()->FinishTrackAsyncEvaluation(); + + dart_isolate_context->dispatcher()->PostToDart(page->isDedicated(), ReturnInvokeEventResultToDart, persistent_handle, + result_callback, result); +} + +static void ReturnDumpByteCodeResultToDart(Dart_Handle persistent_handle, DumpQuickjsByteCodeCallback result_callback) { + Dart_Handle handle = Dart_HandleFromPersistent_DL(persistent_handle); + result_callback(handle); + Dart_DeletePersistentHandle_DL(persistent_handle); +} + +void WebFPage::DumpQuickJsByteCodeInternal(void* page_, + int64_t profile_id, + const char* code, + int32_t code_len, + uint8_t** parsed_bytecodes, + uint64_t* bytecode_len, + const char* url, + Dart_PersistentHandle persistent_handle, + DumpQuickjsByteCodeCallback result_callback) { + auto page = reinterpret_cast(page_); + auto dart_isolate_context = page->executingContext()->dartIsolateContext(); + + dart_isolate_context->profiler()->StartTrackEvaluation(profile_id); + + assert(std::this_thread::get_id() == page->currentThread()); + uint8_t* bytes = page->dumpByteCode(code, code_len, url, bytecode_len); + *parsed_bytecodes = bytes; + + dart_isolate_context->profiler()->FinishTrackEvaluation(profile_id); + + dart_isolate_context->dispatcher()->PostToDart(page->isDedicated(), ReturnDumpByteCodeResultToDart, persistent_handle, + result_callback); +} + +} // namespace webf diff --git a/bridge/foundation/native_value.h b/bridge/foundation/native_value.h index be7ffdd164..c55499a8d0 100644 --- a/bridge/foundation/native_value.h +++ b/bridge/foundation/native_value.h @@ -46,28 +46,6 @@ struct NativeValue : public DartReadable { int32_t tag; }; -struct NativeFunctionContext; - -using CallNativeFunction = void (*)(NativeFunctionContext* functionContext, - int32_t argc, - NativeValue* argv, - NativeValue* returnValue); - -static void call_native_function(NativeFunctionContext* functionContext, - int32_t argc, - NativeValue* argv, - NativeValue* returnValue); - -struct NativeFunctionContext { - CallNativeFunction call; - NativeFunctionContext(ExecutingContext* context, JSValue callback); - ~NativeFunctionContext(); - JSValue m_callback{JS_NULL}; - ExecutingContext* m_context{nullptr}; - JSContext* m_ctx{nullptr}; - list_head link; -}; - NativeValue Native_NewNull(); NativeValue Native_NewString(SharedNativeString* string); NativeValue Native_NewCString(const std::string& string); diff --git a/bridge/foundation/rust_readable.cc b/bridge/foundation/rust_readable.cc index 8fcb9d21ce..7e00eba7b2 100644 --- a/bridge/foundation/rust_readable.cc +++ b/bridge/foundation/rust_readable.cc @@ -14,7 +14,7 @@ namespace webf { void* RustReadable::operator new(std::size_t size) { #if defined(_WIN32) - return HeapAlloc(GetProcessHeap(), HEAP_GENERATE_EXCEPTIONS, size); + return CoTaskMemAlloc(size); #else return malloc(size); #endif @@ -22,8 +22,9 @@ void* RustReadable::operator new(std::size_t size) { void RustReadable::operator delete(void* memory) noexcept { #if defined(_WIN32) - HeapFree(GetProcessHeap(), 0, memory); + return CoTaskMemFree(memory); #else + return free(memory); #endif } diff --git a/bridge/include/plugin_api/executing_context.h b/bridge/include/plugin_api/executing_context.h index 53e9617648..f1237d2521 100644 --- a/bridge/include/plugin_api/executing_context.h +++ b/bridge/include/plugin_api/executing_context.h @@ -5,6 +5,7 @@ #ifndef WEBF_CORE_RUST_API_EXECUTING_CONTEXT_H_ #define WEBF_CORE_RUST_API_EXECUTING_CONTEXT_H_ +#include "foundation/native_value.h" #include "core/native/native_function.h" #include "document.h" #include "exception_state.h" @@ -20,6 +21,21 @@ using PublicContextGetDocument = WebFValue (*)( using PublicContextGetWindow = WebFValue (*)(ExecutingContext*); using PublicContextGetExceptionState = WebFValue (*)(); using PublicFinishRecordingUIOperations = void (*)(ExecutingContext* context); +using PublicWebFInvokeModule = NativeValue (*)(ExecutingContext*, + const char*, + const char*, + SharedExceptionState*); +using PublicWebFInvokeModuleWithParams = NativeValue (*)(ExecutingContext*, + const char*, + const char*, + NativeValue*, + SharedExceptionState*); +using PublicWebFInvokeModuleWithParamsAndCallback = NativeValue (*)(ExecutingContext*, + const char*, + const char*, + NativeValue*, + WebFNativeFunctionContext*, + SharedExceptionState*); using PublicContextSetTimeout = int32_t (*)(ExecutingContext*, WebFNativeFunctionContext*, int32_t, @@ -38,6 +54,21 @@ struct ExecutingContextWebFMethods { static WebFValue window(ExecutingContext* context); static WebFValue CreateExceptionState(); static void FinishRecordingUIOperations(ExecutingContext* context); + static NativeValue WebFInvokeModule(ExecutingContext* context, + const char* module_name, + const char* method, + SharedExceptionState* shared_exception_state); + static NativeValue WebFInvokeModuleWithParams(ExecutingContext* context, + const char* module_name, + const char* method, + NativeValue* params, + SharedExceptionState* shared_exception_state); + static NativeValue WebFInvokeModuleWithParamsAndCallback(ExecutingContext* context, + const char* module_name, + const char* method, + NativeValue* params, + WebFNativeFunctionContext* callback_context, + SharedExceptionState* shared_exception_state); static int32_t SetTimeout(ExecutingContext* context, WebFNativeFunctionContext* callback_context, int32_t timeout, @@ -54,6 +85,9 @@ struct ExecutingContextWebFMethods { PublicContextGetWindow context_get_window{window}; PublicContextGetExceptionState context_get_exception_state{CreateExceptionState}; PublicFinishRecordingUIOperations context_finish_recording_ui_operations{FinishRecordingUIOperations}; + PublicWebFInvokeModule context_webf_invoke_module{WebFInvokeModule}; + PublicWebFInvokeModuleWithParams context_webf_invoke_module_with_params{WebFInvokeModuleWithParams}; + PublicWebFInvokeModuleWithParamsAndCallback context_webf_invoke_module_with_params_and_callback{WebFInvokeModuleWithParamsAndCallback}; PublicContextSetTimeout context_set_timeout{SetTimeout}; PublicContextSetInterval context_set_interval{SetInterval}; PublicContextClearTimeout context_clear_timeout{ClearTimeout}; diff --git a/bridge/rusty_webf_sys/Cargo.toml b/bridge/rusty_webf_sys/Cargo.toml index 4fe851bce0..633aca08d0 100644 --- a/bridge/rusty_webf_sys/Cargo.toml +++ b/bridge/rusty_webf_sys/Cargo.toml @@ -15,5 +15,5 @@ libc = "0.2.0" [dependencies.windows] version = "0.58.0" features = [ - "Win32_System_Memory" -] \ No newline at end of file + "Win32_System_Com", +] diff --git a/bridge/rusty_webf_sys/src/executing_context.rs b/bridge/rusty_webf_sys/src/executing_context.rs index 82253e7ca8..608069f992 100644 --- a/bridge/rusty_webf_sys/src/executing_context.rs +++ b/bridge/rusty_webf_sys/src/executing_context.rs @@ -3,6 +3,8 @@ */ use std::ffi::*; +use native_value::NativeValue; + use crate::*; #[repr(C)] @@ -12,6 +14,9 @@ pub struct ExecutingContextRustMethods { pub get_window: extern "C" fn(*const OpaquePtr) -> RustValue, pub create_exception_state: extern "C" fn() -> RustValue, pub finish_recording_ui_operations: extern "C" fn(executing_context: *const OpaquePtr) -> c_void, + pub webf_invoke_module: extern "C" fn(executing_context: *const OpaquePtr, module_name: *const c_char, method: *const c_char, exception_state: *const OpaquePtr) -> NativeValue, + pub webf_invoke_module_with_params: extern "C" fn(executing_context: *const OpaquePtr, module_name: *const c_char, method: *const c_char, params: *const NativeValue, exception_state: *const OpaquePtr) -> NativeValue, + pub webf_invoke_module_with_params_and_callback: extern "C" fn(executing_context: *const OpaquePtr, module_name: *const c_char, method: *const c_char, params: *const NativeValue, exception_state: *const OpaquePtr) -> NativeValue, pub set_timeout: extern "C" fn(*const OpaquePtr, *const WebFNativeFunctionContext, c_int, *const OpaquePtr) -> c_int, pub set_interval: extern "C" fn(*const OpaquePtr, *const WebFNativeFunctionContext, c_int, *const OpaquePtr) -> c_int, pub clear_timeout: extern "C" fn(*const OpaquePtr, c_int, *const OpaquePtr), @@ -81,6 +86,34 @@ impl ExecutingContext { ExceptionState::initialize(result.value, result.method_pointer) } + pub fn webf_invoke_module(&self, module_name: &str, method: &str, exception_state: &ExceptionState) -> Result { + let module_name = CString::new(module_name).unwrap(); + let method = CString::new(method).unwrap(); + let result = unsafe { + ((*self.method_pointer).webf_invoke_module)(self.ptr, module_name.as_ptr(), method.as_ptr(), exception_state.ptr) + }; + + if exception_state.has_exception() { + return Err(exception_state.stringify(self)); + } + + Ok(result) + } + + pub fn webf_invoke_module_with_params(&self, module_name: &str, method: &str, params: &NativeValue, exception_state: &ExceptionState) -> Result { + let module_name = CString::new(module_name).unwrap(); + let method = CString::new(method).unwrap(); + let result = unsafe { + ((*self.method_pointer).webf_invoke_module_with_params)(self.ptr, module_name.as_ptr(), method.as_ptr(), params, exception_state.ptr) + }; + + if exception_state.has_exception() { + return Err(exception_state.stringify(self)); + } + + Ok(result) + } + pub fn set_timeout_with_callback(&self, callback: TimeoutCallback, exception_state: &ExceptionState) -> Result { self.set_timeout_with_callback_and_timeout(callback, 0, exception_state) } diff --git a/bridge/rusty_webf_sys/src/lib.rs b/bridge/rusty_webf_sys/src/lib.rs index ca4ac50867..8f1e0413c7 100644 --- a/bridge/rusty_webf_sys/src/lib.rs +++ b/bridge/rusty_webf_sys/src/lib.rs @@ -52,6 +52,7 @@ pub mod ui_event_init; pub mod webf_event_listener; pub mod webf_function; mod memory_utils; +pub mod native_value; pub use executing_context::*; pub use document::*; @@ -101,6 +102,7 @@ pub use transition_event_init::*; pub use ui_event_init::*; pub use webf_event_listener::*; pub use webf_function::*; +pub use native_value::*; #[repr(C)] pub struct OpaquePtr; diff --git a/bridge/rusty_webf_sys/src/memory_utils.rs b/bridge/rusty_webf_sys/src/memory_utils.rs index 22a447eb2d..9e354067d7 100644 --- a/bridge/rusty_webf_sys/src/memory_utils.rs +++ b/bridge/rusty_webf_sys/src/memory_utils.rs @@ -1,21 +1,17 @@ -#[cfg(target_os = "windows")] -use windows::Win32; -use libc; use crate::OpaquePtr; +use libc; +#[cfg(target_os = "windows")] +use windows::Win32::System::Com::CoTaskMemFree; pub fn safe_free_cpp_ptr(ptr: *const T) { unsafe { if cfg!(target_os = "windows") { #[cfg(target_os = "windows")] { - Win32::System::Memory::HeapFree( - Win32::System::Memory::GetProcessHeap().unwrap(), - Win32::System::Memory::HEAP_FLAGS(0), - Option::from(ptr as *const libc::c_void) - ).expect("Failed to call HeapFree"); + CoTaskMemFree(Option::from(ptr as *const libc::c_void)); } } else { libc::free(ptr.cast_mut() as *mut libc::c_void); } } -} \ No newline at end of file +} diff --git a/bridge/rusty_webf_sys/src/native_value.rs b/bridge/rusty_webf_sys/src/native_value.rs new file mode 100644 index 0000000000..69dd45ac1b --- /dev/null +++ b/bridge/rusty_webf_sys/src/native_value.rs @@ -0,0 +1,150 @@ +use std::ffi::*; +use std::mem; +#[cfg(target_os = "windows")] +use windows::Win32::System::Com::{CoTaskMemAlloc, CoTaskMemFree}; + +use crate::memory_utils::safe_free_cpp_ptr; + +#[repr(C)] +pub enum NativeTag { + TagString = 0, + TagInt = 1, + TagBool = 2, + TagNull = 3, + TagFloat64 = 4, + TagJson = 5, + TagList = 6, + TagPointer = 7, + TagFunction = 8, + TagAsyncFunction = 9, + TagUint8Bytes = 10, +} + +#[repr(C)] +#[derive(Clone, Copy)] +pub union ValueField { + pub int64: i64, + pub float64: f64, + pub ptr: *mut c_void, +} + +#[repr(C)] +#[derive(Clone, Copy)] +pub struct NativeValue { + pub u: ValueField, + pub uint32: u32, + pub tag: i32, +} + +#[repr(C)] +pub struct SharedNativeString { + pub string_: *mut u16, + pub length_: u32, +} + +impl NativeValue { + pub fn new() -> Self { + let size = mem::size_of::(); + + #[cfg(target_os = "windows")] + let ptr = unsafe { CoTaskMemAlloc(size) }; + + #[cfg(not(target_os = "windows"))] + let ptr = unsafe { libc::malloc(size) }; + + let ptr = ptr as *mut NativeValue; + let value = unsafe { ptr.read() }; + value + } + + pub fn new_string(val: &str) -> Self { + let len = val.len(); + let size = len * mem::size_of::(); + + #[cfg(target_os = "windows")] + let ptr = unsafe { CoTaskMemAlloc(size) }; + + #[cfg(not(target_os = "windows"))] + let ptr = unsafe { libc::malloc(size) }; + + let ptr = ptr as *mut u16; + + for (i, c) in val.encode_utf16().enumerate() { + unsafe { + ptr.add(i).write(c); + } + } + + let mut value = Self::new(); + value.tag = NativeTag::TagString as i32; + value.u.ptr = ptr as *mut c_void; + value.uint32 = len as u32; + value + } + + pub fn to_string(&self) -> String { + let ptr = unsafe { + self.u.ptr as *mut SharedNativeString + }; + let string_struct = unsafe { ptr.read() }; + let slice = unsafe { std::slice::from_raw_parts(string_struct.string_, string_struct.length_.try_into().unwrap()) }; + String::from_utf16_lossy(slice) + } + + pub fn new_null() -> Self { + let mut value = Self::new(); + value.tag = NativeTag::TagNull as i32; + value.u.int64 = 0; + value.uint32 = 0; + value + } + + pub fn new_float64(val: f64) -> Self { + let mut value = Self::new(); + value.tag = NativeTag::TagFloat64 as i32; + value.u.float64 = val; + value.uint32 = 0; + value + } + + pub fn new_bool(val: bool) -> Self { + let mut value = Self::new(); + value.tag = NativeTag::TagBool as i32; + value.u.int64 = if val { 1 } else { 0 }; + value.uint32 = 0; + value + } + + pub fn new_int64(val: i64) -> Self { + let mut value = Self::new(); + value.tag = NativeTag::TagInt as i32; + value.u.int64 = val; + value.uint32 = 0; + value + } + + pub fn new_list(values: Vec) -> Self { + let size = values.len(); + let array_size = size * mem::size_of::(); + + #[cfg(target_os = "windows")] + let array_ptr = unsafe { CoTaskMemAlloc(array_size) }; + + #[cfg(not(target_os = "windows"))] + let array_ptr = unsafe { libc::malloc(array_size) }; + + let array_ptr = array_ptr as *mut NativeValue; + + for (i, val) in values.iter().enumerate() { + unsafe { + array_ptr.add(i).write(*val); + } + } + + let mut value = Self::new(); + value.tag = NativeTag::TagList as i32; + value.u.ptr = array_ptr as *mut c_void; + value.uint32 = size as u32; + value + } +} diff --git a/webf/example/rust_builder/rust/src/lib.rs b/webf/example/rust_builder/rust/src/lib.rs index 5fd63f752d..b30c9cfa1d 100644 --- a/webf/example/rust_builder/rust/src/lib.rs +++ b/webf/example/rust_builder/rust/src/lib.rs @@ -1,7 +1,7 @@ use std::ffi::{c_void, CString}; use webf_sys::event::Event; use webf_sys::executing_context::ExecutingContextRustMethods; -use webf_sys::{element, initialize_webf_api, AddEventListenerOptions, EventMethods, EventTargetMethods, RustValue}; +use webf_sys::{element, initialize_webf_api, AddEventListenerOptions, EventMethods, EventTargetMethods, NativeValue, RustValue}; use webf_sys::element::Element; use webf_sys::node::NodeMethods; @@ -12,6 +12,20 @@ pub extern "C" fn init_webf_app(handle: RustValue) let exception_state = context.create_exception_state(); let document = context.document(); + let param1 = NativeValue::new_bool(true); + let param2 = NativeValue::new_bool(true); + let param3 = NativeValue::new_bool(true); + let param4 = NativeValue::new_bool(true); + + let params_vec = vec![param1, param2, param3, param4]; + let params = NativeValue::new_list(params_vec); + + let ua_string = context.webf_invoke_module_with_params("Navigator", "getUserAgent", ¶ms, &exception_state).unwrap(); + + let ua_string = ua_string.to_string(); + + println!("User Agent: {}", ua_string); + let timer_callback = Box::new(move || { println!("Timer Callback"); });