Gitweb links:

...log 
http://git.netsurf-browser.org/netsurf.git/shortlog/c17e588b66360e984241a80077ce986a9182f0de
...commit 
http://git.netsurf-browser.org/netsurf.git/commit/c17e588b66360e984241a80077ce986a9182f0de
...tree 
http://git.netsurf-browser.org/netsurf.git/tree/c17e588b66360e984241a80077ce986a9182f0de

The branch, master has been updated
       via  c17e588b66360e984241a80077ce986a9182f0de (commit)
      from  35e9b5de6d59436568d9cbb951c98e716716bd7e (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commitdiff 
http://git.netsurf-browser.org/netsurf.git/commit/?id=c17e588b66360e984241a80077ce986a9182f0de
commit c17e588b66360e984241a80077ce986a9182f0de
Author: Daniel Silverstone <[email protected]>
Commit: Daniel Silverstone <[email protected]>

    Javascript: Support setTimeout and friends
    
    Signed-off-by: Daniel Silverstone <[email protected]>

diff --git a/content/handlers/javascript/duktape/Window.bnd 
b/content/handlers/javascript/duktape/Window.bnd
index bdabf11..57f8f78 100644
--- a/content/handlers/javascript/duktape/Window.bnd
+++ b/content/handlers/javascript/duktape/Window.bnd
@@ -11,12 +11,163 @@
 class Window {
        private struct browser_window * win;
        private struct html_content * htmlc;
+       private struct window_schedule_s * schedule_ring;
        prologue %{
 #include "utils/nsurl.h"
 #include "netsurf/browser_window.h"
 #include "content/hlcache.h"
 #include "html/html.h"
 #include "html/html_internal.h"
+#include "desktop/gui_internal.h"
+#include "netsurf/misc.h"
+#include "utils/ring.h"
+
+#define WINDOW_CALLBACKS MAGIC(WindowCallbacks)
+
+static size_t next_handle = 0;
+
+typedef struct window_schedule_s {
+       window_private_t *owner;
+       duk_context *ctx;
+       struct window_schedule_s *r_next;
+       struct window_schedule_s *r_prev;
+       size_t handle;
+       int repeat_timeout;
+} window_schedule_t;
+
+static void window_remove_callback_bits(duk_context *ctx, size_t handle) {
+       /* stack is ... */
+       duk_push_global_object(ctx);
+       duk_get_prop_string(ctx, -1, WINDOW_CALLBACKS);
+       /* stack is ..., win, cbt */
+       duk_push_int(ctx, (duk_int_t)handle);
+       /* ..., win, cbt, handle */
+       duk_del_prop(ctx, -2);
+       /* ..., win, cbt */
+       duk_pop_2(ctx);
+       /* ... */
+}
+
+static void window_call_callback(duk_context *ctx, size_t handle) {
+       NSLOG(dukky, DEEPDEBUG, "ctx=%p, handle=%zd", ctx, handle);
+       /* Stack is ... */
+       duk_push_context_dump(ctx);
+       NSLOG(dukky, DEEPDEBUG, "On entry to callback, stack is: %s", 
duk_get_string(ctx, -1));
+       duk_pop(ctx);
+       duk_push_global_object(ctx);
+       duk_get_prop_string(ctx, -1, WINDOW_CALLBACKS);
+       duk_push_int(ctx, (duk_int_t)handle);
+       duk_get_prop(ctx, -2);
+       /* ..., win, cbt, cbo */
+       /* What we want to do is call cbo.func passing all of cbo.args */
+       duk_get_prop_string(ctx, -1, "func");
+       duk_get_prop_string(ctx, -2, "args");
+       /* ..., win, cbt, cbo, func, argarr */
+       duk_size_t arrlen = duk_get_length(ctx, -1);
+       for (duk_size_t i = 0; i < arrlen; ++i) {
+               duk_push_int(ctx, (duk_int_t)i);
+               duk_get_prop(ctx, -(2+i));
+       }
+       /* ..., win, cbt, cbo, func, argarr, args... */
+       duk_remove(ctx, -(arrlen+1));
+       /* ..., win, cbt, cbo, func, args... */
+       duk_push_context_dump(ctx);
+       NSLOG(dukky, DEEPDEBUG, "Just before call with %d args: %s", 
(int)arrlen, duk_get_string(ctx, -1));
+       duk_pop(ctx);
+       (void) dukky_pcall(ctx, arrlen, true);
+       /* ..., win, cbt, cbo, retval */
+       duk_pop_n(ctx, 4);
+       /* ... */
+       duk_push_context_dump(ctx);
+       NSLOG(dukky, DEEPDEBUG, "On leaving callback, stack is: %s", 
duk_get_string(ctx, -1));
+       duk_pop(ctx);
+}
+
+static void window_schedule_callback(void *p) {
+       window_schedule_t *priv = (window_schedule_t *)p;
+
+       NSLOG(dukky, DEEPDEBUG, "Entered window scheduler callback: %zd", 
priv->handle);
+
+       window_call_callback(priv->ctx, priv->handle);
+
+       if (priv->repeat_timeout > 0) {
+               /* Reschedule */
+               NSLOG(dukky, DEEPDEBUG, "Rescheduling repeating callback %zd", 
priv->handle);
+               guit->misc->schedule(priv->repeat_timeout, 
window_schedule_callback, priv);
+       } else {
+               NSLOG(dukky, DEEPDEBUG, "Removing completed callback %zd", 
priv->handle);
+               /* Remove this from the ring */
+               RING_REMOVE(priv->owner->schedule_ring, priv);
+               window_remove_callback_bits(priv->ctx, priv->handle);
+               /* TODO: Remove the entry from the JS part */
+               free(priv);
+       }
+}
+
+static size_t window_alloc_new_callback(duk_context *ctx, window_private_t 
*window,
+                                       bool repeating, int timeout) {
+       size_t new_handle = next_handle++;
+       window_schedule_t *sched = calloc(sizeof *sched, 1);
+       if (sched == NULL) {
+               return new_handle;
+       }
+       sched->owner = window;
+       sched->ctx = ctx;
+       sched->handle = new_handle;
+       sched->repeat_timeout = repeating ? timeout : 0;
+
+       RING_INSERT(window->schedule_ring, sched);
+
+       /* Next, the duktape stack looks like: func, timeout, ...
+        * In order to proceed, we want to put into the WINDOW_CALLBACKS
+        * keyed by the handle, an object containing the call to make and
+        * the array of arguments to call the function with
+        */
+       duk_idx_t nargs = duk_get_top(ctx) - 2;
+       duk_push_global_object(ctx);
+       duk_get_prop_string(ctx, -1, WINDOW_CALLBACKS);
+       duk_push_int(ctx, (duk_int_t)new_handle);
+       duk_push_object(ctx);
+       /* stack is: func, timeout, ..., win, cbt, handle, cbo */
+
+       /* put the function into the cbo */
+       duk_dup(ctx, 0);
+       duk_put_prop_string(ctx, -2, "func");
+
+       /* Now the arguments */
+       duk_push_array(ctx);
+       for (duk_idx_t i = 0; i < nargs; ++i) {
+               duk_dup(ctx, 2 + i); /* Dup the arg */
+               duk_put_prop_index(ctx, -2, i); /* arr[i] = arg[i] */
+       }
+       duk_put_prop_string(ctx, -2, "args");
+       /* stack is: func, timeout, ..., win, cbt, handle, cbo */
+       duk_put_prop(ctx, -3);
+       /* stack is: func, timeout, ..., win, cbt */
+       duk_pop_2(ctx);
+       /* And we're back to func, timeout, ... */
+
+       guit->misc->schedule(timeout, window_schedule_callback, sched);
+       NSLOG(dukky, DEEPDEBUG, "Scheduled callback %zd for %d ms from now", 
new_handle, timeout);
+
+       return new_handle;
+}
+
+static void window_remove_callback_by_handle(duk_context *ctx,
+                                            window_private_t *window,
+                                            size_t handle) {
+       RING_ITERATE_START(window_schedule_t, window->schedule_ring, sched) {
+               if (sched->handle == handle) {
+                       NSLOG(dukky, DEEPDEBUG, "Cancelled callback %zd", 
sched->handle);
+                       guit->misc->schedule(-1, window_schedule_callback, 
sched);
+                       RING_REMOVE(window->schedule_ring, sched);
+                       window_remove_callback_bits(ctx, sched->handle);
+                       free(sched);
+                       RING_ITERATE_STOP(window->schedule_ring, sched);
+               }
+       } RING_ITERATE_END(window->schedule_ring, sched);
+}
+
 %};
 };
 
@@ -25,10 +176,21 @@ init Window(struct browser_window *win, struct 
html_content *htmlc)
        /* element window */
        priv->win = win;
        priv->htmlc = htmlc;
-       NSLOG(netsurf, INFO, "win=%p htmlc=%p", priv->win, priv->htmlc);
+       priv->schedule_ring = NULL;
+       NSLOG(netsurf, DEEPDEBUG, "win=%p htmlc=%p", priv->win, priv->htmlc);
 
-       NSLOG(netsurf, INFO,
+       NSLOG(netsurf, DEEPDEBUG,
              "URL is %s", nsurl_access(browser_window_access_url(priv->win)));
+       duk_push_object(ctx);
+       duk_put_prop_string(ctx, 0, WINDOW_CALLBACKS);
+%}
+
+fini Window()
+%{
+       /* Cheaply iterate the schedule ring, cancelling any pending callbacks 
*/
+       while (priv->schedule_ring != NULL) {
+               window_remove_callback_by_handle(ctx, priv, 
priv->schedule_ring->handle);
+       }
 %}
 
 prototype Window()
@@ -142,3 +304,53 @@ method Window::alert()
        NSLOG(netsurf, INFO, "JS ALERT: %*s", (int)msg_len, msg);
        return 0;
 %}
+
+method Window::setTimeout()
+%{
+       duk_idx_t argc = duk_get_top(ctx);
+       if (argc < 2) {
+               /* not enough arguments */
+               return duk_error(ctx, DUK_RET_TYPE_ERROR, 
dukky_error_fmt_argument, 2, argc);
+       }
+
+       /* func, timeout, args... */
+       duk_int_t timeout = duk_get_int(ctx, 1);
+       if (timeout < 10) { timeout = 10; }
+       size_t handle = window_alloc_new_callback(ctx, priv, false, 
(int)timeout);
+
+       duk_push_int(ctx, (duk_int_t)handle);
+       return 1;
+%}
+
+method Window::setInterval()
+%{
+       duk_idx_t argc = duk_get_top(ctx);
+       if (argc < 2) {
+               /* not enough arguments */
+               return duk_error(ctx, DUK_RET_TYPE_ERROR, 
dukky_error_fmt_argument, 2, argc);
+       }
+
+       /* func, timeout, args... */
+       duk_int_t timeout = duk_get_int(ctx, 1);
+       if (timeout < 10) { timeout = 10; }
+       size_t handle = window_alloc_new_callback(ctx, priv, true, 
(int)timeout);
+
+       duk_push_int(ctx, (duk_int_t)handle);
+       return 1;
+%}
+
+method Window::clearTimeout()
+%{
+       duk_int_t handle = duk_get_int(ctx, 0);
+       window_remove_callback_by_handle(ctx, priv, (size_t) handle);
+
+       return 0;
+%}
+
+method Window::clearInterval()
+%{
+       duk_int_t handle = duk_get_int(ctx, 0);
+       window_remove_callback_by_handle(ctx, priv, (size_t) handle);
+
+       return 0;
+%}
diff --git a/content/handlers/javascript/duktape/dukky.c 
b/content/handlers/javascript/duktape/dukky.c
index 152b080..750d14b 100644
--- a/content/handlers/javascript/duktape/dukky.c
+++ b/content/handlers/javascript/duktape/dukky.c
@@ -649,6 +649,62 @@ static duk_ret_t dukky_safe_get(duk_context *ctx, void 
*udata)
        return 1;
 }
 
+static void dukky_dump_error(duk_context *ctx)
+{
+       /* stack is ..., errobj */
+       duk_idx_t stacktop = duk_get_top(ctx);
+       if (!duk_is_error(ctx, stacktop - 1)) {
+               NSLOG(dukky, INFO, "Uncaught non-Error derived error in JS: 
%s", duk_safe_to_string(ctx, stacktop - 1));
+       } else {
+#define GETTER(what)                                           \
+               if (duk_has_prop_string(ctx, stacktop - 1, what)) {     \
+                       NSLOG(dukky, DEEPDEBUG, "Fetching " what); \
+                       duk_dup(ctx, stacktop - 1);                     \
+                       if (duk_safe_call(ctx, dukky_safe_get, (void *)what, 1, 
1) != DUK_EXEC_SUCCESS) { \
+                               NSLOG(dukky, DEBUG, "Error fetching " what ": 
%s", duk_safe_to_string(ctx, -1)); \
+                       } else { \
+                               NSLOG(dukky, DEEPDEBUG, "Success fetching " 
what);      \
+                       }                                               \
+               } else {                                                \
+                       NSLOG(dukky, DEBUG, "Faking " what);            \
+                       duk_push_string(ctx, "?" what "?");             \
+               }
+               GETTER("name");
+               GETTER("message");
+               GETTER("fileName");
+               GETTER("lineNumber");
+               GETTER("stack");
+               NSLOG(dukky, DEBUG, "Uncaught error in JS: %s: %s",
+                     duk_safe_to_string(ctx, -5), duk_safe_to_string(ctx, -4));
+               NSLOG(dukky, DEBUG, "              was at: %s line %s",
+               duk_safe_to_string(ctx, -3), duk_safe_to_string(ctx, -2));
+               NSLOG(dukky, DEBUG, "         Stack trace: %s",
+                     duk_safe_to_string(ctx, -1));
+#undef GETTER
+       }
+       duk_set_top(ctx, stacktop);
+}
+
+duk_int_t dukky_pcall(duk_context *ctx, duk_size_t argc, bool reset_timeout)
+{
+       if (reset_timeout) {
+               duk_memory_functions funcs;
+               jscontext *jsctx;
+               duk_get_memory_functions(ctx, &funcs);
+               jsctx = funcs.udata;
+               (void) nsu_getmonotonic_ms(&jsctx->exec_start_time);
+       }
+
+       duk_int_t ret = duk_pcall(ctx, argc);
+       if (ret) {
+               /* Something went wrong calling this... */
+               dukky_dump_error(ctx);
+       }
+
+       return ret;
+}
+
+
 bool js_exec(jscontext *ctx, const char *txt, size_t txtlen)
 {
        assert(ctx);
@@ -674,35 +730,7 @@ bool js_exec(jscontext *ctx, const char *txt, size_t 
txtlen)
        return duk_get_boolean(CTX, 0);
 
 handle_error:
-       if (!duk_is_error(CTX, 0)) {
-               NSLOG(dukky, INFO, "Uncaught non-Error derived error in JS: 
%s", duk_safe_to_string(CTX, 0));
-       } else {
-#define GETTER(what)                                           \
-               if (duk_has_prop_string(CTX, 0, what)) {        \
-                       NSLOG(dukky, DEEPDEBUG, "Fetching " what); \
-                       duk_dup(CTX, 0);                        \
-                       if (duk_safe_call(CTX, dukky_safe_get, (void *)what, 1, 
1) != DUK_EXEC_SUCCESS) { \
-                               NSLOG(dukky, DEBUG, "Error fetching " what ": 
%s", duk_safe_to_string(CTX, -1)); \
-                       } else { \
-                               NSLOG(dukky, DEEPDEBUG, "Success fetching " 
what);      \
-                       }                                               \
-               } else {                                                \
-                       NSLOG(dukky, DEBUG, "Faking " what);            \
-                       duk_push_string(CTX, "?" what "?");             \
-               }
-               GETTER("name");
-               GETTER("message");
-               GETTER("fileName");
-               GETTER("lineNumber");
-               GETTER("stack");
-               NSLOG(dukky, DEBUG, "Uncaught error in JS: %s: %s",
-                     duk_safe_to_string(CTX, 1), duk_safe_to_string(CTX, 2));
-               NSLOG(dukky, DEBUG, "              was at: %s line %s",
-               duk_safe_to_string(CTX, 3), duk_safe_to_string(CTX, 4));
-               NSLOG(dukky, DEBUG, "         Stack trace: %s",
-                     duk_safe_to_string(CTX, 5));
-#undef GETTER
-       }
+       dukky_dump_error(CTX);
        return false;
 }
 
diff --git a/content/handlers/javascript/duktape/dukky.h 
b/content/handlers/javascript/duktape/dukky.h
index 1a01a51..7e8a786 100644
--- a/content/handlers/javascript/duktape/dukky.h
+++ b/content/handlers/javascript/duktape/dukky.h
@@ -47,4 +47,7 @@ typedef enum {
 
 void dukky_shuffle_array(duk_context *ctx, duk_uarridx_t idx);
 
+/* pcall something, and if it errored, also dump the error to the log */
+duk_int_t dukky_pcall(duk_context *ctx, duk_size_t argc, bool reset_timeout);
+
 #endif
diff --git a/test/js/settimeout.html b/test/js/settimeout.html
new file mode 100644
index 0000000..1755973
--- /dev/null
+++ b/test/js/settimeout.html
@@ -0,0 +1,17 @@
+<html>
+  <head>
+    <title>setTimeout and setInterval</title>
+    <script>
+      var counter = 0;
+      var interval_handle = setInterval(function() {
+          console.log("Called back ", counter, " times");
+          counter = counter + 1;
+      }, 100);
+      setTimeout(function() {clearInterval(interval_handle);}, 10000);
+    </script>
+  </head>
+  <body>
+    Check the log, it should be printing a callback indicator for ten
+    seconds and then stop.
+  </body>
+</html>


-----------------------------------------------------------------------

Summary of changes:
 content/handlers/javascript/duktape/Window.bnd |  216 +++++++++++++++++++++++-
 content/handlers/javascript/duktape/dukky.c    |   86 ++++++----
 content/handlers/javascript/duktape/dukky.h    |    3 +
 test/js/settimeout.html                        |   17 ++
 4 files changed, 291 insertions(+), 31 deletions(-)
 create mode 100644 test/js/settimeout.html

diff --git a/content/handlers/javascript/duktape/Window.bnd 
b/content/handlers/javascript/duktape/Window.bnd
index bdabf11..57f8f78 100644
--- a/content/handlers/javascript/duktape/Window.bnd
+++ b/content/handlers/javascript/duktape/Window.bnd
@@ -11,12 +11,163 @@
 class Window {
        private struct browser_window * win;
        private struct html_content * htmlc;
+       private struct window_schedule_s * schedule_ring;
        prologue %{
 #include "utils/nsurl.h"
 #include "netsurf/browser_window.h"
 #include "content/hlcache.h"
 #include "html/html.h"
 #include "html/html_internal.h"
+#include "desktop/gui_internal.h"
+#include "netsurf/misc.h"
+#include "utils/ring.h"
+
+#define WINDOW_CALLBACKS MAGIC(WindowCallbacks)
+
+static size_t next_handle = 0;
+
+typedef struct window_schedule_s {
+       window_private_t *owner;
+       duk_context *ctx;
+       struct window_schedule_s *r_next;
+       struct window_schedule_s *r_prev;
+       size_t handle;
+       int repeat_timeout;
+} window_schedule_t;
+
+static void window_remove_callback_bits(duk_context *ctx, size_t handle) {
+       /* stack is ... */
+       duk_push_global_object(ctx);
+       duk_get_prop_string(ctx, -1, WINDOW_CALLBACKS);
+       /* stack is ..., win, cbt */
+       duk_push_int(ctx, (duk_int_t)handle);
+       /* ..., win, cbt, handle */
+       duk_del_prop(ctx, -2);
+       /* ..., win, cbt */
+       duk_pop_2(ctx);
+       /* ... */
+}
+
+static void window_call_callback(duk_context *ctx, size_t handle) {
+       NSLOG(dukky, DEEPDEBUG, "ctx=%p, handle=%zd", ctx, handle);
+       /* Stack is ... */
+       duk_push_context_dump(ctx);
+       NSLOG(dukky, DEEPDEBUG, "On entry to callback, stack is: %s", 
duk_get_string(ctx, -1));
+       duk_pop(ctx);
+       duk_push_global_object(ctx);
+       duk_get_prop_string(ctx, -1, WINDOW_CALLBACKS);
+       duk_push_int(ctx, (duk_int_t)handle);
+       duk_get_prop(ctx, -2);
+       /* ..., win, cbt, cbo */
+       /* What we want to do is call cbo.func passing all of cbo.args */
+       duk_get_prop_string(ctx, -1, "func");
+       duk_get_prop_string(ctx, -2, "args");
+       /* ..., win, cbt, cbo, func, argarr */
+       duk_size_t arrlen = duk_get_length(ctx, -1);
+       for (duk_size_t i = 0; i < arrlen; ++i) {
+               duk_push_int(ctx, (duk_int_t)i);
+               duk_get_prop(ctx, -(2+i));
+       }
+       /* ..., win, cbt, cbo, func, argarr, args... */
+       duk_remove(ctx, -(arrlen+1));
+       /* ..., win, cbt, cbo, func, args... */
+       duk_push_context_dump(ctx);
+       NSLOG(dukky, DEEPDEBUG, "Just before call with %d args: %s", 
(int)arrlen, duk_get_string(ctx, -1));
+       duk_pop(ctx);
+       (void) dukky_pcall(ctx, arrlen, true);
+       /* ..., win, cbt, cbo, retval */
+       duk_pop_n(ctx, 4);
+       /* ... */
+       duk_push_context_dump(ctx);
+       NSLOG(dukky, DEEPDEBUG, "On leaving callback, stack is: %s", 
duk_get_string(ctx, -1));
+       duk_pop(ctx);
+}
+
+static void window_schedule_callback(void *p) {
+       window_schedule_t *priv = (window_schedule_t *)p;
+
+       NSLOG(dukky, DEEPDEBUG, "Entered window scheduler callback: %zd", 
priv->handle);
+
+       window_call_callback(priv->ctx, priv->handle);
+
+       if (priv->repeat_timeout > 0) {
+               /* Reschedule */
+               NSLOG(dukky, DEEPDEBUG, "Rescheduling repeating callback %zd", 
priv->handle);
+               guit->misc->schedule(priv->repeat_timeout, 
window_schedule_callback, priv);
+       } else {
+               NSLOG(dukky, DEEPDEBUG, "Removing completed callback %zd", 
priv->handle);
+               /* Remove this from the ring */
+               RING_REMOVE(priv->owner->schedule_ring, priv);
+               window_remove_callback_bits(priv->ctx, priv->handle);
+               /* TODO: Remove the entry from the JS part */
+               free(priv);
+       }
+}
+
+static size_t window_alloc_new_callback(duk_context *ctx, window_private_t 
*window,
+                                       bool repeating, int timeout) {
+       size_t new_handle = next_handle++;
+       window_schedule_t *sched = calloc(sizeof *sched, 1);
+       if (sched == NULL) {
+               return new_handle;
+       }
+       sched->owner = window;
+       sched->ctx = ctx;
+       sched->handle = new_handle;
+       sched->repeat_timeout = repeating ? timeout : 0;
+
+       RING_INSERT(window->schedule_ring, sched);
+
+       /* Next, the duktape stack looks like: func, timeout, ...
+        * In order to proceed, we want to put into the WINDOW_CALLBACKS
+        * keyed by the handle, an object containing the call to make and
+        * the array of arguments to call the function with
+        */
+       duk_idx_t nargs = duk_get_top(ctx) - 2;
+       duk_push_global_object(ctx);
+       duk_get_prop_string(ctx, -1, WINDOW_CALLBACKS);
+       duk_push_int(ctx, (duk_int_t)new_handle);
+       duk_push_object(ctx);
+       /* stack is: func, timeout, ..., win, cbt, handle, cbo */
+
+       /* put the function into the cbo */
+       duk_dup(ctx, 0);
+       duk_put_prop_string(ctx, -2, "func");
+
+       /* Now the arguments */
+       duk_push_array(ctx);
+       for (duk_idx_t i = 0; i < nargs; ++i) {
+               duk_dup(ctx, 2 + i); /* Dup the arg */
+               duk_put_prop_index(ctx, -2, i); /* arr[i] = arg[i] */
+       }
+       duk_put_prop_string(ctx, -2, "args");
+       /* stack is: func, timeout, ..., win, cbt, handle, cbo */
+       duk_put_prop(ctx, -3);
+       /* stack is: func, timeout, ..., win, cbt */
+       duk_pop_2(ctx);
+       /* And we're back to func, timeout, ... */
+
+       guit->misc->schedule(timeout, window_schedule_callback, sched);
+       NSLOG(dukky, DEEPDEBUG, "Scheduled callback %zd for %d ms from now", 
new_handle, timeout);
+
+       return new_handle;
+}
+
+static void window_remove_callback_by_handle(duk_context *ctx,
+                                            window_private_t *window,
+                                            size_t handle) {
+       RING_ITERATE_START(window_schedule_t, window->schedule_ring, sched) {
+               if (sched->handle == handle) {
+                       NSLOG(dukky, DEEPDEBUG, "Cancelled callback %zd", 
sched->handle);
+                       guit->misc->schedule(-1, window_schedule_callback, 
sched);
+                       RING_REMOVE(window->schedule_ring, sched);
+                       window_remove_callback_bits(ctx, sched->handle);
+                       free(sched);
+                       RING_ITERATE_STOP(window->schedule_ring, sched);
+               }
+       } RING_ITERATE_END(window->schedule_ring, sched);
+}
+
 %};
 };
 
@@ -25,10 +176,21 @@ init Window(struct browser_window *win, struct 
html_content *htmlc)
        /* element window */
        priv->win = win;
        priv->htmlc = htmlc;
-       NSLOG(netsurf, INFO, "win=%p htmlc=%p", priv->win, priv->htmlc);
+       priv->schedule_ring = NULL;
+       NSLOG(netsurf, DEEPDEBUG, "win=%p htmlc=%p", priv->win, priv->htmlc);
 
-       NSLOG(netsurf, INFO,
+       NSLOG(netsurf, DEEPDEBUG,
              "URL is %s", nsurl_access(browser_window_access_url(priv->win)));
+       duk_push_object(ctx);
+       duk_put_prop_string(ctx, 0, WINDOW_CALLBACKS);
+%}
+
+fini Window()
+%{
+       /* Cheaply iterate the schedule ring, cancelling any pending callbacks 
*/
+       while (priv->schedule_ring != NULL) {
+               window_remove_callback_by_handle(ctx, priv, 
priv->schedule_ring->handle);
+       }
 %}
 
 prototype Window()
@@ -142,3 +304,53 @@ method Window::alert()
        NSLOG(netsurf, INFO, "JS ALERT: %*s", (int)msg_len, msg);
        return 0;
 %}
+
+method Window::setTimeout()
+%{
+       duk_idx_t argc = duk_get_top(ctx);
+       if (argc < 2) {
+               /* not enough arguments */
+               return duk_error(ctx, DUK_RET_TYPE_ERROR, 
dukky_error_fmt_argument, 2, argc);
+       }
+
+       /* func, timeout, args... */
+       duk_int_t timeout = duk_get_int(ctx, 1);
+       if (timeout < 10) { timeout = 10; }
+       size_t handle = window_alloc_new_callback(ctx, priv, false, 
(int)timeout);
+
+       duk_push_int(ctx, (duk_int_t)handle);
+       return 1;
+%}
+
+method Window::setInterval()
+%{
+       duk_idx_t argc = duk_get_top(ctx);
+       if (argc < 2) {
+               /* not enough arguments */
+               return duk_error(ctx, DUK_RET_TYPE_ERROR, 
dukky_error_fmt_argument, 2, argc);
+       }
+
+       /* func, timeout, args... */
+       duk_int_t timeout = duk_get_int(ctx, 1);
+       if (timeout < 10) { timeout = 10; }
+       size_t handle = window_alloc_new_callback(ctx, priv, true, 
(int)timeout);
+
+       duk_push_int(ctx, (duk_int_t)handle);
+       return 1;
+%}
+
+method Window::clearTimeout()
+%{
+       duk_int_t handle = duk_get_int(ctx, 0);
+       window_remove_callback_by_handle(ctx, priv, (size_t) handle);
+
+       return 0;
+%}
+
+method Window::clearInterval()
+%{
+       duk_int_t handle = duk_get_int(ctx, 0);
+       window_remove_callback_by_handle(ctx, priv, (size_t) handle);
+
+       return 0;
+%}
diff --git a/content/handlers/javascript/duktape/dukky.c 
b/content/handlers/javascript/duktape/dukky.c
index 152b080..750d14b 100644
--- a/content/handlers/javascript/duktape/dukky.c
+++ b/content/handlers/javascript/duktape/dukky.c
@@ -649,6 +649,62 @@ static duk_ret_t dukky_safe_get(duk_context *ctx, void 
*udata)
        return 1;
 }
 
+static void dukky_dump_error(duk_context *ctx)
+{
+       /* stack is ..., errobj */
+       duk_idx_t stacktop = duk_get_top(ctx);
+       if (!duk_is_error(ctx, stacktop - 1)) {
+               NSLOG(dukky, INFO, "Uncaught non-Error derived error in JS: 
%s", duk_safe_to_string(ctx, stacktop - 1));
+       } else {
+#define GETTER(what)                                           \
+               if (duk_has_prop_string(ctx, stacktop - 1, what)) {     \
+                       NSLOG(dukky, DEEPDEBUG, "Fetching " what); \
+                       duk_dup(ctx, stacktop - 1);                     \
+                       if (duk_safe_call(ctx, dukky_safe_get, (void *)what, 1, 
1) != DUK_EXEC_SUCCESS) { \
+                               NSLOG(dukky, DEBUG, "Error fetching " what ": 
%s", duk_safe_to_string(ctx, -1)); \
+                       } else { \
+                               NSLOG(dukky, DEEPDEBUG, "Success fetching " 
what);      \
+                       }                                               \
+               } else {                                                \
+                       NSLOG(dukky, DEBUG, "Faking " what);            \
+                       duk_push_string(ctx, "?" what "?");             \
+               }
+               GETTER("name");
+               GETTER("message");
+               GETTER("fileName");
+               GETTER("lineNumber");
+               GETTER("stack");
+               NSLOG(dukky, DEBUG, "Uncaught error in JS: %s: %s",
+                     duk_safe_to_string(ctx, -5), duk_safe_to_string(ctx, -4));
+               NSLOG(dukky, DEBUG, "              was at: %s line %s",
+               duk_safe_to_string(ctx, -3), duk_safe_to_string(ctx, -2));
+               NSLOG(dukky, DEBUG, "         Stack trace: %s",
+                     duk_safe_to_string(ctx, -1));
+#undef GETTER
+       }
+       duk_set_top(ctx, stacktop);
+}
+
+duk_int_t dukky_pcall(duk_context *ctx, duk_size_t argc, bool reset_timeout)
+{
+       if (reset_timeout) {
+               duk_memory_functions funcs;
+               jscontext *jsctx;
+               duk_get_memory_functions(ctx, &funcs);
+               jsctx = funcs.udata;
+               (void) nsu_getmonotonic_ms(&jsctx->exec_start_time);
+       }
+
+       duk_int_t ret = duk_pcall(ctx, argc);
+       if (ret) {
+               /* Something went wrong calling this... */
+               dukky_dump_error(ctx);
+       }
+
+       return ret;
+}
+
+
 bool js_exec(jscontext *ctx, const char *txt, size_t txtlen)
 {
        assert(ctx);
@@ -674,35 +730,7 @@ bool js_exec(jscontext *ctx, const char *txt, size_t 
txtlen)
        return duk_get_boolean(CTX, 0);
 
 handle_error:
-       if (!duk_is_error(CTX, 0)) {
-               NSLOG(dukky, INFO, "Uncaught non-Error derived error in JS: 
%s", duk_safe_to_string(CTX, 0));
-       } else {
-#define GETTER(what)                                           \
-               if (duk_has_prop_string(CTX, 0, what)) {        \
-                       NSLOG(dukky, DEEPDEBUG, "Fetching " what); \
-                       duk_dup(CTX, 0);                        \
-                       if (duk_safe_call(CTX, dukky_safe_get, (void *)what, 1, 
1) != DUK_EXEC_SUCCESS) { \
-                               NSLOG(dukky, DEBUG, "Error fetching " what ": 
%s", duk_safe_to_string(CTX, -1)); \
-                       } else { \
-                               NSLOG(dukky, DEEPDEBUG, "Success fetching " 
what);      \
-                       }                                               \
-               } else {                                                \
-                       NSLOG(dukky, DEBUG, "Faking " what);            \
-                       duk_push_string(CTX, "?" what "?");             \
-               }
-               GETTER("name");
-               GETTER("message");
-               GETTER("fileName");
-               GETTER("lineNumber");
-               GETTER("stack");
-               NSLOG(dukky, DEBUG, "Uncaught error in JS: %s: %s",
-                     duk_safe_to_string(CTX, 1), duk_safe_to_string(CTX, 2));
-               NSLOG(dukky, DEBUG, "              was at: %s line %s",
-               duk_safe_to_string(CTX, 3), duk_safe_to_string(CTX, 4));
-               NSLOG(dukky, DEBUG, "         Stack trace: %s",
-                     duk_safe_to_string(CTX, 5));
-#undef GETTER
-       }
+       dukky_dump_error(CTX);
        return false;
 }
 
diff --git a/content/handlers/javascript/duktape/dukky.h 
b/content/handlers/javascript/duktape/dukky.h
index 1a01a51..7e8a786 100644
--- a/content/handlers/javascript/duktape/dukky.h
+++ b/content/handlers/javascript/duktape/dukky.h
@@ -47,4 +47,7 @@ typedef enum {
 
 void dukky_shuffle_array(duk_context *ctx, duk_uarridx_t idx);
 
+/* pcall something, and if it errored, also dump the error to the log */
+duk_int_t dukky_pcall(duk_context *ctx, duk_size_t argc, bool reset_timeout);
+
 #endif
diff --git a/test/js/settimeout.html b/test/js/settimeout.html
new file mode 100644
index 0000000..1755973
--- /dev/null
+++ b/test/js/settimeout.html
@@ -0,0 +1,17 @@
+<html>
+  <head>
+    <title>setTimeout and setInterval</title>
+    <script>
+      var counter = 0;
+      var interval_handle = setInterval(function() {
+          console.log("Called back ", counter, " times");
+          counter = counter + 1;
+      }, 100);
+      setTimeout(function() {clearInterval(interval_handle);}, 10000);
+    </script>
+  </head>
+  <body>
+    Check the log, it should be printing a callback indicator for ten
+    seconds and then stop.
+  </body>
+</html>


-- 
NetSurf Browser

_______________________________________________
netsurf-commits mailing list
[email protected]
http://listmaster.pepperfish.net/cgi-bin/mailman/listinfo/netsurf-commits-netsurf-browser.org

Reply via email to