📄 spidermonkey.c
字号:
/* The SpiderMonkey ECMAScript backend. *//* $Id: spidermonkey.c,v 1.147.2.8 2005/04/06 08:59:38 jonas Exp $ */#ifdef HAVE_CONFIG_H#include "config.h"#endif/* For wild SpiderMonkey installations. */#ifdef CONFIG_BEOS#define XP_BEOS#elif CONFIG_OS2#define XP_OS2#elif CONFIG_RISCOS#error Out of luck, buddy!#elif CONFIG_UNIX#define XP_UNIX#elif CONFIG_WIN32#define XP_WIN#endif#include <jsapi.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include "elinks.h"#include "bfu/dialog.h"#include "cookies/cookies.h"#include "dialogs/menu.h"#include "dialogs/status.h"#include "document/html/frames.h"#include "document/document.h"#include "document/forms.h"#include "document/view.h"#include "ecmascript/ecmascript.h"#include "ecmascript/spidermonkey.h"#include "intl/gettext/libintl.h"#include "lowlevel/select.h"#include "lowlevel/sysname.h"#include "osdep/newwin.h"#include "protocol/http/http.h"#include "protocol/uri.h"#include "sched/task.h"#include "terminal/tab.h"#include "terminal/terminal.h"#include "util/conv.h"#include "util/string.h"#include "viewer/text/draw.h"#include "viewer/text/form.h"#include "viewer/text/link.h"#include "viewer/text/vs.h"/*** Global methods *//* TODO? Are there any which need to be implemented? *//*** Classes */enum prop_type { JSPT_UNDEF, JSPT_INT, JSPT_DOUBLE, JSPT_STRING, JSPT_ASTRING, JSPT_BOOLEAN, JSPT_OBJECT,};struct jsval_property { enum prop_type type; union { int boolean; int number; jsdouble floatnum; JSObject *object; unsigned char *string; } value;};static voidset_prop_undef(struct jsval_property *prop){ memset(prop, 'J', sizeof(struct jsval_property)); /* Active security ;) */ prop->type = JSPT_UNDEF;}static voidset_prop_object(struct jsval_property *prop, JSObject *object){ prop->value.object = object; prop->type = JSPT_OBJECT;}static voidset_prop_boolean(struct jsval_property *prop, int boolean){ prop->value.boolean = boolean; prop->type = JSPT_BOOLEAN;}static voidset_prop_string(struct jsval_property *prop, unsigned char *string){ prop->value.string = string; prop->type = JSPT_STRING;}static voidset_prop_astring(struct jsval_property *prop, unsigned char *string){ prop->value.string = string; prop->type = JSPT_ASTRING;}static voidset_prop_int(struct jsval_property *prop, int number){ prop->value.number = number; prop->type = JSPT_INT;}#if 0 /* not yet used. */static voidset_prop_double(struct jsval_property *prop, jsdouble floatnum){ prop->value.floatnum = floatnum; prop->type = JSPT_DOUBLE;}#endifstatic voidvalue_to_jsval(JSContext *ctx, jsval *vp, struct jsval_property *prop){ switch (prop->type) { case JSPT_STRING: case JSPT_ASTRING: if (!prop->value.string) { *vp = JSVAL_NULL; break; } *vp = STRING_TO_JSVAL(JS_NewStringCopyZ(ctx, prop->value.string)); if (prop->type == JSPT_ASTRING) mem_free(prop->value.string); break; case JSPT_BOOLEAN: *vp = BOOLEAN_TO_JSVAL(prop->value.boolean); break; case JSPT_DOUBLE: *vp = DOUBLE_TO_JSVAL(prop->value.floatnum); break; case JSPT_INT: *vp = INT_TO_JSVAL(prop->value.number); break; case JSPT_OBJECT: *vp = OBJECT_TO_JSVAL(prop->value.object); break; case JSPT_UNDEF: default: *vp = JSVAL_NULL; break; }}union jsval_union { jsint boolean; jsdouble *number; unsigned char *string;};static voidjsval_to_value(JSContext *ctx, jsval *vp, JSType type, union jsval_union *var){ jsval val; if (JS_ConvertValue(ctx, *vp, type, &val) == JS_FALSE) { switch (type) { case JSTYPE_BOOLEAN: var->boolean = JS_FALSE; break; case JSTYPE_NUMBER: var->number = NULL; break; case JSTYPE_STRING: var->string = NULL; break; case JSTYPE_VOID: case JSTYPE_OBJECT: case JSTYPE_FUNCTION: case JSTYPE_LIMIT: default: INTERNAL("Invalid type %d in jsval_to_value()", type); break; } return; } switch (type) { case JSTYPE_BOOLEAN: var->boolean = JSVAL_TO_BOOLEAN(val); break; case JSTYPE_NUMBER: var->number = JSVAL_TO_DOUBLE(val); break; case JSTYPE_STRING: var->string = JS_GetStringBytes(JS_ValueToString(ctx, val)); break; case JSTYPE_VOID: case JSTYPE_OBJECT: case JSTYPE_FUNCTION: case JSTYPE_LIMIT: default: INTERNAL("Invalid type %d in jsval_to_value()", type); break; }}static JSBool window_get_property(JSContext *ctx, JSObject *obj, jsval id, jsval *vp);static JSBool window_set_property(JSContext *ctx, JSObject *obj, jsval id, jsval *vp);static const JSClass window_class = { "window", JSCLASS_HAS_PRIVATE, JS_PropertyStub, JS_PropertyStub, window_get_property, window_set_property, JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub};enum window_prop { JSP_WIN_CLOSED, JSP_WIN_PARENT, JSP_WIN_SELF, JSP_WIN_TOP,};/* "location" is special because we need to simulate "location.href" * when the code is asking directly for "location". We do not register * it as a "known" property since that was yielding strange bugs * (SpiderMonkey was still asking us about the "location" string after * assigning to it once), instead we do just a little string * comparing. */static const JSPropertySpec window_props[] = { { "closed", JSP_WIN_CLOSED, JSPROP_ENUMERATE | JSPROP_READONLY }, { "parent", JSP_WIN_PARENT, JSPROP_ENUMERATE | JSPROP_READONLY }, { "self", JSP_WIN_SELF, JSPROP_ENUMERATE | JSPROP_READONLY }, { "top", JSP_WIN_TOP, JSPROP_ENUMERATE | JSPROP_READONLY }, { "window", JSP_WIN_SELF, JSPROP_ENUMERATE | JSPROP_READONLY }, { NULL }};static JSObject *try_resolve_frame(struct document_view *doc_view, unsigned char *id){ struct session *ses = doc_view->session; struct frame *target; assert(ses); target = ses_find_frame(ses, id); if (!target) return NULL; if (target->vs.ecmascript_fragile) ecmascript_reset_state(&target->vs); if (!target->vs.ecmascript) return NULL; return JS_GetGlobalObject(target->vs.ecmascript->backend_data);}#if 0static struct frame_desc *find_child_frame(struct document_view *doc_view, struct frame_desc *tframe){ struct frameset_desc *frameset = doc_view->document->frame_desc; int i; if (!frameset) return NULL; for (i = 0; i < frameset->n; i++) { struct frame_desc *frame = &frameset->frame_desc[i]; if (frame == tframe) return frame; } return NULL;}#endifstatic JSBoolwindow_get_property(JSContext *ctx, JSObject *obj, jsval id, jsval *vp){ struct view_state *vs = JS_GetPrivate(ctx, obj); struct jsval_property prop; set_prop_undef(&prop); /* No need for special window.location measurements - when * location is then evaluated in string context, toString() * is called which we overrode for that class below, so * everything's fine. */ if (JSVAL_IS_STRING(id)) { struct document_view *doc_view = vs->doc_view; JSObject *obj; union jsval_union v; jsval_to_value(ctx, &id, JSTYPE_STRING, &v); obj = try_resolve_frame(doc_view, v.string); /* TODO: Try other lookups (mainly element lookup) until * something yields data. */ if (!obj) return JS_TRUE; set_prop_object(&prop, obj); goto convert; } else if (!JSVAL_IS_INT(id)) return JS_TRUE; switch (JSVAL_TO_INT(id)) { case JSP_WIN_CLOSED: /* TODO: It will be a major PITA to implement this properly. * Well, perhaps not so much if we introduce reference tracking * for (struct session)? Still... --pasky */ set_prop_boolean(&prop, 0); break; case JSP_WIN_SELF: set_prop_object(&prop, obj); break; case JSP_WIN_PARENT: /* XXX: It would be nice if the following worked, yes. * The problem is that we get called at the point where * document.frame properties are going to be mostly NULL. * But the problem is deeper because at that time we are * yet building scrn_frames so our parent might not be there * yet (XXX: is this true?). The true solution will be to just * have struct document_view *(document_view.parent). --pasky */ /* FIXME: So now we alias window.parent to window.top, which is * INCORRECT but works for the most common cases of just two * frames. Better something than nothing. */#if 0 { /* This is horrible. */ struct document_view *doc_view = vs->doc_view; struct session *ses = doc_view->session; struct frame_desc *frame = doc_view->document->frame; if (!ses->doc_view->document->frame_desc) { INTERNAL("Looking for parent but there're no frames."); break; } assert(frame); doc_view = ses->doc_view; if (find_child_frame(doc_view, frame)) goto found_parent; foreach (doc_view, ses->scrn_frames) { if (find_child_frame(doc_view, frame)) goto found_parent; } INTERNAL("Cannot find frame %s parent.",doc_view->name); break;found_parent: some_domain_security_check(); if (doc_view->vs.ecmascript_fragile) ecmascript_reset_state(&doc_view->vs); assert(doc_view->ecmascript); set_prop_object(&prop, JS_GetGlobalObject(doc_view->ecmascript->backend_data)); break; }#endif case JSP_WIN_TOP: { struct document_view *doc_view = vs->doc_view; struct document_view *top_view = doc_view->session->doc_view; JSObject *newjsframe; assert(top_view && top_view->vs); if (top_view->vs->ecmascript_fragile) ecmascript_reset_state(top_view->vs); if (!top_view->vs->ecmascript) break; newjsframe = JS_GetGlobalObject(top_view->vs->ecmascript->backend_data); /* Keep this unrolled this way. Will have to check document.domain * JS property. */ /* Note that this check is perhaps overparanoid. If top windows * is alien but some other child window is not, we should still * let the script walk thru. That'd mean moving the check to * other individual properties in this switch. */ if (compare_uri(vs->uri, top_view->vs->uri, URI_HOST)) set_prop_object(&prop, newjsframe); else /****X*X*X*** SECURITY VIOLATION! RED ALERT, SHIELDS UP! ***X*X*X****\ |* (Pasky was apparently looking at the Links2 JS code . ___ ^.^ *| \* for too long.) `.(,_,)\o/ */ set_prop_undef(&prop); break; } default: INTERNAL("Invalid ID %d in window_get_property().", JSVAL_TO_INT(id)); return JS_TRUE; }convert: value_to_jsval(ctx, vp, &prop); return JS_TRUE;}static void location_goto(struct document_view *doc_view, unsigned char *url);static JSBoolwindow_set_property(JSContext *ctx, JSObject *obj, jsval id, jsval *vp){ struct view_state *vs = JS_GetPrivate(ctx, obj); union jsval_union v; if (JSVAL_IS_STRING(id)) { jsval_to_value(ctx, &id, JSTYPE_STRING, &v); if (!strcmp(v.string, "location")) { struct document_view *doc_view = vs->doc_view; jsval_to_value(ctx, vp, JSTYPE_STRING, &v); location_goto(doc_view, v.string); /* Do NOT touch our .location property, evil * SpiderMonkey!! */ return JS_FALSE; } return JS_TRUE; } else if (!JSVAL_IS_INT(id)) return JS_TRUE; switch (JSVAL_TO_INT(id)) { default: INTERNAL("Invalid ID %d in window_set_property().", JSVAL_TO_INT(id)); return JS_TRUE; } return JS_TRUE;}static JSBool window_alert(JSContext *ctx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);static JSBool window_open(JSContext *ctx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);static const JSFunctionSpec window_funcs[] = { { "alert", window_alert, 1 }, { "open", window_open, 3 }, { NULL }};static JSBoolwindow_alert(JSContext *ctx, JSObject *obj, uintN argc, jsval *argv, jsval *rval){ struct view_state *vs = JS_GetPrivate(ctx, obj); union jsval_union v; struct jsval_property prop; set_prop_undef(&prop); if (argc != 1)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -