diff --git a/src/ecmascript/Makefile b/src/ecmascript/Makefile
index 628e304f3..3637ef007 100644
--- a/src/ecmascript/Makefile
+++ b/src/ecmascript/Makefile
@@ -12,9 +12,9 @@ SUBDIRS-$(CONFIG_ECMASCRIPT_SMJS) += spidermonkey
OBJS-$(CONFIG_ECMASCRIPT_SMJS) += ecmascript.obj ecmascript-c.obj localstorage-db.o spidermonkey.obj timer.o
-OBJS-$(CONFIG_MUJS) += ecmascript.obj ecmascript-c.obj localstorage-db.o mujs.o timer.o
+OBJS-$(CONFIG_MUJS) += ecmascript.obj ecmascript-c.o localstorage-db.o mujs.o timer.o
-OBJS-$(CONFIG_QUICKJS) += ecmascript.obj ecmascript-c.obj localstorage-db.o quickjs.o timer.o
+OBJS-$(CONFIG_QUICKJS) += ecmascript.obj ecmascript-c.o localstorage-db.o quickjs.o timer.o
ifeq ($(CONFIG_ECMASCRIPT_SMJS), yes)
CONFIG_ANY_SPIDERMONKEY = yes
diff --git a/src/ecmascript/ecmascript-c.c b/src/ecmascript/ecmascript-c.c
new file mode 100644
index 000000000..95b17c889
--- /dev/null
+++ b/src/ecmascript/ecmascript-c.c
@@ -0,0 +1,473 @@
+/* ECMAScript helper functions */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "elinks.h"
+
+#include "dialogs/status.h"
+#include "document/document.h"
+#include "document/libdom/mapa.h"
+#include "document/view.h"
+#include "ecmascript/ecmascript.h"
+#include "ecmascript/ecmascript-c.h"
+#ifdef CONFIG_MUJS
+#include "ecmascript/mujs.h"
+#include "ecmascript/mujs/element.h"
+#endif
+#ifdef CONFIG_QUICKJS
+#include "ecmascript/quickjs.h"
+#include "ecmascript/quickjs/element.h"
+#endif
+#ifdef CONFIG_ECMASCRIPT_SMJS
+#include "ecmascript/spidermonkey.h"
+#include "ecmascript/spidermonkey/element.h"
+#endif
+#include "intl/libintl.h"
+#include "protocol/uri.h"
+#include "session/session.h"
+#include "session/task.h"
+#include "terminal/event.h"
+#include "util/conv.h"
+#include "util/memory.h"
+#include "util/string.h"
+#include "viewer/text/form.h"
+#include "viewer/text/view.h"
+
+extern int interpreter_count;
+extern int ecmascript_enabled;
+
+int
+ecmascript_get_interpreter_count(void)
+{
+ return interpreter_count;
+}
+
+void
+toggle_ecmascript(struct session *ses)
+{
+ ecmascript_enabled = !ecmascript_enabled;
+
+ if (ecmascript_enabled) {
+ mem_free_set(&ses->status.window_status, stracpy(_("Ecmascript enabled", ses->tab->term)));
+ } else {
+ mem_free_set(&ses->status.window_status, stracpy(_("Ecmascript disabled", ses->tab->term)));
+ }
+ print_screen_status(ses);
+}
+
+void
+ecmascript_protocol_handler(struct session *ses, struct uri *uri)
+{
+ struct document_view *doc_view = current_frame(ses);
+ struct string current_url = INIT_STRING(struri(uri), (int)strlen(struri(uri)));
+ char *redirect_url, *redirect_abs_url;
+ struct uri *redirect_uri;
+
+ if (!doc_view) /* Blank initial document. TODO: Start at about:blank? */
+ return;
+ assert(doc_view->vs);
+ if (doc_view->vs->ecmascript_fragile)
+ ecmascript_reset_state(doc_view->vs);
+ if (!doc_view->vs->ecmascript)
+ return;
+
+ redirect_url = ecmascript_eval_stringback(doc_view->vs->ecmascript,
+ ¤t_url);
+ if (!redirect_url)
+ return;
+ /* XXX: This code snippet is duplicated over here,
+ * location_set_property(), html_a() and who knows where else. */
+ redirect_abs_url = join_urls(doc_view->document->uri,
+ trim_chars(redirect_url, ' ', 0));
+ mem_free(redirect_url);
+ if (!redirect_abs_url)
+ return;
+ redirect_uri = get_uri(redirect_abs_url, URI_NONE);
+ mem_free(redirect_abs_url);
+ if (!redirect_uri)
+ return;
+
+ /* XXX: Is that safe to do at this point? --pasky */
+ goto_uri_frame(ses, redirect_uri, doc_view->name,
+ CACHE_MODE_NORMAL);
+ done_uri(redirect_uri);
+}
+
+static void
+add_snippets(struct ecmascript_interpreter *interpreter,
+ LIST_OF(struct ecmascript_string_list_item) *doc_snippets,
+ LIST_OF(struct ecmascript_string_list_item) *queued_snippets)
+{
+ struct ecmascript_string_list_item *doc_current = (struct ecmascript_string_list_item *)doc_snippets->next;
+
+#ifdef CONFIG_LEDS
+ if (list_empty(*queued_snippets) && interpreter->vs->doc_view->session)
+ unset_led_value(interpreter->vs->doc_view->session->status.ecmascript_led);
+#endif
+
+ if (list_empty(*doc_snippets)
+ || !get_opt_bool("ecmascript.enable", NULL))
+ return;
+
+ /* We do this all only once per view_state now. */
+ if (!list_empty(*queued_snippets)) {
+ /* So if we already did it, we shouldn't need to do it again.
+ * This is the case of moving around in history - we have all
+ * what happenned recorded in the view_state and needn't bother
+ * again. */
+#ifdef CONFIG_DEBUG
+ /* Hopefully. */
+ struct ecmascript_string_list_item *iterator = queued_snippets->next;
+
+ while (iterator != (struct ecmascript_string_list_item *) queued_snippets) {
+ if (doc_current == (struct ecmascript_string_list_item *) doc_snippets) {
+ INTERNAL("add_snippets(): doc_snippets shorter than queued_snippets!");
+ return;
+ }
+#if 0
+ DBG("Comparing snippets\n%.*s\n###### vs #####\n%.*s\n #####",
+ iterator->string.length, iterator->string.source,
+ doc_current->string.length, doc_current->string.source);
+#endif
+ assert(!strlcmp(iterator->string.source,
+ iterator->string.length,
+ doc_current->string.source,
+ doc_current->string.length));
+
+ doc_current = doc_current->next;
+ iterator = iterator->next;
+ }
+#endif
+ return;
+ }
+
+ assert(doc_current);
+ for (; doc_current != (struct ecmascript_string_list_item *) doc_snippets;
+ doc_current = doc_current->next) {
+ add_to_ecmascript_string_list(queued_snippets, doc_current->string.source,
+ doc_current->string.length, doc_current->element_offset);
+#if 0
+ DBG("Adding snippet\n%.*s\n #####",
+ doc_current->string.length,
+ doc_current->string.source);
+#endif
+ }
+}
+
+static void
+process_snippets(struct ecmascript_interpreter *interpreter,
+ LIST_OF(struct ecmascript_string_list_item) *snippets,
+ struct ecmascript_string_list_item **current)
+{
+ if (!*current)
+ *current = (struct ecmascript_string_list_item *)snippets->next;
+ for (; *current != (struct ecmascript_string_list_item *) snippets;
+ (*current) = (*current)->next) {
+ struct string *string = &(*current)->string;
+ char *uristring;
+ struct uri *uri;
+ struct cache_entry *cached;
+ struct fragment *fragment;
+
+ if (string->length == 0)
+ continue;
+
+ if (*string->source != '^') {
+ /* Evaluate snippet */
+ ecmascript_eval(interpreter, string, NULL, (*current)->element_offset);
+ continue;
+ }
+
+ /* Eval external snippet */
+ uristring = string->source + 1;
+ if (!*uristring) continue;
+
+ uri = get_uri(uristring, URI_BASE);
+ if (!uri) continue;
+
+ cached = get_redirected_cache_entry(uri);
+ done_uri(uri);
+
+ if (!cached) {
+ /* At this time (!gradual_rerendering), we should've
+ * already retrieved this though. So it must've been
+ * that it went away because unused and the cache was
+ * already too full. */
+#if 0
+ /* Disabled because gradual rerendering can be triggered
+ * by numerous events other than a ecmascript reference
+ * completing like the original document and CSS. Problem
+ * is that we should never continue this loop but rather
+ * break out if that is the case. Somehow we need to
+ * be able to derive URI loading problems at this point
+ * or maybe remove reference snippets if they fail to load.
+ *
+ * This FIFO queue handling should be used for also CSS
+ * imports so it would be cool if it could be general
+ * enough for that. Using it for frames with the FIFOing
+ * disabled probably wouldn't hurt either.
+ *
+ * To top this thing off it would be nice if it also
+ * handled dependency tracking between references so that
+ * CSS documents will not disappear from the cache
+ * before all referencing HTML documents has been deleted
+ * from it.
+ *
+ * Reported as bug 533. */
+ /* Pasky's explanation: If we get the doc in a single
+ * shot, before calling draw_formatted() we didn't have
+ * anything additional queued for loading and the cache
+ * entry was already loaded, so we didn't get
+ * gradual_loading set. But then while parsing the
+ * document we got some external references and trying
+ * to process them right now. Boom.
+ *
+ * The obvious solution would be to always call
+ * draw_formatted() with gradual_loading in
+ * doc_loading_callback() and if we are sure the
+ * loading is really over, call it one more time
+ * without gradual_loading set. I'm not sure about
+ * the implications though so I won't do it before
+ * 0.10.0. --pasky */
+ ERROR("The script of %s was lost in too full a cache!",
+ uristring);
+#endif
+ continue;
+ }
+
+ fragment = get_cache_fragment(cached);
+ if (fragment) {
+ struct string code = INIT_STRING(fragment->data, (int)fragment->length);
+
+ ecmascript_eval(interpreter, &code, NULL, (*current)->element_offset);
+ }
+ }
+ check_for_rerender(interpreter, "eval");
+}
+
+void
+check_for_snippets(struct view_state *vs, struct document_options *options, struct document *document)
+{
+ if (!vs->ecmascript_fragile)
+ assert(vs->ecmascript);
+ if (!options->dump && !options->gradual_rerendering) {
+ /* We also reset the state if the underlying document changed
+ * from the last time we did the snippets. This may be
+ * triggered i.e. when redrawing a document which has been
+ * reloaded in a different tab meanwhile (OTOH we don't want
+ * to reset the state if we are redrawing a document we have
+ * already drawn before).
+ *
+ * (vs->ecmascript->onload_snippets_owner) check may be
+ * superfluous since we should always have
+ * vs->ecmascript_fragile set in those cases; that's why we
+ * don't ever bother to re-zero it if we are suddenly doing
+ * gradual rendering again.
+ *
+ * XXX: What happens if a document is still loading in the
+ * other tab when we press ^L here? */
+ if (vs->ecmascript_fragile
+ || (vs->ecmascript
+ && vs->ecmascript->onload_snippets_cache_id
+ && document->cache_id != vs->ecmascript->onload_snippets_cache_id))
+ ecmascript_reset_state(vs);
+ /* If ecmascript_reset_state cannot construct a new
+ * ECMAScript interpreter, it sets vs->ecmascript =
+ * NULL and vs->ecmascript_fragile = 1. */
+ if (vs->ecmascript) {
+ vs->ecmascript->onload_snippets_cache_id = document->cache_id;
+
+ /* Passing of the onload_snippets pointers
+ * gives *_snippets() some feeling of
+ * universality, shall we ever get any other
+ * snippets (?). */
+ add_snippets(vs->ecmascript,
+ &document->onload_snippets,
+ &vs->ecmascript->onload_snippets);
+ process_snippets(vs->ecmascript,
+ &vs->ecmascript->onload_snippets,
+ &vs->ecmascript->current_onload_snippet);
+ check_for_rerender(vs->ecmascript, "process_snippets");
+ }
+ }
+}
+
+void
+kill_ecmascript_timeouts(struct document *document)
+{
+ struct ecmascript_timeout *t;
+
+ foreach(t, document->timeouts) {
+ kill_timer(&t->tid);
+ done_string(&t->code);
+ }
+}
+
+void
+ecmascript_put_interpreter(struct ecmascript_interpreter *interpreter)
+{
+ assert(interpreter);
+ assert(interpreter->backend_nesting == 0);
+ /* If the assertion fails, it is better to leak the
+ * interpreter than to corrupt memory. */
+ if_assert_failed return;
+#ifdef CONFIG_MUJS
+ mujs_put_interpreter(interpreter);
+#elif defined(CONFIG_QUICKJS)
+ quickjs_put_interpreter(interpreter);
+#else
+ spidermonkey_put_interpreter(interpreter);
+#endif
+ free_ecmascript_string_list(&interpreter->onload_snippets);
+ done_string(&interpreter->code);
+ free_ecmascript_string_list(&interpreter->writecode);
+ /* Is it superfluous? */
+ if (interpreter->vs->doc_view) {
+ struct ecmascript_timeout *t;
+
+ foreach (t, interpreter->vs->doc_view->document->timeouts) {
+ kill_timer(&t->tid);
+ done_string(&t->code);
+ }
+ free_list(interpreter->vs->doc_view->document->timeouts);
+ }
+ interpreter->vs->ecmascript = NULL;
+ interpreter->vs->ecmascript_fragile = 1;
+ mem_free(interpreter);
+ --interpreter_count;
+}
+
+void
+check_events_for_element(struct ecmascript_interpreter *ecmascript, dom_node *element, struct term_event *ev)
+{
+ const char *event_name = script_event_hook_name[SEVHOOK_ONKEYDOWN];
+
+ check_element_event(ecmascript, element, event_name, ev);
+ event_name = script_event_hook_name[SEVHOOK_ONKEYUP];
+ check_element_event(ecmascript, element, event_name, ev);
+ event_name = script_event_hook_name[SEVHOOK_ONKEYPRESS];
+ check_element_event(ecmascript, element, event_name, ev);
+}
+
+void
+ecmascript_reset_state(struct view_state *vs)
+{
+ struct form_view *fv;
+ int i;
+
+ /* Normally, if vs->ecmascript == NULL, the associated
+ * ecmascript_obj pointers are also NULL. However, they might
+ * be non-NULL if the ECMAScript objects have been lazily
+ * created because of scripts running in sibling HTML frames. */
+ foreach (fv, vs->forms)
+ ecmascript_detach_form_view(fv);
+ for (i = 0; i < vs->form_info_len; i++)
+ ecmascript_detach_form_state(&vs->form_info[i]);
+
+ vs->ecmascript_fragile = 0;
+ if (vs->ecmascript)
+ ecmascript_put_interpreter(vs->ecmascript);
+
+ vs->ecmascript = ecmascript_get_interpreter(vs);
+ if (!vs->ecmascript)
+ vs->ecmascript_fragile = 1;
+}
+
+int
+ecmascript_eval_boolback(struct ecmascript_interpreter *interpreter,
+ struct string *code)
+{
+ int result;
+
+ if (!get_ecmascript_enable(interpreter))
+ return -1;
+ assert(interpreter);
+ interpreter->backend_nesting++;
+#ifdef CONFIG_MUJS
+ result = mujs_eval_boolback(interpreter, code);
+#elif defined(CONFIG_QUICKJS)
+ result = quickjs_eval_boolback(interpreter, code);
+#else
+ result = spidermonkey_eval_boolback(interpreter, code);
+#endif
+ interpreter->backend_nesting--;
+
+ check_for_rerender(interpreter, "boolback");
+
+ return result;
+}
+
+int
+ecmascript_current_link_evhook(struct document_view *doc_view, enum script_event_hook_type type)
+{
+ struct link *link;
+ struct script_event_hook *evhook;
+
+ assert(doc_view && doc_view->vs);
+ link = get_current_link(doc_view);
+ if (!link) return -1;
+ if (!doc_view->vs->ecmascript) return -1;
+
+ void *mapa = (void *)doc_view->document->element_map;
+
+ if (mapa) {
+ dom_node *elem = (dom_node *)find_in_map(mapa, link->element_offset);
+
+ if (elem) {
+ const char *event_name = script_event_hook_name[(int)type];
+ check_element_event(doc_view->vs->ecmascript, elem, event_name, NULL);
+ }
+ }
+
+ if (!link->event_hooks) return -1;
+
+ foreach (evhook, *link->event_hooks) {
+ char *ret;
+
+ if (evhook->type != type) continue;
+ ret = evhook->src;
+ while ((ret = strstr(ret, "return ")))
+ while (*ret != ' ') *ret++ = ' ';
+ {
+ struct string src = INIT_STRING(evhook->src, (int)strlen(evhook->src));
+ /* TODO: Some even handlers return a bool. */
+ if (!ecmascript_eval_boolback(doc_view->vs->ecmascript, &src))
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+void
+ecmascript_detach_form_view(struct form_view *fv)
+{
+#ifdef CONFIG_MUJS
+#elif defined(CONFIG_QUICKJS)
+ quickjs_detach_form_view(fv);
+#else
+ spidermonkey_detach_form_view(fv);
+#endif
+}
+
+void ecmascript_detach_form_state(struct form_state *fs)
+{
+#ifdef CONFIG_MUJS
+#elif defined(CONFIG_QUICKJS)
+ quickjs_detach_form_state(fs);
+#else
+ spidermonkey_detach_form_state(fs);
+#endif
+}
+
+void ecmascript_moved_form_state(struct form_state *fs)
+{
+#ifdef CONFIG_MUJS
+#elif defined(CONFIG_QUICKJS)
+ quickjs_moved_form_state(fs);
+#else
+ spidermonkey_moved_form_state(fs);
+#endif
+}
diff --git a/src/ecmascript/ecmascript-c.cpp b/src/ecmascript/ecmascript-c.cpp
index 95b17c889..59def124e 100644
--- a/src/ecmascript/ecmascript-c.cpp
+++ b/src/ecmascript/ecmascript-c.cpp
@@ -1,473 +1 @@
-/* ECMAScript helper functions */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "elinks.h"
-
-#include "dialogs/status.h"
-#include "document/document.h"
-#include "document/libdom/mapa.h"
-#include "document/view.h"
-#include "ecmascript/ecmascript.h"
-#include "ecmascript/ecmascript-c.h"
-#ifdef CONFIG_MUJS
-#include "ecmascript/mujs.h"
-#include "ecmascript/mujs/element.h"
-#endif
-#ifdef CONFIG_QUICKJS
-#include "ecmascript/quickjs.h"
-#include "ecmascript/quickjs/element.h"
-#endif
-#ifdef CONFIG_ECMASCRIPT_SMJS
-#include "ecmascript/spidermonkey.h"
-#include "ecmascript/spidermonkey/element.h"
-#endif
-#include "intl/libintl.h"
-#include "protocol/uri.h"
-#include "session/session.h"
-#include "session/task.h"
-#include "terminal/event.h"
-#include "util/conv.h"
-#include "util/memory.h"
-#include "util/string.h"
-#include "viewer/text/form.h"
-#include "viewer/text/view.h"
-
-extern int interpreter_count;
-extern int ecmascript_enabled;
-
-int
-ecmascript_get_interpreter_count(void)
-{
- return interpreter_count;
-}
-
-void
-toggle_ecmascript(struct session *ses)
-{
- ecmascript_enabled = !ecmascript_enabled;
-
- if (ecmascript_enabled) {
- mem_free_set(&ses->status.window_status, stracpy(_("Ecmascript enabled", ses->tab->term)));
- } else {
- mem_free_set(&ses->status.window_status, stracpy(_("Ecmascript disabled", ses->tab->term)));
- }
- print_screen_status(ses);
-}
-
-void
-ecmascript_protocol_handler(struct session *ses, struct uri *uri)
-{
- struct document_view *doc_view = current_frame(ses);
- struct string current_url = INIT_STRING(struri(uri), (int)strlen(struri(uri)));
- char *redirect_url, *redirect_abs_url;
- struct uri *redirect_uri;
-
- if (!doc_view) /* Blank initial document. TODO: Start at about:blank? */
- return;
- assert(doc_view->vs);
- if (doc_view->vs->ecmascript_fragile)
- ecmascript_reset_state(doc_view->vs);
- if (!doc_view->vs->ecmascript)
- return;
-
- redirect_url = ecmascript_eval_stringback(doc_view->vs->ecmascript,
- ¤t_url);
- if (!redirect_url)
- return;
- /* XXX: This code snippet is duplicated over here,
- * location_set_property(), html_a() and who knows where else. */
- redirect_abs_url = join_urls(doc_view->document->uri,
- trim_chars(redirect_url, ' ', 0));
- mem_free(redirect_url);
- if (!redirect_abs_url)
- return;
- redirect_uri = get_uri(redirect_abs_url, URI_NONE);
- mem_free(redirect_abs_url);
- if (!redirect_uri)
- return;
-
- /* XXX: Is that safe to do at this point? --pasky */
- goto_uri_frame(ses, redirect_uri, doc_view->name,
- CACHE_MODE_NORMAL);
- done_uri(redirect_uri);
-}
-
-static void
-add_snippets(struct ecmascript_interpreter *interpreter,
- LIST_OF(struct ecmascript_string_list_item) *doc_snippets,
- LIST_OF(struct ecmascript_string_list_item) *queued_snippets)
-{
- struct ecmascript_string_list_item *doc_current = (struct ecmascript_string_list_item *)doc_snippets->next;
-
-#ifdef CONFIG_LEDS
- if (list_empty(*queued_snippets) && interpreter->vs->doc_view->session)
- unset_led_value(interpreter->vs->doc_view->session->status.ecmascript_led);
-#endif
-
- if (list_empty(*doc_snippets)
- || !get_opt_bool("ecmascript.enable", NULL))
- return;
-
- /* We do this all only once per view_state now. */
- if (!list_empty(*queued_snippets)) {
- /* So if we already did it, we shouldn't need to do it again.
- * This is the case of moving around in history - we have all
- * what happenned recorded in the view_state and needn't bother
- * again. */
-#ifdef CONFIG_DEBUG
- /* Hopefully. */
- struct ecmascript_string_list_item *iterator = queued_snippets->next;
-
- while (iterator != (struct ecmascript_string_list_item *) queued_snippets) {
- if (doc_current == (struct ecmascript_string_list_item *) doc_snippets) {
- INTERNAL("add_snippets(): doc_snippets shorter than queued_snippets!");
- return;
- }
-#if 0
- DBG("Comparing snippets\n%.*s\n###### vs #####\n%.*s\n #####",
- iterator->string.length, iterator->string.source,
- doc_current->string.length, doc_current->string.source);
-#endif
- assert(!strlcmp(iterator->string.source,
- iterator->string.length,
- doc_current->string.source,
- doc_current->string.length));
-
- doc_current = doc_current->next;
- iterator = iterator->next;
- }
-#endif
- return;
- }
-
- assert(doc_current);
- for (; doc_current != (struct ecmascript_string_list_item *) doc_snippets;
- doc_current = doc_current->next) {
- add_to_ecmascript_string_list(queued_snippets, doc_current->string.source,
- doc_current->string.length, doc_current->element_offset);
-#if 0
- DBG("Adding snippet\n%.*s\n #####",
- doc_current->string.length,
- doc_current->string.source);
-#endif
- }
-}
-
-static void
-process_snippets(struct ecmascript_interpreter *interpreter,
- LIST_OF(struct ecmascript_string_list_item) *snippets,
- struct ecmascript_string_list_item **current)
-{
- if (!*current)
- *current = (struct ecmascript_string_list_item *)snippets->next;
- for (; *current != (struct ecmascript_string_list_item *) snippets;
- (*current) = (*current)->next) {
- struct string *string = &(*current)->string;
- char *uristring;
- struct uri *uri;
- struct cache_entry *cached;
- struct fragment *fragment;
-
- if (string->length == 0)
- continue;
-
- if (*string->source != '^') {
- /* Evaluate snippet */
- ecmascript_eval(interpreter, string, NULL, (*current)->element_offset);
- continue;
- }
-
- /* Eval external snippet */
- uristring = string->source + 1;
- if (!*uristring) continue;
-
- uri = get_uri(uristring, URI_BASE);
- if (!uri) continue;
-
- cached = get_redirected_cache_entry(uri);
- done_uri(uri);
-
- if (!cached) {
- /* At this time (!gradual_rerendering), we should've
- * already retrieved this though. So it must've been
- * that it went away because unused and the cache was
- * already too full. */
-#if 0
- /* Disabled because gradual rerendering can be triggered
- * by numerous events other than a ecmascript reference
- * completing like the original document and CSS. Problem
- * is that we should never continue this loop but rather
- * break out if that is the case. Somehow we need to
- * be able to derive URI loading problems at this point
- * or maybe remove reference snippets if they fail to load.
- *
- * This FIFO queue handling should be used for also CSS
- * imports so it would be cool if it could be general
- * enough for that. Using it for frames with the FIFOing
- * disabled probably wouldn't hurt either.
- *
- * To top this thing off it would be nice if it also
- * handled dependency tracking between references so that
- * CSS documents will not disappear from the cache
- * before all referencing HTML documents has been deleted
- * from it.
- *
- * Reported as bug 533. */
- /* Pasky's explanation: If we get the doc in a single
- * shot, before calling draw_formatted() we didn't have
- * anything additional queued for loading and the cache
- * entry was already loaded, so we didn't get
- * gradual_loading set. But then while parsing the
- * document we got some external references and trying
- * to process them right now. Boom.
- *
- * The obvious solution would be to always call
- * draw_formatted() with gradual_loading in
- * doc_loading_callback() and if we are sure the
- * loading is really over, call it one more time
- * without gradual_loading set. I'm not sure about
- * the implications though so I won't do it before
- * 0.10.0. --pasky */
- ERROR("The script of %s was lost in too full a cache!",
- uristring);
-#endif
- continue;
- }
-
- fragment = get_cache_fragment(cached);
- if (fragment) {
- struct string code = INIT_STRING(fragment->data, (int)fragment->length);
-
- ecmascript_eval(interpreter, &code, NULL, (*current)->element_offset);
- }
- }
- check_for_rerender(interpreter, "eval");
-}
-
-void
-check_for_snippets(struct view_state *vs, struct document_options *options, struct document *document)
-{
- if (!vs->ecmascript_fragile)
- assert(vs->ecmascript);
- if (!options->dump && !options->gradual_rerendering) {
- /* We also reset the state if the underlying document changed
- * from the last time we did the snippets. This may be
- * triggered i.e. when redrawing a document which has been
- * reloaded in a different tab meanwhile (OTOH we don't want
- * to reset the state if we are redrawing a document we have
- * already drawn before).
- *
- * (vs->ecmascript->onload_snippets_owner) check may be
- * superfluous since we should always have
- * vs->ecmascript_fragile set in those cases; that's why we
- * don't ever bother to re-zero it if we are suddenly doing
- * gradual rendering again.
- *
- * XXX: What happens if a document is still loading in the
- * other tab when we press ^L here? */
- if (vs->ecmascript_fragile
- || (vs->ecmascript
- && vs->ecmascript->onload_snippets_cache_id
- && document->cache_id != vs->ecmascript->onload_snippets_cache_id))
- ecmascript_reset_state(vs);
- /* If ecmascript_reset_state cannot construct a new
- * ECMAScript interpreter, it sets vs->ecmascript =
- * NULL and vs->ecmascript_fragile = 1. */
- if (vs->ecmascript) {
- vs->ecmascript->onload_snippets_cache_id = document->cache_id;
-
- /* Passing of the onload_snippets pointers
- * gives *_snippets() some feeling of
- * universality, shall we ever get any other
- * snippets (?). */
- add_snippets(vs->ecmascript,
- &document->onload_snippets,
- &vs->ecmascript->onload_snippets);
- process_snippets(vs->ecmascript,
- &vs->ecmascript->onload_snippets,
- &vs->ecmascript->current_onload_snippet);
- check_for_rerender(vs->ecmascript, "process_snippets");
- }
- }
-}
-
-void
-kill_ecmascript_timeouts(struct document *document)
-{
- struct ecmascript_timeout *t;
-
- foreach(t, document->timeouts) {
- kill_timer(&t->tid);
- done_string(&t->code);
- }
-}
-
-void
-ecmascript_put_interpreter(struct ecmascript_interpreter *interpreter)
-{
- assert(interpreter);
- assert(interpreter->backend_nesting == 0);
- /* If the assertion fails, it is better to leak the
- * interpreter than to corrupt memory. */
- if_assert_failed return;
-#ifdef CONFIG_MUJS
- mujs_put_interpreter(interpreter);
-#elif defined(CONFIG_QUICKJS)
- quickjs_put_interpreter(interpreter);
-#else
- spidermonkey_put_interpreter(interpreter);
-#endif
- free_ecmascript_string_list(&interpreter->onload_snippets);
- done_string(&interpreter->code);
- free_ecmascript_string_list(&interpreter->writecode);
- /* Is it superfluous? */
- if (interpreter->vs->doc_view) {
- struct ecmascript_timeout *t;
-
- foreach (t, interpreter->vs->doc_view->document->timeouts) {
- kill_timer(&t->tid);
- done_string(&t->code);
- }
- free_list(interpreter->vs->doc_view->document->timeouts);
- }
- interpreter->vs->ecmascript = NULL;
- interpreter->vs->ecmascript_fragile = 1;
- mem_free(interpreter);
- --interpreter_count;
-}
-
-void
-check_events_for_element(struct ecmascript_interpreter *ecmascript, dom_node *element, struct term_event *ev)
-{
- const char *event_name = script_event_hook_name[SEVHOOK_ONKEYDOWN];
-
- check_element_event(ecmascript, element, event_name, ev);
- event_name = script_event_hook_name[SEVHOOK_ONKEYUP];
- check_element_event(ecmascript, element, event_name, ev);
- event_name = script_event_hook_name[SEVHOOK_ONKEYPRESS];
- check_element_event(ecmascript, element, event_name, ev);
-}
-
-void
-ecmascript_reset_state(struct view_state *vs)
-{
- struct form_view *fv;
- int i;
-
- /* Normally, if vs->ecmascript == NULL, the associated
- * ecmascript_obj pointers are also NULL. However, they might
- * be non-NULL if the ECMAScript objects have been lazily
- * created because of scripts running in sibling HTML frames. */
- foreach (fv, vs->forms)
- ecmascript_detach_form_view(fv);
- for (i = 0; i < vs->form_info_len; i++)
- ecmascript_detach_form_state(&vs->form_info[i]);
-
- vs->ecmascript_fragile = 0;
- if (vs->ecmascript)
- ecmascript_put_interpreter(vs->ecmascript);
-
- vs->ecmascript = ecmascript_get_interpreter(vs);
- if (!vs->ecmascript)
- vs->ecmascript_fragile = 1;
-}
-
-int
-ecmascript_eval_boolback(struct ecmascript_interpreter *interpreter,
- struct string *code)
-{
- int result;
-
- if (!get_ecmascript_enable(interpreter))
- return -1;
- assert(interpreter);
- interpreter->backend_nesting++;
-#ifdef CONFIG_MUJS
- result = mujs_eval_boolback(interpreter, code);
-#elif defined(CONFIG_QUICKJS)
- result = quickjs_eval_boolback(interpreter, code);
-#else
- result = spidermonkey_eval_boolback(interpreter, code);
-#endif
- interpreter->backend_nesting--;
-
- check_for_rerender(interpreter, "boolback");
-
- return result;
-}
-
-int
-ecmascript_current_link_evhook(struct document_view *doc_view, enum script_event_hook_type type)
-{
- struct link *link;
- struct script_event_hook *evhook;
-
- assert(doc_view && doc_view->vs);
- link = get_current_link(doc_view);
- if (!link) return -1;
- if (!doc_view->vs->ecmascript) return -1;
-
- void *mapa = (void *)doc_view->document->element_map;
-
- if (mapa) {
- dom_node *elem = (dom_node *)find_in_map(mapa, link->element_offset);
-
- if (elem) {
- const char *event_name = script_event_hook_name[(int)type];
- check_element_event(doc_view->vs->ecmascript, elem, event_name, NULL);
- }
- }
-
- if (!link->event_hooks) return -1;
-
- foreach (evhook, *link->event_hooks) {
- char *ret;
-
- if (evhook->type != type) continue;
- ret = evhook->src;
- while ((ret = strstr(ret, "return ")))
- while (*ret != ' ') *ret++ = ' ';
- {
- struct string src = INIT_STRING(evhook->src, (int)strlen(evhook->src));
- /* TODO: Some even handlers return a bool. */
- if (!ecmascript_eval_boolback(doc_view->vs->ecmascript, &src))
- return 0;
- }
- }
-
- return 1;
-}
-
-void
-ecmascript_detach_form_view(struct form_view *fv)
-{
-#ifdef CONFIG_MUJS
-#elif defined(CONFIG_QUICKJS)
- quickjs_detach_form_view(fv);
-#else
- spidermonkey_detach_form_view(fv);
-#endif
-}
-
-void ecmascript_detach_form_state(struct form_state *fs)
-{
-#ifdef CONFIG_MUJS
-#elif defined(CONFIG_QUICKJS)
- quickjs_detach_form_state(fs);
-#else
- spidermonkey_detach_form_state(fs);
-#endif
-}
-
-void ecmascript_moved_form_state(struct form_state *fs)
-{
-#ifdef CONFIG_MUJS
-#elif defined(CONFIG_QUICKJS)
- quickjs_moved_form_state(fs);
-#else
- spidermonkey_moved_form_state(fs);
-#endif
-}
+#include "ecmascript/ecmascript-c.c"
diff --git a/src/ecmascript/meson.build b/src/ecmascript/meson.build
index 7eb863325..8769c51d8 100644
--- a/src/ecmascript/meson.build
+++ b/src/ecmascript/meson.build
@@ -17,12 +17,12 @@ if CONFIG_ANY_SPIDERMONKEY
endif
if conf_data.get('CONFIG_MUJS')
- srcs += files('ecmascript.cpp', 'ecmascript-c.cpp', 'localstorage-db.c', 'mujs.c', 'timer.c')
+ srcs += files('ecmascript.cpp', 'ecmascript-c.c', 'localstorage-db.c', 'mujs.c', 'timer.c')
subdir('mujs')
endif
if conf_data.get('CONFIG_QUICKJS')
- srcs += files('ecmascript.cpp', 'ecmascript-c.cpp', 'localstorage-db.c', 'quickjs.c', 'timer.c')
+ srcs += files('ecmascript.cpp', 'ecmascript-c.c', 'localstorage-db.c', 'quickjs.c', 'timer.c')
subdir('quickjs')
endif