diff --git a/bridge/bindings/qjs/qjs_engine_patch.cc b/bridge/bindings/qjs/qjs_engine_patch.cc index 9d91196bf2..20794ab10e 100644 --- a/bridge/bindings/qjs/qjs_engine_patch.cc +++ b/bridge/bindings/qjs/qjs_engine_patch.cc @@ -238,7 +238,7 @@ struct JSObject { uint16_t* JS_ToUnicode(JSContext* ctx, JSValueConst value, uint32_t* length) { if (JS_VALUE_GET_TAG(value) != JS_TAG_STRING) { - value = JS_ToString(ctx, value); + value = JS_ToPropertyKey(ctx, value); if (JS_IsException(value)) return nullptr; } else { diff --git a/bridge/core/built_in_string.json5 b/bridge/core/built_in_string.json5 index 0134d23d7e..2e93b706f8 100644 --- a/bridge/core/built_in_string.json5 +++ b/bridge/core/built_in_string.json5 @@ -3,234 +3,237 @@ "templates": [ { "template": "make_names", - "filename": "built_in_string" + "filename": "built_in_string", + "options": { + "add_atom_prefix": true + } } ] }, "data": [ - ["null", "null"], - ["false", "false"], - ["true", "true"], - ["if", "if"], - ["else", "else"], - ["return", "return"], - ["var", "var"], - ["this", "this"], - ["delete", "delete"], - ["void", "void"], - ["typeof", "typeof"], - ["new", "new"], - ["in", "in"], - ["instanceof", "instanceof"], - ["do", "do"], - ["while", "while"], - ["for", "for"], - ["break", "break"], - ["continue", "continue"], - ["switch", "switch"], - ["case", "case"], - ["default", "default"], - ["throw", "throw"], - ["try", "try"], - ["catch", "catch"], - ["finally", "finally"], - ["function", "function"], - ["debugger", "debugger"], - ["with", "with"], - ["class", "class"], - ["const", "const"], - ["enum", "enum"], - ["export", "export"], - ["extends", "extends"], - ["import", "import"], - ["super", "super"], - ["implements", "implements"], - ["interface", "interface"], - ["let", "let"], - ["package", "package"], - ["private", "private"], - ["protected", "protected"], - ["public", "public"], - ["static", "static"], - ["yield", "yield"], - ["await", "await"], - ["empty_string", ""], - ["length", "length"], - ["fileName", "fileName"], - ["lineNumber", "lineNumber"], - ["message", "message"], - ["errors", "errors"], - ["stack", "stack"], - ["name", "name"], - ["toString", "toString"], - ["toLocaleString", "toLocaleString"], - ["valueOf", "valueOf"], - ["eval", "eval"], - ["prototype", "prototype"], - ["constructor", "constructor"], - ["configurable", "configurable"], - ["writable", "writable"], - ["enumerable", "enumerable"], - ["value", "value"], - ["get", "get"], - ["set", "set"], - ["of", "of"], - ["__proto__", "__proto__"], - ["undefined", "undefined"], - ["number", "number"], - ["boolean", "boolean"], - ["string", "string"], - ["object", "object"], - ["symbol", "symbol"], - ["integer", "integer"], - ["unknown", "unknown"], - ["arguments", "arguments"], - ["callee", "callee"], - ["caller", "caller"], - ["_eval_", ""], - ["_ret_", ""], - ["_var_", ""], - ["_arg_var_", ""], - ["_with_", ""], - ["lastIndex", "lastIndex"], - ["target", "target"], - ["index", "index"], - ["input", "input"], - ["defineProperties", "defineProperties"], - ["apply", "apply"], - ["join", "join"], - ["concat", "concat"], - ["split", "split"], - ["construct", "construct"], - ["getPrototypeOf", "getPrototypeOf"], - ["setPrototypeOf", "setPrototypeOf"], - ["isExtensible", "isExtensible"], - ["preventExtensions", "preventExtensions"], - ["has", "has"], - ["deleteProperty", "deleteProperty"], - ["defineProperty", "defineProperty"], - ["getOwnPropertyDescriptor", "getOwnPropertyDescriptor"], - ["ownKeys", "ownKeys"], - ["add", "add"], - ["done", "done"], - ["next", "next"], - ["values", "values"], - ["source", "source"], - ["flags", "flags"], - ["global", "global"], - ["unicode", "unicode"], - ["raw", "raw"], - ["new_target", "new.target"], - ["this_active_func", "this.active_func"], - ["home_object", ""], - ["computed_field", ""], - ["static_computed_field", ""], - ["class_fields_init", ""], - ["brand", ""], - ["hash_constructor", "#constructor"], - ["as", "as"], - ["from", "from"], - ["meta", "meta"], - ["_default_", "*default*"], - ["_star_", "*"], - ["Module", "Module"], - ["then", "then"], - ["resolve", "resolve"], - ["reject", "reject"], - ["promise", "promise"], - ["proxy", "proxy"], - ["revoke", "revoke"], - ["async", "async"], - ["exec", "exec"], - ["groups", "groups"], - ["status", "status"], - ["reason", "reason"], - ["globalThis", "globalThis"], - ["bigint", "bigint"], - ["bigfloat", "bigfloat"], - ["bigdecimal", "bigdecimal"], - ["roundingMode", "roundingMode"], - ["maximumSignificantDigits", "maximumSignificantDigits"], - ["maximumFractionDigits", "maximumFractionDigits"], - ["not_equal", "not-equal"], - ["timed_out", "timed-out"], - ["ok", "ok"], - ["toJSON", "toJSON"], - ["Object", "Object"], - ["Array", "Array"], - ["Error", "Error"], - ["Number", "Number"], - ["String", "String"], - ["Boolean", "Boolean"], - ["Symbol", "Symbol"], - ["Arguments", "Arguments"], - ["Math", "Math"], - ["JSON", "JSON"], - ["Date", "Date"], - ["Function", "Function"], - ["GeneratorFunction", "GeneratorFunction"], - ["ForInIterator", "ForInIterator"], - ["RegExp", "RegExp"], - ["ArrayBuffer", "ArrayBuffer"], - ["SharedArrayBuffer", "SharedArrayBuffer"], - ["Uint8ClampedArray", "Uint8ClampedArray"], - ["Int8Array", "Int8Array"], - ["Uint8Array", "Uint8Array"], - ["Int16Array", "Int16Array"], - ["Uint16Array", "Uint16Array"], - ["Int32Array", "Int32Array"], - ["Uint32Array", "Uint32Array"], - ["BigInt64Array", "BigInt64Array"], - ["BigUint64Array", "BigUint64Array"], - ["Float32Array", "Float32Array"], - ["Float64Array", "Float64Array"], - ["DataView", "DataView"], - ["BigInt", "BigInt"], - ["BigFloat", "BigFloat"], - ["BigFloatEnv", "BigFloatEnv"], - ["BigDecimal", "BigDecimal"], - ["OperatorSet", "OperatorSet"], - ["Operators", "Operators"], - ["Map", "Map"], - ["Set", "Set"], - ["WeakMap", "WeakMap"], - ["WeakSet", "WeakSet"], - ["Map_Iterator", "Map Iterator"], - ["Set_Iterator", "Set Iterator"], - ["Array_Iterator", "Array Iterator"], - ["String_Iterator", "String Iterator"], - ["RegExp_String_Iterator", "RegExp String Iterator"], - ["Generator", "Generator"], - ["Proxy", "Proxy"], - ["Promise", "Promise"], - ["PromiseResolveFunction", "PromiseResolveFunction"], - ["PromiseRejectFunction", "PromiseRejectFunction"], - ["AsyncFunction", "AsyncFunction"], - ["AsyncFunctionResolve", "AsyncFunctionResolve"], - ["AsyncFunctionReject", "AsyncFunctionReject"], - ["AsyncGeneratorFunction", "AsyncGeneratorFunction"], - ["AsyncGenerator", "AsyncGenerator"], - ["EvalError", "EvalError"], - ["RangeError", "RangeError"], - ["ReferenceError", "ReferenceError"], - ["SyntaxError", "SyntaxError"], - ["TypeError", "TypeError"], - ["URIError", "URIError"], - ["InternalError", "InternalError"], - ["Private_brand", ""], - ["Symbol_toPrimitive", "Symbol.toPrimitive"], - ["Symbol_iterator", "Symbol.iterator"], - ["Symbol_match", "Symbol.match"], - ["Symbol_matchAll", "Symbol.matchAll"], - ["Symbol_replace", "Symbol.replace"], - ["Symbol_search", "Symbol.search"], - ["Symbol_split", "Symbol.split"], - ["Symbol_toStringTag", "Symbol.toStringTag"], - ["Symbol_isConcatSpreadable", "Symbol.isConcatSpreadable"], - ["Symbol_hasInstance", "Symbol.hasInstance"], - ["Symbol_species", "Symbol.species"], - ["Symbol_unscopables", "Symbol.unscopables"], - ["Symbol_asyncIterator", "Symbol.asyncIterator"], - ["Symbol_operatorSet", "Symbol.operatorSet"] + "null", + "false", + "true", + "if", + "else", + "return", + "var", + "this", + "delete", + "void", + "typeof", + "new", + "in", + "instanceof", + "do", + "while", + "for", + "break", + "continue", + "switch", + "case", + "default", + "throw", + "try", + "catch", + "finally", + "function", + "debugger", + "with", + "class", + "const", + "enum", + "export", + "extends", + "import", + "super", + "implements", + "interface", + "let", + "package", + "private", + "protected", + "public", + "static", + "yield", + "await", + "empty_string", + "length", + "fileName", + "lineNumber", + "message", + "errors", + "stack", + "name", + "toString", + "toLocaleString", + "valueOf", + "eval", + "prototype", + "constructor", + "configurable", + "writable", + "enumerable", + "value", + "get", + "set", + "of", + "__proto__", + "undefined", + "number", + "boolean", + "string", + "object", + "symbol", + "integer", + "unknown", + "arguments", + "callee", + "caller", + "_eval_", + "_ret_", + "_var_", + "_arg_var_", + "_with_", + "lastIndex", + "target", + "index", + "input", + "defineProperties", + "apply", + "join", + "concat", + "split", + "construct", + "getPrototypeOf", + "setPrototypeOf", + "isExtensible", + "preventExtensions", + "has", + "deleteProperty", + "defineProperty", + "getOwnPropertyDescriptor", + "ownKeys", + "add", + "done", + "next", + "values", + "source", + "flags", + "global", + "unicode", + "raw", + "new_target", + "this_active_func", + "home_object", + "computed_field", + "static_computed_field", + "class_fields_init", + "brand", + "hash_constructor", + "as", + "from", + "meta", + "_default_", + "_star_", + "Module", + "then", + "resolve", + "reject", + "promise", + "proxy", + "revoke", + "async", + "exec", + "groups", + "status", + "reason", + "globalThis", +// "bigint", +// "bigfloat", +// "bigdecimal", +// "roundingMode", +// "maximumSignificantDigits", +// "maximumFractionDigits", + "not_equal", + "timed_out", + "ok", + "toJSON", + "Object", + "Array", + "Error", + "Number", + "String", + "Boolean", + "Symbol", + "Arguments", + "Math", + "JSON", + "Date", + "Function", + "GeneratorFunction", + "ForInIterator", + "RegExp", + "ArrayBuffer", + "SharedArrayBuffer", + "Uint8ClampedArray", + "Int8Array", + "Uint8Array", + "Int16Array", + "Uint16Array", + "Int32Array", + "Uint32Array", +// "BigInt64Array", +// "BigUint64Array", + "Float32Array", + "Float64Array", + "DataView", +// "BigInt", +// "BigFloat", +// "BigFloatEnv", +// "BigDecimal", +// "OperatorSet", +// "Operators", + "Map", + "Set", + "WeakMap", + "WeakSet", + "Map_Iterator", + "Set_Iterator", + "Array_Iterator", + "String_Iterator", + "RegExp_String_Iterator", + "Generator", + "Proxy", + "Promise", + "PromiseResolveFunction", + "PromiseRejectFunction", + "AsyncFunction", + "AsyncFunctionResolve", + "AsyncFunctionReject", + "AsyncGeneratorFunction", + "AsyncGenerator", + "EvalError", + "RangeError", + "ReferenceError", + "SyntaxError", + "TypeError", + "URIError", + "InternalError", + "Private_brand", + "Symbol_toPrimitive", + "Symbol_iterator", + "Symbol_match", + "Symbol_matchAll", + "Symbol_replace", + "Symbol_search", + "Symbol_split", + "Symbol_toStringTag", + "Symbol_isConcatSpreadable", + "Symbol_hasInstance", + "Symbol_species", + "Symbol_unscopables", + "Symbol_asyncIterator", +// "Symbol_operatorSet", ] } diff --git a/bridge/core/html/custom/widget_element.cc b/bridge/core/html/custom/widget_element.cc index a08744c7b4..b6d943a251 100644 --- a/bridge/core/html/custom/widget_element.cc +++ b/bridge/core/html/custom/widget_element.cc @@ -4,6 +4,7 @@ */ #include "widget_element.h" +#include "built_in_string.h" #include "core/dom/document.h" #include "foundation/native_value_converter.h" @@ -58,6 +59,10 @@ ScriptValue WidgetElement::item(const AtomicString& key, ExceptionState& excepti return ScriptValue::Empty(ctx()); } + if (key == built_in_string::kSymbol_toStringTag) { + return ScriptValue(ctx(), tagName().ToNativeString().release()); + } + return ScriptValue(ctx(), GetBindingProperty(key, exception_state)); } diff --git a/bridge/core/html/custom/widget_element_test.cc b/bridge/core/html/custom/widget_element_test.cc index 5f820e7816..bf7af0b392 100644 --- a/bridge/core/html/custom/widget_element_test.cc +++ b/bridge/core/html/custom/widget_element_test.cc @@ -29,3 +29,23 @@ TEST(WidgetElement, setPropertyEventHandler) { EXPECT_EQ(errorCalled, false); } + +TEST(WidgetElement, getPropertyWithSymbolToStringTag) { + bool static errorCalled = false; + bool static logCalled = false; + webf::WebFPage::consoleMessageHandler = [](void* ctx, const std::string& message, int logLevel) { + EXPECT_STREQ(message.c_str(), "FLUTTER-CHECKBOX"); + logCalled = true; + }; + auto bridge = TEST_init([](int32_t contextId, const char* errmsg) { + WEBF_LOG(VERBOSE) << errmsg; + errorCalled = true; + }); + auto context = bridge->GetExecutingContext(); + const char* code = + "let checkbox = document.createElement('flutter-checkbox'); " + "console.log(checkbox[Symbol.toStringTag])"; + bridge->evaluateScript(code, strlen(code), "vm://", 0); + + EXPECT_EQ(errorCalled, false); +} diff --git a/bridge/scripts/code_generator/bin/code_generator.js b/bridge/scripts/code_generator/bin/code_generator.js index 72400e3835..3f264a4589 100644 --- a/bridge/scripts/code_generator/bin/code_generator.js +++ b/bridge/scripts/code_generator/bin/code_generator.js @@ -112,7 +112,7 @@ function genCodeFromJSONData() { let targetTemplateHeaderData = templates.find(t => t.filename === targetTemplate.template + '.h'); let targetTemplateBodyData = templates.find(t => t.filename === targetTemplate.template + '.cc'); blob.filename = targetTemplate.filename; - let result = generateJSONTemplate(blobs[i], targetTemplateHeaderData, targetTemplateBodyData, depsBlob); + let result = generateJSONTemplate(blobs[i], targetTemplateHeaderData, targetTemplateBodyData, depsBlob, targetTemplate.options); let dist = blob.dist; let genFilePath = path.join(dist, targetTemplate.filename); fs.writeFileSync(genFilePath + '.h', result.header); diff --git a/bridge/scripts/code_generator/src/json/generator.ts b/bridge/scripts/code_generator/src/json/generator.ts index f682ddbd8b..0ae8cd2c63 100644 --- a/bridge/scripts/code_generator/src/json/generator.ts +++ b/bridge/scripts/code_generator/src/json/generator.ts @@ -2,13 +2,14 @@ import {JSONBlob} from './JSONBlob'; import {JSONTemplate} from './JSONTemplate'; import _ from 'lodash'; -function generateHeader(blob: JSONBlob, template: JSONTemplate, deps?: JSONBlob[]): string { +function generateHeader(blob: JSONBlob, template: JSONTemplate, deps?: JSONBlob[], options: GenerateJSONOptions = {}): string { let compiled = _.template(template.raw); return compiled({ _: _, name: blob.filename, template_path: blob.source, data: blob.json.data, + options, deps, upperCamelCase }).split('\n').filter(str => { @@ -21,22 +22,27 @@ function upperCamelCase(name: string) { return _.upperFirst(_.camelCase(name)); } -function generateBody(blob: JSONBlob, template: JSONTemplate, deps?: JSONBlob[]): string { +function generateBody(blob: JSONBlob, template: JSONTemplate, deps?: JSONBlob[], options: GenerateJSONOptions = {}): string { let compiled = _.template(template.raw); return compiled({ template_path: blob.source, name: blob.filename, data: blob.json.data, deps, + options, upperCamelCase, }).split('\n').filter(str => { return str.trim().length > 0; }).join('\n'); } -export function generateJSONTemplate(blob: JSONBlob, headerTemplate: JSONTemplate, bodyTemplate?: JSONTemplate, depsBlob?: JSONBlob[]) { - let header = generateHeader(blob, headerTemplate, depsBlob); - let body = bodyTemplate ? generateBody(blob, bodyTemplate, depsBlob) : ''; +type GenerateJSONOptions = { + add_atom_prefix?: boolean; +}; + +export function generateJSONTemplate(blob: JSONBlob, headerTemplate: JSONTemplate, bodyTemplate?: JSONTemplate, depsBlob?: JSONBlob[], options: GenerateJSONOptions = {}) { + let header = generateHeader(blob, headerTemplate, depsBlob, options); + let body = bodyTemplate ? generateBody(blob, bodyTemplate, depsBlob, options) : ''; return { header: header, diff --git a/bridge/scripts/code_generator/templates/json_templates/make_names.cc.tpl b/bridge/scripts/code_generator/templates/json_templates/make_names.cc.tpl index 1b43b8b6ce..1e91191c76 100644 --- a/bridge/scripts/code_generator/templates/json_templates/make_names.cc.tpl +++ b/bridge/scripts/code_generator/templates/json_templates/make_names.cc.tpl @@ -32,12 +32,18 @@ const AtomicString& k<%= name %> = reinterpret_cast(&names_storag void Init(JSContext* ctx) { struct NameEntry { - const char* str; + <% if (options.add_atom_prefix) { %> + JSAtom atom; + <% } else { %> + const char* str; + <% } %> }; static const NameEntry kNames[] = { <% _.forEach(data, function(name) { %> - <% if (Array.isArray(name)) { %> + <% if (options.add_atom_prefix) { %> + { JS_ATOM_<%= name %> }, + <% } else if (Array.isArray(name)) { %> { "<%= name[1] %>" }, <% } else if(_.isObject(name)) { %> { "<%= name.name %>" }, @@ -57,7 +63,12 @@ void Init(JSContext* ctx) { for(size_t i = 0; i < std::size(kNames); i ++) { void* address = reinterpret_cast(&names_storage) + i; - new (address) AtomicString(ctx, kNames[i].str); + <% if (options.add_atom_prefix) { %> + new (address) AtomicString(ctx, kNames[i].atom); + <% } else { %> + new (address) AtomicString(ctx, kNames[i].str); + <% } %> + } <% if (deps && deps.html_attribute_names) { %> diff --git a/bridge/third_party/quickjs/include/quickjs/quickjs.h b/bridge/third_party/quickjs/include/quickjs/quickjs.h index 89fdb23ad4..6b4921a1c4 100644 --- a/bridge/third_party/quickjs/include/quickjs/quickjs.h +++ b/bridge/third_party/quickjs/include/quickjs/quickjs.h @@ -32,6 +32,12 @@ extern "C" { #endif +/* define to include Atomics.* operations which depend on the OS + threads */ +#if !defined(EMSCRIPTEN) +#define CONFIG_ATOMICS +#endif + #if defined(__GNUC__) || defined(__clang__) #define js_likely(x) __builtin_expect(!!(x), 1) #define js_unlikely(x) __builtin_expect(!!(x), 0) @@ -188,12 +194,6 @@ static inline JS_BOOL JS_VALUE_IS_NAN(JSValue v) { #else /* !JS_NAN_BOXING */ -/* define to include Atomics.* operations which depend on the OS - threads */ -#if !defined(EMSCRIPTEN) -#define CONFIG_ATOMICS -#endif - typedef union JSValueUnion { int32_t int32; double float64;