NetSurf
dukky.c
Go to the documentation of this file.
1/*
2 * Copyright 2012 Vincent Sanders <vince@netsurf-browser.org>
3 * Copyright 2015 Daniel Dilverstone <dsilvers@netsurf-browser.org>
4 * Copyright 2016 Michael Drake <tlsa@netsurf-browser.org>
5 * Copyright 2016 John-Mark Bell <jmb@netsurf-browser.org>
6 *
7 * This file is part of NetSurf, http://www.netsurf-browser.org/
8 *
9 * NetSurf is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; version 2 of the License.
12 *
13 * NetSurf is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 */
21
22/**
23 * \file
24 * Duktapeish implementation of javascript engine functions.
25 */
26
27#include <stdint.h>
28#include <nsutils/time.h>
29
30#include "netsurf/inttypes.h"
31#include "utils/utils.h"
32#include "utils/nsoption.h"
33#include "utils/log.h"
34#include "utils/corestrings.h"
35#include "content/content.h"
36
37#include "javascript/js.h"
38#include "javascript/content.h"
39
40#include "duktape/binding.h"
41#include "duktape/generics.js.inc"
42#include "duktape/polyfill.js.inc"
43
44#include "duktape.h"
45#include "dukky.h"
46
47#include <dom/dom.h>
48
49#define EVENT_MAGIC MAGIC(EVENT_MAP)
50#define HANDLER_LISTENER_MAGIC MAGIC(HANDLER_LISTENER_MAP)
51#define HANDLER_MAGIC MAGIC(HANDLER_MAP)
52#define EVENT_LISTENER_JS_MAGIC MAGIC(EVENT_LISTENER_JS_MAP)
53#define GENERICS_MAGIC MAGIC(GENERICS_TABLE)
54#define THREAD_MAP MAGIC(THREAD_MAP)
55
56/**
57 * dukky javascript heap
58 */
59struct jsheap {
60 duk_context *ctx; /**< duktape base context */
61 duk_uarridx_t next_thread; /**< monotonic thread counter */
62 bool pending_destroy; /**< Whether this heap is pending destruction */
63 unsigned int live_threads; /**< number of live threads */
65};
66
67/**
68 * dukky javascript thread
69 */
70struct jsthread {
71 bool pending_destroy; /**< Whether this thread is pending destruction */
72 unsigned int in_use; /**< The number of times this thread is in use */
73 jsheap *heap; /**< The heap this thread belongs to */
74 duk_context *ctx; /**< The duktape thread context */
75 duk_uarridx_t thread_idx; /**< The thread number */
76};
77
79{
80 /* ... obj args protoname nargs */
81 int nargs = duk_get_int(ctx, -1);
82 duk_pop(ctx);
83 /* ... obj args protoname */
84 duk_get_global_string(ctx, PROTO_MAGIC);
85 /* .. obj args protoname prototab */
86 duk_dup(ctx, -2);
87 /* ... obj args protoname prototab protoname */
88 duk_get_prop(ctx, -2);
89 /* ... obj args protoname prototab {proto/undefined} */
90 if (duk_is_undefined(ctx, -1)) {
91 NSLOG(dukky, WARNING,
92 "Unable to find dukky prototype for `%s` - falling back to HTMLUnknownElement",
93 duk_get_string(ctx, -3) + 2 /* Skip the two unprintables */);
94 duk_pop(ctx);
95 duk_push_string(ctx, PROTO_NAME(HTMLUNKNOWNELEMENT));
96 duk_get_prop(ctx, -2);
97 }
98 /* ... obj args protoname prototab proto */
99 duk_remove(ctx, -3);
100 /* ... obj args prototab proto */
101 duk_dup(ctx, -1);
102 /* ... obj args prototab proto proto */
103 duk_set_prototype(ctx, -(nargs+4));
104 /* ... obj[proto] args prototab proto */
105 duk_get_prop_string(ctx, -1, INIT_MAGIC);
106 /* ... obj[proto] args prototab proto initfn */
107 duk_insert(ctx, -(nargs+4));
108 /* ... initfn obj[proto] args prototab proto */
109 duk_pop_2(ctx);
110 /* ... initfn obj[proto] args */
111 NSLOG(dukky, DEEPDEBUG, "Call the init function");
112 duk_call(ctx, nargs + 1);
113 return 1; /* The object */
114}
115
116duk_ret_t dukky_create_object(duk_context *ctx, const char *name, int args)
117{
118 duk_ret_t ret;
119 NSLOG(dukky, DEEPDEBUG, "name=%s nargs=%d", name + 2, args);
120 /* ... args */
121 duk_push_object(ctx);
122 /* ... args obj */
123 duk_push_object(ctx);
124 /* ... args obj handlers */
126 /* ... args obj */
127 duk_push_object(ctx);
128 /* ... args obj handlers */
130 /* ... args obj */
131 duk_insert(ctx, -(args+1));
132 /* ... obj args */
133 duk_push_string(ctx, name);
134 /* ... obj args name */
135 duk_push_int(ctx, args);
136 /* ... obj args name nargs */
137 if ((ret = duk_safe_call(ctx, dukky_populate_object, NULL, args + 3, 1))
139 return ret;
140 NSLOG(dukky, DEEPDEBUG, "created");
141 return DUK_EXEC_SUCCESS;
142}
143
144
145
148{
149 int top_at_fail = duk_get_top(ctx) - 2;
150 /* ... nodeptr klass */
151 duk_get_global_string(ctx, NODE_MAGIC);
152 /* ... nodeptr klass nodes */
153 duk_dup(ctx, -3);
154 /* ... nodeptr klass nodes nodeptr */
155 duk_get_prop(ctx, -2);
156 /* ... nodeptr klass nodes node/undefined */
157 if (duk_is_undefined(ctx, -1)) {
158 /* ... nodeptr klass nodes undefined */
159 duk_pop(ctx);
160 /* ... nodeptr klass nodes */
161 duk_push_object(ctx);
162 /* ... nodeptr klass nodes obj */
163 duk_push_object(ctx);
164 /* ... nodeptr klass nodes obj handlers */
166 /* ... nodeptr klass nodes obj */
167 duk_push_object(ctx);
168 /* ... nodeptr klass nodes obj handlers */
170 /* ... nodeptr klass nodes obj */
171 duk_dup(ctx, -4);
172 /* ... nodeptr klass nodes obj nodeptr */
173 duk_dup(ctx, -4);
174 /* ... nodeptr klass nodes obj nodeptr klass */
175 duk_push_int(ctx, 1);
176 /* ... nodeptr klass nodes obj nodeptr klass 1 */
177 if (duk_safe_call(ctx, dukky_populate_object, NULL, 4, 1)
178 != DUK_EXEC_SUCCESS) {
179 duk_set_top(ctx, top_at_fail);
180 NSLOG(dukky, ERROR, "Failed to populate object prototype");
181 return false;
182 }
183 /* ... nodeptr klass nodes node */
184 duk_dup(ctx, -4);
185 /* ... nodeptr klass nodes node nodeptr */
186 duk_dup(ctx, -2);
187 /* ... nodeptr klass nodes node nodeptr node */
188 duk_put_prop(ctx, -4);
189 /* ... nodeptr klass nodes node */
190 }
191 /* ... nodeptr klass nodes node */
192 duk_insert(ctx, -4);
193 /* ... node nodeptr klass nodes */
194 duk_pop_3(ctx);
195 /* ... node */
197 duk_dup(ctx, -1);
198 const char * what = duk_safe_to_string(ctx, -1);
199 NSLOG(dukky, DEEPDEBUG, "Created: %s", what);
200 duk_pop(ctx);
201 }
202 return true;
203}
204
205#define SET_HTML_CLASS(CLASS) \
206 *html_class = PROTO_NAME(HTML##CLASS##ELEMENT); \
207 *html_class_len = \
208 SLEN(PROTO_NAME(HTML)) + \
209 SLEN(#CLASS) + \
210 SLEN("ELEMENT");
211
212static void dukky_html_element_class_from_tag_type(dom_html_element_type type,
213 const char **html_class, size_t *html_class_len)
214{
215 switch(type) {
216 case DOM_HTML_ELEMENT_TYPE_HTML:
217 SET_HTML_CLASS(HTML)
218 break;
219 case DOM_HTML_ELEMENT_TYPE_HEAD:
220 SET_HTML_CLASS(HEAD)
221 break;
222 case DOM_HTML_ELEMENT_TYPE_META:
223 SET_HTML_CLASS(META)
224 break;
225 case DOM_HTML_ELEMENT_TYPE_BASE:
226 SET_HTML_CLASS(BASE)
227 break;
228 case DOM_HTML_ELEMENT_TYPE_TITLE:
229 SET_HTML_CLASS(TITLE)
230 break;
231 case DOM_HTML_ELEMENT_TYPE_BODY:
232 SET_HTML_CLASS(BODY)
233 break;
234 case DOM_HTML_ELEMENT_TYPE_DIV:
235 SET_HTML_CLASS(DIV)
236 break;
237 case DOM_HTML_ELEMENT_TYPE_FORM:
238 SET_HTML_CLASS(FORM)
239 break;
240 case DOM_HTML_ELEMENT_TYPE_LINK:
241 SET_HTML_CLASS(LINK)
242 break;
243 case DOM_HTML_ELEMENT_TYPE_BUTTON:
244 SET_HTML_CLASS(BUTTON)
245 break;
246 case DOM_HTML_ELEMENT_TYPE_INPUT:
247 SET_HTML_CLASS(INPUT)
248 break;
249 case DOM_HTML_ELEMENT_TYPE_TEXTAREA:
250 SET_HTML_CLASS(TEXTAREA)
251 break;
252 case DOM_HTML_ELEMENT_TYPE_OPTGROUP:
253 SET_HTML_CLASS(OPTGROUP)
254 break;
255 case DOM_HTML_ELEMENT_TYPE_OPTION:
256 SET_HTML_CLASS(OPTION)
257 break;
258 case DOM_HTML_ELEMENT_TYPE_SELECT:
259 SET_HTML_CLASS(SELECT)
260 break;
261 case DOM_HTML_ELEMENT_TYPE_HR:
263 break;
264 case DOM_HTML_ELEMENT_TYPE_DL:
265 SET_HTML_CLASS(DLIST)
266 break;
267 case DOM_HTML_ELEMENT_TYPE_DIR:
268 SET_HTML_CLASS(DIRECTORY)
269 break;
270 case DOM_HTML_ELEMENT_TYPE_MENU:
271 SET_HTML_CLASS(MENU)
272 break;
273 case DOM_HTML_ELEMENT_TYPE_FIELDSET:
274 SET_HTML_CLASS(FIELDSET)
275 break;
276 case DOM_HTML_ELEMENT_TYPE_LEGEND:
277 SET_HTML_CLASS(LEGEND)
278 break;
279 case DOM_HTML_ELEMENT_TYPE_P:
280 SET_HTML_CLASS(PARAGRAPH)
281 break;
282 case DOM_HTML_ELEMENT_TYPE_H1:
283 case DOM_HTML_ELEMENT_TYPE_H2:
284 case DOM_HTML_ELEMENT_TYPE_H3:
285 case DOM_HTML_ELEMENT_TYPE_H4:
286 case DOM_HTML_ELEMENT_TYPE_H5:
287 case DOM_HTML_ELEMENT_TYPE_H6:
288 SET_HTML_CLASS(HEADING)
289 break;
290 case DOM_HTML_ELEMENT_TYPE_BLOCKQUOTE:
291 case DOM_HTML_ELEMENT_TYPE_Q:
292 SET_HTML_CLASS(QUOTE)
293 break;
294 case DOM_HTML_ELEMENT_TYPE_PRE:
295 SET_HTML_CLASS(PRE)
296 break;
297 case DOM_HTML_ELEMENT_TYPE_BR:
299 break;
300 case DOM_HTML_ELEMENT_TYPE_LABEL:
301 SET_HTML_CLASS(LABEL)
302 break;
303 case DOM_HTML_ELEMENT_TYPE_UL:
304 SET_HTML_CLASS(ULIST)
305 break;
306 case DOM_HTML_ELEMENT_TYPE_OL:
307 SET_HTML_CLASS(OLIST)
308 break;
309 case DOM_HTML_ELEMENT_TYPE_LI:
311 break;
312 case DOM_HTML_ELEMENT_TYPE_FONT:
313 SET_HTML_CLASS(FONT)
314 break;
315 case DOM_HTML_ELEMENT_TYPE_DEL:
316 case DOM_HTML_ELEMENT_TYPE_INS:
317 SET_HTML_CLASS(MOD)
318 break;
319 case DOM_HTML_ELEMENT_TYPE_A:
320 SET_HTML_CLASS(ANCHOR)
321 break;
322 case DOM_HTML_ELEMENT_TYPE_BASEFONT:
323 SET_HTML_CLASS(BASEFONT)
324 break;
325 case DOM_HTML_ELEMENT_TYPE_IMG:
326 SET_HTML_CLASS(IMAGE)
327 break;
328 case DOM_HTML_ELEMENT_TYPE_OBJECT:
329 SET_HTML_CLASS(OBJECT)
330 break;
331 case DOM_HTML_ELEMENT_TYPE_PARAM:
332 SET_HTML_CLASS(PARAM)
333 break;
334 case DOM_HTML_ELEMENT_TYPE_APPLET:
335 SET_HTML_CLASS(APPLET)
336 break;
337 case DOM_HTML_ELEMENT_TYPE_MAP:
338 SET_HTML_CLASS(MAP)
339 break;
340 case DOM_HTML_ELEMENT_TYPE_AREA:
341 SET_HTML_CLASS(AREA)
342 break;
343 case DOM_HTML_ELEMENT_TYPE_SCRIPT:
344 SET_HTML_CLASS(SCRIPT)
345 break;
346 case DOM_HTML_ELEMENT_TYPE_CAPTION:
347 SET_HTML_CLASS(TABLECAPTION)
348 break;
349 case DOM_HTML_ELEMENT_TYPE_TD:
350 case DOM_HTML_ELEMENT_TYPE_TH:
351 SET_HTML_CLASS(TABLECELL)
352 break;
353 case DOM_HTML_ELEMENT_TYPE_COL:
354 case DOM_HTML_ELEMENT_TYPE_COLGROUP:
355 SET_HTML_CLASS(TABLECOL)
356 break;
357 case DOM_HTML_ELEMENT_TYPE_THEAD:
358 case DOM_HTML_ELEMENT_TYPE_TBODY:
359 case DOM_HTML_ELEMENT_TYPE_TFOOT:
360 SET_HTML_CLASS(TABLESECTION)
361 break;
362 case DOM_HTML_ELEMENT_TYPE_TABLE:
363 SET_HTML_CLASS(TABLE)
364 break;
365 case DOM_HTML_ELEMENT_TYPE_TR:
366 SET_HTML_CLASS(TABLEROW)
367 break;
368 case DOM_HTML_ELEMENT_TYPE_STYLE:
369 SET_HTML_CLASS(STYLE)
370 break;
371 case DOM_HTML_ELEMENT_TYPE_FRAMESET:
372 SET_HTML_CLASS(FRAMESET)
373 break;
374 case DOM_HTML_ELEMENT_TYPE_FRAME:
375 SET_HTML_CLASS(FRAME)
376 break;
377 case DOM_HTML_ELEMENT_TYPE_IFRAME:
379 break;
380 case DOM_HTML_ELEMENT_TYPE_ISINDEX:
381 SET_HTML_CLASS(ISINDEX)
382 break;
383 case DOM_HTML_ELEMENT_TYPE_CANVAS:
384 SET_HTML_CLASS(CANVAS)
385 break;
386 case DOM_HTML_ELEMENT_TYPE__COUNT:
387 assert(type != DOM_HTML_ELEMENT_TYPE__COUNT);
389 case DOM_HTML_ELEMENT_TYPE__UNKNOWN:
390 SET_HTML_CLASS(UNKNOWN)
391 break;
392 default:
393 /* Known HTML element without a specialisation */
394 *html_class = PROTO_NAME(HTMLELEMENT);
395 *html_class_len =
396 SLEN(PROTO_NAME(HTML)) +
397 SLEN("ELEMENT");
398 break;
399 }
400 return;
401}
402
403#undef SET_HTML_CLASS
404
405static void
406dukky_push_node_klass(duk_context *ctx, struct dom_node *node)
407{
408 dom_node_type nodetype;
409 dom_exception err;
410
411 err = dom_node_get_node_type(node, &nodetype);
412 if (err != DOM_NO_ERR) {
413 /* Oh bum, just node then */
414 duk_push_string(ctx, PROTO_NAME(NODE));
415 return;
416 }
417
418 switch(nodetype) {
419 case DOM_ELEMENT_NODE: {
420 dom_string *namespace;
421 dom_html_element_type type;
422 const char *html_class;
423 size_t html_class_len;
424 err = dom_node_get_namespace(node, &namespace);
425 if (err != DOM_NO_ERR) {
426 /* Feck it, element */
427 NSLOG(dukky, ERROR,
428 "dom_node_get_namespace() failed");
429 duk_push_string(ctx, PROTO_NAME(ELEMENT));
430 break;
431 }
432 if (namespace == NULL) {
433 /* No namespace, -> element */
434 NSLOG(dukky, DEBUG, "no namespace");
435 duk_push_string(ctx, PROTO_NAME(ELEMENT));
436 break;
437 }
438
439 if (dom_string_isequal(namespace, corestring_dom_html_namespace) == false) {
440 /* definitely not an HTML element of some kind */
441 duk_push_string(ctx, PROTO_NAME(ELEMENT));
442 dom_string_unref(namespace);
443 break;
444 }
445 dom_string_unref(namespace);
446
447 err = dom_html_element_get_tag_type(node, &type);
448 if (err != DOM_NO_ERR) {
449 type = DOM_HTML_ELEMENT_TYPE__UNKNOWN;
450 }
451
453 &html_class, &html_class_len);
454
455 duk_push_lstring(ctx, html_class, html_class_len);
456 break;
457 }
458 case DOM_TEXT_NODE:
459 duk_push_string(ctx, PROTO_NAME(TEXT));
460 break;
461 case DOM_COMMENT_NODE:
462 duk_push_string(ctx, PROTO_NAME(COMMENT));
463 break;
464 case DOM_DOCUMENT_NODE:
465 duk_push_string(ctx, PROTO_NAME(DOCUMENT));
466 break;
467 case DOM_ATTRIBUTE_NODE:
468 case DOM_PROCESSING_INSTRUCTION_NODE:
469 case DOM_DOCUMENT_TYPE_NODE:
470 case DOM_DOCUMENT_FRAGMENT_NODE:
471 case DOM_NOTATION_NODE:
472 case DOM_ENTITY_REFERENCE_NODE:
473 case DOM_ENTITY_NODE:
474 case DOM_CDATA_SECTION_NODE:
475 default:
476 /* Oh bum, just node then */
477 duk_push_string(ctx, PROTO_NAME(NODE));
478 }
479}
480
482dukky_push_node(duk_context *ctx, struct dom_node *node)
483{
484 NSLOG(dukky, DEEPDEBUG, "Pushing node %p", node);
485 /* First check if we can find the node */
486 /* ... */
487 duk_get_global_string(ctx, NODE_MAGIC);
488 /* ... nodes */
489 duk_push_pointer(ctx, node);
490 /* ... nodes nodeptr */
491 duk_get_prop(ctx, -2);
492 /* ... nodes node/undefined */
493 if (!duk_is_undefined(ctx, -1)) {
494 /* ... nodes node */
495 duk_insert(ctx, -2);
496 /* ... node nodes */
497 duk_pop(ctx);
498 /* ... node */
500 duk_dup(ctx, -1);
501 const char * what = duk_safe_to_string(ctx, -1);
502 NSLOG(dukky, DEEPDEBUG, "Found it memoised: %s", what);
503 duk_pop(ctx);
504 }
505 return true;
506 }
507 /* ... nodes undefined */
508 duk_pop_2(ctx);
509 /* ... */
510 /* We couldn't, so now we determine the node type and then
511 * we ask for it to be created
512 */
513 duk_push_pointer(ctx, node);
514 /* ... nodeptr */
515 dukky_push_node_klass(ctx, node);
516 /* ... nodeptr klass */
517 return dukky_push_node_stacked(ctx);
518}
519
520static duk_ret_t
522{
523 return duk_error(ctx, DUK_ERR_ERROR, "Bad constructor");
524}
525
526void
527dukky_inject_not_ctr(duk_context *ctx, int idx, const char *name)
528{
529 /* ... p[idx] ... proto */
531 /* ... p[idx] ... proto cons */
532 duk_insert(ctx, -2);
533 /* ... p[idx] ... cons proto */
534 duk_put_prop_string(ctx, -2, "prototype");
535 /* ... p[idx] ... cons[proto] */
536 duk_put_prop_string(ctx, idx, name);
537 /* ... p ... */
538 return;
539}
540
541/* Duktape heap utility functions */
542
543/* We need to override the defaults because not all platforms are fully ANSI
544 * compatible. E.g. RISC OS gets upset if we malloc or realloc a zero byte
545 * block, as do debugging tools such as Electric Fence by Bruce Perens.
546 */
547
548static void *dukky_alloc_function(void *udata, duk_size_t size)
549{
550 if (size == 0)
551 return NULL;
552
553 return malloc(size);
554}
555
556static void *dukky_realloc_function(void *udata, void *ptr, duk_size_t size)
557{
558 if (ptr == NULL && size == 0)
559 return NULL;
560
561 if (size == 0) {
562 free(ptr);
563 return NULL;
564 }
565
566 return realloc(ptr, size);
567}
568
569
570static void dukky_free_function(void *udata, void *ptr)
571{
572 if (ptr != NULL)
573 free(ptr);
574}
575
576/* exported interface documented in js.h */
578{
579 /** TODO: Forces JS on for our testing, needs changing before a release
580 * lest we incur the wrath of others.
581 */
582 /* Disabled force-on for forthcoming release */
583 /* nsoption_set_bool(enable_javascript, true);
584 */
586}
587
588
589/* exported interface documented in js.h */
590void js_finalise(void)
591{
592 /* NADA for now */
593}
594
595
596/* exported interface documented in js.h */
598js_newheap(int timeout, jsheap **heap)
599{
600 duk_context *ctx;
601 jsheap *ret = calloc(1, sizeof(*ret));
602 *heap = NULL;
603 NSLOG(dukky, DEBUG, "Creating new duktape javascript heap");
604 if (ret == NULL) return NSERROR_NOMEM;
605 ctx = ret->ctx = duk_create_heap(
609 ret,
610 NULL);
611 if (ret->ctx == NULL) { free(ret); return NSERROR_NOMEM; }
612 /* Create the prototype stuffs */
614 duk_push_boolean(ctx, true);
615 duk_put_prop_string(ctx, -2, "protos");
616 duk_put_global_string(ctx, PROTO_MAGIC);
617 /* Create prototypes here */
618 dukky_create_prototypes(ctx);
619 /* Now create the thread map */
620 duk_push_object(ctx);
622
623 *heap = ret;
624 return NSERROR_OK;
625}
626
627
628static void dukky_destroyheap(jsheap *heap)
629{
630 assert(heap->pending_destroy == true);
631 assert(heap->live_threads == 0);
632 NSLOG(dukky, DEBUG, "Destroying duktape javascript context");
633 duk_destroy_heap(heap->ctx);
634 free(heap);
635}
636
637/* exported interface documented in js.h */
639{
640 heap->pending_destroy = true;
641 if (heap->live_threads == 0) {
642 dukky_destroyheap(heap);
643 }
644}
645
646/* Just for here, the CTX is in ret, not thread */
647#define CTX (ret->ctx)
648
649/* exported interface documented in js.h */
650nserror js_newthread(jsheap *heap, void *win_priv, void *doc_priv, jsthread **thread)
651{
652 jsthread *ret;
653 assert(heap != NULL);
654 assert(heap->pending_destroy == false);
655
656 ret = calloc(1, sizeof (*ret));
657 if (ret == NULL) {
658 NSLOG(dukky, ERROR, "Unable to allocate new JS thread structure");
659 return NSERROR_NOMEM;
660 }
661
662 NSLOG(dukky, DEBUG,
663 "New javascript/duktape thread, win_priv=%p, doc_priv=%p",
664 win_priv, doc_priv);
665
666 /* create new thread */
667 duk_get_global_string(heap->ctx, THREAD_MAP); /* ... threads */
668 duk_push_thread(heap->ctx); /* ... threads thread */
669 ret->heap = heap;
670 ret->ctx = duk_require_context(heap->ctx, -1);
671 ret->thread_idx = heap->next_thread++;
672 duk_put_prop_index(heap->ctx, -2, ret->thread_idx);
673 heap->live_threads++;
674 duk_pop(heap->ctx); /* ... */
675 duk_push_int(CTX, 0);
676 duk_push_int(CTX, 1);
677 duk_push_int(CTX, 2);
678 /* Manufacture a Window object */
679 /* win_priv is a browser_window, doc_priv is an html content struct */
680 duk_push_pointer(CTX, win_priv);
681 duk_push_pointer(CTX, doc_priv);
682 dukky_create_object(CTX, PROTO_NAME(WINDOW), 2);
684 duk_put_prop_string(CTX, -2, PROTO_MAGIC);
686
687 /* Now we need to prepare our node mapping table */
689 duk_push_pointer(CTX, NULL);
691 duk_put_prop(CTX, -3);
692 duk_put_global_string(CTX, NODE_MAGIC);
693
694 /* And now the event mapping table */
697
698 /* Now load the polyfills */
699 /* ... */
700 duk_push_string(CTX, "polyfill.js");
701 /* ..., polyfill.js */
703 (const char *)polyfill_js, polyfill_js_len) != 0) {
704 NSLOG(dukky, CRITICAL, "%s", duk_safe_to_string(CTX, -1));
705 NSLOG(dukky, CRITICAL, "Unable to compile polyfill.js, thread aborted");
706 js_destroythread(ret);
707 return NSERROR_INIT_FAILED;
708 }
709 /* ..., (generics.js) */
710 if (dukky_pcall(CTX, 0, true) != 0) {
711 NSLOG(dukky, CRITICAL, "Unable to run polyfill.js, thread aborted");
712 js_destroythread(ret);
713 return NSERROR_INIT_FAILED;
714 }
715 /* ..., result */
716 duk_pop(CTX);
717 /* ... */
718
719 /* Now load the NetSurf table in */
720 /* ... */
721 duk_push_string(CTX, "generics.js");
722 /* ..., generics.js */
724 (const char *)generics_js, generics_js_len) != 0) {
725 NSLOG(dukky, CRITICAL, "%s", duk_safe_to_string(CTX, -1));
726 NSLOG(dukky, CRITICAL, "Unable to compile generics.js, thread aborted");
727 js_destroythread(ret);
728 return NSERROR_INIT_FAILED;
729 }
730 /* ..., (generics.js) */
731 if (dukky_pcall(CTX, 0, true) != 0) {
732 NSLOG(dukky, CRITICAL, "Unable to run generics.js, thread aborted");
733 js_destroythread(ret);
734 return NSERROR_INIT_FAILED;
735 }
736 /* ..., result */
737 duk_pop(CTX);
738 /* ... */
740 /* ..., Win */
741 duk_get_prop_string(CTX, -1, "NetSurf");
742 /* ..., Win, NetSurf */
744 /* ..., Win */
745 duk_del_prop_string(CTX, -1, "NetSurf");
746 duk_pop(CTX);
747 /* ... */
748
749 dukky_log_stack_frame(CTX, "New thread created");
750 NSLOG(dukky, DEBUG, "New thread is %p in heap %p", thread, heap);
751 *thread = ret;
752
753 return NSERROR_OK;
754}
755
756/* Now switch to the long term CTX behaviour */
757#undef CTX
758#define CTX (thread->ctx)
759
760/* exported interface documented in js.h */
762{
763 /* We can always close down a thread, it might just confuse
764 * the code running, though we don't mind since we're in the
765 * process of destruction at this point
766 */
768
769 /* Closing down the extant thread */
770 NSLOG(dukky, DEBUG, "Closing down extant thread %p in heap %p", thread, thread->heap);
771 duk_get_global_string(CTX, MAGIC(closedownThread));
772 dukky_pcall(CTX, 0, true);
773
774 /* Restore whatever stack we had */
775 duk_set_top(CTX, top);
776
777 return NSERROR_OK;
778}
779
780/**
781 * Destroy a Duktape thread
782 */
783static void dukky_destroythread(jsthread *thread)
784{
785 jsheap *heap = thread->heap;
786
787 assert(thread->in_use == 0);
788 assert(thread->pending_destroy == true);
789
790 /* Closing down the extant thread */
791 NSLOG(dukky, DEBUG, "Closing down extant thread %p in heap %p", thread, heap);
792 duk_get_global_string(CTX, MAGIC(closedownThread));
793 dukky_pcall(CTX, 0, true);
794
795 /* Now delete the thread from the heap */
796 duk_get_global_string(heap->ctx, THREAD_MAP); /* ... threads */
797 duk_del_prop_index(heap->ctx, -1, thread->thread_idx);
798 duk_pop(heap->ctx); /* ... */
799
800 /* We can now free the thread object */
801 free(thread);
802
803 /* Finally give the heap a chance to clean up */
804 duk_gc(heap->ctx, 0);
805 duk_gc(heap->ctx, DUK_GC_COMPACT);
806 heap->live_threads--;
807
808 /* And if the heap should now go, blow it away */
809 if (heap->pending_destroy == true && heap->live_threads == 0) {
810 dukky_destroyheap(heap);
811 }
812}
813
814/* exported interface documented in js.h */
816{
817 thread->pending_destroy = true;
818 if (thread->in_use == 0) {
819 dukky_destroythread(thread);
820 }
821}
822
823static void dukky_enter_thread(jsthread *thread)
824{
825 assert(thread != NULL);
826 thread->in_use++;
827}
828
829static void dukky_leave_thread(jsthread *thread)
830{
831 assert(thread != NULL);
832 assert(thread->in_use > 0);
833
834 thread->in_use--;
835 if (thread->in_use == 0 && thread->pending_destroy == true) {
836 dukky_destroythread(thread);
837 }
838}
839
841{
842#define JS_EXEC_TIMEOUT_MS 10000 /* 10 seconds */
843 jsheap *heap = (jsheap *) udata;
844 uint64_t now;
845
846 (void) nsu_getmonotonic_ms(&now);
847
848 /* This function may be called during duk heap construction,
849 * so only test for execution timeout if we've recorded a
850 * start time.
851 */
852 return heap->exec_start_time != 0 &&
853 now > (heap->exec_start_time + JS_EXEC_TIMEOUT_MS);
854}
855
857{
858 /* stack is ..., errobj */
859 duk_dup_top(ctx);
860 /* ..., errobj, errobj */
861 NSLOG(jserrors, WARNING, "Uncaught error in JS: %s", duk_safe_to_stacktrace(ctx, -1));
862 /* ..., errobj, errobj.stackstring */
863 duk_pop(ctx);
864 /* ..., errobj */
865}
866
868{
870 jsheap *heap;
871 duk_get_memory_functions(ctx, &funcs);
872 heap = funcs.udata;
873 (void) nsu_getmonotonic_ms(&heap->exec_start_time);
874}
875
876duk_int_t dukky_pcall(duk_context *ctx, duk_size_t argc, bool reset_timeout)
877{
878 if (reset_timeout) {
880 }
881
882 duk_int_t ret = duk_pcall(ctx, argc);
883 if (ret) {
884 /* Something went wrong calling this... */
885 dukky_dump_error(ctx);
886 }
887
888 return ret;
889}
890
891
892void dukky_push_generics(duk_context *ctx, const char *generic)
893{
894 /* ... */
896 /* ..., generics */
897 duk_get_prop_string(ctx, -1, generic);
898 /* ..., generics, generic */
899 duk_remove(ctx, -2);
900 /* ..., generic */
901}
902
904{
906 return 1;
907}
908
909void dukky_log_stack_frame(duk_context *ctx, const char * reason)
910{
911 if (duk_safe_call(ctx, dukky_push_context_dump, NULL, 0, 1) != 0) {
912 duk_pop(ctx);
913 duk_push_string(ctx, "[???]");
914 }
915 NSLOG(dukky, DEEPDEBUG, "%s, stack is: %s", reason, duk_safe_to_string(ctx, -1));
916 duk_pop(ctx);
917}
918
919
920/* exported interface documented in js.h */
921bool
922js_exec(jsthread *thread, const uint8_t *txt, size_t txtlen, const char *name)
923{
924 bool ret = false;
925 assert(thread);
926
927 if (txt == NULL || txtlen == 0) {
928 return false;
929 }
930
931 if (thread->pending_destroy) {
932 NSLOG(dukky, DEEPDEBUG, "Skipping exec call because thread is dead");
933 return false;
934 }
935
936 dukky_enter_thread(thread);
937
938 duk_set_top(CTX, 0);
939 NSLOG(dukky, DEEPDEBUG, "Running %"PRIsizet" bytes from %s", txtlen, name);
940 /* NSLOG(dukky, DEEPDEBUG, "\n%s\n", txt); */
941
943 if (name != NULL) {
944 duk_push_string(CTX, name);
945 } else {
946 duk_push_string(CTX, "?unknown source?");
947 }
950 (const char *)txt,
951 txtlen) != 0) {
952 NSLOG(dukky, DEBUG, "Failed to compile JavaScript input");
953 goto handle_error;
954 }
955
956 if (duk_pcall(CTX, 0/*nargs*/) == DUK_EXEC_ERROR) {
957 NSLOG(dukky, DEBUG, "Failed to execute JavaScript");
958 goto handle_error;
959 }
960
961 if (duk_get_top(CTX) == 0) duk_push_boolean(CTX, false);
962 NSLOG(dukky, DEEPDEBUG, "Returning %s",
963 duk_get_boolean(CTX, 0) ? "true" : "false");
964 ret = duk_get_boolean(CTX, 0);
965 goto out;
966
967handle_error:
969out:
970 dukky_leave_thread(thread);
971 return ret;
972}
973
974static const char* dukky_event_proto(dom_event *evt)
975{
976 const char *ret = PROTO_NAME(EVENT);
977 dom_string *type = NULL;
978 dom_exception err;
979
980 err = dom_event_get_type(evt, &type);
981 if (err != DOM_NO_ERR) {
982 goto out;
983 }
984
985 if (dom_string_isequal(type, corestring_dom_keydown)) {
986 ret = PROTO_NAME(KEYBOARDEVENT);
987 goto out;
988 } else if (dom_string_isequal(type, corestring_dom_keyup)) {
989 ret = PROTO_NAME(KEYBOARDEVENT);
990 goto out;
991 } else if (dom_string_isequal(type, corestring_dom_keypress)) {
992 ret = PROTO_NAME(KEYBOARDEVENT);
993 goto out;
994 }
995
996out:
997 if (type != NULL) {
998 dom_string_unref(type);
999 }
1000
1001 return ret;
1002}
1003
1004/*** New style event handling ***/
1005
1006void dukky_push_event(duk_context *ctx, dom_event *evt)
1007{
1008 /* ... */
1010 /* ... events */
1011 duk_push_pointer(ctx, evt);
1012 /* ... events eventptr */
1013 duk_get_prop(ctx, -2);
1014 /* ... events event? */
1015 if (duk_is_undefined(ctx, -1)) {
1016 /* ... events undefined */
1017 duk_pop(ctx);
1018 /* ... events */
1019 duk_push_pointer(ctx, evt);
1021 /* ... events err */
1022 duk_pop(ctx);
1023 /* ... events */
1024 duk_push_object(ctx);
1025 /* ... events eobj[meh] */
1026 }
1027 /* ... events eobj */
1028 duk_push_pointer(ctx, evt);
1029 /* ... events eobj eventptr */
1030 duk_dup(ctx, -2);
1031 /* ... events eobj eventptr eobj */
1032 duk_put_prop(ctx, -4);
1033 /* ... events eobj */
1034 }
1035 /* ... events event */
1036 duk_replace(ctx, -2);
1037 /* ... event */
1038}
1039
1040static void dukky_push_handler_code_(duk_context *ctx, dom_string *name,
1041 dom_event_target *et)
1042{
1043 dom_string *onname, *val;
1044 dom_element *ele = (dom_element *)et;
1045 dom_exception exc;
1046 dom_node_type ntype;
1047
1048 /* If et is NULL, then we're actually dealing with the Window object
1049 * which has no default handlers and no way to assign handlers
1050 * which aren't directly stored in the HANDLER_MAGIC
1051 */
1052 if (et == NULL) {
1053 duk_push_lstring(ctx, "", 0);
1054 return;
1055 }
1056
1057 /* The rest of this assumes et is a proper event target and expands
1058 * out from there based on the assumption that all valid event targets
1059 * are nodes.
1060 */
1061 exc = dom_node_get_node_type(et, &ntype);
1062 if (exc != DOM_NO_ERR) {
1063 duk_push_lstring(ctx, "", 0);
1064 return;
1065 }
1066
1067 if (ntype != DOM_ELEMENT_NODE) {
1068 duk_push_lstring(ctx, "", 0);
1069 return;
1070 }
1071
1072 exc = dom_string_concat(corestring_dom_on, name, &onname);
1073 if (exc != DOM_NO_ERR) {
1074 duk_push_lstring(ctx, "", 0);
1075 return;
1076 }
1077
1078 exc = dom_element_get_attribute(ele, onname, &val);
1079 if ((exc != DOM_NO_ERR) || (val == NULL)) {
1080 dom_string_unref(onname);
1081 duk_push_lstring(ctx, "", 0);
1082 return;
1083 }
1084
1085 dom_string_unref(onname);
1086 duk_push_lstring(ctx, dom_string_data(val), dom_string_length(val));
1087 dom_string_unref(val);
1088}
1089
1091 dom_string *name,
1092 dom_event_target *et)
1093{
1094 /* Must be entered as:
1095 * ... node(et)
1096 */
1098 /* ... node handlers */
1099 duk_push_lstring(ctx, dom_string_data(name), dom_string_length(name));
1100 /* ... node handlers name */
1101 duk_get_prop(ctx, -2);
1102 /* ... node handlers handler? */
1103 if (duk_is_undefined(ctx, -1)) {
1104 /* ... node handlers undefined */
1105 duk_pop_2(ctx);
1106 /* ... node */
1107 dukky_push_handler_code_(ctx, name, et);
1108 /* ... node handlercode? */
1109 /* TODO: If this is null, clean up and propagate */
1110 /* ... node handlercode */
1111 /** @todo This is entirely wrong, but it's hard to get right */
1112 duk_push_string(ctx, "function (event) {");
1113 /* ... node handlercode prefix */
1114 duk_insert(ctx, -2);
1115 /* ... node prefix handlercode */
1116 duk_push_string(ctx, "}");
1117 /* ... node prefix handlercode suffix */
1118 duk_concat(ctx, 3);
1119 /* ... node fullhandlersrc */
1120 duk_push_string(ctx, "internal raw uncompiled handler");
1121 /* ... node fullhandlersrc filename */
1122 if (duk_pcompile(ctx, DUK_COMPILE_FUNCTION) != 0) {
1123 /* ... node err */
1124 NSLOG(dukky, DEBUG,
1125 "Unable to proceed with handler, could not compile");
1126 duk_pop_2(ctx);
1127 return false;
1128 }
1129 /* ... node handler */
1130 duk_insert(ctx, -2);
1131 /* ... handler node */
1132 } else {
1133 /* ... node handlers handler */
1134 duk_insert(ctx, -3);
1135 /* ... handler node handlers */
1136 duk_pop(ctx);
1137 /* ... handler node */
1138 }
1139 /* ... handler node */
1140 return true;
1141}
1142
1143static void dukky_generic_event_handler(dom_event *evt, void *pw)
1144{
1145 duk_context *ctx = (duk_context *)pw;
1146 dom_string *name;
1147 dom_exception exc;
1148 dom_event_target *targ;
1149 dom_event_flow_phase phase;
1150 duk_uarridx_t idx;
1152
1153 NSLOG(dukky, DEBUG, "Handling an event in duktape interface...");
1154 exc = dom_event_get_type(evt, &name);
1155 if (exc != DOM_NO_ERR) {
1156 NSLOG(dukky, DEBUG, "Unable to find the event name");
1157 return;
1158 }
1159 NSLOG(dukky, DEBUG, "Event's name is %*s", (int)dom_string_length(name),
1160 dom_string_data(name));
1161 exc = dom_event_get_event_phase(evt, &phase);
1162 if (exc != DOM_NO_ERR) {
1163 NSLOG(dukky, WARNING, "Unable to get event phase");
1164 return;
1165 }
1166 NSLOG(dukky, DEBUG, "Event phase is: %s (%d)",
1167 phase == DOM_CAPTURING_PHASE ? "capturing" : phase == DOM_AT_TARGET ? "at-target" : phase == DOM_BUBBLING_PHASE ? "bubbling" : "unknown",
1168 (int)phase);
1169
1170 exc = dom_event_get_current_target(evt, &targ);
1171 if (exc != DOM_NO_ERR) {
1172 dom_string_unref(name);
1173 NSLOG(dukky, DEBUG, "Unable to find the event target");
1174 return;
1175 }
1176
1177 /* If we're capturing right now, we skip the 'event handler'
1178 * and go straight to the extras
1179 */
1180 if (phase == DOM_CAPTURING_PHASE)
1181 goto handle_extras;
1182
1183 /* ... */
1184 if (dukky_push_node(ctx, (dom_node *)targ) == false) {
1185 dom_string_unref(name);
1186 dom_node_unref(targ);
1187 NSLOG(dukky, DEBUG,
1188 "Unable to push JS node representation?!");
1189 return;
1190 }
1191 /* ... node */
1193 ctx, name, (dom_event_target *)targ) == false) {
1194 /* ... */
1195 goto handle_extras;
1196 }
1197 /* ... handler node */
1198 dukky_push_event(ctx, evt);
1199 /* ... handler node event */
1201 if (duk_pcall_method(ctx, 1) != 0) {
1202 /* Failed to run the method */
1203 /* ... err */
1204 NSLOG(dukky, DEBUG,
1205 "OH NOES! An error running a callback. Meh.");
1206 exc = dom_event_stop_immediate_propagation(evt);
1207 if (exc != DOM_NO_ERR)
1208 NSLOG(dukky, DEBUG,
1209 "WORSE! could not stop propagation");
1210 duk_get_prop_string(ctx, -1, "name");
1211 duk_get_prop_string(ctx, -2, "message");
1212 duk_get_prop_string(ctx, -3, "fileName");
1213 duk_get_prop_string(ctx, -4, "lineNumber");
1214 duk_get_prop_string(ctx, -5, "stack");
1215 /* ... err name message fileName lineNumber stack */
1216 NSLOG(dukky, DEBUG, "Uncaught error in JS: %s: %s",
1217 duk_safe_to_string(ctx, -5),
1218 duk_safe_to_string(ctx, -4));
1219 NSLOG(dukky, INFO, " was at: %s line %s",
1220 duk_safe_to_string(ctx, -3),
1221 duk_safe_to_string(ctx, -2));
1222 NSLOG(dukky, INFO, " Stack trace: %s",
1223 duk_safe_to_string(ctx, -1));
1224
1225 duk_pop_n(ctx, 6);
1226 /* ... */
1227 goto handle_extras;
1228 }
1229 /* ... result */
1230 if (duk_is_boolean(ctx, -1) &&
1231 duk_to_boolean(ctx, -1) == 0) {
1232 dom_event_prevent_default(evt);
1233 }
1234 duk_pop(ctx);
1235handle_extras:
1236 /* ... */
1237 duk_push_lstring(ctx, dom_string_data(name), dom_string_length(name));
1238 dukky_push_node(ctx, (dom_node *)targ);
1239 /* ... type node */
1240 if (dukky_event_target_push_listeners(ctx, true)) {
1241 /* Nothing to do */
1242 duk_pop(ctx);
1243 goto out;
1244 }
1245 /* ... sublisteners */
1246 duk_push_array(ctx);
1247 /* ... sublisteners copy */
1248 idx = 0;
1249 while (duk_get_prop_index(ctx, -2, idx)) {
1250 /* ... sublisteners copy handler */
1251 duk_get_prop_index(ctx, -1, 1);
1252 /* ... sublisteners copy handler flags */
1253 if ((event_listener_flags)duk_to_int(ctx, -1) & ELF_ONCE) {
1254 duk_dup(ctx, -4);
1255 /* ... subl copy handler flags subl */
1256 dukky_shuffle_array(ctx, idx);
1257 duk_pop(ctx);
1258 /* ... subl copy handler flags */
1259 }
1260 duk_pop(ctx);
1261 /* ... sublisteners copy handler */
1262 duk_put_prop_index(ctx, -2, idx);
1263 /* ... sublisteners copy */
1264 idx++;
1265 }
1266 /* ... sublisteners copy undefined */
1267 duk_pop(ctx);
1268 /* ... sublisteners copy */
1269 duk_insert(ctx, -2);
1270 /* ... copy sublisteners */
1271 duk_pop(ctx);
1272 /* ... copy */
1273 idx = 0;
1274 while (duk_get_prop_index(ctx, -1, idx++)) {
1275 /* ... copy handler */
1276 if (duk_get_prop_index(ctx, -1, 2)) {
1277 /* ... copy handler meh */
1278 duk_pop_2(ctx);
1279 continue;
1280 }
1281 duk_pop(ctx);
1282 duk_get_prop_index(ctx, -1, 0);
1283 duk_get_prop_index(ctx, -2, 1);
1284 /* ... copy handler callback flags */
1285 flags = (event_listener_flags)duk_get_int(ctx, -1);
1286 duk_pop(ctx);
1287 /* ... copy handler callback */
1288 if (((phase == DOM_CAPTURING_PHASE) && !(flags & ELF_CAPTURE)) ||
1289 ((phase != DOM_CAPTURING_PHASE) && (flags & ELF_CAPTURE))) {
1290 duk_pop_2(ctx);
1291 /* ... copy */
1292 continue;
1293 }
1294 /* ... copy handler callback */
1295 dukky_push_node(ctx, (dom_node *)targ);
1296 /* ... copy handler callback node */
1297 dukky_push_event(ctx, evt);
1298 /* ... copy handler callback node event */
1300 if (duk_pcall_method(ctx, 1) != 0) {
1301 /* Failed to run the method */
1302 /* ... copy handler err */
1303 NSLOG(dukky, DEBUG,
1304 "OH NOES! An error running a callback. Meh.");
1305 exc = dom_event_stop_immediate_propagation(evt);
1306 if (exc != DOM_NO_ERR)
1307 NSLOG(dukky, DEBUG,
1308 "WORSE! could not stop propagation");
1309 duk_get_prop_string(ctx, -1, "name");
1310 duk_get_prop_string(ctx, -2, "message");
1311 duk_get_prop_string(ctx, -3, "fileName");
1312 duk_get_prop_string(ctx, -4, "lineNumber");
1313 duk_get_prop_string(ctx, -5, "stack");
1314 /* ... err name message fileName lineNumber stack */
1315 NSLOG(dukky, DEBUG, "Uncaught error in JS: %s: %s",
1316 duk_safe_to_string(ctx, -5),
1317 duk_safe_to_string(ctx, -4));
1318 NSLOG(dukky, DEBUG,
1319 " was at: %s line %s",
1320 duk_safe_to_string(ctx, -3),
1321 duk_safe_to_string(ctx, -2));
1322 NSLOG(dukky, DEBUG, " Stack trace: %s",
1323 duk_safe_to_string(ctx, -1));
1324
1325 duk_pop_n(ctx, 7);
1326 /* ... copy */
1327 continue;
1328 }
1329 /* ... copy handler result */
1330 if (duk_is_boolean(ctx, -1) &&
1331 duk_to_boolean(ctx, -1) == 0) {
1332 dom_event_prevent_default(evt);
1333 }
1334 duk_pop_2(ctx);
1335 /* ... copy */
1336 }
1337 duk_pop_2(ctx);
1338out:
1339 /* ... */
1340 dom_node_unref(targ);
1341 dom_string_unref(name);
1342}
1343
1345 struct dom_element *ele,
1346 dom_string *name,
1347 bool capture)
1348{
1349 dom_event_listener *listen = NULL;
1350 dom_exception exc;
1351
1352 /* ... */
1353 if (ele == NULL) {
1354 /* A null element is the Window object */
1356 } else {
1357 /* Non null elements must be pushed as a node object */
1358 if (dukky_push_node(ctx, (struct dom_node *)ele) == false)
1359 return;
1360 }
1361 /* ... node */
1363 /* ... node handlers */
1364 duk_push_lstring(ctx, dom_string_data(name), dom_string_length(name));
1365 /* ... node handlers name */
1366 if (duk_has_prop(ctx, -2)) {
1367 /* ... node handlers */
1368 duk_pop_2(ctx);
1369 /* ... */
1370 return;
1371 }
1372 /* ... node handlers */
1373 duk_push_lstring(ctx, dom_string_data(name), dom_string_length(name));
1374 /* ... node handlers name */
1375 duk_push_boolean(ctx, true);
1376 /* ... node handlers name true */
1377 duk_put_prop(ctx, -3);
1378 /* ... node handlers */
1379 duk_pop_2(ctx);
1380 /* ... */
1381 if (ele == NULL) {
1382 /* Nothing more to do, Window doesn't register in the
1383 * normal event listener flow
1384 */
1385 return;
1386 }
1387
1388 /* Otherwise add an event listener to the element */
1389 exc = dom_event_listener_create(dukky_generic_event_handler, ctx,
1390 &listen);
1391 if (exc != DOM_NO_ERR) return;
1392 exc = dom_event_target_add_event_listener(
1393 ele, name, listen, capture);
1394 if (exc != DOM_NO_ERR) {
1395 NSLOG(dukky, DEBUG,
1396 "Unable to register listener for %p.%*s", ele,
1397 (int)dom_string_length(name), dom_string_data(name));
1398 } else {
1399 NSLOG(dukky, DEBUG, "have registered listener for %p.%*s",
1400 ele, (int)dom_string_length(name), dom_string_data(name));
1401 }
1402 dom_event_listener_unref(listen);
1403}
1404
1405/* The sub-listeners are a list of {callback,flags} tuples */
1406/* We return true if we created a new sublistener table */
1407/* If we're told to not create, but we want to, we still return true */
1409{
1410 bool ret = false;
1411 /* ... type this */
1413 if (duk_is_undefined(ctx, -1)) {
1414 /* ... type this null */
1415 duk_pop(ctx);
1416 duk_push_object(ctx);
1417 duk_dup(ctx, -1);
1418 /* ... type this listeners listeners */
1420 /* ... type this listeners */
1421 }
1422 /* ... type this listeners */
1423 duk_insert(ctx, -3);
1424 /* ... listeners type this */
1425 duk_pop(ctx);
1426 /* ... listeners type */
1427 duk_dup(ctx, -1);
1428 /* ... listeners type type */
1429 duk_get_prop(ctx, -3);
1430 /* ... listeners type ??? */
1431 if (duk_is_undefined(ctx, -1)) {
1432 /* ... listeners type ??? */
1433 if (dont_create == true) {
1434 duk_pop_3(ctx);
1435 duk_push_undefined(ctx);
1436 return true;
1437 }
1438 duk_pop(ctx);
1439 duk_push_array(ctx);
1440 duk_dup(ctx, -2);
1441 duk_dup(ctx, -2);
1442 /* ... listeners type sublisteners type sublisteners */
1443 duk_put_prop(ctx, -5);
1444 /* ... listeners type sublisteners */
1445 ret = true;
1446 }
1447 duk_insert(ctx, -3);
1448 /* ... sublisteners listeners type */
1449 duk_pop_2(ctx);
1450 /* ... sublisteners */
1451 return ret;
1452}
1453
1454/* Shuffle a duktape array "down" one. This involves iterating from
1455 * the index provided, shuffling elements down, until we reach an
1456 * undefined
1457 */
1459{
1460 /* ... somearr */
1461 while (duk_get_prop_index(ctx, -1, idx + 1)) {
1462 duk_put_prop_index(ctx, -2, idx);
1463 idx++;
1464 }
1465 /* ... somearr undefined */
1466 duk_del_prop_index(ctx, -2, idx + 1);
1467 duk_pop(ctx);
1468}
1469
1470
1471void js_handle_new_element(jsthread *thread, struct dom_element *node)
1472{
1473 assert(thread);
1474 assert(node);
1475 dom_namednodemap *map;
1476 dom_exception exc;
1477 dom_ulong idx;
1478 dom_ulong siz;
1479 dom_attr *attr = NULL;
1480 dom_string *key = NULL;
1481 dom_string *nodename;
1482 duk_bool_t is_body = false;
1483
1484 exc = dom_node_get_node_name(node, &nodename);
1485 if (exc != DOM_NO_ERR) return;
1486
1487 if (nodename == corestring_dom_BODY)
1488 is_body = true;
1489
1490 dom_string_unref(nodename);
1491
1492 exc = dom_node_get_attributes(node, &map);
1493 if (exc != DOM_NO_ERR) return;
1494 if (map == NULL) return;
1495
1496 dukky_enter_thread(thread);
1497
1498 exc = dom_namednodemap_get_length(map, &siz);
1499 if (exc != DOM_NO_ERR) goto out;
1500
1501 for (idx = 0; idx < siz; idx++) {
1502 exc = dom_namednodemap_item(map, idx, &attr);
1503 if (exc != DOM_NO_ERR) goto out;
1504 exc = dom_attr_get_name(attr, &key);
1505 if (exc != DOM_NO_ERR) goto out;
1506 if (is_body && (
1507 key == corestring_dom_onblur ||
1508 key == corestring_dom_onerror ||
1509 key == corestring_dom_onfocus ||
1510 key == corestring_dom_onload ||
1511 key == corestring_dom_onresize ||
1512 key == corestring_dom_onscroll)) {
1513 /* This is a forwarded event, it doesn't matter,
1514 * we should skip registering for it and later
1515 * we will register it for Window itself
1516 */
1517 goto skip_register;
1518 }
1519 if (dom_string_length(key) > 2) {
1520 /* Can be on* */
1521 const uint8_t *data = (const uint8_t *)dom_string_data(key);
1522 if (data[0] == 'o' && data[1] == 'n') {
1523 dom_string *sub = NULL;
1524 exc = dom_string_substr(
1525 key, 2, dom_string_length(key),
1526 &sub);
1527 if (exc == DOM_NO_ERR) {
1529 CTX, node, sub, false);
1530 dom_string_unref(sub);
1531 }
1532 }
1533 }
1534 skip_register:
1535 dom_string_unref(key); key = NULL;
1536 dom_node_unref(attr); attr = NULL;
1537 }
1538
1539out:
1540 if (key != NULL)
1541 dom_string_unref(key);
1542
1543 if (attr != NULL)
1544 dom_node_unref(attr);
1545
1546 dom_namednodemap_unref(map);
1547
1548 dukky_leave_thread(thread);
1549}
1550
1551void js_event_cleanup(jsthread *thread, struct dom_event *evt)
1552{
1553 assert(thread);
1554 dukky_enter_thread(thread);
1555 /* ... */
1557 /* ... EVENT_MAP */
1558 duk_push_pointer(CTX, evt);
1559 /* ... EVENT_MAP eventptr */
1560 duk_del_prop(CTX, -2);
1561 /* ... EVENT_MAP */
1562 duk_pop(CTX);
1563 /* ... */
1564 dukky_leave_thread(thread);
1565}
1566
1567bool js_fire_event(jsthread *thread, const char *type, struct dom_document *doc, struct dom_node *target)
1568{
1569 dom_exception exc;
1570 dom_event *evt;
1571 dom_event_target *body;
1572
1573 NSLOG(dukky, DEBUG, "Event: %s (doc=%p, target=%p)", type, doc,
1574 target);
1575
1576 /** @todo Make this more generic, this only handles load and only
1577 * targetting the window, so that we actually stand a chance of
1578 * getting 3.4 out.
1579 */
1580
1581 if (target != NULL)
1582 /* Swallow non-Window-targetted events quietly */
1583 return true;
1584
1585 if (strcmp(type, "load") != 0)
1586 /* Swallow non-load events quietly */
1587 return true;
1588
1589 /* Okay, we're processing load, targetted at Window, do the single
1590 * thing which gets us there, which is to find the appropriate event
1591 * handler and call it. If we have no event handler on Window then
1592 * we divert to the body, and if there's no event handler there
1593 * we swallow the event silently
1594 */
1595
1596 exc = dom_event_create(&evt);
1597 if (exc != DOM_NO_ERR) return true;
1598 exc = dom_event_init(evt, corestring_dom_load, false, false);
1599 if (exc != DOM_NO_ERR) {
1600 dom_event_unref(evt);
1601 return true;
1602 }
1603 dukky_enter_thread(thread);
1604 /* ... */
1606 /* ... handlers */
1607 duk_push_lstring(CTX, "load", 4);
1608 /* ... handlers "load" */
1609 duk_get_prop(CTX, -2);
1610 /* ... handlers handler? */
1611 if (duk_is_undefined(CTX, -1)) {
1612 /* No handler here, *try* and retrieve a handler from
1613 * the body
1614 */
1615 duk_pop(CTX);
1616 /* ... handlers */
1617 exc = dom_html_document_get_body(doc, &body);
1618 if (exc != DOM_NO_ERR) {
1619 dom_event_unref(evt);
1620 dukky_leave_thread(thread);
1621 return true;
1622 }
1623 dukky_push_node(CTX, (struct dom_node *)body);
1624 /* ... handlers bodynode */
1626 CTX, corestring_dom_load, body) == false) {
1627 /* Unref the body, we don't need it any more */
1628 dom_node_unref(body);
1629 /* ... handlers */
1630 duk_pop(CTX);
1631 dukky_leave_thread(thread);
1632 return true;
1633 }
1634 /* Unref the body, we don't need it any more */
1635 dom_node_unref(body);
1636 /* ... handlers handler bodynode */
1637 duk_pop(CTX);
1638 }
1639 /* ... handlers handler */
1640 duk_insert(CTX, -2);
1641 /* ... handler handlers */
1642 duk_pop(CTX);
1643 /* ... handler */
1645 /* ... handler Window */
1646 dukky_push_event(CTX, evt);
1647 /* ... handler Window event */
1649 if (duk_pcall_method(CTX, 1) != 0) {
1650 /* Failed to run the handler */
1651 /* ... err */
1652 NSLOG(dukky, DEBUG,
1653 "OH NOES! An error running a handler. Meh.");
1654 duk_get_prop_string(CTX, -1, "name");
1655 duk_get_prop_string(CTX, -2, "message");
1656 duk_get_prop_string(CTX, -3, "fileName");
1657 duk_get_prop_string(CTX, -4, "lineNumber");
1658 duk_get_prop_string(CTX, -5, "stack");
1659 /* ... err name message fileName lineNumber stack */
1660 NSLOG(dukky, DEBUG, "Uncaught error in JS: %s: %s",
1662 duk_safe_to_string(CTX, -4));
1663 NSLOG(dukky, DEBUG, " was at: %s line %s",
1665 duk_safe_to_string(CTX, -2));
1666 NSLOG(dukky, DEBUG, " Stack trace: %s",
1667 duk_safe_to_string(CTX, -1));
1668
1669 duk_pop_n(CTX, 6);
1670 /* ... */
1671 js_event_cleanup(thread, evt);
1672 dom_event_unref(evt);
1673 dukky_leave_thread(thread);
1674 return true;
1675 }
1676 /* ... result */
1677 duk_pop(CTX);
1678 /* ... */
1679 js_event_cleanup(thread, evt);
1680 dom_event_unref(evt);
1681 dukky_leave_thread(thread);
1682 return true;
1683}
@ IFRAME
Definition: box.h:89
Content handling interface.
nserror javascript_init(void)
Useful interned string pointers (interface).
duk_small_int_t duk_ret_t
Definition: duk_config.h:2076
duk_small_uint_t duk_bool_t
Definition: duk_config.h:2051
duk_uint_t duk_uarridx_t
Definition: duk_config.h:2068
duk_int_fast32_t duk_int_t
Definition: duk_config.h:2011
size_t duk_size_t
Definition: duk_config.h:1996
void js_destroythread(jsthread *thread)
Destroy a javascript thread.
Definition: dukky.c:815
void dukky_push_generics(duk_context *ctx, const char *generic)
Definition: dukky.c:892
static void dukky_destroythread(jsthread *thread)
Destroy a Duktape thread.
Definition: dukky.c:783
static void dukky_dump_error(duk_context *ctx)
Definition: dukky.c:856
void js_destroyheap(jsheap *heap)
Destroy a previously created heap.
Definition: dukky.c:638
void dukky_shuffle_array(duk_context *ctx, duk_uarridx_t idx)
Definition: dukky.c:1458
#define HANDLER_LISTENER_MAGIC
Definition: dukky.c:50
void js_handle_new_element(jsthread *thread, struct dom_element *node)
Handle a new element being created.
Definition: dukky.c:1471
void dukky_inject_not_ctr(duk_context *ctx, int idx, const char *name)
Definition: dukky.c:527
static void dukky_enter_thread(jsthread *thread)
Definition: dukky.c:823
static void dukky_leave_thread(jsthread *thread)
Definition: dukky.c:829
#define GENERICS_MAGIC
Definition: dukky.c:53
void js_event_cleanup(jsthread *thread, struct dom_event *evt)
Handle an event propagation finished callback.
Definition: dukky.c:1551
void js_finalise(void)
finalise javascript interpreter
Definition: dukky.c:590
void dukky_push_event(duk_context *ctx, dom_event *evt)
Definition: dukky.c:1006
nserror js_newheap(int timeout, jsheap **heap)
Create a new javascript heap.
Definition: dukky.c:598
static void dukky_html_element_class_from_tag_type(dom_html_element_type type, const char **html_class, size_t *html_class_len)
Definition: dukky.c:212
#define CTX
Definition: dukky.c:758
bool dukky_get_current_value_of_event_handler(duk_context *ctx, dom_string *name, dom_event_target *et)
Definition: dukky.c:1090
#define HANDLER_MAGIC
Definition: dukky.c:51
#define EVENT_MAGIC
Definition: dukky.c:49
static void * dukky_realloc_function(void *udata, void *ptr, duk_size_t size)
Definition: dukky.c:556
static void dukky_generic_event_handler(dom_event *evt, void *pw)
Definition: dukky.c:1143
duk_int_t dukky_pcall(duk_context *ctx, duk_size_t argc, bool reset_timeout)
Definition: dukky.c:876
nserror js_newthread(jsheap *heap, void *win_priv, void *doc_priv, jsthread **thread)
Create a new javascript thread.
Definition: dukky.c:650
duk_bool_t dukky_push_node_stacked(duk_context *ctx)
Definition: dukky.c:147
static void dukky_push_handler_code_(duk_context *ctx, dom_string *name, dom_event_target *et)
Definition: dukky.c:1040
static void dukky_destroyheap(jsheap *heap)
Definition: dukky.c:628
void dukky_log_stack_frame(duk_context *ctx, const char *reason)
Definition: dukky.c:909
static void dukky_push_node_klass(duk_context *ctx, struct dom_node *node)
Definition: dukky.c:406
duk_bool_t dukky_push_node(duk_context *ctx, struct dom_node *node)
Definition: dukky.c:482
#define THREAD_MAP
Definition: dukky.c:54
duk_bool_t dukky_check_timeout(void *udata)
Definition: dukky.c:840
#define EVENT_LISTENER_JS_MAGIC
Definition: dukky.c:52
void js_initialise(void)
Initialise javascript interpreter.
Definition: dukky.c:577
bool js_fire_event(jsthread *thread, const char *type, struct dom_document *doc, struct dom_node *target)
fire an event at a dom node
Definition: dukky.c:1567
static void dukky_reset_start_time(duk_context *ctx)
Definition: dukky.c:867
static duk_int_t dukky_push_context_dump(duk_context *ctx, void *udata)
Definition: dukky.c:903
#define SET_HTML_CLASS(CLASS)
Definition: dukky.c:205
duk_ret_t dukky_create_object(duk_context *ctx, const char *name, int args)
Definition: dukky.c:116
static duk_ret_t dukky_populate_object(duk_context *ctx, void *udata)
Definition: dukky.c:78
static void * dukky_alloc_function(void *udata, duk_size_t size)
Definition: dukky.c:548
static duk_ret_t dukky_bad_constructor(duk_context *ctx)
Definition: dukky.c:521
static const char * dukky_event_proto(dom_event *evt)
Definition: dukky.c:974
void dukky_register_event_listener_for(duk_context *ctx, struct dom_element *ele, dom_string *name, bool capture)
Definition: dukky.c:1344
#define JS_EXEC_TIMEOUT_MS
static void dukky_free_function(void *udata, void *ptr)
Definition: dukky.c:570
bool dukky_event_target_push_listeners(duk_context *ctx, bool dont_create)
Definition: dukky.c:1408
bool js_exec(jsthread *thread, const uint8_t *txt, size_t txtlen, const char *name)
execute some javascript in a context
Definition: dukky.c:922
nserror js_closethread(jsthread *thread)
Close a javascript thread.
Definition: dukky.c:761
Duktapeish implementation of javascript engine functions, prototypes.
event_listener_flags
Definition: dukky.h:42
@ ELF_ONCE
Definition: dukky.h:45
@ ELF_CAPTURE
Definition: dukky.h:43
DUK_EXTERNAL void duk_replace(duk_hthread *thr, duk_idx_t to_idx)
Definition: duktape.c:19937
DUK_EXTERNAL const char * duk_get_string(duk_hthread *thr, duk_idx_t idx)
Definition: duktape.c:20443
DUK_EXTERNAL void duk_set_global_object(duk_hthread *thr)
Definition: duktape.c:17230
DUK_EXTERNAL duk_bool_t duk_del_prop_index(duk_hthread *thr, duk_idx_t obj_idx, duk_uarridx_t arr_idx)
Definition: duktape.c:17952
DUK_EXTERNAL duk_bool_t duk_del_prop(duk_hthread *thr, duk_idx_t obj_idx)
Definition: duktape.c:17899
DUK_EXTERNAL duk_bool_t duk_get_boolean(duk_hthread *thr, duk_idx_t idx)
Definition: duktape.c:20231
DUK_EXTERNAL void duk_pop_3(duk_hthread *thr)
Definition: duktape.c:24833
DUK_EXTERNAL void duk_push_global_object(duk_hthread *thr)
Definition: duktape.c:23357
DUK_EXTERNAL duk_idx_t duk_get_top(duk_hthread *thr)
Definition: duktape.c:19072
DUK_EXTERNAL void duk_gc(duk_hthread *thr, duk_uint_t flags)
Definition: duktape.c:17625
DUK_EXTERNAL duk_bool_t duk_put_global_string(duk_hthread *thr, const char *key)
Definition: duktape.c:18451
DUK_EXTERNAL duk_int_t duk_safe_call(duk_hthread *thr, duk_safe_call_function func, void *udata, duk_idx_t nargs, duk_idx_t nrets)
Definition: duktape.c:15481
DUK_EXTERNAL void duk_push_null(duk_hthread *thr)
Definition: duktape.c:22995
DUK_EXTERNAL void duk_call(duk_hthread *thr, duk_idx_t nargs)
Definition: duktape.c:15320
DUK_EXTERNAL const char * duk_push_lstring(duk_hthread *thr, const char *str, duk_size_t len)
Definition: duktape.c:23117
DUK_EXTERNAL duk_bool_t duk_is_undefined(duk_hthread *thr, duk_idx_t idx)
Definition: duktape.c:22660
DUK_EXTERNAL void duk_destroy_heap(duk_hthread *thr)
Definition: duktape.c:17145
DUK_EXTERNAL duk_bool_t duk_put_prop_index(duk_hthread *thr, duk_idx_t obj_idx, duk_uarridx_t arr_idx)
Definition: duktape.c:17870
DUK_EXTERNAL duk_int_t duk_pcall_method(duk_hthread *thr, duk_idx_t nargs)
Definition: duktape.c:15440
DUK_EXTERNAL void duk_dup_top(duk_hthread *thr)
Definition: duktape.c:19792
DUK_EXTERNAL duk_hthread * duk_require_context(duk_hthread *thr, duk_idx_t idx)
Definition: duktape.c:21074
DUK_EXTERNAL void duk_push_int(duk_hthread *thr, duk_int_t val)
Definition: duktape.c:23046
DUK_EXTERNAL void duk_get_memory_functions(duk_hthread *thr, duk_memory_functions *out_funcs)
Definition: duktape.c:17610
DUK_EXTERNAL void duk_pop(duk_hthread *thr)
Definition: duktape.c:24715
DUK_EXTERNAL void duk_push_context_dump(duk_hthread *thr)
Definition: duktape.c:16824
DUK_EXTERNAL duk_int_t duk_to_int(duk_hthread *thr, duk_idx_t idx)
Definition: duktape.c:21660
DUK_EXTERNAL duk_bool_t duk_is_boolean(duk_hthread *thr, duk_idx_t idx)
Definition: duktape.c:22670
DUK_EXTERNAL void duk_remove(duk_hthread *thr, duk_idx_t idx)
Definition: duktape.c:19974
DUK_EXTERNAL duk_bool_t duk_put_prop_string(duk_hthread *thr, duk_idx_t obj_idx, const char *key)
Definition: duktape.c:17836
DUK_EXTERNAL void duk_set_prototype(duk_hthread *thr, duk_idx_t idx)
Definition: duktape.c:18553
DUK_EXTERNAL duk_hthread * duk_create_heap(duk_alloc_function alloc_func, duk_realloc_function realloc_func, duk_free_function free_func, void *heap_udata, duk_fatal_function fatal_handler)
Definition: duktape.c:17094
DUK_EXTERNAL duk_bool_t duk_del_prop_string(duk_hthread *thr, duk_idx_t obj_idx, const char *key)
Definition: duktape.c:17922
DUK_EXTERNAL duk_int_t duk_pcall(duk_hthread *thr, duk_idx_t nargs)
Definition: duktape.c:15390
DUK_EXTERNAL duk_bool_t duk_has_prop(duk_hthread *thr, duk_idx_t obj_idx)
Definition: duktape.c:17984
DUK_EXTERNAL duk_idx_t duk_push_c_function(duk_hthread *thr, duk_c_function func, duk_int_t nargs)
Definition: duktape.c:23806
DUK_EXTERNAL void duk_push_boolean(duk_hthread *thr, duk_bool_t val)
Definition: duktape.c:23004
DUK_EXTERNAL duk_bool_t duk_get_prop_string(duk_hthread *thr, duk_idx_t obj_idx, const char *key)
Definition: duktape.c:17675
DUK_EXTERNAL void duk_push_pointer(duk_hthread *thr, void *val)
Definition: duktape.c:23198
DUK_EXTERNAL duk_idx_t duk_push_object(duk_hthread *thr)
Definition: duktape.c:23545
DUK_EXTERNAL duk_idx_t duk_push_array(duk_hthread *thr)
Definition: duktape.c:23555
DUK_EXTERNAL void duk_insert(duk_hthread *thr, duk_idx_t to_idx)
Definition: duktape.c:19840
DUK_EXTERNAL void duk_pop_2(duk_hthread *thr)
Definition: duktape.c:24804
DUK_EXTERNAL void duk_concat(duk_hthread *thr, duk_idx_t count)
Definition: duktape.c:25701
DUK_EXTERNAL void duk_push_undefined(duk_hthread *thr)
Definition: duktape.c:22983
DUK_EXTERNAL duk_bool_t duk_get_prop(duk_hthread *thr, duk_idx_t obj_idx)
Definition: duktape.c:17652
DUK_EXTERNAL const char * duk_push_string(duk_hthread *thr, const char *str)
Definition: duktape.c:23151
DUK_EXTERNAL void duk_dup(duk_hthread *thr, duk_idx_t from_idx)
Definition: duktape.c:19777
DUK_EXTERNAL duk_bool_t duk_put_prop(duk_hthread *thr, duk_idx_t obj_idx)
Definition: duktape.c:17831
DUK_EXTERNAL void duk_pop_n(duk_hthread *thr, duk_idx_t count)
Definition: duktape.c:24627
DUK_EXTERNAL const char * duk_safe_to_stacktrace(duk_hthread *thr, duk_idx_t idx)
Definition: duktape.c:21844
DUK_EXTERNAL void duk_set_top(duk_hthread *thr, duk_idx_t idx)
Definition: duktape.c:19098
DUK_EXTERNAL duk_int_t duk_get_int(duk_hthread *thr, duk_idx_t idx)
Definition: duktape.c:20341
DUK_EXTERNAL duk_bool_t duk_get_prop_index(duk_hthread *thr, duk_idx_t obj_idx, duk_uarridx_t arr_idx)
Definition: duktape.c:17705
DUK_EXTERNAL duk_bool_t duk_get_global_string(duk_hthread *thr, const char *key)
Definition: duktape.c:18392
DUK_EXTERNAL duk_bool_t duk_to_boolean(duk_hthread *thr, duk_idx_t idx)
Definition: duktape.c:21531
#define DUK_GC_COMPACT
Definition: duktape.h:437
#define duk_push_thread(ctx)
Definition: duktape.h:740
#define DUK_EXEC_SUCCESS
Definition: duktape.h:459
#define DUK_COMPILE_FUNCTION
Definition: duktape.h:370
#define duk_pcompile(ctx, flags)
Definition: duktape.h:1260
#define duk_pcompile_lstring_filename(ctx, flags, buf, len)
Definition: duktape.h:1310
#define duk_safe_to_string(ctx, idx)
Definition: duktape.h:1022
#define duk_error
Definition: duktape.h:579
#define DUK_EXEC_ERROR
Definition: duktape.h:460
#define DUK_ERR_ERROR
Definition: duktape.h:441
#define DUK_COMPILE_EVAL
Definition: duktape.h:369
nserror
Enumeration of error codes.
Definition: errors.h:29
@ NSERROR_INIT_FAILED
Initialisation failed.
Definition: errors.h:38
@ NSERROR_NOMEM
Memory exhaustion.
Definition: errors.h:32
@ NSERROR_OK
No error.
Definition: errors.h:30
const char * type
Definition: filetype.cpp:44
#define MAGIC
Definition: textarea.c:55
Netsurf additional integer type formatting macros.
#define PRIsizet
c99 standard printf formatting for size_t type
Definition: inttypes.h:53
Interface to javascript engine functions.
@ NSLOG_LEVEL_DEEPDEBUG
Definition: log.h:94
#define NSLOG(catname, level, logmsg, args...)
Definition: log.h:116
#define NSLOG_COMPILED_MIN_LEVEL
Definition: log.h:74
dukky javascript heap
Definition: dukky.c:59
duk_uarridx_t next_thread
monotonic thread counter
Definition: dukky.c:61
duk_context * ctx
duktape base context
Definition: dukky.c:60
bool pending_destroy
Whether this heap is pending destruction.
Definition: dukky.c:62
uint64_t exec_start_time
Definition: dukky.c:64
unsigned int live_threads
number of live threads
Definition: dukky.c:63
dukky javascript thread
Definition: dukky.c:70
duk_context * ctx
The duktape thread context.
Definition: dukky.c:74
jsheap * heap
The heap this thread belongs to.
Definition: dukky.c:73
bool pending_destroy
Whether this thread is pending destruction.
Definition: dukky.c:71
duk_uarridx_t thread_idx
The thread number.
Definition: dukky.c:75
unsigned int in_use
The number of times this thread is in use.
Definition: dukky.c:72
Option reading and saving interface.
Interface to a number of general purpose functionality.
#define fallthrough
switch fall through
Definition: utils.h:115
#define SLEN(x)
Calculate length of constant C string.
Definition: utils.h:84