summaryrefslogtreecommitdiff
path: root/javascript/duktape/dukky.c
diff options
context:
space:
mode:
authorVincent Sanders <vince@kyllikki.org>2016-06-07 16:01:04 +0100
committerVincent Sanders <vince@kyllikki.org>2016-06-07 16:01:04 +0100
commit042fcb82b83d19bf08afd3367235ac71a60b3850 (patch)
tree47fe3c15f160b3fac7b0e8ab4f47b495901e0557 /javascript/duktape/dukky.c
parent9754539e2275e33af34b5de9d343b85e8122d871 (diff)
downloadnetsurf-042fcb82b83d19bf08afd3367235ac71a60b3850.tar.gz
netsurf-042fcb82b83d19bf08afd3367235ac71a60b3850.tar.bz2
Move javascript content handler as appropriate for updated source format
Diffstat (limited to 'javascript/duktape/dukky.c')
-rw-r--r--javascript/duktape/dukky.c1135
1 files changed, 0 insertions, 1135 deletions
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 <vince@netsurf-browser.org>
- * Copyright 2015 Daniel Dilverstone <dsilvers@netsurf-browser.org>
- * Copyright 2016 Michael Drake <tlsa@netsurf-browser.org>
- * Copyright 2016 John-Mark Bell <jmb@netsurf-browser.org>
- *
- * 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 <http://www.gnu.org/licenses/>.
- */
-
-/** \file
- * Duktapeish implementation of javascript engine functions.
- */
-
-#include <inttypes.h>
-
-#include <nsutils/time.h>
-
-#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 <dom/dom.h>
-
-#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;
-}