changeset 371:8ac282bd5935

js: add action bindings
author David Demelier <markand@malikania.fr>
date Mon, 25 Oct 2021 12:43:09 +0200
parents ea7a24c814e4
children 3c378be73844
files src/libmlk-core-js/CMakeLists.txt src/libmlk-core-js/core/js-action-stack.c src/libmlk-core-js/core/js-action-stack.h src/libmlk-core-js/core/js-action.c src/libmlk-core-js/core/js-action.h src/libmlk-core-js/core/js-drawable-stack.c src/libmlk-core-js/core/js-drawable.c src/libmlk-core-js/core/js-event.c src/libmlk-core-js/core/js-event.h src/libmlk-core/core/sys.c src/mlk-run/main.c
diffstat 11 files changed, 464 insertions(+), 12 deletions(-) [+]
line wrap: on
line diff
--- a/src/libmlk-core-js/CMakeLists.txt	Sun Oct 24 17:38:01 2021 +0200
+++ b/src/libmlk-core-js/CMakeLists.txt	Mon Oct 25 12:43:09 2021 +0200
@@ -20,6 +20,10 @@
 
 set(
 	SOURCES
+	${libmlk-core-js_SOURCE_DIR}/core/js-action-stack.c
+	${libmlk-core-js_SOURCE_DIR}/core/js-action-stack.h
+	${libmlk-core-js_SOURCE_DIR}/core/js-action.c
+	${libmlk-core-js_SOURCE_DIR}/core/js-action.h
 	${libmlk-core-js_SOURCE_DIR}/core/js-animation.c
 	${libmlk-core-js_SOURCE_DIR}/core/js-animation.h
 	${libmlk-core-js_SOURCE_DIR}/core/js-clock.c
@@ -28,10 +32,10 @@
 	${libmlk-core-js_SOURCE_DIR}/core/js-color.h
 	${libmlk-core-js_SOURCE_DIR}/core/js-core.c
 	${libmlk-core-js_SOURCE_DIR}/core/js-core.h
+	${libmlk-core-js_SOURCE_DIR}/core/js-drawable-stack.c
+	${libmlk-core-js_SOURCE_DIR}/core/js-drawable-stack.h
 	${libmlk-core-js_SOURCE_DIR}/core/js-drawable.c
 	${libmlk-core-js_SOURCE_DIR}/core/js-drawable.h
-	${libmlk-core-js_SOURCE_DIR}/core/js-drawable-stack.c
-	${libmlk-core-js_SOURCE_DIR}/core/js-drawable-stack.h
 	${libmlk-core-js_SOURCE_DIR}/core/js-event.c
 	${libmlk-core-js_SOURCE_DIR}/core/js-event.h
 	${libmlk-core-js_SOURCE_DIR}/core/js-font.c
@@ -44,8 +48,6 @@
 	${libmlk-core-js_SOURCE_DIR}/core/js-painter.h
 	${libmlk-core-js_SOURCE_DIR}/core/js-panic.c
 	${libmlk-core-js_SOURCE_DIR}/core/js-panic.h
-	${libmlk-core-js_SOURCE_DIR}/core/js-trace.c
-	${libmlk-core-js_SOURCE_DIR}/core/js-trace.h
 	${libmlk-core-js_SOURCE_DIR}/core/js-sound.c
 	${libmlk-core-js_SOURCE_DIR}/core/js-sound.h
 	${libmlk-core-js_SOURCE_DIR}/core/js-sprite.c
@@ -54,6 +56,8 @@
 	${libmlk-core-js_SOURCE_DIR}/core/js-state.h
 	${libmlk-core-js_SOURCE_DIR}/core/js-texture.c
 	${libmlk-core-js_SOURCE_DIR}/core/js-texture.h
+	${libmlk-core-js_SOURCE_DIR}/core/js-trace.c
+	${libmlk-core-js_SOURCE_DIR}/core/js-trace.h
 	${libmlk-core-js_SOURCE_DIR}/core/js-window.c
 	${libmlk-core-js_SOURCE_DIR}/core/js-window.h
 )
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/libmlk-core-js/core/js-action-stack.c	Mon Oct 25 12:43:09 2021 +0200
@@ -0,0 +1,143 @@
+/*
+ * js-drawable-stack.h -- core drawable_stack binding
+ *
+ * Copyright (c) 2020-2021 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <assert.h>
+
+#include <core/action.h>
+#include <core/action-stack.h>
+#include <core/alloc.h>
+
+#include "js-event.h"
+#include "js-action-stack.h"
+#include "js-action.h"
+
+#define SIGNATURE DUK_HIDDEN_SYMBOL("Mlk.ActionStack")
+
+static inline struct action_stack *
+self(duk_context *ctx)
+{
+	struct action_stack *sf = NULL;
+
+	duk_push_this(ctx);
+	duk_get_prop_string(ctx, -1, SIGNATURE);
+	sf = duk_to_pointer(ctx, -1);
+	duk_pop_2(ctx);
+
+	if (!sf)
+		return (void)duk_error(ctx, DUK_ERR_TYPE_ERROR, "not a ActionStack object"), NULL;
+
+	return sf;
+}
+
+static duk_ret_t
+ActionStack_constructor(duk_context *ctx)
+{
+	duk_push_this(ctx);
+	duk_push_pointer(ctx, alloc_new0(sizeof (struct action_stack)));
+	duk_put_prop_string(ctx, -2, SIGNATURE);
+	duk_pop(ctx);
+
+	return 0;
+}
+
+static duk_ret_t
+ActionStack_destructor(duk_context *ctx)
+{
+	struct action_stack *st;
+
+	duk_get_prop_string(ctx, 0, SIGNATURE);
+
+	if ((st = duk_to_pointer(ctx, -1))) {
+		action_stack_finish(st);
+		free(st);
+	}
+
+	duk_pop(ctx);
+	duk_del_prop_string(ctx, 0, SIGNATURE);
+
+	return 0;
+}
+
+static duk_ret_t
+ActionStack_add(duk_context *ctx)
+{
+	struct action_stack *st = self(ctx);
+	struct js_action *act = js_action_require(ctx, 0);
+
+	if (action_stack_add(st, &act->act) < 0)
+		action_finish(&act->act);
+	else {
+		duk_push_this(ctx);
+		act->parent = duk_get_heapptr(ctx, -1);
+		duk_push_sprintf(ctx, "%p", act);
+		duk_dup(ctx, 0);
+		duk_put_prop(ctx, -3);
+		duk_pop(ctx);
+	}
+
+	return 0;
+}
+
+static duk_ret_t
+ActionStack_handle(duk_context *ctx)
+{
+	action_stack_handle(self(ctx), js_event_require(ctx, 0));
+
+	return 0;
+}
+
+static duk_ret_t
+ActionStack_update(duk_context *ctx)
+{
+	struct action_stack *st = self(ctx);
+	const unsigned int ticks = duk_require_uint(ctx, 0);
+
+	duk_push_uint(ctx, action_stack_update(st, ticks));
+
+	return 1;
+}
+
+static duk_ret_t
+ActionStack_draw(duk_context *ctx)
+{
+	action_stack_draw(self(ctx));
+
+	return 0;
+}
+
+static duk_function_list_entry methods[] = {
+	{ "add",        ActionStack_add,        1       },
+	{ "handle",     ActionStack_handle,     1       },
+	{ "update",     ActionStack_update,     1       },
+	{ "draw",       ActionStack_draw,       0       },
+	{ NULL,         NULL,                   0       }
+};
+
+void
+js_action_stack_bind(duk_context *ctx)
+{
+	assert(ctx);
+
+	duk_push_c_function(ctx, ActionStack_constructor, 0);
+	duk_push_object(ctx);
+	duk_put_function_list(ctx, -1, methods);
+	duk_push_c_function(ctx, ActionStack_destructor, 1);
+	duk_set_finalizer(ctx, -2);
+	duk_put_prop_string(ctx, -2, "prototype");
+	duk_put_global_string(ctx, "ActionStack");
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/libmlk-core-js/core/js-action-stack.h	Mon Oct 25 12:43:09 2021 +0200
@@ -0,0 +1,27 @@
+/*
+ * js-action-stack.h -- core action_stack binding
+ *
+ * Copyright (c) 2020-2021 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef MLK_CORE_JS_ACTION_STACK_H
+#define MLK_CORE_JS_ACTION_STACK_H
+
+#include <duktape.h>
+
+void
+js_action_stack_bind(duk_context *);
+
+#endif /* !MLK_CORE_JS_ACTION_STACK_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/libmlk-core-js/core/js-action.c	Mon Oct 25 12:43:09 2021 +0200
@@ -0,0 +1,193 @@
+/*
+ * js-action.c -- core action binding
+ *
+ * Copyright (c) 2020-2021 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <assert.h>
+#include <stdlib.h>
+
+#include <core/alloc.h>
+#include <core/action.h>
+
+#include "js-action.h"
+#include "js-event.h"
+
+#define SIGNATURE DUK_HIDDEN_SYMBOL("Mlk.Action")
+
+static inline duk_context *
+callable(struct js_action *data, const char *prop)
+{
+	duk_context *ctx;
+
+	if (!data->ptr)
+		return NULL;
+
+	duk_push_heapptr(data->ctx, data->ptr);
+	duk_get_prop_string(data->ctx, -1, prop);
+	duk_pull(data->ctx, -2);
+
+	if (duk_is_callable(data->ctx, -2))
+		ctx = data->ctx;
+	else {
+		ctx = NULL;
+		duk_pop_n(data->ctx, 2);
+	}
+
+	return ctx;
+}
+
+static void
+handle(struct action *data, const union event *ev)
+{
+	duk_context *ctx;
+
+	if ((ctx = callable(data->data, "handle"))) {
+		js_event_push(ctx, ev);
+		duk_call_method(ctx, 1);
+		duk_pop(ctx);
+	}
+}
+
+static int
+update(struct action *data, unsigned int ticks)
+{
+	duk_context *ctx;
+	int ret = 0;
+
+	if ((ctx = callable(data->data, "update"))) {
+		duk_push_uint(ctx, ticks);
+		duk_call_method(ctx, 1);
+		ret = duk_to_int(ctx, -1);
+		duk_pop(ctx);
+	}
+
+	return ret;
+}
+
+static void
+draw(struct action *data)
+{
+	duk_context *ctx;
+
+	if ((ctx = callable(data->data, "draw"))) {
+		duk_call_method(ctx, 0);
+		duk_pop(ctx);
+	}
+}
+
+static void
+end(struct action *data)
+{
+	duk_context *ctx;
+
+	if ((ctx = callable(data->data, "end"))) {
+		duk_call_method(ctx, 0);
+		duk_pop(ctx);
+	}
+}
+
+static void
+finish(struct action *act)
+{
+	struct js_action *data = act->data;
+
+	/* I must not be called anymore. */
+	data->ptr = NULL;
+
+	/* Remove myself from parent stack if any. */
+	if (data->parent) {
+		duk_push_heapptr(data->ctx, data->parent);
+		duk_push_sprintf(data->ctx, "%p", data);
+		duk_del_prop(data->ctx, -2);
+		duk_pop(data->ctx);
+		data->parent = NULL;
+	}
+
+	if (--data->refc == 0)
+		free(data);
+}
+
+static duk_ret_t
+Action_constructor(duk_context *ctx)
+{
+	struct js_action *data;
+
+	data = alloc_new0(sizeof (*data));
+	data->ctx = ctx;
+	data->refc = 1;
+	data->act.data = data;
+	data->act.handle = handle;
+	data->act.update = update;
+	data->act.finish = finish;
+	data->act.draw = draw;
+	data->act.end = end;
+
+	duk_push_this(ctx);
+	data->ptr = duk_get_heapptr(ctx, -1);
+	duk_push_pointer(ctx, data);
+	duk_put_prop_string(ctx, -2, SIGNATURE);
+	duk_pop(ctx);
+
+	return 0;
+}
+
+static duk_ret_t
+Action_destructor(duk_context *ctx)
+{
+	struct js_action *data;
+
+	duk_get_prop_string(ctx, 0, SIGNATURE);
+
+	if ((data = duk_to_pointer(ctx, -1)))
+		action_finish(&data->act);
+
+	duk_del_prop_string(ctx, 0, SIGNATURE);
+	duk_pop(ctx);
+
+	return 0;
+}
+
+void
+js_action_bind(duk_context *ctx)
+{
+	assert(ctx);
+
+	duk_push_c_function(ctx, Action_constructor, 0);
+	duk_push_object(ctx);
+	duk_push_c_function(ctx, Action_destructor, 1);
+	duk_set_finalizer(ctx, -2);
+	duk_put_prop_string(ctx, -2, "prototype");
+	duk_put_global_string(ctx, "Action");
+}
+
+struct js_action *
+js_action_require(duk_context *ctx, duk_idx_t idx)
+{
+	struct js_action *act = NULL;
+
+	if (duk_is_object(ctx, idx)) {
+		duk_get_prop_string(ctx, idx, SIGNATURE);
+		act = duk_to_pointer(ctx, -1);
+		duk_pop(ctx);
+	}
+
+	if (!act)
+		return (void)duk_error(ctx, DUK_ERR_TYPE_ERROR, "not a Action object"), NULL;
+
+	act->refc++;
+
+	return act;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/libmlk-core-js/core/js-action.h	Mon Oct 25 12:43:09 2021 +0200
@@ -0,0 +1,40 @@
+/*
+ * js-action.h -- core action binding
+ *
+ * Copyright (c) 2020-2021 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef MLK_CORE_JS_ACTION_H
+#define MLK_CORE_JS_ACTION_H
+
+#include <duktape.h>
+
+#include <core/action.h>
+
+struct js_action {
+	duk_context *ctx;
+	void *ptr;
+	void *parent;
+	unsigned int refc;
+	struct action act;
+};
+
+void
+js_action_bind(duk_context *);
+
+struct js_action *
+js_action_require(duk_context *, duk_idx_t);
+
+#endif /* !MLK_CORE_JS_ACTION_H */
--- a/src/libmlk-core-js/core/js-drawable-stack.c	Sun Oct 24 17:38:01 2021 +0200
+++ b/src/libmlk-core-js/core/js-drawable-stack.c	Mon Oct 25 12:43:09 2021 +0200
@@ -38,7 +38,7 @@
 	duk_pop_2(ctx);
 
 	if (!sf)
-		duk_error(ctx, DUK_ERR_TYPE_ERROR, "not a DrawableStack object");
+		return (void)duk_error(ctx, DUK_ERR_TYPE_ERROR, "not a DrawableStack object"), NULL;
 
 	return sf;
 }
@@ -60,12 +60,12 @@
 	struct drawable_stack *st;
 
 	duk_get_prop_string(ctx, 0, SIGNATURE);
-	
+
 	if ((st = duk_to_pointer(ctx, -1))) {
 		drawable_stack_finish(st);
 		free(st);
 	}
-		
+
 	duk_pop(ctx);
 	duk_del_prop_string(ctx, 0, SIGNATURE);
 
--- a/src/libmlk-core-js/core/js-drawable.c	Sun Oct 24 17:38:01 2021 +0200
+++ b/src/libmlk-core-js/core/js-drawable.c	Mon Oct 25 12:43:09 2021 +0200
@@ -43,7 +43,7 @@
 	duk_pop_2(ctx);
 
 	if (!sf)
-		duk_error(ctx, DUK_ERR_TYPE_ERROR, "not a Drawable object");
+		return (void)duk_error(ctx, DUK_ERR_TYPE_ERROR, "not a Drawable object"), NULL;
 
 	return sf;
 }
@@ -225,7 +225,7 @@
 	}
 
 	if (!sf)
-		duk_error(ctx, DUK_ERR_TYPE_ERROR, "not a Drawable object");
+		return (void)duk_error(ctx, DUK_ERR_TYPE_ERROR, "not a Drawable object"), NULL;
 
 	sf->refc++;
 
--- a/src/libmlk-core-js/core/js-event.c	Sun Oct 24 17:38:01 2021 +0200
+++ b/src/libmlk-core-js/core/js-event.c	Mon Oct 25 12:43:09 2021 +0200
@@ -18,10 +18,13 @@
 
 #include <assert.h>
 
+#include <core/alloc.h>
 #include <core/event.h>
 
 #include "js-event.h"
 
+#define SIGNATURE DUK_HIDDEN_SYMBOL("Mlk.Event")
+
 static void
 push_click(duk_context *ctx, const union event *ev)
 {
@@ -262,6 +265,17 @@
 	{ NULL,                 0                       }
 };
 
+static duk_ret_t
+Event_destructor(duk_context *ctx)
+{
+	duk_get_prop_string(ctx, 0, SIGNATURE);
+	free(duk_to_pointer(ctx, -1));
+	duk_del_prop_string(ctx, 0, SIGNATURE);
+	duk_pop(ctx);
+
+	return 0;
+}
+
 void
 js_event_bind(duk_context *ctx)
 {
@@ -272,7 +286,7 @@
 	duk_put_function_list(ctx, -1, functions);
 	duk_push_object(ctx);
 	duk_put_number_list(ctx, -1, types);
-	duk_put_prop_string(ctx, -2, "type");
+	duk_put_prop_string(ctx, -2, "Type");
 	duk_push_object(ctx);
 	duk_put_number_list(ctx, -1, keys);
 	duk_put_prop_string(ctx, -2, "key");
@@ -289,8 +303,33 @@
 void
 js_event_push(duk_context *ctx, const union event *ev)
 {
+	assert(ctx);
+
 	duk_push_object(ctx);
+	duk_push_c_function(ctx, Event_destructor, 1);
+	duk_set_finalizer(ctx, -2);
+	duk_push_pointer(ctx, alloc_dup(ev, sizeof (*ev)));
+	duk_put_prop_string(ctx, -2, SIGNATURE);
 	duk_push_int(ctx, ev->type);
-	duk_put_prop_string(ctx, -2, "Type");
+	duk_put_prop_string(ctx, -2, "type");
 	push[ev->type](ctx, ev);
 }
+
+union event *
+js_event_require(duk_context *ctx, duk_idx_t idx)
+{
+	assert(ctx);
+
+	union event *ev = NULL;
+
+	if (duk_is_object(ctx, idx)) {
+		duk_get_prop_string(ctx, idx, SIGNATURE);
+		ev = duk_to_pointer(ctx, -1);
+		duk_pop(ctx);
+	}
+
+	if (!ev)
+		return (void)duk_error(ctx, DUK_ERR_TYPE_ERROR, "not an Event object"), NULL;
+
+	return ev;
+}
--- a/src/libmlk-core-js/core/js-event.h	Sun Oct 24 17:38:01 2021 +0200
+++ b/src/libmlk-core-js/core/js-event.h	Mon Oct 25 12:43:09 2021 +0200
@@ -29,4 +29,7 @@
 void
 js_event_push(duk_context *, const union event *);
 
+union event *
+js_event_require(duk_context *, duk_idx_t);
+
 #endif /* !MLK_CORE_JS_EVENT_H */
--- a/src/libmlk-core/core/sys.c	Sun Oct 24 17:38:01 2021 +0200
+++ b/src/libmlk-core/core/sys.c	Mon Oct 25 12:43:09 2021 +0200
@@ -131,7 +131,6 @@
 		 *   from: /usr/local/bin
 		 *   to:   /usr/local
 		 */
-		printf("base=%s\n", base);
 		port_strlcpy(path, base, sizeof (path));
 		SDL_free(base);
 
--- a/src/mlk-run/main.c	Sun Oct 24 17:38:01 2021 +0200
+++ b/src/mlk-run/main.c	Mon Oct 25 12:43:09 2021 +0200
@@ -26,6 +26,8 @@
 #include <core/vfs-zip.h>
 #include <core/vfs.h>
 
+#include <core/js-action.h>
+#include <core/js-action-stack.h>
 #include <core/js-animation.h>
 #include <core/js-clock.h>
 #include <core/js-color.h>
@@ -65,6 +67,8 @@
 	/* Brings Mlk global object. */
 	js_core_bind(ctx, &vfs);
 
+	js_action_bind(ctx);
+	js_action_stack_bind(ctx);
 	js_animation_bind(ctx);
 	js_clock_bind(ctx);
 	js_color_bind(ctx);