From 042fcb82b83d19bf08afd3367235ac71a60b3850 Mon Sep 17 00:00:00 2001 From: Vincent Sanders Date: Tue, 7 Jun 2016 16:01:04 +0100 Subject: Move javascript content handler as appropriate for updated source format --- javascript/duktape/dukky.c | 1135 -------------------------------------------- 1 file changed, 1135 deletions(-) delete mode 100644 javascript/duktape/dukky.c (limited to 'javascript/duktape/dukky.c') diff --git a/javascript/duktape/dukky.c b/javascript/duktape/dukky.c deleted file mode 100644 index 7dd3bd71e..000000000 --- a/javascript/duktape/dukky.c +++ /dev/null @@ -1,1135 +0,0 @@ -/* - * Copyright 2012 Vincent Sanders - * Copyright 2015 Daniel Dilverstone - * Copyright 2016 Michael Drake - * Copyright 2016 John-Mark Bell - * - * This file is part of NetSurf, http://www.netsurf-browser.org/ - * - * NetSurf is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * NetSurf is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -/** \file - * Duktapeish implementation of javascript engine functions. - */ - -#include - -#include - -#include "content/content.h" - -#include "utils/utils.h" -#include "utils/nsoption.h" -#include "utils/log.h" -#include "utils/corestrings.h" - -#include "javascript/js.h" -#include "javascript/content.h" - -#include "duktape/binding.h" - -#include "duktape.h" -#include "dukky.h" - -#include - -#define EVENT_MAGIC MAGIC(EVENT_MAP) -#define HANDLER_LISTENER_MAGIC MAGIC(HANDLER_LISTENER_MAP) -#define HANDLER_MAGIC MAGIC(HANDLER_MAP) - -static duk_ret_t dukky_populate_object(duk_context *ctx) -{ - /* ... obj args protoname nargs */ - int nargs = duk_get_int(ctx, -1); - duk_pop(ctx); - /* ... obj args protoname */ - duk_get_global_string(ctx, PROTO_MAGIC); - /* .. obj args protoname prototab */ - duk_insert(ctx, -2); - /* ... obj args prototab protoname */ - duk_get_prop(ctx, -2); - /* ... obj args prototab {proto/undefined} */ - if (duk_is_undefined(ctx, -1)) { - LOG("RuhRoh, couldn't find a prototype, HTMLUnknownElement it is"); - duk_pop(ctx); - duk_push_string(ctx, PROTO_NAME(HTMLUNKNOWNELEMENT)); - duk_get_prop(ctx, -2); - } - /* ... obj args prototab proto */ - duk_dup(ctx, -1); - /* ... obj args prototab proto proto */ - duk_set_prototype(ctx, -(nargs+4)); - /* ... obj[proto] args prototab proto */ - duk_get_prop_string(ctx, -1, INIT_MAGIC); - /* ... obj[proto] args prototab proto initfn */ - duk_insert(ctx, -(nargs+4)); - /* ... initfn obj[proto] args prototab proto */ - duk_pop_2(ctx); - /* ... initfn obj[proto] args */ - LOG("Call the init function"); - duk_call(ctx, nargs + 1); - return 1; /* The object */ -} - -duk_ret_t dukky_create_object(duk_context *ctx, const char *name, int args) -{ - duk_ret_t ret; - LOG("name=%s nargs=%d", name+2, args); - /* ... args */ - duk_push_object(ctx); - /* ... args obj */ - duk_push_object(ctx); - /* ... args obj handlers */ - duk_put_prop_string(ctx, -2, HANDLER_LISTENER_MAGIC); - /* ... args obj */ - duk_push_object(ctx); - /* ... args obj handlers */ - duk_put_prop_string(ctx, -2, HANDLER_MAGIC); - /* ... args obj */ - duk_insert(ctx, -(args+1)); - /* ... obj args */ - duk_push_string(ctx, name); - /* ... obj args name */ - duk_push_int(ctx, args); - /* ... obj args name nargs */ - if ((ret = duk_safe_call(ctx, dukky_populate_object, args + 3, 1)) - != DUK_EXEC_SUCCESS) - return ret; - LOG("created"); - return DUK_EXEC_SUCCESS; -} - - - -duk_bool_t -dukky_push_node_stacked(duk_context *ctx) -{ - int top_at_fail = duk_get_top(ctx) - 2; - /* ... nodeptr klass */ - duk_get_global_string(ctx, NODE_MAGIC); - /* ... nodeptr klass nodes */ - duk_dup(ctx, -3); - /* ... nodeptr klass nodes nodeptr */ - duk_get_prop(ctx, -2); - /* ... nodeptr klass nodes node/undefined */ - if (duk_is_undefined(ctx, -1)) { - /* ... nodeptr klass nodes undefined */ - duk_pop(ctx); - /* ... nodeptr klass nodes */ - duk_push_object(ctx); - /* ... nodeptr klass nodes obj */ - duk_push_object(ctx); - /* ... nodeptr klass nodes obj handlers */ - duk_put_prop_string(ctx, -2, HANDLER_LISTENER_MAGIC); - /* ... nodeptr klass nodes obj */ - duk_push_object(ctx); - /* ... nodeptr klass nodes obj handlers */ - duk_put_prop_string(ctx, -2, HANDLER_MAGIC); - /* ... nodeptr klass nodes obj */ - duk_dup(ctx, -4); - /* ... nodeptr klass nodes obj nodeptr */ - duk_dup(ctx, -4); - /* ... nodeptr klass nodes obj nodeptr klass */ - duk_push_int(ctx, 1); - /* ... nodeptr klass nodes obj nodeptr klass 1 */ - if (duk_safe_call(ctx, dukky_populate_object, 4, 1) - != DUK_EXEC_SUCCESS) { - duk_set_top(ctx, top_at_fail); - LOG("Boo and also hiss"); - return false; - } - /* ... nodeptr klass nodes node */ - duk_dup(ctx, -4); - /* ... nodeptr klass nodes node nodeptr */ - duk_dup(ctx, -2); - /* ... nodeptr klass nodes node nodeptr node */ - duk_put_prop(ctx, -4); - /* ... nodeptr klass nodes node */ - } - /* ... nodeptr klass nodes node */ - duk_insert(ctx, -4); - /* ... node nodeptr klass nodes */ - duk_pop_3(ctx); - /* ... node */ - return true; -} - -#define SET_HTML_CLASS(CLASS) \ - *html_class = PROTO_NAME(HTML##CLASS##ELEMENT); \ - *html_class_len = \ - SLEN(PROTO_NAME(HTML)) + \ - SLEN(#CLASS) + \ - SLEN("ELEMENT"); - -static void dukky_html_element_class_from_tag_type(dom_html_element_type type, - const char **html_class, size_t *html_class_len) -{ - switch(type) { - case DOM_HTML_ELEMENT_TYPE_HTML: - SET_HTML_CLASS(HTML) - break; - case DOM_HTML_ELEMENT_TYPE_HEAD: - SET_HTML_CLASS(HEAD) - break; - case DOM_HTML_ELEMENT_TYPE_META: - SET_HTML_CLASS(META) - break; - case DOM_HTML_ELEMENT_TYPE_BASE: - SET_HTML_CLASS(BASE) - break; - case DOM_HTML_ELEMENT_TYPE_TITLE: - SET_HTML_CLASS(TITLE) - break; - case DOM_HTML_ELEMENT_TYPE_BODY: - SET_HTML_CLASS(BODY) - break; - case DOM_HTML_ELEMENT_TYPE_DIV: - SET_HTML_CLASS(DIV) - break; - case DOM_HTML_ELEMENT_TYPE_FORM: - SET_HTML_CLASS(FORM) - break; - case DOM_HTML_ELEMENT_TYPE_LINK: - SET_HTML_CLASS(LINK) - break; - case DOM_HTML_ELEMENT_TYPE_BUTTON: - SET_HTML_CLASS(BUTTOM) - break; - case DOM_HTML_ELEMENT_TYPE_INPUT: - SET_HTML_CLASS(INPUT) - break; - case DOM_HTML_ELEMENT_TYPE_TEXTAREA: - SET_HTML_CLASS(TEXTAREA) - break; - case DOM_HTML_ELEMENT_TYPE_OPTGROUP: - SET_HTML_CLASS(OPTGROUP) - break; - case DOM_HTML_ELEMENT_TYPE_OPTION: - SET_HTML_CLASS(OPTION) - break; - case DOM_HTML_ELEMENT_TYPE_SELECT: - SET_HTML_CLASS(SELECT) - break; - case DOM_HTML_ELEMENT_TYPE_HR: - SET_HTML_CLASS(HR) - break; - case DOM_HTML_ELEMENT_TYPE_DL: - SET_HTML_CLASS(DLIST) - break; - case DOM_HTML_ELEMENT_TYPE_DIR: - SET_HTML_CLASS(DIRECTORY) - break; - case DOM_HTML_ELEMENT_TYPE_MENU: - SET_HTML_CLASS(MENU) - break; - case DOM_HTML_ELEMENT_TYPE_FIELDSET: - SET_HTML_CLASS(FIELDSET) - break; - case DOM_HTML_ELEMENT_TYPE_LEGEND: - SET_HTML_CLASS(LEGEND) - break; - case DOM_HTML_ELEMENT_TYPE_P: - SET_HTML_CLASS(PARAGRAPH) - break; - case DOM_HTML_ELEMENT_TYPE_H1: - case DOM_HTML_ELEMENT_TYPE_H2: - case DOM_HTML_ELEMENT_TYPE_H3: - case DOM_HTML_ELEMENT_TYPE_H4: - case DOM_HTML_ELEMENT_TYPE_H5: - case DOM_HTML_ELEMENT_TYPE_H6: - SET_HTML_CLASS(HEADING) - break; - case DOM_HTML_ELEMENT_TYPE_BLOCKQUOTE: - case DOM_HTML_ELEMENT_TYPE_Q: - SET_HTML_CLASS(QUOTE) - break; - case DOM_HTML_ELEMENT_TYPE_PRE: - SET_HTML_CLASS(PRE) - break; - case DOM_HTML_ELEMENT_TYPE_BR: - SET_HTML_CLASS(BR) - break; - case DOM_HTML_ELEMENT_TYPE_LABEL: - SET_HTML_CLASS(LABEL) - break; - case DOM_HTML_ELEMENT_TYPE_UL: - SET_HTML_CLASS(ULIST) - break; - case DOM_HTML_ELEMENT_TYPE_OL: - SET_HTML_CLASS(OLIST) - break; - case DOM_HTML_ELEMENT_TYPE_LI: - SET_HTML_CLASS(LI) - break; - case DOM_HTML_ELEMENT_TYPE_FONT: - SET_HTML_CLASS(FONT) - break; - case DOM_HTML_ELEMENT_TYPE_DEL: - case DOM_HTML_ELEMENT_TYPE_INS: - SET_HTML_CLASS(MOD) - break; - case DOM_HTML_ELEMENT_TYPE_A: - SET_HTML_CLASS(ANCHOR) - break; - case DOM_HTML_ELEMENT_TYPE_BASEFONT: - SET_HTML_CLASS(BASEFONT) - break; - case DOM_HTML_ELEMENT_TYPE_IMG: - SET_HTML_CLASS(IMAGE) - break; - case DOM_HTML_ELEMENT_TYPE_OBJECT: - SET_HTML_CLASS(OBJECT) - break; - case DOM_HTML_ELEMENT_TYPE_PARAM: - SET_HTML_CLASS(PARAM) - break; - case DOM_HTML_ELEMENT_TYPE_APPLET: - SET_HTML_CLASS(APPLET) - break; - case DOM_HTML_ELEMENT_TYPE_MAP: - SET_HTML_CLASS(MAP) - break; - case DOM_HTML_ELEMENT_TYPE_AREA: - SET_HTML_CLASS(AREA) - break; - case DOM_HTML_ELEMENT_TYPE_SCRIPT: - SET_HTML_CLASS(SCRIPT) - break; - case DOM_HTML_ELEMENT_TYPE_CAPTION: - SET_HTML_CLASS(TABLECAPTION) - break; - case DOM_HTML_ELEMENT_TYPE_TD: - case DOM_HTML_ELEMENT_TYPE_TH: - SET_HTML_CLASS(TABLECELL) - break; - case DOM_HTML_ELEMENT_TYPE_COL: - case DOM_HTML_ELEMENT_TYPE_COLGROUP: - SET_HTML_CLASS(TABLECOL) - break; - case DOM_HTML_ELEMENT_TYPE_THEAD: - case DOM_HTML_ELEMENT_TYPE_TBODY: - case DOM_HTML_ELEMENT_TYPE_TFOOT: - SET_HTML_CLASS(TABLESECTION) - break; - case DOM_HTML_ELEMENT_TYPE_TABLE: - SET_HTML_CLASS(TABLE) - break; - case DOM_HTML_ELEMENT_TYPE_TR: - SET_HTML_CLASS(TABLEROW) - break; - case DOM_HTML_ELEMENT_TYPE_STYLE: - SET_HTML_CLASS(STYLE) - break; - case DOM_HTML_ELEMENT_TYPE_FRAMESET: - SET_HTML_CLASS(FRAMESET) - break; - case DOM_HTML_ELEMENT_TYPE_FRAME: - SET_HTML_CLASS(FRAME) - break; - case DOM_HTML_ELEMENT_TYPE_IFRAME: - SET_HTML_CLASS(IFRAME) - break; - case DOM_HTML_ELEMENT_TYPE_ISINDEX: - SET_HTML_CLASS(ISINDEX) - break; - case DOM_HTML_ELEMENT_TYPE__COUNT: - assert(type != DOM_HTML_ELEMENT_TYPE__COUNT); - /* fallthrough */ - case DOM_HTML_ELEMENT_TYPE__UNKNOWN: - SET_HTML_CLASS(UNKNOWN) - break; - default: - /* Known HTML element without a specialisation */ - *html_class = PROTO_NAME(HTMLELEMENT); - *html_class_len = - SLEN(PROTO_NAME(HTML)) + - SLEN("ELEMENT"); - break; - } - return; -} - -#undef SET_HTML_CLASS - -static void -dukky_push_node_klass(duk_context *ctx, struct dom_node *node) -{ - dom_node_type nodetype; - dom_exception err; - - err = dom_node_get_node_type(node, &nodetype); - if (err != DOM_NO_ERR) { - /* Oh bum, just node then */ - duk_push_string(ctx, PROTO_NAME(NODE)); - return; - } - - switch(nodetype) { - case DOM_ELEMENT_NODE: { - dom_string *namespace; - dom_html_element_type type; - const char *html_class; - size_t html_class_len; - err = dom_node_get_namespace(node, &namespace); - if (err != DOM_NO_ERR) { - /* Feck it, element */ - LOG("dom_node_get_namespace() failed"); - duk_push_string(ctx, PROTO_NAME(ELEMENT)); - break; - } - if (namespace == NULL) { - /* No namespace, -> element */ - LOG("no namespace"); - duk_push_string(ctx, PROTO_NAME(ELEMENT)); - break; - } - - if (dom_string_isequal(namespace, corestring_dom_html_namespace) == false) { - /* definitely not an HTML element of some kind */ - duk_push_string(ctx, PROTO_NAME(ELEMENT)); - dom_string_unref(namespace); - break; - } - dom_string_unref(namespace); - - err = dom_html_element_get_tag_type(node, &type); - if (err != DOM_NO_ERR) { - type = DOM_HTML_ELEMENT_TYPE__UNKNOWN; - } - - dukky_html_element_class_from_tag_type(type, - &html_class, &html_class_len); - - duk_push_lstring(ctx, html_class, html_class_len); - break; - } - case DOM_TEXT_NODE: - duk_push_string(ctx, PROTO_NAME(TEXT)); - break; - case DOM_COMMENT_NODE: - duk_push_string(ctx, PROTO_NAME(COMMENT)); - break; - case DOM_DOCUMENT_NODE: - duk_push_string(ctx, PROTO_NAME(DOCUMENT)); - break; - case DOM_ATTRIBUTE_NODE: - case DOM_PROCESSING_INSTRUCTION_NODE: - case DOM_DOCUMENT_TYPE_NODE: - case DOM_DOCUMENT_FRAGMENT_NODE: - case DOM_NOTATION_NODE: - case DOM_ENTITY_REFERENCE_NODE: - case DOM_ENTITY_NODE: - case DOM_CDATA_SECTION_NODE: - default: - /* Oh bum, just node then */ - duk_push_string(ctx, PROTO_NAME(NODE)); - } -} - -duk_bool_t -dukky_push_node(duk_context *ctx, struct dom_node *node) -{ - JS_LOG("Pushing node %p", node); - /* First check if we can find the node */ - /* ... */ - duk_get_global_string(ctx, NODE_MAGIC); - /* ... nodes */ - duk_push_pointer(ctx, node); - /* ... nodes nodeptr */ - duk_get_prop(ctx, -2); - /* ... nodes node/undefined */ - if (!duk_is_undefined(ctx, -1)) { - /* ... nodes node */ - duk_insert(ctx, -2); - /* ... node nodes */ - duk_pop(ctx); - /* ... node */ - JS_LOG("Found it memoised"); - return true; - } - /* ... nodes undefined */ - duk_pop_2(ctx); - /* ... */ - /* We couldn't, so now we determine the node type and then - * we ask for it to be created - */ - duk_push_pointer(ctx, node); - /* ... nodeptr */ - dukky_push_node_klass(ctx, node); - /* ... nodeptr klass */ - return dukky_push_node_stacked(ctx); -} - -static duk_ret_t -dukky_bad_constructor(duk_context *ctx) -{ - duk_error(ctx, DUK_ERR_ERROR, "Bad constructor"); - return 0; -} - -void -dukky_inject_not_ctr(duk_context *ctx, int idx, const char *name) -{ - /* ... p[idx] ... proto */ - duk_push_c_function(ctx, dukky_bad_constructor, 0); - /* ... p[idx] ... proto cons */ - duk_insert(ctx, -2); - /* ... p[idx] ... cons proto */ - duk_put_prop_string(ctx, -2, "prototype"); - /* ... p[idx] ... cons[proto] */ - duk_put_prop_string(ctx, idx, name); - /* ... p ... */ - return; -} - -/* Duktape heap utility functions */ - -/* We need to override the defaults because not all platforms are fully ANSI - * compatible. E.g. RISC OS gets upset if we malloc or realloc a zero byte - * block, as do debugging tools such as Electric Fence by Bruce Perens. - */ - -static void *dukky_alloc_function(void *udata, duk_size_t size) -{ - if (size == 0) - return NULL; - - return malloc(size); -} - -static void *dukky_realloc_function(void *udata, void *ptr, duk_size_t size) -{ - if (ptr == NULL && size == 0) - return NULL; - - if (size == 0) { - free(ptr); - return NULL; - } - - return realloc(ptr, size); -} - -static void dukky_free_function(void *udata, void *ptr) -{ - if (ptr != NULL) - free(ptr); -} - - -/**************************************** js.h ******************************/ -struct jscontext { - duk_context *ctx; - duk_context *thread; - uint64_t exec_start_time; -}; - -#define CTX (ctx->thread) - -void js_initialise(void) -{ - /** TODO: Forces JS on for our testing, needs changing before a release - * lest we incur the wrath of others. - */ - /* Disabled force-on for forthcoming release */ - /* nsoption_set_bool(enable_javascript, true); - */ - javascript_init(); -} - -void js_finalise(void) -{ - /* NADA for now */ -} - -#define DUKKY_NEW_PROTOTYPE(klass, uklass, klass_name) \ - dukky_create_prototype(ctx, dukky_##klass##___proto, PROTO_NAME(uklass), klass_name) - -nserror js_newcontext(int timeout, jscallback *cb, void *cbctx, - jscontext **jsctx) -{ - duk_context *ctx; - jscontext *ret = calloc(1, sizeof(*ret)); - *jsctx = NULL; - LOG("Creating new duktape javascript context"); - if (ret == NULL) return NSERROR_NOMEM; - ctx = ret->ctx = duk_create_heap( - dukky_alloc_function, - dukky_realloc_function, - dukky_free_function, - ret, - NULL); - if (ret->ctx == NULL) { free(ret); return NSERROR_NOMEM; } - /* Create the prototype stuffs */ - duk_push_global_object(ctx); - duk_push_boolean(ctx, true); - duk_put_prop_string(ctx, -2, "protos"); - duk_put_global_string(ctx, PROTO_MAGIC); - /* Create prototypes here */ - dukky_create_prototypes(ctx); - - *jsctx = ret; - return NSERROR_OK; -} - -void js_destroycontext(jscontext *ctx) -{ - LOG("Destroying duktape javascript context"); - duk_destroy_heap(ctx->ctx); - free(ctx); -} - -jsobject *js_newcompartment(jscontext *ctx, void *win_priv, void *doc_priv) -{ - assert(ctx != NULL); - /* Pop any active thread off */ - LOG("Yay, new compartment, win_priv=%p, doc_priv=%p", win_priv, doc_priv); - duk_set_top(ctx->ctx, 0); - duk_push_thread(ctx->ctx); - ctx->thread = duk_require_context(ctx->ctx, -1); - duk_push_int(CTX, 0); - duk_push_int(CTX, 1); - duk_push_int(CTX, 2); - /* Manufacture a Window object */ - /* win_priv is a browser_window, doc_priv is an html content struct */ - duk_push_pointer(CTX, win_priv); - duk_push_pointer(CTX, doc_priv); - dukky_create_object(CTX, PROTO_NAME(WINDOW), 2); - duk_push_global_object(CTX); - duk_put_prop_string(CTX, -2, PROTO_MAGIC); - duk_set_global_object(CTX); - - /* Now we need to prepare our node mapping table */ - duk_push_object(CTX); - duk_push_pointer(CTX, NULL); - duk_push_null(CTX); - duk_put_prop(CTX, -3); - duk_put_global_string(CTX, NODE_MAGIC); - - /* And now the event mapping table */ - duk_push_object(CTX); - duk_put_global_string(CTX, EVENT_MAGIC); - - return (jsobject *)ctx; -} - -static duk_ret_t eval_top_string(duk_context *ctx) -{ - duk_eval(ctx); - return 0; -} - -duk_bool_t dukky_check_timeout(void *udata) -{ -#define JS_EXEC_TIMEOUT_MS 10000 /* 10 seconds */ - jscontext *ctx = (jscontext *) udata; - uint64_t now; - - (void) nsu_getmonotonic_ms(&now); - - /* This function may be called during duk heap construction, - * so only test for execution timeout if we've recorded a - * start time. - */ - return ctx->exec_start_time != 0 && - now > (ctx->exec_start_time + JS_EXEC_TIMEOUT_MS); -} - -bool js_exec(jscontext *ctx, const char *txt, size_t txtlen) -{ - assert(ctx); - if (txt == NULL || txtlen == 0) return false; - duk_set_top(CTX, 0); - duk_push_lstring(CTX, txt, txtlen); - - (void) nsu_getmonotonic_ms(&ctx->exec_start_time); - if (duk_safe_call(CTX, eval_top_string, 1, 1) == DUK_EXEC_ERROR) { - duk_get_prop_string(CTX, 0, "name"); - duk_get_prop_string(CTX, 0, "message"); - duk_get_prop_string(CTX, 0, "fileName"); - duk_get_prop_string(CTX, 0, "lineNumber"); - duk_get_prop_string(CTX, 0, "stack"); - LOG("Uncaught error in JS: %s: %s", duk_safe_to_string(CTX, 1), - duk_safe_to_string(CTX, 2)); - LOG(" was at: %s line %s", duk_safe_to_string(CTX, 3), - duk_safe_to_string(CTX, 4)); - LOG(" Stack trace: %s", duk_safe_to_string(CTX, 5)); - return false; - } - if (duk_get_top(CTX) == 0) duk_push_boolean(CTX, false); - LOG("Returning %s", duk_get_boolean(CTX, 0) ? "true" : "false"); - return duk_get_boolean(CTX, 0); -} - -/*** New style event handling ***/ - -static void dukky_push_event(duk_context *ctx, dom_event *evt) -{ - /* ... */ - duk_get_global_string(ctx, EVENT_MAGIC); - /* ... events */ - duk_push_pointer(ctx, evt); - /* ... events eventptr */ - duk_get_prop(ctx, -2); - /* ... events event? */ - if (duk_is_undefined(ctx, -1)) { - /* ... events undefined */ - duk_pop(ctx); - /* ... events */ - duk_push_pointer(ctx, evt); - if (dukky_create_object(ctx, PROTO_NAME(EVENT), 1) != DUK_EXEC_SUCCESS) { - /* ... events err */ - duk_pop(ctx); - /* ... events */ - duk_push_object(ctx); - /* ... events eobj[meh] */ - } - /* ... events eobj */ - duk_push_pointer(ctx, evt); - /* ... events eobj eventptr */ - duk_dup(ctx, -2); - /* ... events eobj eventptr eobj */ - duk_put_prop(ctx, -4); - /* ... events eobj */ - } - /* ... events event */ - duk_replace(ctx, -2); - /* ... event */ -} - -static void dukky_push_handler_code_(duk_context *ctx, dom_string *name, - dom_event_target *et) -{ - dom_string *onname, *val; - dom_element *ele = (dom_element *)et; - dom_exception exc; - dom_node_type ntype; - - /* Currently safe since libdom has no event targets which are not - * nodes. Reconsider this as and when we work out how to have - * window do stuff - */ - exc = dom_node_get_node_type(et, &ntype); - if (exc != DOM_NO_ERR) { - duk_push_lstring(ctx, "", 0); - return; - } - - if (ntype != DOM_ELEMENT_NODE) { - duk_push_lstring(ctx, "", 0); - return; - } - - exc = dom_string_concat(corestring_dom_on, name, &onname); - if (exc != DOM_NO_ERR) { - duk_push_lstring(ctx, "", 0); - return; - } - - exc = dom_element_get_attribute(ele, onname, &val); - if ((exc != DOM_NO_ERR) || (val == NULL)) { - dom_string_unref(onname); - duk_push_lstring(ctx, "", 0); - return; - } - - dom_string_unref(onname); - duk_push_lstring(ctx, dom_string_data(val), dom_string_length(val)); - dom_string_unref(val); -} - -bool dukky_get_current_value_of_event_handler(duk_context *ctx, - dom_string *name, - dom_event_target *et) -{ - /* Must be entered as: - * ... node(et) - */ - duk_get_prop_string(ctx, -1, HANDLER_MAGIC); - /* ... node handlers */ - duk_push_lstring(ctx, dom_string_data(name), dom_string_length(name)); - /* ... node handlers name */ - duk_get_prop(ctx, -2); - /* ... node handlers handler? */ - if (duk_is_undefined(ctx, -1)) { - /* ... node handlers undefined */ - duk_pop_2(ctx); - /* ... node */ - dukky_push_handler_code_(ctx, name, et); - /* ... node handlercode? */ - /* TODO: If this is null, clean up and propagate */ - /* ... node handlercode */ - /** @todo This is entirely wrong, but it's hard to get right */ - duk_push_string(ctx, "function (event) {"); - /* ... node handlercode prefix */ - duk_insert(ctx, -2); - /* ... node prefix handlercode */ - duk_push_string(ctx, "}"); - /* ... node prefix handlercode suffix */ - duk_concat(ctx, 3); - /* ... node fullhandlersrc */ - duk_push_string(ctx, "internal raw uncompiled handler"); - /* ... node fullhandlersrc filename */ - if (duk_pcompile(ctx, DUK_COMPILE_FUNCTION) != 0) { - /* ... node err */ - LOG("Unable to proceed with handler, could not compile"); - duk_pop_2(ctx); - return false; - } - /* ... node handler */ - duk_insert(ctx, -2); - /* ... handler node */ - } else { - /* ... node handlers handler */ - duk_insert(ctx, -3); - /* ... handler node handlers */ - duk_pop(ctx); - /* ... handler node */ - } - /* ... handler node */ - return true; -} - -static void dukky_generic_event_handler(dom_event *evt, void *pw) -{ - duk_memory_functions funcs; - duk_context *ctx = (duk_context *)pw; - jscontext *jsctx; - dom_string *name; - dom_exception exc; - dom_event_target *targ; - dom_event_flow_phase phase; - - /* Retrieve the JS context from the Duktape context */ - duk_get_memory_functions(ctx, &funcs); - jsctx = funcs.udata; - - LOG("WOOP WOOP, An event:"); - exc = dom_event_get_type(evt, &name); - if (exc != DOM_NO_ERR) { - LOG("Unable to find the event name"); - return; - } - LOG("Event's name is %*s", - dom_string_length(name), dom_string_data(name)); - exc = dom_event_get_event_phase(evt, &phase); - if (exc != DOM_NO_ERR) { - LOG("Unable to get event phase"); - return; - } - LOG("Event phase is: %s (%d)", - phase == DOM_CAPTURING_PHASE ? "capturing" : - phase == DOM_AT_TARGET ? "at-target" : - phase == DOM_BUBBLING_PHASE ? "bubbling" : - "unknown", (int)phase); - - exc = dom_event_get_current_target(evt, &targ); - if (exc != DOM_NO_ERR) { - dom_string_unref(name); - LOG("Unable to find the event target"); - return; - } - - /* ... */ - if (dukky_push_node(ctx, (dom_node *)targ) == false) { - dom_string_unref(name); - dom_node_unref(targ); - LOG("Unable to push JS node representation?!"); - return; - } - /* ... node */ - if (dukky_get_current_value_of_event_handler( - ctx, name, (dom_event_target *)targ) == false) { - dom_node_unref(targ); - dom_string_unref(name); - return; - } - /** @todo handle other kinds of event than the generic case */ - dom_node_unref(targ); - dom_string_unref(name); - /* ... handler node */ - dukky_push_event(ctx, evt); - /* ... handler node event */ - (void) nsu_getmonotonic_ms(&jsctx->exec_start_time); - if (duk_pcall_method(ctx, 1) != 0) { - /* Failed to run the method */ - /* ... err */ - LOG("OH NOES! An error running a callback. Meh."); - exc = dom_event_stop_immediate_propagation(evt); - if (exc != DOM_NO_ERR) - LOG("WORSE! could not stop propagation"); - duk_get_prop_string(ctx, -1, "name"); - duk_get_prop_string(ctx, -2, "message"); - duk_get_prop_string(ctx, -3, "fileName"); - duk_get_prop_string(ctx, -4, "lineNumber"); - duk_get_prop_string(ctx, -5, "stack"); - /* ... err name message fileName lineNumber stack */ - LOG("Uncaught error in JS: %s: %s", duk_safe_to_string(ctx, -5), - duk_safe_to_string(ctx, -4)); - LOG(" was at: %s line %s", duk_safe_to_string(ctx, -3), - duk_safe_to_string(ctx, -2)); - LOG(" Stack trace: %s", duk_safe_to_string(ctx, -1)); - - duk_pop_n(ctx, 6); - /* ... */ - return; - } - /* ... result */ - if (duk_is_boolean(ctx, -1) && - duk_to_boolean(ctx, -1) == 0) { - dom_event_prevent_default(evt); - } - duk_pop(ctx); - /* ... */ -} - -void dukky_register_event_listener_for(duk_context *ctx, - struct dom_element *ele, - dom_string *name) -{ - dom_event_listener *listen = NULL; - dom_exception exc; - - /* ... */ - if (dukky_push_node(ctx, (struct dom_node *)ele) == false) - return; - /* ... node */ - duk_get_prop_string(ctx, -1, HANDLER_LISTENER_MAGIC); - /* ... node handlers */ - duk_push_lstring(ctx, dom_string_data(name), dom_string_length(name)); - /* ... node handlers name */ - if (duk_has_prop(ctx, -2)) { - /* ... node handlers */ - duk_pop_2(ctx); - /* ... */ - return; - } - /* ... node handlers */ - duk_push_lstring(ctx, dom_string_data(name), dom_string_length(name)); - /* ... node handlers name */ - duk_push_boolean(ctx, true); - /* ... node handlers name true */ - duk_put_prop(ctx, -3); - /* ... node handlers */ - duk_pop_2(ctx); - /* ... */ - exc = dom_event_listener_create(dukky_generic_event_handler, ctx, - &listen); - if (exc != DOM_NO_ERR) return; - exc = dom_event_target_add_event_listener( - ele, name, listen, false); - if (exc != DOM_NO_ERR) { - LOG("Unable to register listener for %p.%*s", - ele, dom_string_length(name), dom_string_data(name)); - } else { - LOG("have registered listener for %p.%*s", - ele, dom_string_length(name), dom_string_data(name)); - } - dom_event_listener_unref(listen); -} - - -void js_handle_new_element(jscontext *ctx, struct dom_element *node) -{ - assert(ctx); - assert(node); - dom_namednodemap *map; - dom_exception exc; - dom_ulong idx; - dom_ulong siz; - dom_attr *attr = NULL; - dom_string *key = NULL; - dom_string *nodename; - duk_bool_t is_body = false; - - exc = dom_node_get_node_name(node, &nodename); - if (exc != DOM_NO_ERR) return; - - if (nodename == corestring_dom_BODY) - is_body = true; - - dom_string_unref(nodename); - - exc = dom_node_get_attributes(node, &map); - if (exc != DOM_NO_ERR) return; - if (map == NULL) return; - - exc = dom_namednodemap_get_length(map, &siz); - if (exc != DOM_NO_ERR) goto out; - - for (idx = 0; idx < siz; idx++) { - exc = dom_namednodemap_item(map, idx, &attr); - if (exc != DOM_NO_ERR) goto out; - exc = dom_attr_get_name(attr, &key); - if (exc != DOM_NO_ERR) goto out; - if (is_body && ( - key == corestring_dom_onblur || - key == corestring_dom_onerror || - key == corestring_dom_onfocus || - key == corestring_dom_onload || - key == corestring_dom_onresize || - key == corestring_dom_onscroll)) { - /* This is a forwarded event, it doesn't matter, - * we should skip registering for it and later - * we will register it for Window itself - */ - goto skip_register; - } - if (dom_string_length(key) > 2) { - /* Can be on* */ - const uint8_t *data = (const uint8_t *)dom_string_data(key); - if (data[0] == 'o' && data[1] == 'n') { - dom_string *sub = NULL; - exc = dom_string_substr( - key, 2, dom_string_length(key), - &sub); - if (exc == DOM_NO_ERR) { - dukky_register_event_listener_for( - CTX, node, sub); - dom_string_unref(sub); - } - } - } - skip_register: - dom_string_unref(key); key = NULL; - dom_node_unref(attr); attr = NULL; - } - -out: - if (key != NULL) - dom_string_unref(key); - - if (attr != NULL) - dom_node_unref(attr); - - dom_namednodemap_unref(map); -} - -void js_event_cleanup(jscontext *ctx, struct dom_event *evt) -{ - assert(ctx); - /* ... */ - duk_get_global_string(CTX, EVENT_MAGIC); - /* ... EVENT_MAP */ - duk_push_pointer(CTX, evt); - /* ... EVENT_MAP eventptr */ - duk_del_prop(CTX, -2); - /* ... EVENT_MAP */ - duk_pop(CTX); - /* ... */ -} - -bool js_fire_event(jscontext *ctx, const char *type, struct dom_document *doc, struct dom_node *target) -{ - dom_exception exc; - dom_event *evt; - dom_event_target *body; - - LOG("Event: %s (doc=%p, target=%p)", type, doc, target); - - /** @todo Make this more generic, this only handles load and only - * targetting the window, so that we actually stand a chance of - * getting 3.4 out. - */ - - if (target != NULL) - /* Swallow non-Window-targetted events quietly */ - return true; - - if (strcmp(type, "load") != 0) - /* Swallow non-load events quietly */ - return true; - - /* Okay, we're processing load, targetted at Window, do the single - * thing which gets us there, which is to find the appropriate event - * handler and call it. If we have no event handler on Window then - * we divert to the body, and if there's no event handler there - * we swallow the event silently - */ - - exc = dom_event_create(&evt); - if (exc != DOM_NO_ERR) return true; - exc = dom_event_init(evt, corestring_dom_load, false, false); - if (exc != DOM_NO_ERR) { - dom_event_unref(evt); - return true; - } - /* ... */ - duk_get_global_string(CTX, HANDLER_MAGIC); - /* ... handlers */ - duk_push_lstring(CTX, "load", 4); - /* ... handlers "load" */ - duk_get_prop(CTX, -2); - /* ... handlers handler? */ - if (duk_is_undefined(CTX, -1)) { - /* No handler here, *try* and retrieve a handler from - * the body - */ - duk_pop(CTX); - /* ... handlers */ - exc = dom_html_document_get_body(doc, &body); - if (exc != DOM_NO_ERR) { - dom_event_unref(evt); - return true; - } - dukky_push_node(CTX, (struct dom_node *)body); - /* ... handlers bodynode */ - if (dukky_get_current_value_of_event_handler( - CTX, corestring_dom_load, body) == false) { - /* ... handlers */ - duk_pop(CTX); - return true; - } - /* ... handlers handler bodynode */ - duk_pop(CTX); - } - /* ... handlers handler */ - duk_insert(CTX, -2); - /* ... handler handlers */ - duk_pop(CTX); - /* ... handler */ - duk_push_global_object(CTX); - /* ... handler Window */ - dukky_push_event(CTX, evt); - /* ... handler Window event */ - (void) nsu_getmonotonic_ms(&ctx->exec_start_time); - if (duk_pcall_method(CTX, 1) != 0) { - /* Failed to run the handler */ - /* ... err */ - LOG("OH NOES! An error running a handler. Meh."); - duk_get_prop_string(CTX, -1, "name"); - duk_get_prop_string(CTX, -2, "message"); - duk_get_prop_string(CTX, -3, "fileName"); - duk_get_prop_string(CTX, -4, "lineNumber"); - duk_get_prop_string(CTX, -5, "stack"); - /* ... err name message fileName lineNumber stack */ - LOG("Uncaught error in JS: %s: %s", duk_safe_to_string(CTX, -5), - duk_safe_to_string(CTX, -4)); - LOG(" was at: %s line %s", duk_safe_to_string(CTX, -3), - duk_safe_to_string(CTX, -2)); - LOG(" Stack trace: %s", duk_safe_to_string(CTX, -1)); - - duk_pop_n(CTX, 6); - /* ... */ - js_event_cleanup(ctx, evt); - dom_event_unref(evt); - return true; - } - /* ... result */ - duk_pop(CTX); - /* ... */ - js_event_cleanup(ctx, evt); - dom_event_unref(evt); - return true; -} -- cgit v1.2.3