Skip to content

Commit

Permalink
feat(core): expose km_core_keyboard_load_from_blob to WASM
Browse files Browse the repository at this point in the history
  • Loading branch information
ermshiperete committed Dec 9, 2024
1 parent 6c3faa2 commit 1bedc62
Show file tree
Hide file tree
Showing 4 changed files with 123 additions and 36 deletions.
2 changes: 1 addition & 1 deletion core/include/keyman/keyman_core_api_bits.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
#undef _kmn_export_flag
#undef _kmn_import_flag
#undef _kmn_static_flag
#else // How MSVC sepcifies function level attributes adn deprecation
#else // How MSVC sepcifies function level attributes and deprecation
#define _kmn_and
#define _kmn_tag_fn(a) __declspec(a)
#define _kmn_deprecated_flag deprecated
Expand Down
23 changes: 18 additions & 5 deletions core/src/km_core_keyboard_api.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,18 +40,16 @@ namespace
} // namespace

km_core_status
km_core_keyboard_load_from_blob(
keyboard_load_from_blob_internal(
const km_core_path_name kb_name,
const void* blob,
const size_t blob_size,
const std::vector<uint8_t>& buf,
km_core_keyboard** keyboard
) {
assert(keyboard);
if (!keyboard || !blob) {
if (!keyboard) {
return KM_CORE_STATUS_INVALID_ARGUMENT;
}

std::vector<uint8_t> buf((uint8_t*)blob, (uint8_t*)blob + blob_size);
*keyboard = nullptr;
try {
abstract_processor* kp = processor_factory(kb_name, buf);
Expand All @@ -67,6 +65,21 @@ km_core_keyboard_load_from_blob(
return KM_CORE_STATUS_OK;
}

km_core_status
km_core_keyboard_load_from_blob(
const km_core_path_name kb_name,
const void* blob,
const size_t blob_size,
km_core_keyboard** keyboard
) {
if (!blob) {
return KM_CORE_STATUS_INVALID_ARGUMENT;
}

std::vector<uint8_t> buf((uint8_t*)blob, (uint8_t*)blob + blob_size);
return keyboard_load_from_blob_internal(kb_name, buf, keyboard);
}

void
km_core_keyboard_dispose(km_core_keyboard *keyboard)
{
Expand Down
50 changes: 29 additions & 21 deletions core/src/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,6 @@ else
endif

if cpp_compiler.get_id() == 'emscripten'
# TODO: why do we need this defn here?
defns += ['-DKM_CORE_LIBRARY']
icu_if_not_on_wasm = []
else
# only include this if NOT on wasm.
Expand All @@ -54,19 +52,21 @@ if cpp_compiler.get_id() == 'emscripten'
'-g', '-Wlimited-postlink-optimizations',
'-lembind'
]
util_normalize_table_generator = executable(
'util_normalize_table_generator',
['util_normalize_table_generator.cpp'],
cpp_args: defns + warns,
include_directories: [inc],
link_args: links,
dependencies: [icu_uc, icu_i18n],
)

util_normalize_table_generator = executable('util_normalize_table_generator',
['util_normalize_table_generator.cpp'],
cpp_args: defns + warns,
include_directories: [inc],
link_args: links,
dependencies: [icu_uc, icu_i18n],
)

util_normalize_table_h = custom_target('util_normalize_table.h',
output: 'util_normalize_table.h',
command: [util_normalize_table_generator],
capture:true)
util_normalize_table_h = custom_target(
'util_normalize_table.h',
output: 'util_normalize_table.h',
command: [util_normalize_table_generator],
capture:true
)

generated_headers += util_normalize_table_h
endif
Expand Down Expand Up @@ -139,13 +139,21 @@ mock_files = files(
)

if cpp_compiler.get_id() == 'emscripten'
host_links = ['--whole-archive', '-sALLOW_MEMORY_GROWTH=1', '-sMODULARIZE=1',
'-sEXPORT_ES6', '-sENVIRONMENT=web,webview',
'--emit-tsd', 'km-core-interface.d.ts', '-sERROR_ON_UNDEFINED_SYMBOLS=0']

links += ['-sEXPORTED_RUNTIME_METHODS=[\'UTF8ToString\',\'stringToNewUTF8\',\'wasmExports\']',
# Forcing inclusion of debug symbols
'-g', '-Wlimited-postlink-optimizations', '--bind']
links += [
'-sEXPORTED_RUNTIME_METHODS=[\'UTF8ToString\',\'stringToNewUTF8\',\'wasmExports\']',
# Forcing inclusion of debug symbols
'-g', '-Wlimited-postlink-optimizations',
'-lembind'
]
host_links = [
'--whole-archive',
'-sALLOW_MEMORY_GROWTH=1',
'-sMODULARIZE=1', '-sEXPORT_NAME=createCoreProcessor',
'-sEXPORT_ES6',
'-sENVIRONMENT=web,webview',
'--emit-tsd', 'km-core-interface.d.ts',
# '-sERROR_ON_UNDEFINED_SYMBOLS=0'
]
endif

lib = library('keymancore',
Expand Down
84 changes: 75 additions & 9 deletions core/src/wasm.cpp
Original file line number Diff line number Diff line change
@@ -1,20 +1,19 @@
#ifdef __EMSCRIPTEN__
#ifdef __EMSCRIPTEN__
#include <emscripten/emscripten.h>
#include <emscripten/bind.h>

#else
#define EMSCRIPTEN_KEEPALIVE
#endif
#include <vector>

#ifdef __cplusplus
#define EXTERN extern "C" EMSCRIPTEN_KEEPALIVE
#else
#define EXTERN EMSCRIPTEN_KEEPALIVE
#endif

#include "processor.hpp"
#include <keyman_core.h>

namespace em = emscripten;

constexpr km_core_attr const engine_attrs = {
256,
KM_CORE_LIB_CURRENT,
Expand All @@ -24,21 +23,88 @@ constexpr km_core_attr const engine_attrs = {
"SIL International"
};

EMSCRIPTEN_KEEPALIVE km_core_attr const & tmp_wasm_attributes() {
EMSCRIPTEN_KEEPALIVE km_core_attr const& tmp_wasm_attributes() {
return engine_attrs;
}

template <typename T> class CoreReturn {
public:
CoreReturn(int status = 0, const T* obj = nullptr) : status(status), object(obj) {
}
void setStatus(int status) {
this->status = status;
}
int getStatus() const {
return status;
}
void setObject(const T* obj) {
object = obj;
}
const T* getObject() const {
return object;
}

private:
int status;
const T* object;
};

km_core_status
keyboard_load_from_blob_internal(const km_core_path_name kb_name, const std::vector<uint8_t>& buf, km_core_keyboard** keyboard);

EMSCRIPTEN_KEEPALIVE const CoreReturn<km_core_keyboard>*
km_core_keyboard_load_from_blob_wasm(
std::string kb_name,
const emscripten::val& blob_val
) {
std::vector<uint8_t> blob;
km_core_keyboard* keyboard_ptr = nullptr;

const auto length = blob_val["length"].as<unsigned>();
blob.resize(length);

emscripten::val memoryView{emscripten::typed_memory_view(length, blob.data())};
memoryView.call<void>("set", blob_val);
km_core_status retVal = ::keyboard_load_from_blob_internal(kb_name.c_str(), blob, &keyboard_ptr);
return new CoreReturn<km_core_keyboard>(retVal, keyboard_ptr);
}

EMSCRIPTEN_BINDINGS(core_interface) {

emscripten::value_object<km_core_attr>("km_core_attr")
em::value_object<km_core_attr>("km_core_attr")
.field("max_context", &km_core_attr::max_context)
.field("current", &km_core_attr::current)
.field("revision", &km_core_attr::revision)
.field("age", &km_core_attr::age)
.field("technology", &km_core_attr::technology)
//.field("vendor", &km_core_attr::vendor, emscripten::allow_raw_pointers())
//.field("vendor", &km_core_attr::vendor, em::allow_raw_pointers())
;

emscripten::function("tmp_wasm_attributes", &tmp_wasm_attributes);
em::function("tmp_wasm_attributes", &tmp_wasm_attributes);


// Unfortunately embind has an open issue with enums and typescript where it
// only generates a type for the enum, but not the values in a usable way.
// Therefore it's not much use to expose the enum here.
// See https://github.com/emscripten-core/emscripten/issues/18585

// em::enum_<km_core_status_codes>("km_core_status_codes")
// .value("OK", KM_CORE_STATUS_OK)
// .value("NO_MEM", KM_CORE_STATUS_NO_MEM)
// .value("IO_ERROR", KM_CORE_STATUS_IO_ERROR)
// .value("INVALID_ARGUMENT", KM_CORE_STATUS_INVALID_ARGUMENT)
// .value("KEY_ERROR", KM_CORE_STATUS_KEY_ERROR)
// .value("INSUFFICENT_BUFFER", KM_CORE_STATUS_INSUFFICENT_BUFFER)
// .value("INVALID_UTF", KM_CORE_STATUS_INVALID_UTF)
// .value("INVALID_KEYBOARD", KM_CORE_STATUS_INVALID_KEYBOARD)
// .value("NOT_IMPLEMENTED", KM_CORE_STATUS_NOT_IMPLEMENTED)
// .value("OS_ERROR", KM_CORE_STATUS_OS_ERROR);

em::class_<km_core_keyboard>("km_core_keyboard");
em::class_<CoreReturn<km_core_keyboard>>("CoreKeyboardReturn")
.property("status", &CoreReturn<km_core_keyboard>::getStatus)
.property("object", &CoreReturn<km_core_keyboard>::getObject, em::allow_raw_pointers());

em::function("keyboard_load_from_blob", &km_core_keyboard_load_from_blob_wasm, em::allow_raw_pointers());
}
#endif

0 comments on commit 1bedc62

Please sign in to comment.