mirror of
https://github.com/rkd77/elinks.git
synced 2024-12-04 14:46:47 -05:00
Merge branch 'elinks-0.12' into elinks-0.13
This commit is contained in:
commit
bbee237ff0
28
NEWS
28
NEWS
@ -22,8 +22,6 @@ Miscellaneous:
|
||||
document.css.media.
|
||||
* bug 638: Propagate the existence of $DISPLAY from slave terminals to
|
||||
mailcap test commands.
|
||||
* bug 698: Attach controls to the intended form even if it is
|
||||
incorrectly nested in a table. (Was broken in 0.11.4.)
|
||||
* bug 963: New option document.css.ignore_display_none.
|
||||
* bug 977: Fixed crash when opening in new tab a non link with onclick
|
||||
attribute.
|
||||
@ -64,14 +62,38 @@ ELinks 0.12pre1.GIT now:
|
||||
To be released as 0.12pre2, 0.12rc1, or even 0.12.0. This branch
|
||||
generally also includes the bug fixes made in ELinks 0.11.4.GIT.
|
||||
|
||||
* bug 954, enhancement 952: Keep track of ECMAScript form and input
|
||||
objects instead of constructing new ones on every access. When the
|
||||
corresponding ELinks internal objects are destroyed, detach the
|
||||
ECMAScript objects from them, to prevent crashes. (Bug 954 was
|
||||
first added in ELinks 0.11.4, and the bug 620 fix in ELinks 0.12pre1
|
||||
made crashes more likely.)
|
||||
* critical bug 1029 in user SMJS: Prefer JS_CallFunctionValue over
|
||||
JS_CallFunction, which can crash if given a closure.
|
||||
* critical bug 1031: Use the same JSRuntime for both user SMJS and
|
||||
scripts on web pages, to work around SpiderMonkey bug 378918.
|
||||
* bug 698: Attach controls to the intended form even if it is
|
||||
incorrectly nested in a table. (Was broken in 0.11.4.)
|
||||
* minor bug 951: SpiderMonkey scripting objects used to prevent ELinks
|
||||
from removing files from the memory cache
|
||||
|
||||
Bugs that should be removed from NEWS before the 0.12.0 release:
|
||||
|
||||
* critical: Fix crash after a tab was opened during reload. This was
|
||||
triggered by the bug 620 fix in ELinks 0.12pre1.
|
||||
* major bug 1026 in user SMJS: Protect the callback of elinks.load_uri
|
||||
from the garbage collector. The elinks.load_uri method was added in
|
||||
ELinks 0.12pre1.
|
||||
* bug 955: Reset buttons no longer run FORM/@onsubmit, and
|
||||
``harmless'' buttons no longer submit the form. ELinks 0.12pre1
|
||||
was the first release that had these bugs.
|
||||
* bug 1033: Fix memory leak in ECMAScript window.open. ELinks 0.12pre1
|
||||
was the first release that had this bug.
|
||||
* bug 1034: ``Content-Encoding: deflate'' allows a zlib header as
|
||||
specified in RFC 2616.
|
||||
* Global ECMAScript functions alert, open, and setTimeout again work
|
||||
with SEE. ELinks 0.12pre1 was the first release that supported SEE
|
||||
at all.
|
||||
|
||||
ELinks 0.12pre1:
|
||||
----------------
|
||||
@ -237,6 +259,8 @@ To be released as 0.11.5.
|
||||
|
||||
* critical bug 1027 in user SMJS: make elinks.keymaps treat null and
|
||||
"none" as equivalent actions, avoiding a segfault
|
||||
* critical bug 1030: an assertion used to fail in the search dialog
|
||||
on systems that lack a usable <regex.h>
|
||||
* major bug 503: various fixes in parsing and updating of elinks.conf
|
||||
* build bug 1021: fixed uninitialized variable in http_got_header
|
||||
|
||||
|
19
configure.in
19
configure.in
@ -1408,6 +1408,25 @@ AC_SUBST(LIBDIR)
|
||||
EL_LOG_CONFIG(CONFDIR, [System configuration directory], [])
|
||||
EL_LOG_CONFIG(LOCALEDIR, [Locale catalogs directory], [])
|
||||
|
||||
|
||||
AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <stddef.h>
|
||||
]], [[#if !defined(__TINYC__) || !defined(alloca)
|
||||
#error not tcc
|
||||
#endif ]])],[cf_result=yes],[cf_result=no])
|
||||
|
||||
if test "$cf_result" = "yes"; then
|
||||
AC_DEFINE([HAVE_ALLOCA])
|
||||
AC_DEFINE([_ALLOCA_H], [1], [Define as 1 if you are using Tiny C Compiler
|
||||
with the GNU C Library, and <alloca.h> of glibc would otherwise
|
||||
override the alloca macro defined in <stddef.h> of TCC.
|
||||
If <alloca.h> of glibc sees the _ALLOCA_H macro, it assumes
|
||||
it has already been included, and does not redefine alloca.
|
||||
This might not work in future glibc versions though, because
|
||||
the names of the #include guard macros are not documented.
|
||||
The incompatibility has been reported to the tinycc-devel
|
||||
mailing list on 2008-07-14. If a future version of TCC provides
|
||||
an <alloca.h> of its own, this hack won't be needed.])
|
||||
fi
|
||||
# ===================================================================
|
||||
# A little fine tuning of gcc specific options (continued)
|
||||
# ===================================================================
|
||||
|
@ -131,7 +131,7 @@ yet if it does not work in the Mozilla browsers neither ;-).
|
||||
Now, I would still like NJS or a new JS engine from scratch...
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
...and you don't fear some coding? That's fine then! ELinks is in no way tied
|
||||
\...and you don't fear some coding? That's fine then! ELinks is in no way tied
|
||||
to SpiderMonkey, in fact the ECMAScript support was carefully implemented so
|
||||
that there are no SpiderMonkey references outside of
|
||||
`src/ecmascript/spidermonkey.*`. If you want to implement an alternative
|
||||
|
@ -20,8 +20,7 @@ Note that if you don't use dietlibc, you definitively want to add `-Os` or
|
||||
`-O2` to `CFLAGS`; GCC 2.95 does not know `-Os`, and some say `-O2` gives
|
||||
smaller executables even for GCC 3.x.
|
||||
|
||||
[NOTE]
|
||||
.Warning
|
||||
[TIP]
|
||||
===============================================================================
|
||||
If you use these `CFLAGS` on Cygwin and you get unresolved symbols (`htons` and
|
||||
suite in particular), try removing `-fno-inline` parameter.
|
||||
@ -38,8 +37,8 @@ $ ./configure --disable-ipv6 --disable-backtrace --disable-nls \
|
||||
|
||||
You can disable bookmarks, globhist and more, too, if you want to.
|
||||
|
||||
[NOTE]
|
||||
.Notes
|
||||
[TIP]
|
||||
.Other configure options that can reduce the size
|
||||
===============================================================================
|
||||
- \--disable-backtrace disables internal backtrace code.
|
||||
- \--disable-nls disables i18n support.
|
||||
|
@ -338,8 +338,8 @@ render_document(struct view_state *vs, struct document_view *doc_view,
|
||||
|
||||
if (doc_view->session
|
||||
&& doc_view->session->reloadlevel > CACHE_MODE_NORMAL)
|
||||
while (vs->form_info_len)
|
||||
mem_free_if(vs->form_info[--vs->form_info_len].value);
|
||||
for (; vs->form_info_len > 0; vs->form_info_len--)
|
||||
done_form_state(&vs->form_info[vs->form_info_len - 1]);
|
||||
|
||||
shrink_memory(0);
|
||||
|
||||
|
@ -8,6 +8,16 @@ SUBDIRS-$(CONFIG_ECMASCRIPT_SMJS) += spidermonkey
|
||||
OBJS-$(CONFIG_ECMASCRIPT_SEE) += see.o
|
||||
OBJS-$(CONFIG_ECMASCRIPT_SMJS) += spidermonkey.o
|
||||
|
||||
ifeq ($(CONFIG_ECMASCRIPT_SMJS), yes)
|
||||
CONFIG_ANY_SPIDERMONKEY = yes
|
||||
else ifeq ($(CONFIG_SCRIPTING_SPIDERMONKEY), yes)
|
||||
CONFIG_ANY_SPIDERMONKEY = yes
|
||||
else
|
||||
CONFIG_ANY_SPIDERMONKEY = no
|
||||
endif
|
||||
|
||||
OBJS-$(CONFIG_ANY_SPIDERMONKEY) += spidermonkey-shared.o
|
||||
|
||||
OBJS = ecmascript.o
|
||||
|
||||
include $(top_srcdir)/Makefile.lib
|
||||
|
@ -214,6 +214,33 @@ ecmascript_eval_boolback(struct ecmascript_interpreter *interpreter,
|
||||
return result;
|
||||
}
|
||||
|
||||
void
|
||||
ecmascript_detach_form_view(struct form_view *fv)
|
||||
{
|
||||
#ifdef CONFIG_ECMASCRIPT_SEE
|
||||
see_detach_form_view(fv);
|
||||
#else
|
||||
spidermonkey_detach_form_view(fv);
|
||||
#endif
|
||||
}
|
||||
|
||||
void ecmascript_detach_form_state(struct form_state *fs)
|
||||
{
|
||||
#ifdef CONFIG_ECMASCRIPT_SEE
|
||||
see_detach_form_state(fs);
|
||||
#else
|
||||
spidermonkey_detach_form_state(fs);
|
||||
#endif
|
||||
}
|
||||
|
||||
void ecmascript_moved_form_state(struct form_state *fs)
|
||||
{
|
||||
#ifdef CONFIG_ECMASCRIPT_SEE
|
||||
see_moved_form_state(fs);
|
||||
#else
|
||||
spidermonkey_moved_form_state(fs);
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
ecmascript_reset_state(struct view_state *vs)
|
||||
@ -221,15 +248,19 @@ 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);
|
||||
|
||||
foreach (fv, vs->forms)
|
||||
fv->ecmascript_obj = NULL;
|
||||
for (i = 0; i < vs->form_info_len; i++)
|
||||
vs->form_info[i].ecmascript_obj = NULL;
|
||||
|
||||
vs->ecmascript = ecmascript_get_interpreter(vs);
|
||||
if (!vs->ecmascript)
|
||||
vs->ecmascript_fragile = 1;
|
||||
|
@ -8,6 +8,8 @@
|
||||
#include "main/module.h"
|
||||
#include "util/time.h"
|
||||
|
||||
struct form_state;
|
||||
struct form_view;
|
||||
struct string;
|
||||
struct terminal;
|
||||
struct uri;
|
||||
@ -70,6 +72,10 @@ void ecmascript_free_urls(struct module *module);
|
||||
struct ecmascript_interpreter *ecmascript_get_interpreter(struct view_state*vs);
|
||||
void ecmascript_put_interpreter(struct ecmascript_interpreter *interpreter);
|
||||
|
||||
void ecmascript_detach_form_view(struct form_view *fv);
|
||||
void ecmascript_detach_form_state(struct form_state *fs);
|
||||
void ecmascript_moved_form_state(struct form_state *fs);
|
||||
|
||||
void ecmascript_reset_state(struct view_state *vs);
|
||||
|
||||
void ecmascript_eval(struct ecmascript_interpreter *interpreter, struct string *code, struct string *ret);
|
||||
|
@ -7,6 +7,10 @@ struct string;
|
||||
void *see_get_interpreter(struct ecmascript_interpreter *interpreter);
|
||||
void see_put_interpreter(struct ecmascript_interpreter *interpreter);
|
||||
|
||||
void see_detach_form_view(struct form_view *fv);
|
||||
void see_detach_form_state(struct form_state *fs);
|
||||
void see_moved_form_state(struct form_state *fs);
|
||||
|
||||
void see_eval(struct ecmascript_interpreter *interpreter, struct string *code, struct string *ret);
|
||||
unsigned char *see_eval_stringback(struct ecmascript_interpreter *interpreter, struct string *code);
|
||||
int see_eval_boolback(struct ecmascript_interpreter *interpreter, struct string *code);
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include "document/forms.h"
|
||||
#include "document/view.h"
|
||||
#include "ecmascript/ecmascript.h"
|
||||
#include "ecmascript/see.h"
|
||||
#include "ecmascript/see/checktype.h"
|
||||
#include "ecmascript/see/document.h"
|
||||
#include "ecmascript/see/form.h"
|
||||
@ -56,8 +57,9 @@ static void js_input_focus(struct SEE_interpreter *, struct SEE_object *, struct
|
||||
static void js_input_select(struct SEE_interpreter *, struct SEE_object *, struct SEE_object *, int, struct SEE_value **, struct SEE_value *);
|
||||
static int input_canput(struct SEE_interpreter *, struct SEE_object *, struct SEE_string *);
|
||||
static int input_hasproperty(struct SEE_interpreter *, struct SEE_object *, struct SEE_string *);
|
||||
static struct js_input *js_get_input_object(struct SEE_interpreter *, struct js_form *, int);
|
||||
static struct js_input *js_get_form_control_object(struct SEE_interpreter *, struct js_form *, enum form_type, int);
|
||||
static struct js_input *js_get_input_object(struct SEE_interpreter *, struct js_form *, struct form_state *);
|
||||
static void input_finalize(struct SEE_interpreter *, void *, void *);
|
||||
static struct js_input *js_get_form_control_object(struct SEE_interpreter *, struct js_form *, enum form_type, struct form_state *);
|
||||
|
||||
static void js_form_elems_item(struct SEE_interpreter *, struct SEE_object *, struct SEE_object *, int, struct SEE_value **, struct SEE_value *);
|
||||
static void js_form_elems_namedItem(struct SEE_interpreter *, struct SEE_object *, struct SEE_object *, int, struct SEE_value **, struct SEE_value *);
|
||||
@ -75,6 +77,7 @@ static int form_canput(struct SEE_interpreter *, struct SEE_object *, struct SEE
|
||||
static int form_hasproperty(struct SEE_interpreter *, struct SEE_object *, struct SEE_string *);
|
||||
static void js_form_reset(struct SEE_interpreter *, struct SEE_object *, struct SEE_object *, int, struct SEE_value **, struct SEE_value *);
|
||||
static void js_form_submit(struct SEE_interpreter *, struct SEE_object *, struct SEE_object *, int, struct SEE_value **, struct SEE_value *);
|
||||
static void form_finalize(struct SEE_interpreter *, void *, void *);
|
||||
|
||||
|
||||
struct SEE_objectclass js_input_object_class = {
|
||||
@ -140,7 +143,7 @@ struct js_input {
|
||||
struct SEE_object *click;
|
||||
struct SEE_object *focus;
|
||||
struct SEE_object *select;
|
||||
int form_number;
|
||||
struct form_state *fs;
|
||||
};
|
||||
|
||||
struct js_forms_object {
|
||||
@ -159,12 +162,21 @@ struct js_form_elems {
|
||||
|
||||
|
||||
static inline struct form_state *
|
||||
form_state_of_js_input(struct view_state *vs, const struct js_input *input)
|
||||
form_state_of_js_input(struct SEE_interpreter *interp,
|
||||
const struct js_input *input)
|
||||
{
|
||||
assert(input->form_number >= 0);
|
||||
assert(input->form_number < vs->form_info_len);
|
||||
if_assert_failed return NULL;
|
||||
return &vs->form_info[input->form_number];
|
||||
struct form_state *fs = input->fs;
|
||||
|
||||
if (!fs)
|
||||
SEE_error_throw(interp, interp->Error,
|
||||
"Input field has been destroyed");
|
||||
|
||||
assert(fs->ecmascript_obj == input);
|
||||
if_assert_failed
|
||||
SEE_error_throw(interp, interp->Error,
|
||||
"Internal corruption");
|
||||
|
||||
return fs;
|
||||
}
|
||||
|
||||
static void
|
||||
@ -177,7 +189,7 @@ input_get(struct SEE_interpreter *interp, struct SEE_object *o,
|
||||
struct document *document = doc_view->document;
|
||||
struct js_input *input = (struct js_input *)o;
|
||||
struct js_form *parent = input->parent;
|
||||
struct form_state *fs = form_state_of_js_input(vs, input);
|
||||
struct form_state *fs = form_state_of_js_input(interp, input);
|
||||
struct form_control *fc = find_form_control(document, fs);
|
||||
int linknum;
|
||||
struct link *link = NULL;
|
||||
@ -280,7 +292,7 @@ input_put(struct SEE_interpreter *interp, struct SEE_object *o,
|
||||
struct document_view *doc_view = vs->doc_view;
|
||||
struct document *document = doc_view->document;
|
||||
struct js_input *input = (struct js_input *)o;
|
||||
struct form_state *fs = form_state_of_js_input(vs, input);
|
||||
struct form_state *fs = form_state_of_js_input(interp, input);
|
||||
struct form_control *fc = find_form_control(document, fs);
|
||||
int linknum;
|
||||
struct link *link = NULL;
|
||||
@ -380,7 +392,7 @@ js_input_click(struct SEE_interpreter *interp, struct SEE_object *self,
|
||||
struct js_input *input = (
|
||||
see_check_class(interp, thisobj, &js_input_object_class),
|
||||
(struct js_input *)thisobj);
|
||||
struct form_state *fs = form_state_of_js_input(vs, input);
|
||||
struct form_state *fs = form_state_of_js_input(interp, input);
|
||||
struct form_control *fc;
|
||||
int linknum;
|
||||
|
||||
@ -415,7 +427,7 @@ js_input_focus(struct SEE_interpreter *interp, struct SEE_object *self,
|
||||
struct js_input *input = (
|
||||
see_check_class(interp, thisobj, &js_input_object_class),
|
||||
(struct js_input *)thisobj);
|
||||
struct form_state *fs = form_state_of_js_input(vs, input);
|
||||
struct form_state *fs = form_state_of_js_input(interp, input);
|
||||
struct form_control *fc;
|
||||
int linknum;
|
||||
|
||||
@ -460,19 +472,23 @@ input_hasproperty(struct SEE_interpreter *interp, struct SEE_object *o,
|
||||
}
|
||||
|
||||
static struct js_input *
|
||||
js_get_input_object(struct SEE_interpreter *interp, struct js_form *jsform, int num)
|
||||
js_get_input_object(struct SEE_interpreter *interp, struct js_form *jsform,
|
||||
struct form_state *fs)
|
||||
{
|
||||
struct js_input *jsinput;
|
||||
struct js_input *jsinput = fs->ecmascript_obj;
|
||||
|
||||
if (jsinput) {
|
||||
assert(jsinput->fs == fs);
|
||||
if_assert_failed return NULL;
|
||||
|
||||
return jsinput;
|
||||
}
|
||||
|
||||
#if 0
|
||||
if (fs->ecmascript_obj)
|
||||
return fs->ecmascript_obj;
|
||||
#endif
|
||||
/* jsform ('form') is input's parent */
|
||||
/* FIXME: That is NOT correct since the real containing element
|
||||
* should be its parent, but gimme DOM first. --pasky */
|
||||
jsinput = SEE_NEW(interp, struct js_input);
|
||||
jsinput = SEE_NEW_FINALIZE(interp, struct js_input,
|
||||
input_finalize, NULL);
|
||||
|
||||
jsinput->object.objectclass = &js_input_object_class;
|
||||
jsinput->object.Prototype = NULL;
|
||||
@ -482,14 +498,15 @@ js_get_input_object(struct SEE_interpreter *interp, struct js_form *jsform, int
|
||||
jsinput->focus = SEE_cfunction_make(interp, js_input_focus, s_focus, 0);
|
||||
jsinput->select = SEE_cfunction_make(interp, js_input_select, s_select, 0);
|
||||
|
||||
jsinput->form_number = num;
|
||||
jsinput->parent = jsform;
|
||||
jsinput->fs = fs;
|
||||
fs->ecmascript_obj = jsinput;
|
||||
return jsinput;
|
||||
}
|
||||
|
||||
static struct js_input *
|
||||
js_get_form_control_object(struct SEE_interpreter *interp, struct js_form *jsform,
|
||||
enum form_type type, int num)
|
||||
enum form_type type, struct form_state *fs)
|
||||
{
|
||||
switch (type) {
|
||||
case FC_TEXT:
|
||||
@ -503,7 +520,7 @@ js_get_form_control_object(struct SEE_interpreter *interp, struct js_form *jsfor
|
||||
case FC_BUTTON:
|
||||
case FC_HIDDEN:
|
||||
case FC_SELECT:
|
||||
return js_get_input_object(interp, jsform, num);
|
||||
return js_get_input_object(interp, jsform, fs);
|
||||
|
||||
case FC_TEXTAREA:
|
||||
/* TODO */
|
||||
@ -515,8 +532,90 @@ js_get_form_control_object(struct SEE_interpreter *interp, struct js_form *jsfor
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
input_finalize(struct SEE_interpreter *interp, void *jsinput_void, void *dummy)
|
||||
{
|
||||
struct js_input *jsinput = jsinput_void;
|
||||
struct form_state *fs = jsinput->fs;
|
||||
|
||||
if (fs) {
|
||||
/* Reset jsinput->fs in case some ELinks code uses it
|
||||
* even after this finalizer has run. Such use should
|
||||
* not be possible but the explanation is somewhat
|
||||
* complex so it seems safest to do this.
|
||||
*
|
||||
* Unlike SpiderMonkey, Boehm's GC allows a finalizer
|
||||
* to resurrect the object by making something point
|
||||
* to it. And it's a conservative GC so it can see
|
||||
* such a pointer where none actually exists. However
|
||||
* it also implicitly unregisters the finalizer before
|
||||
* calling it, so the object becomes just a chunk of
|
||||
* memory that nothing really uses, even if the GC
|
||||
* never realizes it is garbage. */
|
||||
jsinput->fs = NULL;
|
||||
|
||||
/* If this assertion fails, leave fs->ecmascript_obj
|
||||
* unchanged, because it may point to a different
|
||||
* structure whose js_input.fs pointer will later have
|
||||
* to be updated to avoid crashes.
|
||||
*
|
||||
* If the assertion fails and we leave jsinput->fs
|
||||
* unchanged, and something then deletes fs,
|
||||
* jsinput->fs becomes a dangling pointer because fs
|
||||
* does not know about jsinput. So that's why the
|
||||
* assertion comes after the jsinput->fs assignment
|
||||
* above. */
|
||||
assert(fs->ecmascript_obj == jsinput);
|
||||
if_assert_failed return;
|
||||
|
||||
fs->ecmascript_obj = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
see_detach_form_state(struct form_state *fs)
|
||||
{
|
||||
struct js_input *jsinput = fs->ecmascript_obj;
|
||||
|
||||
if (jsinput) {
|
||||
/* If this assertion fails, it is not clear whether
|
||||
* jsinput->fs should be reset; crashes seem possible
|
||||
* either way. Resetting it is easiest. */
|
||||
assert(jsinput->fs == fs);
|
||||
if_assert_failed {}
|
||||
|
||||
jsinput->fs = NULL;
|
||||
fs->ecmascript_obj = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
see_moved_form_state(struct form_state *fs)
|
||||
{
|
||||
struct js_input *jsinput = fs->ecmascript_obj;
|
||||
|
||||
if (jsinput)
|
||||
jsinput->fs = fs;
|
||||
}
|
||||
|
||||
|
||||
static inline struct form_view *
|
||||
form_view_of_js_form(struct SEE_interpreter *interp,
|
||||
const struct js_form *jsform)
|
||||
{
|
||||
struct form_view *fv = jsform->fv;
|
||||
|
||||
if (!fv)
|
||||
SEE_error_throw(interp, interp->Error,
|
||||
"Form has been destroyed");
|
||||
|
||||
assert(fv->ecmascript_obj == jsform);
|
||||
if_assert_failed
|
||||
SEE_error_throw(interp, interp->Error,
|
||||
"Internal corruption");
|
||||
|
||||
return fv;
|
||||
}
|
||||
|
||||
static void
|
||||
js_form_elems_item(struct SEE_interpreter *interp, struct SEE_object *self,
|
||||
@ -531,7 +630,7 @@ js_form_elems_item(struct SEE_interpreter *interp, struct SEE_object *self,
|
||||
see_check_class(interp, thisobj, &js_form_elems_class),
|
||||
(struct js_form_elems *)thisobj);
|
||||
struct js_form *parent_form = jsfe->parent;
|
||||
struct form_view *fv = parent_form->fv;
|
||||
struct form_view *fv = form_view_of_js_form(interp, parent_form);
|
||||
struct form *form = find_form_by_form_view(document, fv);
|
||||
struct form_control *fc;
|
||||
unsigned char *string;
|
||||
@ -553,7 +652,7 @@ js_form_elems_item(struct SEE_interpreter *interp, struct SEE_object *self,
|
||||
struct form_state *fs = find_form_state(doc_view, fc);
|
||||
|
||||
if (fs) {
|
||||
struct js_input *fcobj = js_get_form_control_object(interp, parent_form, fc->type, fc->g_ctrl_num);
|
||||
struct js_input *fcobj = js_get_form_control_object(interp, parent_form, fc->type, fs);
|
||||
|
||||
if (fcobj)
|
||||
SEE_SET_OBJECT(res, (struct SEE_object *)fcobj);
|
||||
@ -577,7 +676,7 @@ js_form_elems_namedItem(struct SEE_interpreter *interp, struct SEE_object *self,
|
||||
see_check_class(interp, thisobj, &js_form_elems_class),
|
||||
(struct js_form_elems *)thisobj);
|
||||
struct js_form *parent_form = jsfe->parent;
|
||||
struct form_view *fv = parent_form->fv;
|
||||
struct form_view *fv = form_view_of_js_form(interp, parent_form);
|
||||
struct form *form = find_form_by_form_view(document, fv);
|
||||
struct form_control *fc;
|
||||
unsigned char *string;
|
||||
@ -594,7 +693,7 @@ js_form_elems_namedItem(struct SEE_interpreter *interp, struct SEE_object *self,
|
||||
struct form_state *fs = find_form_state(doc_view, fc);
|
||||
|
||||
if (fs) {
|
||||
struct js_input *fcobj = js_get_form_control_object(interp, parent_form, fc->type, fc->g_ctrl_num);
|
||||
struct js_input *fcobj = js_get_form_control_object(interp, parent_form, fc->type, fs);
|
||||
|
||||
if (fcobj)
|
||||
SEE_SET_OBJECT(res, (struct SEE_object *)fcobj);
|
||||
@ -615,7 +714,7 @@ form_elems_get(struct SEE_interpreter *interp, struct SEE_object *o,
|
||||
struct document *document = doc_view->document;
|
||||
struct js_form_elems *jsfe = (struct js_form_elems *)o;
|
||||
struct js_form *parent_form = jsfe->parent;
|
||||
struct form_view *fv = parent_form->fv;
|
||||
struct form_view *fv = form_view_of_js_form(interp, parent_form);
|
||||
struct form *form = find_form_by_form_view(document, fv);
|
||||
|
||||
if (p == s_length) {
|
||||
@ -783,7 +882,7 @@ form_get(struct SEE_interpreter *interp, struct SEE_object *o,
|
||||
struct view_state *vs = g->win->vs;
|
||||
struct document_view *doc_view = vs->doc_view;
|
||||
struct js_form *js_form = (struct js_form *)o;
|
||||
struct form_view *fv = js_form->fv;
|
||||
struct form_view *fv = form_view_of_js_form(interp, js_form);
|
||||
struct form *form = find_form_by_form_view(doc_view->document, fv);
|
||||
struct SEE_string *str;
|
||||
|
||||
@ -857,7 +956,7 @@ form_get(struct SEE_interpreter *interp, struct SEE_object *o,
|
||||
continue;
|
||||
fs = find_form_state(doc_view, fc);
|
||||
if (fs) {
|
||||
fcobj = js_get_form_control_object(interp, js_form, fc->type, fc->g_ctrl_num);
|
||||
fcobj = js_get_form_control_object(interp, js_form, fc->type, fs);
|
||||
|
||||
if (fcobj)
|
||||
SEE_SET_OBJECT(res, (struct SEE_object *)fcobj);
|
||||
@ -876,7 +975,7 @@ form_put(struct SEE_interpreter *interp, struct SEE_object *o,
|
||||
struct view_state *vs = g->win->vs;
|
||||
struct document_view *doc_view = vs->doc_view;
|
||||
struct js_form *js_form = (struct js_form *)o;
|
||||
struct form_view *fv = js_form->fv;
|
||||
struct form_view *fv = form_view_of_js_form(interp, js_form);
|
||||
struct form *form = find_form_by_form_view(doc_view->document, fv);
|
||||
unsigned char *string = see_value_to_unsigned_char(interp, val);
|
||||
|
||||
@ -938,7 +1037,7 @@ js_form_reset(struct SEE_interpreter *interp, struct SEE_object *self,
|
||||
struct js_form *js_form = (
|
||||
see_check_class(interp, thisobj, &js_form_class),
|
||||
(struct js_form *)thisobj);
|
||||
struct form_view *fv = js_form->fv;
|
||||
struct form_view *fv = form_view_of_js_form(interp, js_form);
|
||||
struct form *form = find_form_by_form_view(doc_view->document, fv);
|
||||
|
||||
assert(form);
|
||||
@ -960,7 +1059,7 @@ js_form_submit(struct SEE_interpreter *interp, struct SEE_object *self,
|
||||
struct js_form *js_form = (
|
||||
see_check_class(interp, thisobj, &js_form_class),
|
||||
(struct js_form *)thisobj);
|
||||
struct form_view *fv = js_form->fv;
|
||||
struct form_view *fv = form_view_of_js_form(interp, js_form);
|
||||
struct form *form = find_form_by_form_view(doc_view->document, fv);
|
||||
|
||||
assert(form);
|
||||
@ -971,27 +1070,89 @@ js_form_submit(struct SEE_interpreter *interp, struct SEE_object *self,
|
||||
struct js_form *js_get_form_object(struct SEE_interpreter *interp,
|
||||
struct js_document_object *doc, struct form_view *fv)
|
||||
{
|
||||
struct js_form *js_form;
|
||||
struct js_form *js_form = fv->ecmascript_obj;
|
||||
|
||||
if (js_form) {
|
||||
assert(js_form->fv == fv);
|
||||
if_assert_failed return NULL;
|
||||
|
||||
return js_form;
|
||||
}
|
||||
|
||||
#if 0
|
||||
if (fv->ecmascript_obj)
|
||||
return fv->ecmascript_obj;
|
||||
#endif
|
||||
/* jsdoc ('document') is fv's parent */
|
||||
/* FIXME: That is NOT correct since the real containing element
|
||||
* should be its parent, but gimme DOM first. --pasky */
|
||||
js_form = SEE_NEW(interp, struct js_form);
|
||||
js_form = SEE_NEW_FINALIZE(interp, struct js_form,
|
||||
form_finalize, NULL);
|
||||
js_form->object.objectclass = &js_form_class;
|
||||
js_form->object.Prototype = NULL; /* TODO: use prototype for form */
|
||||
js_form->parent = doc;
|
||||
js_form->reset = SEE_cfunction_make(interp, js_form_reset, s_reset, 0);
|
||||
js_form->submit = SEE_cfunction_make(interp, js_form_submit, s_submit, 0);
|
||||
js_form->fv = fv;
|
||||
|
||||
js_form->fv = fv;
|
||||
fv->ecmascript_obj = js_form;
|
||||
return js_form;
|
||||
}
|
||||
|
||||
static void
|
||||
form_finalize(struct SEE_interpreter *interp, void *jsform_void, void *dummy)
|
||||
{
|
||||
struct js_form *jsform = jsform_void;
|
||||
struct form_view *fv = jsform->fv;
|
||||
|
||||
if (fv) {
|
||||
/* Reset jsform->fv in case some ELinks code uses it
|
||||
* even after this finalizer has run. Such use should
|
||||
* not be possible but the explanation is somewhat
|
||||
* complex so it seems safest to do this.
|
||||
*
|
||||
* Unlike SpiderMonkey, Boehm's GC allows a finalizer
|
||||
* to resurrect the object by making something point
|
||||
* to it. And it's a conservative GC so it can see
|
||||
* such a pointer where none actually exists. However
|
||||
* it also implicitly unregisters the finalizer before
|
||||
* calling it, so the object becomes just a chunk of
|
||||
* memory that nothing really uses, even if the GC
|
||||
* never realizes it is garbage. */
|
||||
jsform->fv = NULL;
|
||||
|
||||
/* If this assertion fails, leave fv->ecmascript_obj
|
||||
* unchanged, because it may point to a different
|
||||
* structure whose js_form.fv pointer will later have
|
||||
* to be updated to avoid crashes.
|
||||
*
|
||||
* If the assertion fails and we leave jsform->fv
|
||||
* unchanged, and something then deletes fv,
|
||||
* jsform->fv becomes a dangling pointer because fv
|
||||
* does not know about jsform. So that's why the
|
||||
* assertion comes after the jsform->fv assignment
|
||||
* above. */
|
||||
assert(fv->ecmascript_obj == jsform);
|
||||
if_assert_failed return;
|
||||
|
||||
fv->ecmascript_obj = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
see_detach_form_view(struct form_view *fv)
|
||||
{
|
||||
struct js_form *jsform = fv->ecmascript_obj;
|
||||
|
||||
if (jsform) {
|
||||
/* If this assertion fails, it is not clear whether
|
||||
* jsform->fv should be reset; crashes seem possible
|
||||
* either way. Resetting it is easiest. */
|
||||
assert(jsform->fv == fv);
|
||||
if_assert_failed {}
|
||||
|
||||
jsform->fv = NULL;
|
||||
fv->ecmascript_obj = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
init_js_forms_object(struct ecmascript_interpreter *interpreter)
|
||||
{
|
||||
|
@ -211,7 +211,9 @@ js_window_alert(struct SEE_interpreter *interp, struct SEE_object *self,
|
||||
struct view_state *vs = win->vs;
|
||||
unsigned char *string;
|
||||
|
||||
see_check_class(interp, thisobj, &js_window_object_class);
|
||||
/* Do not check thisobj->objectclass. ELinks sets this
|
||||
* function as a property of both the window object and the
|
||||
* global object, so thisobj may validly refer to either. */
|
||||
|
||||
SEE_SET_BOOLEAN(res, 1);
|
||||
if (argc < 1)
|
||||
@ -240,7 +242,7 @@ js_window_open(struct SEE_interpreter *interp, struct SEE_object *self,
|
||||
struct document_view *doc_view = vs->doc_view;
|
||||
struct session *ses = doc_view->session;
|
||||
unsigned char *frame = "";
|
||||
unsigned char *url;
|
||||
unsigned char *url, *url2;
|
||||
struct uri *uri;
|
||||
struct SEE_value url_value;
|
||||
#if 0
|
||||
@ -248,7 +250,9 @@ js_window_open(struct SEE_interpreter *interp, struct SEE_object *self,
|
||||
static int ratelimit_count;
|
||||
#endif
|
||||
|
||||
see_check_class(interp, thisobj, &js_window_object_class);
|
||||
/* Do not check thisobj->objectclass. ELinks sets this
|
||||
* function as a property of both the window object and the
|
||||
* global object, so thisobj may validly refer to either. */
|
||||
|
||||
SEE_SET_OBJECT(res, (struct SEE_object *)win);
|
||||
if (get_opt_bool("ecmascript.block_window_opening", ses)) {
|
||||
@ -291,10 +295,11 @@ js_window_open(struct SEE_interpreter *interp, struct SEE_object *self,
|
||||
}
|
||||
/* TODO: Support for window naming and perhaps some window features? */
|
||||
|
||||
url = join_urls(doc_view->document->uri, url);
|
||||
if (!url) return;
|
||||
uri = get_uri(url, 0);
|
||||
url2 = join_urls(doc_view->document->uri, url);
|
||||
mem_free(url);
|
||||
if (!url2) return;
|
||||
uri = get_uri(url2, 0);
|
||||
mem_free(url2);
|
||||
if (!uri) return;
|
||||
|
||||
if (*frame && strcasecmp(frame, "_blank")) {
|
||||
@ -341,7 +346,9 @@ js_setTimeout(struct SEE_interpreter *interp, struct SEE_object *self,
|
||||
unsigned char *code;
|
||||
int timeout;
|
||||
|
||||
see_check_class(interp, thisobj, &js_window_object_class);
|
||||
/* Do not check thisobj->objectclass. ELinks sets this
|
||||
* function as a property of both the window object and the
|
||||
* global object, so thisobj may validly refer to either. */
|
||||
|
||||
if (argc != 2) return;
|
||||
ei = ((struct global_object *)interp)->interpreter;
|
||||
|
140
src/ecmascript/spidermonkey-shared.c
Normal file
140
src/ecmascript/spidermonkey-shared.c
Normal file
@ -0,0 +1,140 @@
|
||||
/** SpiderMonkey support for both user scripts and web scripts.
|
||||
* @file */
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "elinks.h"
|
||||
|
||||
#include "ecmascript/spidermonkey-shared.h"
|
||||
|
||||
/** A shared runtime used for both user scripts (scripting/smjs/) and
|
||||
* scripts on web pages (ecmascript/spidermonkey/).
|
||||
*
|
||||
* SpiderMonkey has bugs that corrupt memory when multiple JSRuntimes
|
||||
* are used: https://bugzilla.mozilla.org/show_bug.cgi?id=378918 and
|
||||
* perhaps others. */
|
||||
JSRuntime *spidermonkey_runtime;
|
||||
|
||||
/** A JSContext that can be used in JS_SetPrivate and JS_GetPrivate
|
||||
* when no better one is available. This context has no global
|
||||
* object, so scripts cannot be evaluated in it.
|
||||
*
|
||||
* XXX: This also works around a crash on exit. SMJS will crash on
|
||||
* JS_DestroyRuntime if the given runtime has never had any context
|
||||
* created, which will be the case if one closes ELinks without having
|
||||
* loaded any documents. */
|
||||
JSContext *spidermonkey_empty_context;
|
||||
|
||||
/** A reference count for ::spidermonkey_runtime so that modules using
|
||||
* it can be initialized and shut down in arbitrary order. */
|
||||
static int spidermonkey_runtime_refcount;
|
||||
|
||||
/** Initialize ::spidermonkey_runtime and ::spidermonkey_empty_context.
|
||||
* If already initialized, just increment the reference count.
|
||||
*
|
||||
* @return 1 if successful or 0 on error. If this succeeds, the
|
||||
* caller must eventually call spidermonkey_runtime_release(). */
|
||||
int
|
||||
spidermonkey_runtime_addref(void)
|
||||
{
|
||||
if (spidermonkey_runtime_refcount == 0) {
|
||||
assert(spidermonkey_runtime == NULL);
|
||||
assert(spidermonkey_empty_context == NULL);
|
||||
if_assert_failed return 0;
|
||||
|
||||
spidermonkey_runtime = JS_NewRuntime(4L * 1024L * 1024L);
|
||||
if (!spidermonkey_runtime) return 0;
|
||||
|
||||
spidermonkey_empty_context = JS_NewContext(spidermonkey_runtime,
|
||||
0);
|
||||
if (!spidermonkey_empty_context) {
|
||||
/* Perhaps JS_DestroyRuntime will now crash
|
||||
* because no context was created, but there's
|
||||
* not much else to do. */
|
||||
JS_DestroyRuntime(spidermonkey_runtime);
|
||||
spidermonkey_runtime = NULL;
|
||||
JS_ShutDown();
|
||||
}
|
||||
}
|
||||
|
||||
assert(spidermonkey_runtime);
|
||||
assert(spidermonkey_empty_context);
|
||||
spidermonkey_runtime_refcount++;
|
||||
assert(spidermonkey_runtime_refcount > 0);
|
||||
if_assert_failed { spidermonkey_runtime_refcount--; return 0; }
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** Release a reference to ::spidermonkey_runtime, and destroy it if
|
||||
* that was the last reference. If spidermonkey_runtime_addref()
|
||||
* failed, then this must not be called. */
|
||||
void
|
||||
spidermonkey_runtime_release(void)
|
||||
{
|
||||
assert(spidermonkey_runtime_refcount > 0);
|
||||
assert(spidermonkey_runtime);
|
||||
assert(spidermonkey_empty_context);
|
||||
if_assert_failed return;
|
||||
|
||||
--spidermonkey_runtime_refcount;
|
||||
if (spidermonkey_runtime_refcount == 0) {
|
||||
JS_DestroyContext(spidermonkey_empty_context);
|
||||
spidermonkey_empty_context = NULL;
|
||||
JS_DestroyRuntime(spidermonkey_runtime);
|
||||
spidermonkey_runtime = NULL;
|
||||
JS_ShutDown();
|
||||
}
|
||||
}
|
||||
|
||||
/** An ELinks-specific replacement for JS_DefineFunctions().
|
||||
*
|
||||
* @relates spidermonkeyFunctionSpec */
|
||||
JSBool
|
||||
spidermonkey_DefineFunctions(JSContext *cx, JSObject *obj,
|
||||
const spidermonkeyFunctionSpec *fs)
|
||||
{
|
||||
for (; fs->name; fs++) {
|
||||
if (!JS_DefineFunction(cx, obj, fs->name, fs->call,
|
||||
fs->nargs, 0))
|
||||
return JS_FALSE;
|
||||
}
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
/** An ELinks-specific replacement for JS_InitClass().
|
||||
*
|
||||
* @relates spidermonkeyFunctionSpec */
|
||||
JSObject *
|
||||
spidermonkey_InitClass(JSContext *cx, JSObject *obj,
|
||||
JSObject *parent_proto, JSClass *clasp,
|
||||
JSNative constructor, uintN nargs,
|
||||
JSPropertySpec *ps,
|
||||
const spidermonkeyFunctionSpec *fs,
|
||||
JSPropertySpec *static_ps,
|
||||
const spidermonkeyFunctionSpec *static_fs)
|
||||
{
|
||||
JSObject *proto = JS_InitClass(cx, obj, parent_proto, clasp,
|
||||
constructor, nargs,
|
||||
ps, NULL, static_ps, NULL);
|
||||
|
||||
if (proto == NULL)
|
||||
return NULL;
|
||||
|
||||
if (fs) {
|
||||
if (!spidermonkey_DefineFunctions(cx, proto, fs))
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (static_fs) {
|
||||
JSObject *cons_obj = JS_GetConstructor(cx, proto);
|
||||
|
||||
if (cons_obj == NULL)
|
||||
return NULL;
|
||||
if (!spidermonkey_DefineFunctions(cx, cons_obj, static_fs))
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return proto;
|
||||
}
|
74
src/ecmascript/spidermonkey-shared.h
Normal file
74
src/ecmascript/spidermonkey-shared.h
Normal file
@ -0,0 +1,74 @@
|
||||
#ifndef EL__ECMASCRIPT_SPIDERMONKEY_SHARED_H
|
||||
#define EL__ECMASCRIPT_SPIDERMONKEY_SHARED_H
|
||||
|
||||
/* For wild SpiderMonkey installations. */
|
||||
#ifdef CONFIG_OS_BEOS
|
||||
#define XP_BEOS
|
||||
#elif CONFIG_OS_OS2
|
||||
#define XP_OS2
|
||||
#elif CONFIG_OS_RISCOS
|
||||
#error Out of luck, buddy!
|
||||
#elif CONFIG_OS_UNIX
|
||||
#define XP_UNIX
|
||||
#elif CONFIG_OS_WIN32
|
||||
#define XP_WIN
|
||||
#endif
|
||||
|
||||
#include <jsapi.h>
|
||||
|
||||
#include "util/string.h"
|
||||
|
||||
extern JSRuntime *spidermonkey_runtime;
|
||||
extern JSContext *spidermonkey_empty_context;
|
||||
int spidermonkey_runtime_addref(void);
|
||||
void spidermonkey_runtime_release(void);
|
||||
|
||||
/** An ELinks-specific replacement for JSFunctionSpec.
|
||||
*
|
||||
* Bug 1016: In SpiderMonkey 1.7 bundled with XULRunner 1.8, jsapi.h
|
||||
* defines JSFunctionSpec in different ways depending on whether
|
||||
* MOZILLA_1_8_BRANCH is defined, and there is no obvious way for
|
||||
* ELinks to check whether MOZILLA_1_8_BRANCH was defined when the
|
||||
* library was built. Avoid the unstable JSFunctionSpec definitions
|
||||
* and use this ELinks-specific structure instead. */
|
||||
typedef struct spidermonkeyFunctionSpec {
|
||||
const char *name;
|
||||
JSNative call;
|
||||
uint8 nargs;
|
||||
/* ELinks does not use "flags" and "extra" so omit them here. */
|
||||
} spidermonkeyFunctionSpec;
|
||||
|
||||
JSBool spidermonkey_DefineFunctions(JSContext *cx, JSObject *obj,
|
||||
const spidermonkeyFunctionSpec *fs);
|
||||
JSObject *spidermonkey_InitClass(JSContext *cx, JSObject *obj,
|
||||
JSObject *parent_proto, JSClass *clasp,
|
||||
JSNative constructor, uintN nargs,
|
||||
JSPropertySpec *ps,
|
||||
const spidermonkeyFunctionSpec *fs,
|
||||
JSPropertySpec *static_ps,
|
||||
const spidermonkeyFunctionSpec *static_fs);
|
||||
|
||||
static void undef_to_jsval(JSContext *ctx, jsval *vp);
|
||||
static unsigned char *jsval_to_string(JSContext *ctx, jsval *vp);
|
||||
|
||||
/* Inline functions */
|
||||
|
||||
static inline void
|
||||
undef_to_jsval(JSContext *ctx, jsval *vp)
|
||||
{
|
||||
*vp = JSVAL_NULL;
|
||||
}
|
||||
|
||||
static inline unsigned char *
|
||||
jsval_to_string(JSContext *ctx, jsval *vp)
|
||||
{
|
||||
jsval val;
|
||||
|
||||
if (JS_ConvertValue(ctx, *vp, JSTYPE_STRING, &val) == JS_FALSE) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return empty_string_or_(JS_GetStringBytes(JS_ValueToString(ctx, val)));
|
||||
}
|
||||
|
||||
#endif
|
@ -55,7 +55,7 @@
|
||||
|
||||
/* TODO? Are there any which need to be implemented? */
|
||||
|
||||
static JSRuntime *jsrt;
|
||||
static int js_module_init_ok;
|
||||
|
||||
static void
|
||||
error_reporter(JSContext *ctx, const char *message, JSErrorReport *report)
|
||||
@ -138,19 +138,14 @@ setup_safeguard(struct ecmascript_interpreter *interpreter,
|
||||
static void
|
||||
spidermonkey_init(struct module *xxx)
|
||||
{
|
||||
jsrt = JS_NewRuntime(0x400000UL);
|
||||
/* XXX: This is a hack to avoid a crash on exit. SMJS will crash
|
||||
* on JS_DestroyRuntime if the given runtime has never had any context
|
||||
* created, which will be the case if one closes ELinks without having
|
||||
* loaded any documents. */
|
||||
JS_DestroyContext(JS_NewContext(jsrt, 0));
|
||||
js_module_init_ok = spidermonkey_runtime_addref();
|
||||
}
|
||||
|
||||
static void
|
||||
spidermonkey_done(struct module *xxx)
|
||||
{
|
||||
JS_DestroyRuntime(jsrt);
|
||||
JS_ShutDown();
|
||||
if (js_module_init_ok)
|
||||
spidermonkey_runtime_release();
|
||||
}
|
||||
|
||||
|
||||
@ -162,8 +157,10 @@ spidermonkey_get_interpreter(struct ecmascript_interpreter *interpreter)
|
||||
*statusbar_obj, *menubar_obj, *navigator_obj;
|
||||
|
||||
assert(interpreter);
|
||||
if (!js_module_init_ok) return NULL;
|
||||
|
||||
ctx = JS_NewContext(jsrt, 8192 /* Stack allocation chunk size */);
|
||||
ctx = JS_NewContext(spidermonkey_runtime,
|
||||
8192 /* Stack allocation chunk size */);
|
||||
if (!ctx)
|
||||
return NULL;
|
||||
interpreter->backend_data = ctx;
|
||||
@ -237,6 +234,7 @@ spidermonkey_put_interpreter(struct ecmascript_interpreter *interpreter)
|
||||
JSContext *ctx;
|
||||
|
||||
assert(interpreter);
|
||||
if (!js_module_init_ok) return;
|
||||
ctx = interpreter->backend_data;
|
||||
JS_DestroyContext(ctx);
|
||||
interpreter->backend_data = NULL;
|
||||
@ -251,6 +249,7 @@ spidermonkey_eval(struct ecmascript_interpreter *interpreter,
|
||||
jsval rval;
|
||||
|
||||
assert(interpreter);
|
||||
if (!js_module_init_ok) return;
|
||||
ctx = interpreter->backend_data;
|
||||
setup_safeguard(interpreter, ctx);
|
||||
interpreter->ret = ret;
|
||||
@ -267,6 +266,7 @@ spidermonkey_eval_stringback(struct ecmascript_interpreter *interpreter,
|
||||
jsval rval;
|
||||
|
||||
assert(interpreter);
|
||||
if (!js_module_init_ok) return NULL;
|
||||
ctx = interpreter->backend_data;
|
||||
setup_safeguard(interpreter, ctx);
|
||||
interpreter->ret = NULL;
|
||||
@ -294,6 +294,7 @@ spidermonkey_eval_boolback(struct ecmascript_interpreter *interpreter,
|
||||
int ret;
|
||||
|
||||
assert(interpreter);
|
||||
if (!js_module_init_ok) return 0;
|
||||
ctx = interpreter->backend_data;
|
||||
setup_safeguard(interpreter, ctx);
|
||||
interpreter->ret = NULL;
|
||||
|
@ -7,6 +7,10 @@ struct string;
|
||||
void *spidermonkey_get_interpreter(struct ecmascript_interpreter *interpreter);
|
||||
void spidermonkey_put_interpreter(struct ecmascript_interpreter *interpreter);
|
||||
|
||||
void spidermonkey_detach_form_view(struct form_view *fv);
|
||||
void spidermonkey_detach_form_state(struct form_state *fs);
|
||||
void spidermonkey_moved_form_state(struct form_state *fs);
|
||||
|
||||
void spidermonkey_eval(struct ecmascript_interpreter *interpreter, struct string *code, struct string *ret);
|
||||
unsigned char *spidermonkey_eval_stringback(struct ecmascript_interpreter *interpreter, struct string *code);
|
||||
int spidermonkey_eval_boolback(struct ecmascript_interpreter *interpreter, struct string *code);
|
||||
|
@ -2,6 +2,6 @@ top_builddir=../../..
|
||||
include $(top_builddir)/Makefile.config
|
||||
INCLUDES += $(SPIDERMONKEY_CFLAGS)
|
||||
|
||||
OBJS = document.o form.o location.o navigator.o unibar.o util.o window.o
|
||||
OBJS = document.o form.o location.o navigator.o unibar.o window.o
|
||||
|
||||
include $(top_srcdir)/Makefile.lib
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include "document/forms.h"
|
||||
#include "document/view.h"
|
||||
#include "ecmascript/ecmascript.h"
|
||||
#include "ecmascript/spidermonkey.h"
|
||||
#include "ecmascript/spidermonkey/document.h"
|
||||
#include "ecmascript/spidermonkey/form.h"
|
||||
#include "ecmascript/spidermonkey/window.h"
|
||||
@ -56,28 +57,15 @@ static const JSClass form_class; /* defined below */
|
||||
|
||||
static JSBool input_get_property(JSContext *ctx, JSObject *obj, jsval id, jsval *vp);
|
||||
static JSBool input_set_property(JSContext *ctx, JSObject *obj, jsval id, jsval *vp);
|
||||
|
||||
/* Indexes of reserved slots in instances of @input_class. */
|
||||
enum {
|
||||
/* The slot contains an integer used as an index to
|
||||
* view_state.form_info[]. This allows ELinks to reallocate
|
||||
* form_info[] without keeping track of SMJS objects that
|
||||
* refer to its elements. We do not use JSCLASS_HAS_PRIVATE
|
||||
* for that because SMJS expects the private data to be an
|
||||
* aligned pointer. */
|
||||
JSRS_INPUT_FSINDEX,
|
||||
|
||||
/* Number of reserved slots. */
|
||||
JSRS_INPUT_COUNT
|
||||
};
|
||||
static void input_finalize(JSContext *ctx, JSObject *obj);
|
||||
|
||||
/* Each @input_class object must have a @form_class parent. */
|
||||
static const JSClass input_class = {
|
||||
"input", /* here, we unleash ourselves */
|
||||
JSCLASS_HAS_RESERVED_SLOTS(JSRS_INPUT_COUNT),
|
||||
JSCLASS_HAS_PRIVATE, /* struct form_state *, or NULL if detached */
|
||||
JS_PropertyStub, JS_PropertyStub,
|
||||
input_get_property, input_set_property,
|
||||
JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub
|
||||
JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, input_finalize
|
||||
};
|
||||
|
||||
/* Tinyids of properties. Use negative values to distinguish these
|
||||
@ -146,23 +134,18 @@ static unicode_val_T jsval_to_accesskey(JSContext *ctx, jsval *vp);
|
||||
|
||||
|
||||
static struct form_state *
|
||||
input_get_form_state(JSContext *ctx, JSObject *obj, struct view_state *vs)
|
||||
input_get_form_state(JSContext *ctx, JSObject *jsinput)
|
||||
{
|
||||
jsval val;
|
||||
int n;
|
||||
JSBool ok;
|
||||
struct form_state *fs = JS_GetInstancePrivate(ctx, jsinput,
|
||||
(JSClass *) &input_class,
|
||||
NULL);
|
||||
|
||||
ok = JS_GetReservedSlot(ctx, obj, JSRS_INPUT_FSINDEX, &val);
|
||||
assert(ok);
|
||||
assert(JSVAL_IS_INT(val));
|
||||
if (!fs) return NULL; /* detached */
|
||||
|
||||
assert(fs->ecmascript_obj == jsinput);
|
||||
if_assert_failed return NULL;
|
||||
|
||||
n = JSVAL_TO_INT(val);
|
||||
assert(n >= 0);
|
||||
assert(n < vs->form_info_len);
|
||||
if_assert_failed return NULL;
|
||||
|
||||
return &vs->form_info[n];
|
||||
return fs;
|
||||
}
|
||||
|
||||
/* @input_class.getProperty */
|
||||
@ -199,7 +182,8 @@ input_get_property(JSContext *ctx, JSObject *obj, jsval id, jsval *vp)
|
||||
(JSClass *) &window_class, NULL);
|
||||
doc_view = vs->doc_view;
|
||||
document = doc_view->document;
|
||||
fs = input_get_form_state(ctx, obj, vs);
|
||||
fs = input_get_form_state(ctx, obj);
|
||||
if (!fs) return JS_FALSE; /* detached */
|
||||
fc = find_form_control(document, fs);
|
||||
|
||||
assert(fc);
|
||||
@ -350,7 +334,8 @@ input_set_property(JSContext *ctx, JSObject *obj, jsval id, jsval *vp)
|
||||
(JSClass *) &window_class, NULL);
|
||||
doc_view = vs->doc_view;
|
||||
document = doc_view->document;
|
||||
fs = input_get_form_state(ctx, obj, vs);
|
||||
fs = input_get_form_state(ctx, obj);
|
||||
if (!fs) return JS_FALSE; /* detached */
|
||||
fc = find_form_control(document, fs);
|
||||
|
||||
assert(fc);
|
||||
@ -475,7 +460,8 @@ input_click(JSContext *ctx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
||||
doc_view = vs->doc_view;
|
||||
document = doc_view->document;
|
||||
ses = doc_view->session;
|
||||
fs = input_get_form_state(ctx, obj, vs);
|
||||
fs = input_get_form_state(ctx, obj);
|
||||
if (!fs) return JS_FALSE; /* detached */
|
||||
|
||||
assert(fs);
|
||||
fc = find_form_control(document, fs);
|
||||
@ -528,7 +514,8 @@ input_focus(JSContext *ctx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
||||
doc_view = vs->doc_view;
|
||||
document = doc_view->document;
|
||||
ses = doc_view->session;
|
||||
fs = input_get_form_state(ctx, obj, vs);
|
||||
fs = input_get_form_state(ctx, obj);
|
||||
if (!fs) return JS_FALSE; /* detached */
|
||||
|
||||
assert(fs);
|
||||
fc = find_form_control(document, fs);
|
||||
@ -555,26 +542,99 @@ input_select(JSContext *ctx, JSObject *obj, uintN argc, jsval *argv, jsval *rval
|
||||
}
|
||||
|
||||
static JSObject *
|
||||
get_input_object(JSContext *ctx, JSObject *jsform, long number)
|
||||
get_input_object(JSContext *ctx, JSObject *jsform, struct form_state *fs)
|
||||
{
|
||||
#if 0
|
||||
if (fs->ecmascript_obj)
|
||||
return fs->ecmascript_obj;
|
||||
#endif
|
||||
JSObject *jsinput = fs->ecmascript_obj;
|
||||
|
||||
if (jsinput) {
|
||||
/* This assumes JS_GetInstancePrivate cannot GC. */
|
||||
assert(JS_GetInstancePrivate(ctx, jsinput,
|
||||
(JSClass *) &input_class, NULL)
|
||||
== fs);
|
||||
if_assert_failed return NULL;
|
||||
|
||||
return jsinput;
|
||||
}
|
||||
|
||||
/* jsform ('form') is input's parent */
|
||||
/* FIXME: That is NOT correct since the real containing element
|
||||
* should be its parent, but gimme DOM first. --pasky */
|
||||
JSObject *jsinput = JS_NewObject(ctx, (JSClass *) &input_class, NULL, jsform);
|
||||
|
||||
jsinput = JS_NewObject(ctx, (JSClass *) &input_class, NULL, jsform);
|
||||
if (!jsinput)
|
||||
return NULL;
|
||||
JS_DefineProperties(ctx, jsinput, (JSPropertySpec *) input_props);
|
||||
spidermonkey_DefineFunctions(ctx, jsinput, input_funcs);
|
||||
JS_SetReservedSlot(ctx, jsinput, JSRS_INPUT_FSINDEX, INT_TO_JSVAL(number));
|
||||
return jsinput;;
|
||||
|
||||
if (!JS_SetPrivate(ctx, jsinput, fs)) /* to @input_class */
|
||||
return NULL;
|
||||
fs->ecmascript_obj = jsinput;
|
||||
return jsinput;
|
||||
}
|
||||
|
||||
static void
|
||||
input_finalize(JSContext *ctx, JSObject *jsinput)
|
||||
{
|
||||
struct form_state *fs = JS_GetInstancePrivate(ctx, jsinput,
|
||||
(JSClass *) &input_class,
|
||||
NULL);
|
||||
|
||||
if (fs) {
|
||||
/* If this assertion fails, leave fs->ecmascript_obj
|
||||
* unchanged, because it may point to a different
|
||||
* JSObject whose private pointer will later have to
|
||||
* be updated to avoid crashes. */
|
||||
assert(fs->ecmascript_obj == jsinput);
|
||||
if_assert_failed return;
|
||||
|
||||
fs->ecmascript_obj = NULL;
|
||||
/* No need to JS_SetPrivate, because jsinput is being
|
||||
* destroyed. */
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
spidermonkey_detach_form_state(struct form_state *fs)
|
||||
{
|
||||
JSObject *jsinput = fs->ecmascript_obj;
|
||||
|
||||
if (jsinput) {
|
||||
/* This assumes JS_GetInstancePrivate and JS_SetPrivate
|
||||
* cannot GC. */
|
||||
|
||||
/* If this assertion fails, it is not clear whether
|
||||
* the private pointer of jsinput should be reset;
|
||||
* crashes seem possible either way. Resetting it is
|
||||
* easiest. */
|
||||
assert(JS_GetInstancePrivate(spidermonkey_empty_context,
|
||||
jsinput,
|
||||
(JSClass *) &input_class, NULL)
|
||||
== fs);
|
||||
if_assert_failed {}
|
||||
|
||||
JS_SetPrivate(spidermonkey_empty_context, jsinput, NULL);
|
||||
fs->ecmascript_obj = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
spidermonkey_moved_form_state(struct form_state *fs)
|
||||
{
|
||||
JSObject *jsinput = fs->ecmascript_obj;
|
||||
|
||||
if (jsinput) {
|
||||
/* This assumes JS_SetPrivate cannot GC. If it could,
|
||||
* then the GC might call input_finalize for some
|
||||
* other object whose struct form_state has also been
|
||||
* reallocated, and an assertion would fail in
|
||||
* input_finalize. */
|
||||
JS_SetPrivate(spidermonkey_empty_context, jsinput, fs);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static JSObject *
|
||||
get_form_control_object(JSContext *ctx, JSObject *jsform, enum form_type type, int number)
|
||||
get_form_control_object(JSContext *ctx, JSObject *jsform,
|
||||
enum form_type type, struct form_state *fs)
|
||||
{
|
||||
switch (type) {
|
||||
case FC_TEXT:
|
||||
@ -588,7 +648,7 @@ get_form_control_object(JSContext *ctx, JSObject *jsform, enum form_type type, i
|
||||
case FC_BUTTON:
|
||||
case FC_HIDDEN:
|
||||
case FC_SELECT:
|
||||
return get_input_object(ctx, jsform, (long)number);
|
||||
return get_input_object(ctx, jsform, fs);
|
||||
|
||||
case FC_TEXTAREA:
|
||||
/* TODO */
|
||||
@ -601,7 +661,7 @@ get_form_control_object(JSContext *ctx, JSObject *jsform, enum form_type type, i
|
||||
}
|
||||
|
||||
|
||||
|
||||
static struct form_view *form_get_form_view(JSContext *ctx, JSObject *jsform, jsval *argv);
|
||||
static JSBool form_elements_get_property(JSContext *ctx, JSObject *obj, jsval id, jsval *vp);
|
||||
|
||||
/* Each @form_elements_class object must have a @form_class parent. */
|
||||
@ -666,8 +726,8 @@ form_elements_get_property(JSContext *ctx, JSObject *obj, jsval id, jsval *vp)
|
||||
(JSClass *) &window_class, NULL);
|
||||
doc_view = vs->doc_view;
|
||||
document = doc_view->document;
|
||||
form_view = JS_GetInstancePrivate(ctx, parent_form,
|
||||
(JSClass *) &form_class, NULL);
|
||||
form_view = form_get_form_view(ctx, parent_form, NULL);
|
||||
if (!form_view) return JS_FALSE; /* detached */
|
||||
form = find_form_by_form_view(document, form_view);
|
||||
|
||||
if (JSVAL_IS_STRING(id)) {
|
||||
@ -724,8 +784,8 @@ form_elements_item(JSContext *ctx, JSObject *obj, uintN argc, jsval *argv, jsval
|
||||
(JSClass *) &window_class, NULL);
|
||||
doc_view = vs->doc_view;
|
||||
document = doc_view->document;
|
||||
form_view = JS_GetInstancePrivate(ctx, parent_form,
|
||||
(JSClass *) &form_class, NULL);
|
||||
form_view = form_get_form_view(ctx, parent_form, NULL);
|
||||
if (!form_view) return JS_FALSE; /* detached */
|
||||
form = find_form_by_form_view(document, form_view);
|
||||
|
||||
if (argc != 1)
|
||||
@ -741,7 +801,7 @@ form_elements_item(JSContext *ctx, JSObject *obj, uintN argc, jsval *argv, jsval
|
||||
struct form_state *fs = find_form_state(doc_view, fc);
|
||||
|
||||
if (fs) {
|
||||
JSObject *fcobj = get_form_control_object(ctx, parent_form, fc->type, fc->g_ctrl_num);
|
||||
JSObject *fcobj = get_form_control_object(ctx, parent_form, fc->type, fs);
|
||||
|
||||
if (fcobj)
|
||||
object_to_jsval(ctx, rval, fcobj);
|
||||
@ -783,8 +843,8 @@ form_elements_namedItem(JSContext *ctx, JSObject *obj, uintN argc, jsval *argv,
|
||||
(JSClass *) &window_class, NULL);
|
||||
doc_view = vs->doc_view;
|
||||
document = doc_view->document;
|
||||
form_view = JS_GetInstancePrivate(ctx, parent_form,
|
||||
(JSClass *) &form_class, NULL);
|
||||
form_view = form_get_form_view(ctx, parent_form, NULL);
|
||||
if (!form_view) return JS_FALSE; /* detached */
|
||||
form = find_form_by_form_view(document, form_view);
|
||||
|
||||
if (argc != 1)
|
||||
@ -801,7 +861,7 @@ form_elements_namedItem(JSContext *ctx, JSObject *obj, uintN argc, jsval *argv,
|
||||
struct form_state *fs = find_form_state(doc_view, fc);
|
||||
|
||||
if (fs) {
|
||||
JSObject *fcobj = get_form_control_object(ctx, parent_form, fc->type, fc->g_ctrl_num);
|
||||
JSObject *fcobj = get_form_control_object(ctx, parent_form, fc->type, fs);
|
||||
|
||||
if (fcobj)
|
||||
object_to_jsval(ctx, rval, fcobj);
|
||||
@ -817,14 +877,15 @@ form_elements_namedItem(JSContext *ctx, JSObject *obj, uintN argc, jsval *argv,
|
||||
|
||||
static JSBool form_get_property(JSContext *ctx, JSObject *obj, jsval id, jsval *vp);
|
||||
static JSBool form_set_property(JSContext *ctx, JSObject *obj, jsval id, jsval *vp);
|
||||
static void form_finalize(JSContext *ctx, JSObject *obj);
|
||||
|
||||
/* Each @form_class object must have a @document_class parent. */
|
||||
static const JSClass form_class = {
|
||||
"form",
|
||||
JSCLASS_HAS_PRIVATE, /* struct form_view * */
|
||||
JSCLASS_HAS_PRIVATE, /* struct form_view *, or NULL if detached */
|
||||
JS_PropertyStub, JS_PropertyStub,
|
||||
form_get_property, form_set_property,
|
||||
JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub
|
||||
JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, form_finalize
|
||||
};
|
||||
|
||||
/* Tinyids of properties. Use negative values to distinguish these
|
||||
@ -861,6 +922,21 @@ static const spidermonkeyFunctionSpec form_funcs[] = {
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
static struct form_view *
|
||||
form_get_form_view(JSContext *ctx, JSObject *jsform, jsval *argv)
|
||||
{
|
||||
struct form_view *fv = JS_GetInstancePrivate(ctx, jsform,
|
||||
(JSClass *) &form_class,
|
||||
argv);
|
||||
|
||||
if (!fv) return NULL; /* detached */
|
||||
|
||||
assert(fv->ecmascript_obj == jsform);
|
||||
if_assert_failed return NULL;
|
||||
|
||||
return fv;
|
||||
}
|
||||
|
||||
/* @form_class.getProperty */
|
||||
static JSBool
|
||||
form_get_property(JSContext *ctx, JSObject *obj, jsval id, jsval *vp)
|
||||
@ -888,7 +964,8 @@ form_get_property(JSContext *ctx, JSObject *obj, jsval id, jsval *vp)
|
||||
vs = JS_GetInstancePrivate(ctx, parent_win,
|
||||
(JSClass *) &window_class, NULL);
|
||||
doc_view = vs->doc_view;
|
||||
fv = JS_GetInstancePrivate(ctx, obj, (JSClass *) &form_class, NULL);
|
||||
fv = form_get_form_view(ctx, obj, NULL);
|
||||
if (!fv) return JS_FALSE; /* detached */
|
||||
form = find_form_by_form_view(doc_view->document, fv);
|
||||
|
||||
assert(form);
|
||||
@ -908,7 +985,7 @@ form_get_property(JSContext *ctx, JSObject *obj, jsval id, jsval *vp)
|
||||
undef_to_jsval(ctx, vp);
|
||||
fs = find_form_state(doc_view, fc);
|
||||
if (fs) {
|
||||
fcobj = get_form_control_object(ctx, obj, fc->type, fc->g_ctrl_num);
|
||||
fcobj = get_form_control_object(ctx, obj, fc->type, fs);
|
||||
if (fcobj)
|
||||
object_to_jsval(ctx, vp, fcobj);
|
||||
}
|
||||
@ -1022,7 +1099,8 @@ form_set_property(JSContext *ctx, JSObject *obj, jsval id, jsval *vp)
|
||||
vs = JS_GetInstancePrivate(ctx, parent_win,
|
||||
(JSClass *) &window_class, NULL);
|
||||
doc_view = vs->doc_view;
|
||||
fv = JS_GetInstancePrivate(ctx, obj, (JSClass *) &form_class, NULL);
|
||||
fv = form_get_form_view(ctx, obj, NULL);
|
||||
if (!fv) return JS_FALSE; /* detached */
|
||||
form = find_form_by_form_view(doc_view->document, fv);
|
||||
|
||||
assert(form);
|
||||
@ -1102,7 +1180,8 @@ form_reset(JSContext *ctx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
||||
vs = JS_GetInstancePrivate(ctx, parent_win,
|
||||
(JSClass *) &window_class, NULL);
|
||||
doc_view = vs->doc_view;
|
||||
fv = JS_GetInstancePrivate(ctx, obj, (JSClass *) &form_class, argv);
|
||||
fv = form_get_form_view(ctx, obj, argv);
|
||||
if (!fv) return JS_FALSE; /* detached */
|
||||
form = find_form_by_form_view(doc_view->document, fv);
|
||||
|
||||
assert(form);
|
||||
@ -1139,7 +1218,8 @@ form_submit(JSContext *ctx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
||||
(JSClass *) &window_class, NULL);
|
||||
doc_view = vs->doc_view;
|
||||
ses = doc_view->session;
|
||||
fv = JS_GetInstancePrivate(ctx, obj, (JSClass *) &form_class, argv);
|
||||
fv = form_get_form_view(ctx, obj, argv);
|
||||
if (!fv) return JS_FALSE; /* detached */
|
||||
form = find_form_by_form_view(doc_view->document, fv);
|
||||
|
||||
assert(form);
|
||||
@ -1153,21 +1233,79 @@ form_submit(JSContext *ctx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
||||
JSObject *
|
||||
get_form_object(JSContext *ctx, JSObject *jsdoc, struct form_view *fv)
|
||||
{
|
||||
#if 0
|
||||
if (fv->ecmascript_obj)
|
||||
return fv->ecmascript_obj;
|
||||
#endif
|
||||
JSObject *jsform = fv->ecmascript_obj;
|
||||
|
||||
if (jsform) {
|
||||
/* This assumes JS_GetInstancePrivate cannot GC. */
|
||||
assert(JS_GetInstancePrivate(ctx, jsform,
|
||||
(JSClass *) &form_class, NULL)
|
||||
== fv);
|
||||
if_assert_failed return NULL;
|
||||
|
||||
return jsform;
|
||||
}
|
||||
|
||||
/* jsdoc ('document') is fv's parent */
|
||||
/* FIXME: That is NOT correct since the real containing element
|
||||
* should be its parent, but gimme DOM first. --pasky */
|
||||
JSObject *jsform = JS_NewObject(ctx, (JSClass *) &form_class, NULL, jsdoc);
|
||||
|
||||
jsform = JS_NewObject(ctx, (JSClass *) &form_class, NULL, jsdoc);
|
||||
if (jsform == NULL)
|
||||
return NULL;
|
||||
JS_DefineProperties(ctx, jsform, (JSPropertySpec *) form_props);
|
||||
spidermonkey_DefineFunctions(ctx, jsform, form_funcs);
|
||||
JS_SetPrivate(ctx, jsform, fv); /* to @form_class */
|
||||
|
||||
if (!JS_SetPrivate(ctx, jsform, fv)) /* to @form_class */
|
||||
return NULL;
|
||||
fv->ecmascript_obj = jsform;
|
||||
return fv->ecmascript_obj;
|
||||
return jsform;
|
||||
}
|
||||
|
||||
static void
|
||||
form_finalize(JSContext *ctx, JSObject *jsform)
|
||||
{
|
||||
struct form_view *fv = JS_GetInstancePrivate(ctx, jsform,
|
||||
(JSClass *) &form_class,
|
||||
NULL);
|
||||
|
||||
if (fv) {
|
||||
/* If this assertion fails, leave fv->ecmascript_obj
|
||||
* unchanged, because it may point to a different
|
||||
* JSObject whose private pointer will later have to
|
||||
* be updated to avoid crashes. */
|
||||
assert(fv->ecmascript_obj == jsform);
|
||||
if_assert_failed return;
|
||||
|
||||
fv->ecmascript_obj = NULL;
|
||||
/* No need to JS_SetPrivate, because the object is
|
||||
* being destroyed. */
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
spidermonkey_detach_form_view(struct form_view *fv)
|
||||
{
|
||||
JSObject *jsform = fv->ecmascript_obj;
|
||||
|
||||
if (jsform) {
|
||||
/* This assumes JS_GetInstancePrivate and JS_SetPrivate
|
||||
* cannot GC. */
|
||||
|
||||
/* If this assertion fails, it is not clear whether
|
||||
* the private pointer of jsform should be reset;
|
||||
* crashes seem possible either way. Resetting it is
|
||||
* easiest. */
|
||||
assert(JS_GetInstancePrivate(spidermonkey_empty_context,
|
||||
jsform,
|
||||
(JSClass *) &form_class, NULL)
|
||||
== fv);
|
||||
if_assert_failed {}
|
||||
|
||||
JS_SetPrivate(spidermonkey_empty_context, jsform, NULL);
|
||||
fv->ecmascript_obj = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static JSBool forms_get_property(JSContext *ctx, JSObject *obj, jsval id, jsval *vp);
|
||||
|
||||
/* Each @forms_class object must have a @document_class parent. */
|
||||
|
@ -1,60 +0,0 @@
|
||||
/* Better compatibility across versions of SpiderMonkey. */
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "elinks.h"
|
||||
|
||||
#include "ecmascript/spidermonkey/util.h"
|
||||
|
||||
/** An ELinks-specific replacement for JS_DefineFunctions().
|
||||
*
|
||||
* @relates spidermonkeyFunctionSpec */
|
||||
JSBool
|
||||
spidermonkey_DefineFunctions(JSContext *cx, JSObject *obj,
|
||||
const spidermonkeyFunctionSpec *fs)
|
||||
{
|
||||
for (; fs->name; fs++) {
|
||||
if (!JS_DefineFunction(cx, obj, fs->name, fs->call,
|
||||
fs->nargs, 0))
|
||||
return JS_FALSE;
|
||||
}
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
/** An ELinks-specific replacement for JS_InitClass().
|
||||
*
|
||||
* @relates spidermonkeyFunctionSpec */
|
||||
JSObject *
|
||||
spidermonkey_InitClass(JSContext *cx, JSObject *obj,
|
||||
JSObject *parent_proto, JSClass *clasp,
|
||||
JSNative constructor, uintN nargs,
|
||||
JSPropertySpec *ps,
|
||||
const spidermonkeyFunctionSpec *fs,
|
||||
JSPropertySpec *static_ps,
|
||||
const spidermonkeyFunctionSpec *static_fs)
|
||||
{
|
||||
JSObject *proto = JS_InitClass(cx, obj, parent_proto, clasp,
|
||||
constructor, nargs,
|
||||
ps, NULL, static_ps, NULL);
|
||||
|
||||
if (proto == NULL)
|
||||
return NULL;
|
||||
|
||||
if (fs) {
|
||||
if (!spidermonkey_DefineFunctions(cx, proto, fs))
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (static_fs) {
|
||||
JSObject *cons_obj = JS_GetConstructor(cx, proto);
|
||||
|
||||
if (cons_obj == NULL)
|
||||
return NULL;
|
||||
if (!spidermonkey_DefineFunctions(cx, cons_obj, static_fs))
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return proto;
|
||||
}
|
@ -2,32 +2,16 @@
|
||||
#ifndef EL__ECMASCRIPT_SPIDERMONKEY_UTIL_H
|
||||
#define EL__ECMASCRIPT_SPIDERMONKEY_UTIL_H
|
||||
|
||||
/* For wild SpiderMonkey installations. */
|
||||
#ifdef CONFIG_OS_BEOS
|
||||
#define XP_BEOS
|
||||
#elif CONFIG_OS_OS2
|
||||
#define XP_OS2
|
||||
#elif CONFIG_OS_RISCOS
|
||||
#error Out of luck, buddy!
|
||||
#elif CONFIG_OS_UNIX
|
||||
#define XP_UNIX
|
||||
#elif CONFIG_OS_WIN32
|
||||
#define XP_WIN
|
||||
#endif
|
||||
|
||||
#include <jsapi.h>
|
||||
#include "ecmascript/spidermonkey-shared.h"
|
||||
#include "util/memory.h"
|
||||
#include "util/string.h"
|
||||
|
||||
static void string_to_jsval(JSContext *ctx, jsval *vp, unsigned char *string);
|
||||
static void astring_to_jsval(JSContext *ctx, jsval *vp, unsigned char *string);
|
||||
static void int_to_jsval(JSContext *ctx, jsval *vp, int number);
|
||||
static void object_to_jsval(JSContext *ctx, jsval *vp, JSObject *object);
|
||||
static void boolean_to_jsval(JSContext *ctx, jsval *vp, int boolean);
|
||||
static void undef_to_jsval(JSContext *ctx, jsval *vp);
|
||||
|
||||
static int jsval_to_boolean(JSContext *ctx, jsval *vp);
|
||||
static unsigned char *jsval_to_string(JSContext *ctx, jsval *vp);
|
||||
|
||||
|
||||
|
||||
@ -68,12 +52,6 @@ boolean_to_jsval(JSContext *ctx, jsval *vp, int boolean)
|
||||
*vp = BOOLEAN_TO_JSVAL(boolean);
|
||||
}
|
||||
|
||||
static inline void
|
||||
undef_to_jsval(JSContext *ctx, jsval *vp)
|
||||
{
|
||||
*vp = JSVAL_NULL;
|
||||
}
|
||||
|
||||
|
||||
static inline int
|
||||
jsval_to_boolean(JSContext *ctx, jsval *vp)
|
||||
@ -87,41 +65,4 @@ jsval_to_boolean(JSContext *ctx, jsval *vp)
|
||||
return JSVAL_TO_BOOLEAN(val);
|
||||
}
|
||||
|
||||
static inline unsigned char *
|
||||
jsval_to_string(JSContext *ctx, jsval *vp)
|
||||
{
|
||||
jsval val;
|
||||
|
||||
if (JS_ConvertValue(ctx, *vp, JSTYPE_STRING, &val) == JS_FALSE) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return empty_string_or_(JS_GetStringBytes(JS_ValueToString(ctx, val)));
|
||||
}
|
||||
|
||||
/** An ELinks-specific replacement for JSFunctionSpec.
|
||||
*
|
||||
* Bug 1016: In SpiderMonkey 1.7 bundled with XULRunner 1.8, jsapi.h
|
||||
* defines JSFunctionSpec in different ways depending on whether
|
||||
* MOZILLA_1_8_BRANCH is defined, and there is no obvious way for
|
||||
* ELinks to check whether MOZILLA_1_8_BRANCH was defined when the
|
||||
* library was built. Avoid the unstable JSFunctionSpec definitions
|
||||
* and use this ELinks-specific structure instead. */
|
||||
typedef struct spidermonkeyFunctionSpec {
|
||||
const char *name;
|
||||
JSNative call;
|
||||
uint8 nargs;
|
||||
/* ELinks does not use "flags" and "extra" so omit them here. */
|
||||
} spidermonkeyFunctionSpec;
|
||||
|
||||
JSBool spidermonkey_DefineFunctions(JSContext *cx, JSObject *obj,
|
||||
const spidermonkeyFunctionSpec *fs);
|
||||
JSObject *spidermonkey_InitClass(JSContext *cx, JSObject *obj,
|
||||
JSObject *parent_proto, JSClass *clasp,
|
||||
JSNative constructor, uintN nargs,
|
||||
JSPropertySpec *ps,
|
||||
const spidermonkeyFunctionSpec *fs,
|
||||
JSPropertySpec *static_ps,
|
||||
const spidermonkeyFunctionSpec *static_fs);
|
||||
|
||||
#endif
|
||||
|
@ -342,7 +342,7 @@ window_open(JSContext *ctx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
||||
struct document_view *doc_view;
|
||||
struct session *ses;
|
||||
unsigned char *frame = "";
|
||||
unsigned char *url;
|
||||
unsigned char *url, *url2;
|
||||
struct uri *uri;
|
||||
static time_t ratelimit_start;
|
||||
static int ratelimit_count;
|
||||
@ -387,10 +387,13 @@ window_open(JSContext *ctx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
||||
|
||||
/* TODO: Support for window naming and perhaps some window features? */
|
||||
|
||||
url = join_urls(doc_view->document->uri, url);
|
||||
if (!url) return JS_TRUE;
|
||||
uri = get_uri(url, 0);
|
||||
url2 = join_urls(doc_view->document->uri, url);
|
||||
mem_free(url);
|
||||
if (!url2) {
|
||||
return JS_TRUE;
|
||||
}
|
||||
uri = get_uri(url2, 0);
|
||||
mem_free(url2);
|
||||
if (!uri) return JS_TRUE;
|
||||
|
||||
|
||||
|
@ -30,6 +30,7 @@ struct deflate_enc_data {
|
||||
int fdread;
|
||||
|
||||
unsigned int last_read:1;
|
||||
unsigned int after_first_read:1;
|
||||
|
||||
/* A buffer for data that has been read from the file but not
|
||||
* yet decompressed. z_stream.next_in and z_stream.avail_in
|
||||
@ -59,6 +60,7 @@ deflate_open(int window_size, struct stream_encoded *stream, int fd)
|
||||
copy_struct(&data->deflate_stream, &null_z_stream);
|
||||
data->fdread = fd;
|
||||
data->last_read = 0;
|
||||
data->after_first_read = 0;
|
||||
|
||||
err = inflateInit2(&data->deflate_stream, window_size);
|
||||
if (err != Z_OK) {
|
||||
@ -70,12 +72,14 @@ deflate_open(int window_size, struct stream_encoded *stream, int fd)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if 0
|
||||
static int
|
||||
deflate_raw_open(struct stream_encoded *stream, int fd)
|
||||
{
|
||||
/* raw DEFLATE with neither zlib nor gzip header */
|
||||
return deflate_open(-MAX_WBITS, stream, fd);
|
||||
}
|
||||
#endif
|
||||
|
||||
static int
|
||||
deflate_gzip_open(struct stream_encoded *stream, int fd)
|
||||
@ -89,6 +93,7 @@ deflate_read(struct stream_encoded *stream, unsigned char *buf, int len)
|
||||
{
|
||||
struct deflate_enc_data *data = (struct deflate_enc_data *) stream->data;
|
||||
int err = 0;
|
||||
int l = 0;
|
||||
|
||||
if (!data) return -1;
|
||||
|
||||
@ -101,7 +106,7 @@ deflate_read(struct stream_encoded *stream, unsigned char *buf, int len)
|
||||
|
||||
do {
|
||||
if (data->deflate_stream.avail_in == 0) {
|
||||
int l = safe_read(data->fdread, data->buf,
|
||||
l = safe_read(data->fdread, data->buf,
|
||||
ELINKS_DEFLATE_BUFFER_LENGTH);
|
||||
|
||||
if (l == -1) {
|
||||
@ -117,7 +122,39 @@ deflate_read(struct stream_encoded *stream, unsigned char *buf, int len)
|
||||
data->deflate_stream.next_in = data->buf;
|
||||
data->deflate_stream.avail_in = l;
|
||||
}
|
||||
restart:
|
||||
err = inflate(&data->deflate_stream, Z_SYNC_FLUSH);
|
||||
if (err == Z_DATA_ERROR && !data->after_first_read) {
|
||||
/* RFC 2616 requires a zlib header for
|
||||
* "Content-Encoding: deflate", but some HTTP
|
||||
* servers (Microsoft-IIS/6.0 at blogs.msdn.com,
|
||||
* and reportedly Apache with mod_deflate) omit
|
||||
* that, causing Z_DATA_ERROR. Clarification of
|
||||
* the term "deflate" has been requested for the
|
||||
* next version of HTTP:
|
||||
* http://www3.tools.ietf.org/wg/httpbis/trac/ticket/73
|
||||
*
|
||||
* Try to recover by telling zlib not to expect
|
||||
* the header. If the error does not happen on
|
||||
* the first inflate() call, then it is too late
|
||||
* to recover because ELinks may already have
|
||||
* discarded part of the input data.
|
||||
*
|
||||
* TODO: This fallback to raw DEFLATE is currently
|
||||
* enabled for "Content-Encoding: gzip" too. It
|
||||
* might be better to fall back to no compression
|
||||
* at all, because Apache can send that header for
|
||||
* uncompressed *.gz.md5 files. */
|
||||
data->after_first_read = 1;
|
||||
inflateEnd(&data->deflate_stream);
|
||||
data->deflate_stream.avail_out = len;
|
||||
data->deflate_stream.next_out = buf;
|
||||
data->deflate_stream.next_in = data->buf;
|
||||
data->deflate_stream.avail_in = l;
|
||||
err = inflateInit2(&data->deflate_stream, -MAX_WBITS);
|
||||
if (err == Z_OK) goto restart;
|
||||
}
|
||||
data->after_first_read = 1;
|
||||
if (err == Z_STREAM_END) {
|
||||
data->last_read = 1;
|
||||
break;
|
||||
@ -211,7 +248,7 @@ static const unsigned char *const deflate_extensions[] = { NULL };
|
||||
const struct decoding_backend deflate_decoding_backend = {
|
||||
"deflate",
|
||||
deflate_extensions,
|
||||
deflate_raw_open,
|
||||
deflate_gzip_open,
|
||||
deflate_read,
|
||||
deflate_raw_decode_buffer,
|
||||
deflate_close,
|
||||
|
@ -7,7 +7,7 @@
|
||||
#include "elinks.h"
|
||||
|
||||
#include "config/kbdbind.h"
|
||||
#include "ecmascript/spidermonkey/util.h"
|
||||
#include "ecmascript/spidermonkey-shared.h"
|
||||
#include "scripting/smjs/core.h"
|
||||
#include "scripting/smjs/elinks_object.h"
|
||||
#include "session/session.h"
|
||||
|
@ -7,7 +7,7 @@
|
||||
#include "elinks.h"
|
||||
|
||||
#include "bookmarks/bookmarks.h"
|
||||
#include "ecmascript/spidermonkey/util.h"
|
||||
#include "ecmascript/spidermonkey-shared.h"
|
||||
#include "main/event.h"
|
||||
#include "scripting/smjs/core.h"
|
||||
#include "scripting/smjs/elinks_object.h"
|
||||
|
@ -1,7 +1,7 @@
|
||||
#ifndef EL__SCRIPTING_SMJS_BOOKMARKS_H
|
||||
#define EL__SCRIPTING_SMJS_BOOKMARKS_H
|
||||
|
||||
#include "ecmascript/spidermonkey/util.h"
|
||||
#include "ecmascript/spidermonkey-shared.h"
|
||||
|
||||
void smjs_init_bookmarks_interface(void);
|
||||
|
||||
|
@ -7,7 +7,7 @@
|
||||
#include "elinks.h"
|
||||
|
||||
#include "cache/cache.h"
|
||||
#include "ecmascript/spidermonkey/util.h"
|
||||
#include "ecmascript/spidermonkey-shared.h"
|
||||
#include "protocol/uri.h"
|
||||
#include "scripting/smjs/cache_object.h"
|
||||
#include "scripting/smjs/core.h"
|
||||
|
@ -7,7 +7,7 @@
|
||||
#include "elinks.h"
|
||||
|
||||
#include "config/home.h"
|
||||
#include "ecmascript/spidermonkey/util.h"
|
||||
#include "ecmascript/spidermonkey-shared.h"
|
||||
#include "main/module.h"
|
||||
#include "osdep/osdep.h"
|
||||
#include "scripting/scripting.h"
|
||||
@ -68,8 +68,6 @@ reported:
|
||||
JS_ClearPendingException(ctx);
|
||||
}
|
||||
|
||||
static JSRuntime *smjs_rt;
|
||||
|
||||
static int
|
||||
smjs_do_file(unsigned char *path)
|
||||
{
|
||||
@ -127,13 +125,11 @@ smjs_load_hooks(void)
|
||||
void
|
||||
init_smjs(struct module *module)
|
||||
{
|
||||
smjs_rt = JS_NewRuntime(1L * 1024L * 1024L);
|
||||
if (!smjs_rt) return;
|
||||
if (!spidermonkey_runtime_addref()) return;
|
||||
|
||||
smjs_ctx = JS_NewContext(smjs_rt, 8192);
|
||||
smjs_ctx = JS_NewContext(spidermonkey_runtime, 8192);
|
||||
if (!smjs_ctx) {
|
||||
JS_DestroyRuntime(smjs_rt);
|
||||
smjs_rt = NULL;
|
||||
spidermonkey_runtime_release();
|
||||
return;
|
||||
}
|
||||
|
||||
@ -154,9 +150,15 @@ cleanup_smjs(struct module *module)
|
||||
{
|
||||
if (!smjs_ctx) return;
|
||||
|
||||
/* These calls also finalize all JSObjects that have been
|
||||
* allocated in the JSRuntime, so cache_entry_finalize gets
|
||||
* called and resets each cache_entry.jsobject = NULL. */
|
||||
/* JS_DestroyContext also collects garbage in the JSRuntime.
|
||||
* Because the JSObjects created in smjs_ctx have not been
|
||||
* made visible to any other JSContext, and the garbage
|
||||
* collector of SpiderMonkey is precise, SpiderMonkey
|
||||
* finalizes all of those objects, so cache_entry_finalize
|
||||
* gets called and resets each cache_entry.jsobject = NULL.
|
||||
* If the garbage collector were conservative, ELinks would
|
||||
* have to call smjs_detach_cache_entry_object on each cache
|
||||
* entry before it releases the runtime here. */
|
||||
JS_DestroyContext(smjs_ctx);
|
||||
JS_DestroyRuntime(smjs_rt);
|
||||
spidermonkey_runtime_release();
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
#ifndef EL__SCRIPTING_SMJS_CORE_H
|
||||
#define EL__SCRIPTING_SMJS_CORE_H
|
||||
|
||||
#include "ecmascript/spidermonkey/util.h"
|
||||
#include "ecmascript/spidermonkey-shared.h"
|
||||
|
||||
struct module;
|
||||
struct session;
|
||||
|
@ -8,7 +8,7 @@
|
||||
|
||||
#include "bfu/msgbox.h"
|
||||
#include "config/home.h"
|
||||
#include "ecmascript/spidermonkey/util.h"
|
||||
#include "ecmascript/spidermonkey-shared.h"
|
||||
#include "intl/gettext/libintl.h"
|
||||
#include "protocol/uri.h"
|
||||
#include "scripting/scripting.h"
|
||||
@ -69,7 +69,7 @@ elinks_set_location(JSContext *ctx, JSObject *obj, jsval id, jsval *vp)
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
/* function "alert" in the object returned by smjs_get_elinks_object() */
|
||||
/* @elinks_funcs{"alert"} */
|
||||
static JSBool
|
||||
elinks_alert(JSContext *ctx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
||||
{
|
||||
@ -90,7 +90,7 @@ elinks_alert(JSContext *ctx, JSObject *obj, uintN argc, jsval *argv, jsval *rval
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
/* function "execute" in the object returned by smjs_get_elinks_object() */
|
||||
/* @elinks_funcs{"execute"} */
|
||||
static JSBool
|
||||
elinks_execute(JSContext *ctx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
||||
{
|
||||
@ -117,6 +117,12 @@ static const JSClass elinks_class = {
|
||||
JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub
|
||||
};
|
||||
|
||||
static const spidermonkeyFunctionSpec elinks_funcs[] = {
|
||||
{ "alert", elinks_alert, 1 },
|
||||
{ "execute", elinks_execute, 1 },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
static JSObject *
|
||||
smjs_get_elinks_object(void)
|
||||
{
|
||||
@ -125,24 +131,9 @@ smjs_get_elinks_object(void)
|
||||
assert(smjs_ctx);
|
||||
assert(smjs_global_object);
|
||||
|
||||
jsobj = JS_InitClass(smjs_ctx, smjs_global_object, NULL,
|
||||
jsobj = spidermonkey_InitClass(smjs_ctx, smjs_global_object, NULL,
|
||||
(JSClass *) &elinks_class, NULL, 0, NULL,
|
||||
(JSFunctionSpec *) NULL, NULL, NULL);
|
||||
|
||||
/* Bug 1016: In SpiderMonkey 1.7 bundled with XULRunner 1.8,
|
||||
* jsapi.h defines JSFunctionSpec in different ways depending
|
||||
* on whether MOZILLA_1_8_BRANCH is defined, and there is no
|
||||
* obvious way for ELinks to check whether MOZILLA_1_8_BRANCH
|
||||
* was defined when the library was built. Avoid the unstable
|
||||
* JSFunctionSpec definitions and instead use JS_DefineFunction
|
||||
* directly.
|
||||
*
|
||||
* In elinks/src/ecmascript/spidermonkey/, there is an
|
||||
* ELinks-specific replacement for JSFunctionSpec; however, to
|
||||
* keep the modules independent, elinks/src/scripting/smjs/
|
||||
* does not use that. */
|
||||
JS_DefineFunction(smjs_ctx, jsobj, "alert", elinks_alert, 1, 0);
|
||||
JS_DefineFunction(smjs_ctx, jsobj, "execute", elinks_execute, 1, 0);
|
||||
elinks_funcs, NULL, NULL);
|
||||
|
||||
JS_DefineProperty(smjs_ctx, jsobj, "location", JSVAL_NULL,
|
||||
elinks_get_location, elinks_set_location,
|
||||
@ -176,8 +167,6 @@ JSBool
|
||||
smjs_invoke_elinks_object_method(unsigned char *method, jsval argv[], int argc,
|
||||
jsval *rval)
|
||||
{
|
||||
JSFunction *func;
|
||||
|
||||
assert(smjs_ctx);
|
||||
assert(smjs_elinks_object);
|
||||
assert(rval);
|
||||
@ -190,9 +179,6 @@ smjs_invoke_elinks_object_method(unsigned char *method, jsval argv[], int argc,
|
||||
if (JSVAL_VOID == *rval)
|
||||
return JS_FALSE;
|
||||
|
||||
func = JS_ValueToFunction(smjs_ctx, *rval);
|
||||
if (!func) return JS_FALSE;
|
||||
|
||||
return JS_CallFunction(smjs_ctx, smjs_elinks_object,
|
||||
func, argc, argv, rval);
|
||||
return JS_CallFunctionValue(smjs_ctx, smjs_elinks_object,
|
||||
*rval, argc, argv, rval);
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
#ifndef EL__SCRIPTING_SMJS_ELINKS_OBJECT_H
|
||||
#define EL__SCRIPTING_SMJS_ELINKS_OBJECT_H
|
||||
|
||||
#include "ecmascript/spidermonkey/util.h"
|
||||
#include "ecmascript/spidermonkey-shared.h"
|
||||
|
||||
/* This is the all-powerful elinks object through which all client scripts
|
||||
* will interface with ELinks. */
|
||||
|
@ -6,7 +6,7 @@
|
||||
|
||||
#include "elinks.h"
|
||||
|
||||
#include "ecmascript/spidermonkey/util.h"
|
||||
#include "ecmascript/spidermonkey-shared.h"
|
||||
#include "scripting/scripting.h"
|
||||
#include "scripting/smjs/core.h"
|
||||
#include "scripting/smjs/global_object.h"
|
||||
|
@ -1,7 +1,7 @@
|
||||
#ifndef EL__SCRIPTING_SMJS_GLOBAL_OBJECT_H
|
||||
#define EL__SCRIPTING_SMJS_GLOBAL_OBJECT_H
|
||||
|
||||
#include "ecmascript/spidermonkey/util.h"
|
||||
#include "ecmascript/spidermonkey-shared.h"
|
||||
|
||||
/* The root of the object hierarchy. If object 'foo' has this as its parent,
|
||||
* you can use foo's method and properties with 'foo.<method|property>'. */
|
||||
|
@ -7,7 +7,7 @@
|
||||
#include "elinks.h"
|
||||
|
||||
#include "globhist/globhist.h"
|
||||
#include "ecmascript/spidermonkey/util.h"
|
||||
#include "ecmascript/spidermonkey-shared.h"
|
||||
#include "scripting/smjs/core.h"
|
||||
#include "scripting/smjs/elinks_object.h"
|
||||
#include "util/memory.h"
|
||||
|
@ -7,7 +7,7 @@
|
||||
#include "elinks.h"
|
||||
|
||||
#include "cache/cache.h"
|
||||
#include "ecmascript/spidermonkey/util.h"
|
||||
#include "ecmascript/spidermonkey-shared.h"
|
||||
#include "protocol/uri.h"
|
||||
#include "main/event.h"
|
||||
#include "main/module.h"
|
||||
|
@ -7,7 +7,7 @@
|
||||
#include "elinks.h"
|
||||
|
||||
#include "config/kbdbind.h"
|
||||
#include "ecmascript/spidermonkey/util.h"
|
||||
#include "ecmascript/spidermonkey-shared.h"
|
||||
#include "main/event.h"
|
||||
#include "scripting/smjs/core.h"
|
||||
#include "scripting/smjs/elinks_object.h"
|
||||
@ -55,15 +55,13 @@ smjs_keybinding_action_callback(va_list ap, void *data)
|
||||
jsval rval;
|
||||
struct session *ses = va_arg(ap, struct session *);
|
||||
JSObject *jsobj = data;
|
||||
JSFunction *func = JS_ValueToFunction(smjs_ctx, OBJECT_TO_JSVAL(jsobj));
|
||||
|
||||
evhook_use_params(ses);
|
||||
|
||||
assert(func);
|
||||
|
||||
smjs_ses = ses;
|
||||
|
||||
JS_CallFunction(smjs_ctx, NULL, func, 0, NULL, &rval);
|
||||
JS_CallFunctionValue(smjs_ctx, NULL, OBJECT_TO_JSVAL(jsobj),
|
||||
0, NULL, &rval);
|
||||
|
||||
smjs_ses = NULL;
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
#ifndef EL__SCRIPTING_SMJS_KEYBINDING_H
|
||||
#define EL__SCRIPTING_SMJS_KEYBINDING_H
|
||||
|
||||
#include "ecmascript/spidermonkey/util.h"
|
||||
#include "ecmascript/spidermonkey-shared.h"
|
||||
|
||||
void smjs_init_keybinding_interface(void);
|
||||
|
||||
|
@ -6,7 +6,7 @@
|
||||
|
||||
#include "elinks.h"
|
||||
|
||||
#include "ecmascript/spidermonkey/util.h"
|
||||
#include "ecmascript/spidermonkey-shared.h"
|
||||
#include "network/connection.h"
|
||||
#include "protocol/uri.h"
|
||||
#include "scripting/smjs/core.h"
|
||||
@ -17,7 +17,13 @@
|
||||
|
||||
struct smjs_load_uri_hop {
|
||||
struct session *ses;
|
||||
JSFunction *callback;
|
||||
|
||||
/* SpiderMonkey versions earlier than 1.8 cannot properly call
|
||||
* a closure if given just a JSFunction pointer. They need a
|
||||
* jsval that points to the corresponding JSObject. Besides,
|
||||
* JS_AddNamedRoot is not documented to support JSFunction
|
||||
* pointers. */
|
||||
jsval callback;
|
||||
};
|
||||
|
||||
static void
|
||||
@ -39,20 +45,18 @@ smjs_loading_callback(struct download *download, void *data)
|
||||
* the script is using it. */
|
||||
object_lock(download->cached);
|
||||
|
||||
assert(hop->callback);
|
||||
|
||||
smjs_ses = hop->ses;
|
||||
|
||||
cache_entry_object = smjs_get_cache_entry_object(download->cached);
|
||||
if (!cache_entry_object) goto end;
|
||||
|
||||
args[0] = OBJECT_TO_JSVAL(cache_entry_object);
|
||||
|
||||
JS_CallFunction(smjs_ctx, NULL, hop->callback, 1, args, &rval);
|
||||
JS_CallFunctionValue(smjs_ctx, NULL, hop->callback, 1, args, &rval);
|
||||
|
||||
end:
|
||||
if (download->cached)
|
||||
object_unlock(download->cached);
|
||||
JS_RemoveRoot(smjs_ctx, &hop->callback);
|
||||
mem_free(download->data);
|
||||
mem_free(download);
|
||||
|
||||
@ -85,13 +89,20 @@ smjs_load_uri(JSContext *ctx, JSObject *obj, uintN argc, jsval *argv,
|
||||
|
||||
hop = mem_alloc(sizeof(*hop));
|
||||
if (!hop) {
|
||||
done_uri(uri);
|
||||
mem_free(download);
|
||||
done_uri(uri);
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
hop->callback = JS_ValueToFunction(smjs_ctx, argv[1]);
|
||||
hop->callback = argv[1];
|
||||
hop->ses = smjs_ses;
|
||||
if (!JS_AddNamedRoot(smjs_ctx, &hop->callback,
|
||||
"smjs_load_uri_hop.callback")) {
|
||||
mem_free(hop);
|
||||
mem_free(download);
|
||||
done_uri(uri);
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
download->data = hop;
|
||||
download->callback = (download_callback_T *) smjs_loading_callback;
|
||||
|
@ -8,7 +8,7 @@
|
||||
|
||||
#include "elinks.h"
|
||||
|
||||
#include "ecmascript/spidermonkey/util.h"
|
||||
#include "ecmascript/spidermonkey-shared.h"
|
||||
#include "protocol/uri.h"
|
||||
#include "scripting/smjs/elinks_object.h"
|
||||
#include "scripting/smjs/view_state_object.h"
|
||||
|
@ -30,6 +30,7 @@
|
||||
#include "document/document.h"
|
||||
#include "document/forms.h"
|
||||
#include "document/view.h"
|
||||
#include "ecmascript/ecmascript.h"
|
||||
#include "intl/gettext/libintl.h"
|
||||
#include "formhist/formhist.h"
|
||||
#include "mime/mime.h"
|
||||
@ -251,11 +252,30 @@ find_form_state(struct document_view *doc_view, struct form_control *fc)
|
||||
|
||||
if (n >= vs->form_info_len) {
|
||||
int nn = n + 1;
|
||||
#ifdef CONFIG_ECMASCRIPT
|
||||
const struct form_state *const old_form_info = vs->form_info;
|
||||
#endif
|
||||
|
||||
fs = mem_align_alloc(&vs->form_info, vs->form_info_len, nn, 0);
|
||||
if (!fs) return NULL;
|
||||
vs->form_info = fs;
|
||||
vs->form_info_len = nn;
|
||||
|
||||
#ifdef CONFIG_ECMASCRIPT
|
||||
/* TODO: Standard C does not allow this comparison;
|
||||
* if the memory to which old_form_info pointed has
|
||||
* been freed, then the value of the pointer itself is
|
||||
* indeterminate. Fixing this would require changing
|
||||
* mem_align_alloc to tell the caller whether it did
|
||||
* realloc or not. */
|
||||
if (vs->form_info != old_form_info) {
|
||||
/* vs->form_info[] was moved to a different address.
|
||||
* Update all the ECMAScript objects that have
|
||||
* pointers to its elements. */
|
||||
for (nn = 0; nn < vs->form_info_len; nn++)
|
||||
ecmascript_moved_form_state(&vs->form_info[nn]);
|
||||
}
|
||||
#endif /* CONFIG_ECMASCRIPT */
|
||||
}
|
||||
fs = &vs->form_info[n];
|
||||
|
||||
@ -327,6 +347,29 @@ find_form_by_form_view(struct document *document, struct form_view *fv)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/** Free any data owned by @a fs, but not the struct form_state
|
||||
* itself, because that is normally allocated as part of an array.
|
||||
* @relates form_state */
|
||||
void
|
||||
done_form_state(struct form_state *fs)
|
||||
{
|
||||
#ifdef CONFIG_ECMASCRIPT
|
||||
ecmascript_detach_form_state(fs);
|
||||
#endif
|
||||
mem_free_if(fs->value);
|
||||
}
|
||||
|
||||
/** Free @a fv and any data owned by it. This does not call
|
||||
* del_from_list(fv), so the caller must usually do that first.
|
||||
* @relates form_view */
|
||||
void
|
||||
done_form_view(struct form_view *fv)
|
||||
{
|
||||
#ifdef CONFIG_ECMASCRIPT
|
||||
ecmascript_detach_form_view(fv);
|
||||
#endif
|
||||
mem_free(fv);
|
||||
}
|
||||
|
||||
int
|
||||
get_current_state(struct session *ses)
|
||||
|
@ -113,6 +113,9 @@ struct form_view *find_form_view_in_vs(struct view_state *vs, int form_num);
|
||||
struct form_view *find_form_view(struct document_view *doc_view, struct form *form);
|
||||
struct form *find_form_by_form_view(struct document *document, struct form_view *fv);
|
||||
|
||||
void done_form_state(struct form_state *);
|
||||
void done_form_view(struct form_view *);
|
||||
|
||||
enum frame_event_status field_op(struct session *ses, struct document_view *doc_view, struct link *link, struct term_event *ev);
|
||||
|
||||
void draw_form_entry(struct terminal *term, struct document_view *doc_view, struct link *link);
|
||||
|
@ -262,6 +262,7 @@ get_range(struct document *document, int y, int height, int l,
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef HAVE_REGEX_H
|
||||
/** Returns a string @c doc that is a copy of the text in the search
|
||||
* nodes from @a s1 to (@a s1 + @a doclen - 1) with the space at the
|
||||
* end of each line converted to a new-line character (LF). */
|
||||
@ -293,7 +294,6 @@ get_search_region_from_search_nodes(struct search *s1, struct search *s2,
|
||||
return doc;
|
||||
}
|
||||
|
||||
#ifdef HAVE_REGEX_H
|
||||
struct regex_match_context {
|
||||
struct search *s1;
|
||||
struct search *s2;
|
||||
@ -1579,14 +1579,17 @@ search_typeahead(struct session *ses, struct document_view *doc_view,
|
||||
* a nice cleanup target ;-). --pasky */
|
||||
|
||||
enum search_option {
|
||||
#ifdef HAVE_REGEX_H
|
||||
SEARCH_OPT_REGEX,
|
||||
#endif
|
||||
SEARCH_OPT_CASE,
|
||||
|
||||
SEARCH_OPTIONS,
|
||||
};
|
||||
|
||||
static struct option_resolver resolvers[] = {
|
||||
#ifdef HAVE_REGEX_H
|
||||
{ SEARCH_OPT_REGEX, "regex" },
|
||||
#endif
|
||||
{ SEARCH_OPT_CASE, "case" },
|
||||
};
|
||||
|
||||
@ -1651,7 +1654,11 @@ search_dlg_do(struct terminal *term, struct memory_list *ml,
|
||||
hop->values, SEARCH_OPTIONS);
|
||||
hop->data = data;
|
||||
|
||||
#ifdef HAVE_REGEX_H
|
||||
#define SEARCH_WIDGETS_COUNT 8
|
||||
#else
|
||||
#define SEARCH_WIDGETS_COUNT 5
|
||||
#endif
|
||||
dlg = calloc_dialog(SEARCH_WIDGETS_COUNT, MAX_STR_LEN);
|
||||
if (!dlg) {
|
||||
mem_free(hop);
|
||||
@ -1671,9 +1678,11 @@ search_dlg_do(struct terminal *term, struct memory_list *ml,
|
||||
field = get_dialog_offset(dlg, SEARCH_WIDGETS_COUNT);
|
||||
add_dlg_field(dlg, text, 0, 0, NULL, MAX_STR_LEN, field, history);
|
||||
|
||||
#ifdef HAVE_REGEX_H
|
||||
add_dlg_radio(dlg, _("Normal search", term), 1, 0, &hop->values[SEARCH_OPT_REGEX].number);
|
||||
add_dlg_radio(dlg, _("Regexp search", term), 1, 1, &hop->values[SEARCH_OPT_REGEX].number);
|
||||
add_dlg_radio(dlg, _("Extended regexp search", term), 1, 2, &hop->values[SEARCH_OPT_REGEX].number);
|
||||
#endif
|
||||
add_dlg_radio(dlg, _("Case sensitive", term), 2, 1, &hop->values[SEARCH_OPT_CASE].number);
|
||||
add_dlg_radio(dlg, _("Case insensitive", term), 2, 0, &hop->values[SEARCH_OPT_CASE].number);
|
||||
|
||||
|
@ -45,14 +45,20 @@ init_vs(struct view_state *vs, struct uri *uri, int plain)
|
||||
void
|
||||
destroy_vs(struct view_state *vs, int blast_ecmascript)
|
||||
{
|
||||
int i;
|
||||
struct form_view *fv, *next;
|
||||
|
||||
for (i = 0; i < vs->form_info_len; i++)
|
||||
mem_free_if(vs->form_info[i].value);
|
||||
/* form_state contains a pointer to form_view, so it's safest
|
||||
* to delete the form_state first. */
|
||||
for (; vs->form_info_len > 0; vs->form_info_len--)
|
||||
done_form_state(&vs->form_info[vs->form_info_len - 1]);
|
||||
mem_free_set(&vs->form_info, NULL);
|
||||
|
||||
foreachsafe (fv, next, vs->forms) {
|
||||
del_from_list(fv);
|
||||
done_form_view(fv);
|
||||
}
|
||||
|
||||
if (vs->uri) done_uri(vs->uri);
|
||||
mem_free_if(vs->form_info);
|
||||
free_list(vs->forms);
|
||||
#ifdef CONFIG_ECMASCRIPT
|
||||
if (blast_ecmascript && vs->ecmascript)
|
||||
ecmascript_put_interpreter(vs->ecmascript);
|
||||
@ -79,6 +85,12 @@ copy_vs(struct view_state *dst, struct view_state *src)
|
||||
dst->ecmascript_fragile = 1;
|
||||
#endif
|
||||
|
||||
/* destroy_vs(vs) does mem_free_if(vs->form_info), so each
|
||||
* view_state must have its own form_info. Normally we make a
|
||||
* copy below, but not if src->form_info_len is 0, which it
|
||||
* can be even if src->form_info is not NULL. */
|
||||
dst->form_info = NULL;
|
||||
|
||||
/* Clean as a baby. */
|
||||
dst->doc_view = NULL;
|
||||
|
||||
@ -108,6 +120,9 @@ copy_vs(struct view_state *dst, struct view_state *src)
|
||||
struct form_state *srcfs = &src->form_info[i];
|
||||
struct form_state *dstfs = &dst->form_info[i];
|
||||
|
||||
#ifdef CONFIG_ECMASCRIPT
|
||||
dstfs->ecmascript_obj = NULL;
|
||||
#endif
|
||||
if (srcfs->value)
|
||||
dstfs->value = stracpy(srcfs->value);
|
||||
/* XXX: This makes it O(nm). */
|
||||
|
@ -1,11 +1,9 @@
|
||||
#!/usr/bin/env python
|
||||
import os, time
|
||||
from zlib import *
|
||||
import os, time, zlib
|
||||
|
||||
data1 = '<html><body>Two lines should be visible.<br/>The second line.</body></html>'
|
||||
ob = compressobj(Z_DEFAULT_COMPRESSION, DEFLATED, -MAX_WBITS)
|
||||
cd1 = ob.compress(data1)
|
||||
cd1 += ob.flush()
|
||||
cd1 = zlib.compress(data1)
|
||||
|
||||
length = len(cd1)
|
||||
next_chunk = hex(length - 10)[2:]
|
||||
|
||||
|
22
test/cgi/chunked_raw_deflate.py
Executable file
22
test/cgi/chunked_raw_deflate.py
Executable file
@ -0,0 +1,22 @@
|
||||
#!/usr/bin/env python
|
||||
import os, time
|
||||
from zlib import *
|
||||
|
||||
# According to section 3.5 of RFC 2616, "Content-Encoding: deflate"
|
||||
# requires a ZLIB header. However, Microsoft-IIS/6.0 sends a raw
|
||||
# DEFLATE stream instead. This CGI tests how ELinks handles that.
|
||||
|
||||
data1 = '<html><body>Two lines should be visible.<br/>The second line.</body></html>'
|
||||
ob = compressobj(Z_DEFAULT_COMPRESSION, DEFLATED, -MAX_WBITS)
|
||||
cd1 = ob.compress(data1)
|
||||
cd1 += ob.flush()
|
||||
length = len(cd1)
|
||||
next_chunk = hex(length - 10)[2:]
|
||||
|
||||
os.write(1, "Date: Sun, 20 Jan 2008 15:24:00 GMT\r\nServer: ddd\r\nTransfer-Encoding: chunked\r\nContent-Encoding: deflate\r\nConnection: close\r\nContent-Type: text/html; charset=ISO-8859-1\r\n")
|
||||
os.write(1, "\r\na\r\n")
|
||||
os.write(1, cd1[:10])
|
||||
time.sleep(2)
|
||||
os.write(1, "\r\n%s\r\n" % next_chunk)
|
||||
os.write(1, cd1[10:])
|
||||
os.write(1, "\r\n0\r\n")
|
Loading…
Reference in New Issue
Block a user