From 6dfc0f1486e50ff6a3bb74164cc5e0af6b012deb Mon Sep 17 00:00:00 2001 From: Daniel Silverstone Date: Sat, 4 May 2019 23:06:14 +0100 Subject: Support nodelist indexing Signed-off-by: Daniel Silverstone --- content/handlers/javascript/duktape/Document.bnd | 11 +++++++- content/handlers/javascript/duktape/Element.bnd | 9 ++++++ content/handlers/javascript/duktape/Makefile | 8 +++++- content/handlers/javascript/duktape/Node.bnd | 8 ++++++ content/handlers/javascript/duktape/dukky.c | 36 +++++++++++++++++++++++- content/handlers/javascript/duktape/generics.js | 30 ++++++++++++++++++++ 6 files changed, 99 insertions(+), 3 deletions(-) create mode 100644 content/handlers/javascript/duktape/generics.js diff --git a/content/handlers/javascript/duktape/Document.bnd b/content/handlers/javascript/duktape/Document.bnd index cc8a3a9c1..d27591759 100644 --- a/content/handlers/javascript/duktape/Document.bnd +++ b/content/handlers/javascript/duktape/Document.bnd @@ -18,6 +18,7 @@ prologue Document() #include "content/urldb.h" #define HANDLER_MAGIC MAGIC(HANDLER_MAP) +#define LIST_PROXY_MAGIC MAGIC(LIST_PROXY) %} @@ -344,10 +345,18 @@ method Document::getElementsByTagName() if (nodes == NULL) return 0; /* coerced to undefined */ + duk_get_global_string(ctx, LIST_PROXY_MAGIC); + duk_push_pointer(ctx, nodes); dukky_create_object(ctx, PROTO_NAME(NODELIST), 1); dom_nodelist_unref(nodes); - return 1; + + if (dukky_pcall(ctx, 1, false) != 0) { + NSLOG(dukky, DEBUG, "Unable to construct nodelist?"); + return 0; /* coerced to undefined */ + } + + return 1; /* The Proxy(NodeList) wrapper */ %} getter Document::cookie() diff --git a/content/handlers/javascript/duktape/Element.bnd b/content/handlers/javascript/duktape/Element.bnd index f7e33545f..5e36a5090 100644 --- a/content/handlers/javascript/duktape/Element.bnd +++ b/content/handlers/javascript/duktape/Element.bnd @@ -11,6 +11,7 @@ class Element { prologue %{ #include +#define LIST_PROXY_MAGIC MAGIC(LIST_PROXY) %}; }; @@ -204,10 +205,18 @@ method Element::getElementsByTagName () tagname, &nlist); dom_string_unref(tagname); if (exc != DOM_NO_ERR) return 0; + + duk_get_global_string(ctx, LIST_PROXY_MAGIC); + duk_push_pointer(ctx, nlist); dukky_create_object(ctx, PROTO_NAME(NODELIST), 1); dom_nodelist_unref(nlist); + if (dukky_pcall(ctx, 1, false) != 0) { + NSLOG(dukky, DEBUG, "Unable to construct nodelist?"); + return 0; /* coerced to undefined */ + } + return 1; %} diff --git a/content/handlers/javascript/duktape/Makefile b/content/handlers/javascript/duktape/Makefile index e24a12a2e..c9e9947dd 100644 --- a/content/handlers/javascript/duktape/Makefile +++ b/content/handlers/javascript/duktape/Makefile @@ -4,10 +4,16 @@ # Included by javascript/Makefile # -content/handlers/javascript/duktape/dukky.c: $(OBJROOT)/duktape/binding.h +content/handlers/javascript/duktape/dukky.c: $(OBJROOT)/duktape/binding.h $(OBJROOT)/duktape/generics.js.inc BINDINGS := $(wildcard content/handlers/javascript/duktape/*.bnd) +# Generator for the C include representing the generics.js +$(OBJROOT)/duktape/generics.js.inc: content/handlers/javascript/duktape/generics.js + $(Q)$(MKDIR) -p $(OBJROOT)/duktape + $(VQ)echo " XXD: $<" + $(Q)xxd -i $< | sed -e 's/content_handlers_javascript_duktape_generics_js/generics_js/' > $@ + # ensure genbind generates debugging files GBFLAGS+=-D diff --git a/content/handlers/javascript/duktape/Node.bnd b/content/handlers/javascript/duktape/Node.bnd index fe24b3f11..4140d3335 100644 --- a/content/handlers/javascript/duktape/Node.bnd +++ b/content/handlers/javascript/duktape/Node.bnd @@ -10,6 +10,9 @@ class Node { private dom_node *node; + prologue %{ +#define LIST_PROXY_MAGIC MAGIC(LIST_PROXY) +%} }; init Node(struct dom_node *node) @@ -117,12 +120,17 @@ getter Node::childNodes() duk_pop(ctx); exc = dom_node_get_child_nodes(priv->node, &nlist); if (exc != DOM_NO_ERR) return 0; + duk_get_global_string(ctx, LIST_PROXY_MAGIC); duk_push_pointer(ctx, nlist); if (dukky_create_object(ctx, PROTO_NAME(NODELIST), 1) != DUK_EXEC_SUCCESS) { dom_nodelist_unref(nlist); return 0; } dom_nodelist_unref(nlist); + if (dukky_pcall(ctx, 1, false) != 0) { + NSLOG(dukky, DEBUG, "Unable to construct nodelist?"); + return 0; /* coerced to undefined */ + } duk_dup(ctx, -1); duk_put_prop_string(ctx, 0, MAGIC(childNodes)); } diff --git a/content/handlers/javascript/duktape/dukky.c b/content/handlers/javascript/duktape/dukky.c index 8fa011ebc..68eca81d5 100644 --- a/content/handlers/javascript/duktape/dukky.c +++ b/content/handlers/javascript/duktape/dukky.c @@ -37,6 +37,7 @@ #include "javascript/content.h" #include "duktape/binding.h" +#include "duktape/generics.js.inc" #include "duktape.h" #include "dukky.h" @@ -47,6 +48,7 @@ #define HANDLER_LISTENER_MAGIC MAGIC(HANDLER_LISTENER_MAP) #define HANDLER_MAGIC MAGIC(HANDLER_MAP) #define EVENT_LISTENER_JS_MAGIC MAGIC(EVENT_LISTENER_JS_MAP) +#define LIST_PROXY_MAGIC MAGIC(LIST_PROXY) static duk_ret_t dukky_populate_object(duk_context *ctx, void *udata) { @@ -635,6 +637,38 @@ jsobject *js_newcompartment(jscontext *ctx, void *win_priv, void *doc_priv) duk_push_object(CTX); duk_put_global_string(CTX, EVENT_MAGIC); + /* Now load the NetSurf table in */ + /* ... */ + duk_push_string(CTX, "generics.js"); + /* ..., generics.js */ + if (duk_pcompile_lstring_filename(CTX, DUK_COMPILE_EVAL, + (const char *)generics_js, generics_js_len) != 0) { + NSLOG(dukky, CRITICAL, "%s", duk_safe_to_string(CTX, -1)); + NSLOG(dukky, CRITICAL, "Unable to compile generics.js, compartment aborted"); + return NULL; + } + /* ..., (generics.js) */ + if (dukky_pcall(CTX, 0, true) != 0) { + NSLOG(dukky, CRITICAL, "Unable to run generics.js, compartment aborted"); + return NULL; + } + /* ..., result */ + duk_pop(CTX); + /* ... */ + duk_push_global_object(CTX); + /* ..., Win */ + duk_get_prop_string(CTX, -1, "NetSurf"); + /* ..., Win, NetSurf */ + duk_get_prop_string(CTX, -1, "makeListProxy"); + /* ..., Win, NetSurf, MLP */ + duk_put_global_string(CTX, LIST_PROXY_MAGIC); + /* ..., Win, NetSurf */ + duk_pop(CTX); + /* ..., Win */ + duk_del_prop_string(CTX, -1, "NetSurf"); + duk_pop(CTX); + /* ... */ + return (jsobject *)ctx; } @@ -722,7 +756,7 @@ bool js_exec(jscontext *ctx, const char *txt, size_t txtlen, const char *name) if (txt == NULL || txtlen == 0) return false; duk_set_top(CTX, 0); NSLOG(dukky, DEEPDEBUG, "Running %zd bytes from %s", txtlen, name); - NSLOG(dukky, DEEPDEBUG, "\n%s\n", txt); + /* NSLOG(dukky, DEEPDEBUG, "\n%s\n", txt); */ (void) nsu_getmonotonic_ms(&ctx->exec_start_time); if (name != NULL) { diff --git a/content/handlers/javascript/duktape/generics.js b/content/handlers/javascript/duktape/generics.js new file mode 100644 index 000000000..ee5e8013b --- /dev/null +++ b/content/handlers/javascript/duktape/generics.js @@ -0,0 +1,30 @@ +/* + * Generics for Duktape binding in NetSurf + * + * The result of this *MUST* be setting a NetSurf object only. + * + * That object will then be absorbed into the global object as a hidden + * object which is used by the rest of the bindings. + */ + +var NetSurf = { + /* The make-proxy call for list-type objects */ + makeListProxy: function(inner) { + return new Proxy(inner, { + has: function(target, key) { + if (typeof key == 'number') { + return (key >= 0) && (key < target.length); + } else { + return key in target; + } + }, + get: function(target, key) { + if (typeof key == 'number') { + return target.item(key); + } else { + return target[key]; + } + }, + }); + }, +}; -- cgit v1.2.3