From def8f0570d05b3a0c5acf67b802b5dd066096e9e Mon Sep 17 00:00:00 2001 From: Witold Filipczyk Date: Sat, 1 Apr 2023 10:36:19 +0200 Subject: [PATCH] [quickjs] forms.c --- src/ecmascript/libdom/quickjs/Makefile | 2 +- src/ecmascript/libdom/quickjs/forms.c | 283 ++++++++++++++++++++++ src/ecmascript/libdom/quickjs/mapa.cpp | 16 ++ src/ecmascript/libdom/quickjs/mapa.h | 2 + src/ecmascript/libdom/quickjs/meson.build | 2 +- src/ecmascript/quickjs/form.h | 8 + src/ecmascript/quickjs/forms.cpp | 3 + src/ecmascript/quickjs/forms.h | 8 +- 8 files changed, 321 insertions(+), 3 deletions(-) create mode 100644 src/ecmascript/libdom/quickjs/forms.c diff --git a/src/ecmascript/libdom/quickjs/Makefile b/src/ecmascript/libdom/quickjs/Makefile index 769196dc..9e5dd7b5 100644 --- a/src/ecmascript/libdom/quickjs/Makefile +++ b/src/ecmascript/libdom/quickjs/Makefile @@ -1,6 +1,6 @@ top_builddir=../../../.. include $(top_builddir)/Makefile.config -OBJS = attr.o attributes.o collection.o console.o heartbeat.o history.o input.o keyboard.o localstorage.o location.o mapa.obj message.o navigator.o nodelist.o screen.o unibar.o window.o xhr.o +OBJS = attr.o attributes.o collection.o console.o forms.o heartbeat.o history.o input.o keyboard.o localstorage.o location.o mapa.obj message.o navigator.o nodelist.o screen.o unibar.o window.o xhr.o include $(top_srcdir)/Makefile.lib diff --git a/src/ecmascript/libdom/quickjs/forms.c b/src/ecmascript/libdom/quickjs/forms.c new file mode 100644 index 00000000..c11b675a --- /dev/null +++ b/src/ecmascript/libdom/quickjs/forms.c @@ -0,0 +1,283 @@ +/* The QuickJS object forms. */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include + +#include "elinks.h" + +#include "document/document.h" +#include "document/forms.h" +#include "document/view.h" +#include "ecmascript/ecmascript.h" +#include "ecmascript/libdom/quickjs/mapa.h" +#include "ecmascript/quickjs.h" +#include "ecmascript/quickjs/document.h" +#include "ecmascript/quickjs/form.h" +#include "ecmascript/quickjs/forms.h" +#include "ecmascript/quickjs/input.h" +#include "ecmascript/quickjs/window.h" +#include "viewer/text/form.h" +#include "viewer/text/vs.h" + +#define countof(x) (sizeof(x) / sizeof((x)[0])) + +void *map_forms; +void *map_rev_forms; + +static void +forms_SetOpaque(JSValueConst this_val, void *node) +{ + REF_JS(this_val); + + if (!node) { + attr_erase_from_map_rev(map_rev_forms, this_val); + } else { + attr_save_in_map_rev(map_rev_forms, this_val, node); + } +} + +/* Find the form whose name is @name, which should normally be a + * string (but might not be). */ +static JSValue +js_find_form_by_name(JSContext *ctx, + struct document_view *doc_view, + const char *string) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + struct form *form; + + if (!*string) + return JS_NULL; + + foreach (form, doc_view->document->forms) { + if (form->name && !c_strcasecmp(string, form->name)) { + return js_get_form_object(ctx, JS_NULL, form); + } + } + + return JS_NULL; +} + +static void +js_forms_set_items(JSContext *ctx, JSValueConst this_val, void *node) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + REF_JS(this_val); + + struct view_state *vs; + struct document_view *doc_view; + + struct ecmascript_interpreter *interpreter = (struct ecmascript_interpreter *)JS_GetContextOpaque(ctx); + vs = interpreter->vs; + doc_view = vs->doc_view; + struct document *document = doc_view->document; + int counter = 0; + struct form_view *fv; + + foreach (fv, vs->forms) { + struct form *form = find_form_by_form_view(document, fv); + JSValue v = js_get_form_object(ctx, JS_NULL, form); + + REF_JS(v); + + JS_SetPropertyUint32(ctx, this_val, counter, JS_DupValue(ctx, v)); + + if (form->name) { + if (strcmp(form->name, "item") && strcmp(form->name, "namedItem")) { + JS_SetPropertyStr(ctx, this_val, form->name, JS_DupValue(ctx, v)); + } + } + JS_FreeValue(ctx, v); + counter++; + } +} + +static JSValue +js_forms_get_property_length(JSContext *ctx, JSValueConst this_val) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + REF_JS(this_val); + + struct ecmascript_interpreter *interpreter = (struct ecmascript_interpreter *)JS_GetContextOpaque(ctx); + struct view_state *vs = interpreter->vs; + + if (!vs) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return JS_UNDEFINED; + } + struct document_view *doc_view = vs->doc_view; + struct document *document = doc_view->document; + + return JS_NewInt32(ctx, list_size(&document->forms)); +} + +static JSValue +js_forms_item2(JSContext *ctx, JSValueConst this_val, int index) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + REF_JS(this_val); + + struct view_state *vs; + struct form_view *fv; + int counter = -1; + + struct ecmascript_interpreter *interpreter = (struct ecmascript_interpreter *)JS_GetContextOpaque(ctx); + + vs = interpreter->vs; + struct document_view *doc_view = vs->doc_view; + struct document *document = doc_view->document; + + foreach (fv, vs->forms) { + counter++; + if (counter == index) { + struct form *form = find_form_by_form_view(document, fv); + + return js_get_form_object(ctx, JS_NULL, form); + } + } + + return JS_UNDEFINED; +} + +/* @forms_funcs{"item"} */ +static JSValue +js_forms_item(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + REF_JS(this_val); + + if (argc != 1) { + return JS_UNDEFINED; + } + int index; + + if (JS_ToInt32(ctx, &index, argv[0])) { + return JS_UNDEFINED; + } + + return js_forms_item2(ctx, this_val, index); +} + +/* @forms_funcs{"namedItem"} */ +static JSValue +js_forms_namedItem(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + REF_JS(this_val); + + if (argc != 1) { + return JS_UNDEFINED; + } + + struct ecmascript_interpreter *interpreter = (struct ecmascript_interpreter *)JS_GetContextOpaque(ctx); + struct view_state *vs = interpreter->vs; + struct document_view *doc_view = vs->doc_view; + const char *str; + size_t len; + str = JS_ToCStringLen(ctx, &len, argv[0]); + + if (!str) { + return JS_EXCEPTION; + } + JSValue ret = js_find_form_by_name(ctx, doc_view, str); + JS_FreeCString(ctx, str); + + RETURN_JS(ret); +} + +#if 0 +JSString * +unicode_to_jsstring(JSContext *ctx, unicode_val_T u) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + char16_t buf[2]; + + /* This is supposed to make a string from which + * jsval_to_accesskey() can get the original @u back. + * If @u is a surrogate, then that is not possible, so + * return NULL to indicate an error instead. + * + * If JS_NewUCStringCopyN hits a null character, it truncates + * the string there and pads it with more nulls. However, + * that is not a problem here, because if there is a null + * character in buf[], then it must be the only character. */ + if (u <= 0xFFFF && !is_utf16_surrogate(u)) { + buf[0] = u; + return JS_NewUCStringCopyN(ctx, buf, 1); + } else if (needs_utf16_surrogates(u)) { + buf[0] = get_utf16_high_surrogate(u); + buf[1] = get_utf16_low_surrogate(u); + return JS_NewUCStringCopyN(ctx, buf, 2); + } else { + return NULL; + } +} +#endif + +static JSValue +js_forms_toString(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + REF_JS(this_val); + + return JS_NewString(ctx, "[forms object]"); +} + +static const JSCFunctionListEntry js_forms_proto_funcs[] = { + JS_CGETSET_DEF("length", js_forms_get_property_length, NULL), + JS_CFUNC_DEF("item", 1, js_forms_item), + JS_CFUNC_DEF("namedItem", 1, js_forms_namedItem), + JS_CFUNC_DEF("toString", 0, js_forms_toString) +}; + +JSValue +getForms(JSContext *ctx, void *node) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + JSValue second; + static int initialized; + if (!initialized) { + map_forms = attr_create_new_forms_map(); + map_rev_forms = attr_create_new_forms_map_rev(); + initialized = 1; + } + second = attr_find_in_map(map_forms, node); + + if (!JS_IsNull(second)) { + JSValue r = JS_DupValue(ctx, second); + RETURN_JS(r); + } + JSValue forms_obj = JS_NewArray(ctx); + JS_SetPropertyFunctionList(ctx, forms_obj, js_forms_proto_funcs, countof(js_forms_proto_funcs)); + forms_SetOpaque(forms_obj, node); + js_forms_set_items(ctx, forms_obj, node); + attr_save_in_map(map_forms, node, forms_obj); + + JSValue rr = JS_DupValue(ctx, forms_obj); + RETURN_JS(rr); +} diff --git a/src/ecmascript/libdom/quickjs/mapa.cpp b/src/ecmascript/libdom/quickjs/mapa.cpp index bc9fc6fc..3c0a3989 100644 --- a/src/ecmascript/libdom/quickjs/mapa.cpp +++ b/src/ecmascript/libdom/quickjs/mapa.cpp @@ -56,6 +56,22 @@ attr_create_new_collections_map(void) return (void *)mapa; } +void * +attr_create_new_forms_map(void) +{ + std::map *mapa = new std::map; + + return (void *)mapa; +} + +void * +attr_create_new_forms_map_rev(void) +{ + std::map *mapa = new std::map; + + return (void *)mapa; +} + void * attr_create_new_input_map(void) { diff --git a/src/ecmascript/libdom/quickjs/mapa.h b/src/ecmascript/libdom/quickjs/mapa.h index 3b5c2a5e..fa428bc9 100644 --- a/src/ecmascript/libdom/quickjs/mapa.h +++ b/src/ecmascript/libdom/quickjs/mapa.h @@ -15,6 +15,8 @@ void *attr_create_new_attributes_map(void); void *attr_create_new_attributes_map_rev(void); void *attr_create_new_collections_map(void); void *attr_create_new_collections_map_rev(void); +void *attr_create_new_forms_map(void); +void *attr_create_new_forms_map_rev(void); void *attr_create_new_input_map(void); void *attr_create_new_nodelist_map(void); void *attr_create_new_nodelist_map_rev(void); diff --git a/src/ecmascript/libdom/quickjs/meson.build b/src/ecmascript/libdom/quickjs/meson.build index 5cb09912..9e0a9559 100644 --- a/src/ecmascript/libdom/quickjs/meson.build +++ b/src/ecmascript/libdom/quickjs/meson.build @@ -1,2 +1,2 @@ -srcs += files('attr.c', 'attributes.c', 'collection.c', 'console.c', 'heartbeat.c', 'history.c', 'input.c', 'keyboard.c', 'localstorage.c', 'location.c', +srcs += files('attr.c', 'attributes.c', 'collection.c', 'console.c', 'forms.c', 'heartbeat.c', 'history.c', 'input.c', 'keyboard.c', 'localstorage.c', 'location.c', 'mapa.cpp', 'message.c', 'navigator.c', 'nodelist.c', 'screen.c', 'unibar.c', 'window.c', 'xhr.c') diff --git a/src/ecmascript/quickjs/form.h b/src/ecmascript/quickjs/form.h index 97fc9e0a..c65ee873 100644 --- a/src/ecmascript/quickjs/form.h +++ b/src/ecmascript/quickjs/form.h @@ -3,8 +3,16 @@ #include +#ifdef __cplusplus +extern "C" { +#endif + struct form; JSValue js_get_form_object(JSContext *ctx, JSValueConst jsdoc, struct form *form); +#ifdef __cplusplus +} +#endif + #endif diff --git a/src/ecmascript/quickjs/forms.cpp b/src/ecmascript/quickjs/forms.cpp index 6a672abb..24646f35 100644 --- a/src/ecmascript/quickjs/forms.cpp +++ b/src/ecmascript/quickjs/forms.cpp @@ -49,6 +49,8 @@ #include #include +#ifndef CONFIG_LIBDOM + #define countof(x) (sizeof(x) / sizeof((x)[0])) static std::map map_forms; @@ -355,3 +357,4 @@ getForms(JSContext *ctx, void *node) JSValue rr = JS_DupValue(ctx, forms_obj); RETURN_JS(rr); } +#endif diff --git a/src/ecmascript/quickjs/forms.h b/src/ecmascript/quickjs/forms.h index 2101952b..498b7d34 100644 --- a/src/ecmascript/quickjs/forms.h +++ b/src/ecmascript/quickjs/forms.h @@ -3,11 +3,17 @@ #include +#ifdef __cplusplus +extern "C" { +#endif + struct form; JSValue js_get_form_object(JSContext *ctx, JSValue jsdoc, struct form *form); JSValue getForms(JSContext *ctx, void *node); -//JSString *unicode_to_jsstring(JSContext *ctx, unicode_val_T u); +#ifdef __cplusplus +} +#endif #endif