summaryrefslogtreecommitdiff
path: root/javascript
diff options
context:
space:
mode:
authorDaniel Silverstone <dsilvers@digital-scurf.org>2015-08-09 12:26:28 +0100
committerDaniel Silverstone <dsilvers@digital-scurf.org>2015-08-09 12:26:28 +0100
commit37b118d966598301fc57a6d7cb63312013069934 (patch)
tree4b3273499b6b2fd53d5726442e289e25253713b8 /javascript
parentad82c49a80ac8096a7e9c368b3759b48cf126285 (diff)
downloadnetsurf-37b118d966598301fc57a6d7cb63312013069934.tar.gz
netsurf-37b118d966598301fc57a6d7cb63312013069934.tar.bz2
Add duktape binding support code
Diffstat (limited to 'javascript')
-rw-r--r--javascript/dukky.c356
-rw-r--r--javascript/dukky.h11
2 files changed, 367 insertions, 0 deletions
diff --git a/javascript/dukky.c b/javascript/dukky.c
new file mode 100644
index 000000000..8f69d23c8
--- /dev/null
+++ b/javascript/dukky.c
@@ -0,0 +1,356 @@
+/*
+ * Copyright 2012 Vincent Sanders <vince@netsurf-browser.org>
+ * Copyright 2015 All of us.
+ *
+ * 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 "content/content.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/duktape.h"
+#include "dukky.h"
+
+#include <dom/dom.h>
+
+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_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_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;
+}
+
+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, *tag;
+ 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_node_get_node_name(node, &tag);
+ if (err != DOM_NO_ERR) {
+ duk_push_string(ctx, PROTO_NAME(HTMLUNKNOWNELEMENT));
+ break;
+ }
+
+ duk_push_string(ctx, PROTO_NAME(HTML));
+ duk_push_lstring(ctx, dom_string_data(tag), dom_string_length(tag));
+ dom_string_unref(tag);
+ duk_push_string(ctx, "ELEMENT");
+ duk_concat(ctx, 3);
+
+ 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)
+{
+ 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 */
+ 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);
+}
+
+
+
+/**************************************** js.h ******************************/
+struct jscontext {
+ duk_context *ctx;
+ duk_context *thread;
+};
+
+#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.
+ */
+ 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)
+
+jscontext *js_newcontext(int timeout, jscallback *cb, void *cbctx)
+{
+ duk_context *ctx;
+ jscontext *ret = calloc(1, sizeof(*ret));
+ LOG("Creating new duktape javascript context");
+ if (ret == NULL) return NULL;
+ ctx = ret->ctx = duk_create_heap_default();
+ if (ret->ctx == NULL) { free(ret); return NULL; }
+ /* 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);
+
+ return ret;
+}
+
+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)
+{
+ /* 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_put_global_string(CTX, NODE_MAGIC);
+
+ return (jsobject *)ctx;
+}
+
+static duk_ret_t eval_top_string(duk_context *ctx)
+{
+ duk_eval(ctx);
+ return 0;
+}
+
+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);
+
+ if (duk_safe_call(CTX, eval_top_string, 1, 1) == DUK_EXEC_ERROR) {
+ LOG("JAVASCRIPT WENT BANG: %s", duk_safe_to_string(CTX, 0));
+ 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);
+}
+
+bool js_fire_event(jscontext *ctx, const char *type, struct dom_document *doc, struct dom_node *target)
+{
+ /* La La La */
+ LOG("Oh dear, an event: %s", type);
+ return true;
+}
diff --git a/javascript/dukky.h b/javascript/dukky.h
new file mode 100644
index 000000000..c5aceaf10
--- /dev/null
+++ b/javascript/dukky.h
@@ -0,0 +1,11 @@
+/* DO NOT USE, DODGY BIT FOR VINCE */
+
+#ifndef DUKKY_H
+#define DUKKY_H
+
+duk_ret_t dukky_create_object(duk_context *ctx, const char *name, int args);
+duk_bool_t dukky_push_node_stacked(duk_context *ctx);
+duk_bool_t dukky_push_node(duk_context *ctx, struct dom_node *node);
+
+
+#endif