diff --git a/bridge/CMakeLists.txt b/bridge/CMakeLists.txt index 5246fd1f2a..c6da3e066b 100644 --- a/bridge/CMakeLists.txt +++ b/bridge/CMakeLists.txt @@ -302,6 +302,11 @@ list(APPEND BRIDGE_LINK_LIBS gumbo_parse_static) if (${IS_ANDROID}) find_library(log-lib log) + + if (${ANDROID_ABI} MATCHES "armeabi-v7a" OR ${ANDROID_ABI} MATCHES "x86") + add_definitions(-DANDROID_32_BIT=1) + endif() + add_definitions(-DIS_ANDROID=1) list(APPEND BRIDGE_LINK_LIBS ${log-lib}) endif () diff --git a/bridge/bindings/qjs/bom/window_test.cc b/bridge/bindings/qjs/bom/window_test.cc index 26b997d5d3..92baa1ffde 100644 --- a/bridge/bindings/qjs/bom/window_test.cc +++ b/bridge/bindings/qjs/bom/window_test.cc @@ -79,9 +79,7 @@ window.postMessage({ EXPECT_EQ(logCalled, true); } // Use block scope to release previous page, and allocate new page. - { - TEST_init(); - } + { TEST_init(); } } TEST(Window, location) { diff --git a/bridge/bindings/qjs/dom/custom_event.cc b/bridge/bindings/qjs/dom/custom_event.cc index cb485f724c..4f44d16a6a 100644 --- a/bridge/bindings/qjs/dom/custom_event.cc +++ b/bridge/bindings/qjs/dom/custom_event.cc @@ -27,7 +27,7 @@ JSValue CustomEvent::initCustomEvent(JSContext* ctx, JSValue this_val, int argc, } JSValue typeValue = argv[0]; - eventInstance->nativeEvent->type = jsValueToNativeString(ctx, typeValue).release(); + eventInstance->setType(jsValueToNativeString(ctx, typeValue).release()); if (argc <= 2) { bool canBubble = JS_ToBool(ctx, argv[1]); @@ -83,8 +83,9 @@ CustomEventInstance::CustomEventInstance(CustomEvent* jsCustomEvent, JSAtom cust CustomEventInstance::CustomEventInstance(CustomEvent* jsCustomEvent, NativeCustomEvent* nativeCustomEvent) : nativeCustomEvent(nativeCustomEvent), EventInstance(jsCustomEvent, reinterpret_cast(nativeCustomEvent)) { - JSValue newDetail = JS_NewUnicodeString(jsCustomEvent->context()->runtime(), jsCustomEvent->context()->ctx(), nativeCustomEvent->detail->string, nativeCustomEvent->detail->length); - nativeCustomEvent->detail->free(); + auto* detail = reinterpret_cast(nativeCustomEvent->detail); + JSValue newDetail = JS_NewUnicodeString(jsCustomEvent->context()->runtime(), jsCustomEvent->context()->ctx(), detail->string, detail->length); + detail->free(); m_detail.value(newDetail); JS_FreeValue(m_ctx, newDetail); } diff --git a/bridge/bindings/qjs/dom/custom_event.h b/bridge/bindings/qjs/dom/custom_event.h index 743de158e7..8384bd36f6 100644 --- a/bridge/bindings/qjs/dom/custom_event.h +++ b/bridge/bindings/qjs/dom/custom_event.h @@ -14,7 +14,7 @@ void bindCustomEvent(ExecutionContext* context); struct NativeCustomEvent { NativeEvent nativeEvent; - NativeString* detail{nullptr}; + int64_t detail{0}; }; class CustomEventInstance; diff --git a/bridge/bindings/qjs/dom/document.cc b/bridge/bindings/qjs/dom/document.cc index d2972b7602..4a91366feb 100644 --- a/bridge/bindings/qjs/dom/document.cc +++ b/bridge/bindings/qjs/dom/document.cc @@ -151,7 +151,11 @@ JSValue Document::createEvent(JSContext* ctx, JSValue this_val, int argc, JSValu std::string eventType = std::string(c_eventType); if (eventType == "Event") { std::unique_ptr nativeEventType = jsValueToNativeString(ctx, eventTypeValue); +#if ANDROID_32_BIT + auto nativeEvent = new NativeEvent{reinterpret_cast(nativeEventType.release())}; +#else auto nativeEvent = new NativeEvent{nativeEventType.release()}; +#endif auto document = static_cast(JS_GetOpaque(this_val, Document::classId())); auto e = Event::buildEventInstance(eventType, document->context(), nativeEvent, false); diff --git a/bridge/bindings/qjs/dom/elements/image_element.cc b/bridge/bindings/qjs/dom/elements/image_element.cc index d1999f586d..4b04504627 100644 --- a/bridge/bindings/qjs/dom/elements/image_element.cc +++ b/bridge/bindings/qjs/dom/elements/image_element.cc @@ -105,7 +105,7 @@ ImageElementInstance::ImageElementInstance(ImageElement* element) : ElementInsta } bool ImageElementInstance::dispatchEvent(EventInstance* event) { - std::u16string u16EventType = std::u16string(reinterpret_cast(event->nativeEvent->type->string), event->nativeEvent->type->length); + std::u16string u16EventType = std::u16string(reinterpret_cast(event->type()->string), event->type()->length); std::string eventType = toUTF8(u16EventType); bool result = EventTargetInstance::dispatchEvent(event); diff --git a/bridge/bindings/qjs/dom/event.cc b/bridge/bindings/qjs/dom/event.cc index 2232df0a5b..e62f36ed84 100644 --- a/bridge/bindings/qjs/dom/event.cc +++ b/bridge/bindings/qjs/dom/event.cc @@ -33,7 +33,11 @@ JSValue Event::instanceConstructor(JSContext* ctx, JSValue func_obj, JSValue thi JSValue eventTypeValue = argv[0]; std::string eventType = jsValueToStdString(ctx, eventTypeValue); +#if ANDROID_32_BIT + auto* nativeEvent = new NativeEvent{reinterpret_cast(stringToNativeString(eventType).release())}; +#else auto* nativeEvent = new NativeEvent{stringToNativeString(eventType).release()}; +#endif auto* event = Event::buildEventInstance(eventType, m_context, nativeEvent, false); return event->jsObject; } @@ -42,7 +46,8 @@ std::unordered_map Event::m_eventCreatorMap{}; IMPL_PROPERTY_GETTER(Event, type)(JSContext* ctx, JSValue this_val, int argc, JSValue* argv) { auto* eventInstance = static_cast(JS_GetOpaque(this_val, Event::kEventClassID)); - return JS_NewUnicodeString(ExecutionContext::runtime(), eventInstance->context()->ctx(), eventInstance->nativeEvent->type->string, eventInstance->nativeEvent->type->length); + auto* pType = reinterpret_cast(eventInstance->nativeEvent->type); + return JS_NewUnicodeString(ExecutionContext::runtime(), eventInstance->context()->ctx(), pType->string, pType->length); } IMPL_PROPERTY_GETTER(Event, bubbles)(JSContext* ctx, JSValue this_val, int argc, JSValue* argv) { @@ -68,9 +73,8 @@ IMPL_PROPERTY_GETTER(Event, defaultPrevented)(JSContext* ctx, JSValue this_val, IMPL_PROPERTY_GETTER(Event, target)(JSContext* ctx, JSValue this_val, int argc, JSValue* argv) { auto* eventInstance = static_cast(JS_GetOpaque(this_val, Event::kEventClassID)); - if (eventInstance->nativeEvent->target != nullptr) { - auto instance = reinterpret_cast(eventInstance->nativeEvent->target); - return JS_DupValue(ctx, ensureWindowIsGlobal(instance)); + if (eventInstance->target() != nullptr) { + return JS_DupValue(ctx, ensureWindowIsGlobal(eventInstance->target())); } return JS_NULL; } @@ -78,9 +82,8 @@ IMPL_PROPERTY_GETTER(Event, target)(JSContext* ctx, JSValue this_val, int argc, IMPL_PROPERTY_GETTER(Event, srcElement)(JSContext* ctx, JSValue this_val, int argc, JSValue* argv) { auto* eventInstance = static_cast(JS_GetOpaque(this_val, Event::kEventClassID)); - if (eventInstance->nativeEvent->target != nullptr) { - auto instance = reinterpret_cast(eventInstance->nativeEvent->target); - return JS_DupValue(ctx, ensureWindowIsGlobal(instance)); + if (eventInstance->target() != nullptr) { + return JS_DupValue(ctx, ensureWindowIsGlobal(eventInstance->target())); } return JS_NULL; } @@ -88,9 +91,8 @@ IMPL_PROPERTY_GETTER(Event, srcElement)(JSContext* ctx, JSValue this_val, int ar IMPL_PROPERTY_GETTER(Event, currentTarget)(JSContext* ctx, JSValue this_val, int argc, JSValue* argv) { auto* eventInstance = static_cast(JS_GetOpaque(this_val, Event::kEventClassID)); - if (eventInstance->nativeEvent->currentTarget != nullptr) { - auto instance = reinterpret_cast(eventInstance->nativeEvent->currentTarget); - return JS_DupValue(ctx, ensureWindowIsGlobal(instance)); + if (eventInstance->currentTarget() != nullptr) { + return JS_DupValue(ctx, ensureWindowIsGlobal(eventInstance->currentTarget())); } return JS_NULL; } @@ -164,7 +166,7 @@ JSValue Event::initEvent(JSContext* ctx, JSValue this_val, int argc, JSValue* ar } auto* event = static_cast(JS_GetOpaque(this_val, Event::kEventClassID)); - event->nativeEvent->type = jsValueToNativeString(ctx, typeValue).release(); + event->setType(jsValueToNativeString(ctx, typeValue).release()); if (!JS_IsNull(bubblesValue)) { event->nativeEvent->bubbles = JS_IsBool(bubblesValue) ? 1 : 0; @@ -179,10 +181,36 @@ EventInstance* EventInstance::fromNativeEvent(Event* event, NativeEvent* nativeE return new EventInstance(event, nativeEvent); } +void EventInstance::setType(NativeString* type) const { +#if ANDROID_32_BIT + nativeEvent->type = reinterpret_cast(type); +#else + nativeEvent->type = type; +#endif +} +void EventInstance::setTarget(EventTargetInstance* target) const { +#if ANDROID_32_BIT + nativeEvent->target = reinterpret_cast(target); +#else + nativeEvent->target = target; +#endif +} +void EventInstance::setCurrentTarget(EventTargetInstance* currentTarget) const { +#if ANDROID_32_BIT + nativeEvent->currentTarget = reinterpret_cast(currentTarget); +#else + nativeEvent->currentTarget = currentTarget; +#endif +} + EventInstance::EventInstance(Event* event, NativeEvent* nativeEvent) : nativeEvent(nativeEvent), Instance(event, "Event", nullptr, Event::kEventClassID, finalizer) {} EventInstance::EventInstance(Event* jsEvent, JSAtom eventType, JSValue eventInit) : Instance(jsEvent, "Event", nullptr, Event::kEventClassID, finalizer) { JSValue v = JS_AtomToValue(m_ctx, eventType); +#if ANDROID_32_BIT + nativeEvent = new NativeEvent{reinterpret_cast(jsValueToNativeString(m_ctx, v).release())}; +#else nativeEvent = new NativeEvent{jsValueToNativeString(m_ctx, v).release()}; +#endif JS_FreeValue(m_ctx, v); auto ms = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()); diff --git a/bridge/bindings/qjs/dom/event.h b/bridge/bindings/qjs/dom/event.h index d10457e915..3683b96e36 100644 --- a/bridge/bindings/qjs/dom/event.h +++ b/bridge/bindings/qjs/dom/event.h @@ -53,6 +53,7 @@ namespace kraken::binding::qjs { void bindEvent(ExecutionContext* context); class EventInstance; +class EventTargetInstance; using EventCreator = EventInstance* (*)(ExecutionContext* context, void* nativeEvent); @@ -96,6 +97,21 @@ class Event : public HostClass { friend EventInstance; }; +// Dart generated nativeEvent member are force align to 64-bit system. So all members in NativeEvent should have 64 bit width. +#if ANDROID_32_BIT +struct NativeEvent { + int64_t type{0}; + int64_t bubbles{0}; + int64_t cancelable{0}; + int64_t timeStamp{0}; + int64_t defaultPrevented{0}; + // The pointer address of target EventTargetInstance object. + int64_t target{0}; + // The pointer address of current target EventTargetInstance object. + int64_t currentTarget{0}; +}; +#else +// Use pointer instead of int64_t on 64 bit system can help compiler to choose best register for better running performance. struct NativeEvent { NativeString* type{nullptr}; int64_t bubbles{0}; @@ -107,6 +123,7 @@ struct NativeEvent { // The pointer address of current target EventTargetInstance object. void* currentTarget{nullptr}; }; +#endif struct RawEvent { uint64_t* bytes; @@ -121,10 +138,22 @@ class EventInstance : public Instance { static EventInstance* fromNativeEvent(Event* event, NativeEvent* nativeEvent); NativeEvent* nativeEvent{nullptr}; - inline const bool propagationStopped() { return m_propagationStopped; } - inline const bool cancelled() { return m_cancelled; } - inline void cancelled(bool v) { m_cancelled = v; } - inline const bool propagationImmediatelyStopped() { return m_propagationImmediatelyStopped; } + FORCE_INLINE const bool propagationStopped() { return m_propagationStopped; } + FORCE_INLINE const bool cancelled() { return m_cancelled; } + FORCE_INLINE void cancelled(bool v) { m_cancelled = v; } + FORCE_INLINE const bool propagationImmediatelyStopped() { return m_propagationImmediatelyStopped; } + FORCE_INLINE NativeString* type() { +#if ANDROID_32_BIT + return reinterpret_cast(nativeEvent->type); +#else + return nativeEvent->type; +#endif + }; + void setType(NativeString* type) const; + FORCE_INLINE EventTargetInstance* target() { return reinterpret_cast(nativeEvent->target); } + void setTarget(EventTargetInstance* target) const; + FORCE_INLINE EventTargetInstance* currentTarget() { return reinterpret_cast(nativeEvent->currentTarget); } + void setCurrentTarget(EventTargetInstance* target) const; protected: explicit EventInstance(Event* jsEvent, JSAtom eventType, JSValue eventInit); diff --git a/bridge/bindings/qjs/dom/event_target.cc b/bridge/bindings/qjs/dom/event_target.cc index 5c7950e93d..30ae93e9db 100644 --- a/bridge/bindings/qjs/dom/event_target.cc +++ b/bridge/bindings/qjs/dom/event_target.cc @@ -149,12 +149,18 @@ JSValue EventTarget::dispatchEvent(JSContext* ctx, JSValue this_val, int argc, J JSValue eventValue = argv[0]; auto eventInstance = reinterpret_cast(JS_GetOpaque(eventValue, EventTarget::classId(eventValue))); +#if ANDROID_32_BIT + eventInstance->nativeEvent->target = reinterpret_cast(eventTargetInstance); +#else eventInstance->nativeEvent->target = eventTargetInstance; +#endif return JS_NewBool(ctx, eventTargetInstance->dispatchEvent(eventInstance)); } bool EventTargetInstance::dispatchEvent(EventInstance* event) { - std::u16string u16EventType = std::u16string(reinterpret_cast(event->nativeEvent->type->string), event->nativeEvent->type->length); + auto* pEventType = reinterpret_cast(event->nativeEvent->type); + + std::u16string u16EventType = std::u16string(reinterpret_cast(pEventType->string), pEventType->length); std::string eventType = toUTF8(u16EventType); // protect this util event trigger finished. @@ -184,12 +190,12 @@ bool EventTargetInstance::dispatchEvent(EventInstance* event) { } bool EventTargetInstance::internalDispatchEvent(EventInstance* eventInstance) { - std::u16string u16EventType = std::u16string(reinterpret_cast(eventInstance->nativeEvent->type->string), eventInstance->nativeEvent->type->length); + std::u16string u16EventType = std::u16string(reinterpret_cast(eventInstance->type()->string), eventInstance->type()->length); std::string eventTypeStr = toUTF8(u16EventType); JSAtom eventType = JS_NewAtom(m_ctx, eventTypeStr.c_str()); // Modify the currentTarget to this. - eventInstance->nativeEvent->currentTarget = this; + eventInstance->setCurrentTarget(this); // Dispatch event listeners writen by addEventListener auto _dispatchEvent = [&eventInstance, this](JSValue handler) { @@ -496,7 +502,7 @@ void NativeEventTarget::dispatchEventImpl(int32_t contextId, NativeEventTarget* // So we can reinterpret_cast raw bytes pointer to NativeEvent type directly. auto* nativeEvent = reinterpret_cast(raw->bytes); EventInstance* eventInstance = Event::buildEventInstance(eventType, context, nativeEvent, isCustomEvent == 1); - eventInstance->nativeEvent->target = eventTargetInstance; + eventInstance->setTarget(eventTargetInstance); eventTargetInstance->dispatchEvent(eventInstance); JS_FreeValue(context->ctx(), eventInstance->jsObject); } diff --git a/bridge/bindings/qjs/dom/events/touch_event.cc b/bridge/bindings/qjs/dom/events/touch_event.cc index a807514644..3878fee19f 100644 --- a/bridge/bindings/qjs/dom/events/touch_event.cc +++ b/bridge/bindings/qjs/dom/events/touch_event.cc @@ -117,7 +117,11 @@ JSValue TouchEvent::instanceConstructor(JSContext* ctx, JSValue func_obj, JSValu } auto* nativeEvent = new NativeTouchEvent(); +#if ANDROID_32_BIT + nativeEvent->nativeEvent.type = reinterpret_cast(jsValueToNativeString(ctx, eventTypeValue).release()); +#else nativeEvent->nativeEvent.type = jsValueToNativeString(ctx, eventTypeValue).release(); +#endif if (JS_IsObject(eventInit)) { JSAtom touchesAtom = JS_NewAtom(m_ctx, "touches"); diff --git a/bridge/bindings/qjs/executing_context.cc b/bridge/bindings/qjs/executing_context.cc index 63999a18e3..b9c0ba9d4c 100644 --- a/bridge/bindings/qjs/executing_context.cc +++ b/bridge/bindings/qjs/executing_context.cc @@ -347,7 +347,7 @@ void ExecutionContext::dispatchGlobalErrorEvent(ExecutionContext* context, JSVal } auto* errorEvent = static_cast(JS_GetOpaque(errorEventValue, Event::kEventClassID)); - errorEvent->nativeEvent->target = window; + errorEvent->setTarget(window); context->dispatchErrorEvent(errorEvent); JS_FreeValue(ctx, errorEventConstructor); @@ -378,7 +378,7 @@ static void dispatchPromiseRejectionEvent(const char* eventType, ExecutionContex } auto* rejectEvent = static_cast(JS_GetOpaque(rejectEventValue, Event::kEventClassID)); - rejectEvent->nativeEvent->target = window; + rejectEvent->setTarget(window); window->dispatchEvent(rejectEvent); JS_FreeValue(ctx, errorType); diff --git a/bridge/scripts/code_generator/src/genereate_source.ts b/bridge/scripts/code_generator/src/genereate_source.ts index a05d753a24..0a0c92570d 100644 --- a/bridge/scripts/code_generator/src/genereate_source.ts +++ b/bridge/scripts/code_generator/src/genereate_source.ts @@ -311,7 +311,11 @@ function generateEventConstructorCode(object: ClassObject) { } auto *nativeEvent = new Native${object.name}(); +#if ANDROID_32_BIT + nativeEvent->nativeEvent.type = reinterpret_cast(jsValueToNativeString(ctx, eventTypeValue).release()); +#else nativeEvent->nativeEvent.type = jsValueToNativeString(ctx, eventTypeValue).release(); +#endif ${generateEventInstanceConstructorCode(object)} diff --git a/bridge/test/kraken_test_env.cc b/bridge/test/kraken_test_env.cc index 837ae04149..ae24fb5eb9 100644 --- a/bridge/test/kraken_test_env.cc +++ b/bridge/test/kraken_test_env.cc @@ -161,7 +161,9 @@ void TEST_initWindow(int32_t contextId, void* nativePtr) {} void TEST_initDocument(int32_t contextId, void* nativePtr) {} #if ENABLE_PROFILE -NativePerformanceEntryList* TEST_getPerformanceEntries(int32_t) {} +NativePerformanceEntryList* TEST_getPerformanceEntries(int32_t) { + return nullptr; +} #endif std::once_flag testInitOnceFlag; @@ -258,7 +260,11 @@ void TEST_dispatchEvent(int32_t contextId, EventTargetInstance* eventTarget, con auto nativeEventType = stringToNativeString(type); NativeString* rawEventType = nativeEventType.release(); +#if ANDROID_32_BIT + NativeEvent* nativeEvent = new NativeEvent{reinterpret_cast(rawEventType)}; +#else NativeEvent* nativeEvent = new NativeEvent{rawEventType}; +#endif RawEvent* rawEvent = new RawEvent{reinterpret_cast(nativeEvent)}; diff --git a/kraken/android/jniLibs/x86/libc++_shared.so b/kraken/android/jniLibs/x86/libc++_shared.so new file mode 120000 index 0000000000..f541ad7f39 --- /dev/null +++ b/kraken/android/jniLibs/x86/libc++_shared.so @@ -0,0 +1 @@ +../../../../bridge/build/android/lib/x86/libc++_shared.so \ No newline at end of file diff --git a/kraken/android/jniLibs/x86/libkraken.so b/kraken/android/jniLibs/x86/libkraken.so new file mode 120000 index 0000000000..374227bcfd --- /dev/null +++ b/kraken/android/jniLibs/x86/libkraken.so @@ -0,0 +1 @@ +../../../../bridge/build/android/lib/x86/libkraken.so \ No newline at end of file diff --git a/kraken/android/jniLibs/x86/libquickjs.so b/kraken/android/jniLibs/x86/libquickjs.so new file mode 120000 index 0000000000..a7e4f03071 --- /dev/null +++ b/kraken/android/jniLibs/x86/libquickjs.so @@ -0,0 +1 @@ +../../../../bridge/build/android/lib/x86/libquickjs.so \ No newline at end of file diff --git a/scripts/tasks.js b/scripts/tasks.js index 2ac2e53e19..6d342d6d98 100644 --- a/scripts/tasks.js +++ b/scripts/tasks.js @@ -578,7 +578,7 @@ task('build-ios-frameworks', (done) => { task('build-linux-kraken-lib', (done) => { const buildType = buildMode == 'Release' ? 'Release' : 'Relwithdebinfo'; const cmakeGeneratorTemplate = platform == 'win32' ? 'Ninja' : 'Unix Makefiles'; - + const soBinaryDirectory = path.join(paths.bridge, `build/linux/lib/`); const bridgeCmakeDir = path.join(paths.bridge, 'cmake-build-linux'); // generate project @@ -630,10 +630,11 @@ task('build-android-kraken-lib', (done) => { } } - const archs = ['arm64-v8a', 'armeabi-v7a']; + const archs = ['arm64-v8a', 'armeabi-v7a', 'x86']; const toolChainMap = { 'arm64-v8a': 'aarch64-linux-android', - 'armeabi-v7a': 'arm-linux-androideabi' + 'armeabi-v7a': 'arm-linux-androideabi', + 'x86': 'i686-linux-android' }; const buildType = (buildMode === 'Release' || buildMode == 'Relwithdebinfo') ? 'Relwithdebinfo' : 'Debug'; let externCmakeArgs = [];