mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-12-27 19:09:47 +00:00
64e462e071
- Add multiple window groups to allow windows to execute JS on different threads. - Add new context parameters to JS and libmocha functions for thread safety.
676 lines
17 KiB
C
676 lines
17 KiB
C
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
|
*
|
|
* The contents of this file are subject to the Netscape Public License
|
|
* Version 1.0 (the "NPL"); you may not use this file except in
|
|
* compliance with the NPL. You may obtain a copy of the NPL at
|
|
* http://www.mozilla.org/NPL/
|
|
*
|
|
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
|
* for the specific language governing rights and limitations under the
|
|
* NPL.
|
|
*
|
|
* The Initial Developer of this code under the NPL is Netscape
|
|
* Communications Corporation. Portions created by Netscape are
|
|
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
|
* Reserved.
|
|
*/
|
|
|
|
|
|
/*
|
|
* JS reflection of Navigator Components.
|
|
*
|
|
* Created: Tom Pixley, 4/22/97
|
|
*
|
|
*/
|
|
|
|
#include "lm.h"
|
|
#include "prmem.h"
|
|
#include "np.h"
|
|
#include "net.h"
|
|
#include "fe_proto.h"
|
|
|
|
/*
|
|
* -----------------------------------------------------------------------
|
|
*
|
|
* Data types
|
|
*
|
|
* -----------------------------------------------------------------------
|
|
*/
|
|
|
|
typedef struct JSComponent
|
|
{
|
|
MochaDecoder *decoder;
|
|
JSObject *obj;
|
|
JSString *name;
|
|
ETBoolPtrFunc active_callback;
|
|
ETVoidPtrFunc startup_callback;
|
|
} JSComponent;
|
|
|
|
typedef struct JSComponentArray
|
|
{
|
|
MochaDecoder *decoder;
|
|
JSObject *obj;
|
|
jsint length;
|
|
} JSComponentArray;
|
|
|
|
typedef struct JSPreDefComponent
|
|
{
|
|
const char *name;
|
|
ETVerifyComponentFunc func;
|
|
} JSPreDefComponent;
|
|
|
|
static JSPreDefComponent predef_components[] =
|
|
{
|
|
{0}
|
|
};
|
|
|
|
/*
|
|
* -----------------------------------------------------------------------
|
|
*
|
|
* Reflection of an installed component.
|
|
*
|
|
* -----------------------------------------------------------------------
|
|
*/
|
|
|
|
enum component_slot
|
|
{
|
|
COMPONENT_NAME = -1,
|
|
COMPONENT_ACTIVE = -2
|
|
};
|
|
|
|
|
|
static JSPropertySpec component_props[] =
|
|
{
|
|
{"name", COMPONENT_NAME, JSPROP_ENUMERATE | JSPROP_READONLY},
|
|
{"active", COMPONENT_ACTIVE, JSPROP_ENUMERATE | JSPROP_READONLY},
|
|
{0}
|
|
};
|
|
|
|
extern JSClass lm_component_class;
|
|
|
|
PR_STATIC_CALLBACK(JSBool)
|
|
component_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
|
|
{
|
|
JSComponent *component;
|
|
JSString *str;
|
|
jsint slot;
|
|
|
|
if (!JSVAL_IS_INT(id))
|
|
return JS_TRUE;
|
|
|
|
slot = JSVAL_TO_INT(id);
|
|
|
|
component = JS_GetInstancePrivate(cx, obj, &lm_component_class, NULL);
|
|
if (!component)
|
|
return JS_TRUE;
|
|
|
|
switch (slot) {
|
|
case COMPONENT_NAME:
|
|
str = component->name;
|
|
if (str)
|
|
*vp = STRING_TO_JSVAL(str);
|
|
else
|
|
*vp = JS_GetEmptyStringValue(cx);
|
|
break;
|
|
|
|
case COMPONENT_ACTIVE:
|
|
*vp = JSVAL_FALSE;
|
|
if (ET_moz_CallFunctionBool((ETBoolPtrFunc)component->active_callback, NULL))
|
|
*vp = JSVAL_TRUE;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return JS_TRUE;
|
|
}
|
|
|
|
PR_STATIC_CALLBACK(JSBool)
|
|
component_mozilla_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
|
|
{
|
|
char *name, *type_str, *get_str;
|
|
jsval type, func;
|
|
|
|
if (!JSVAL_IS_STRING(id))
|
|
return JS_TRUE;
|
|
|
|
name = JS_GetStringBytes(JSVAL_TO_STRING(id));
|
|
|
|
type_str = JS_malloc(cx, XP_STRLEN(lm_typePrefix_str) + XP_STRLEN(name) + 1);
|
|
get_str = JS_malloc(cx, XP_STRLEN(lm_getPrefix_str) + XP_STRLEN(name) + 1);
|
|
if (!type_str || !get_str)
|
|
return JS_TRUE;
|
|
|
|
XP_STRCPY(type_str, lm_typePrefix_str);
|
|
XP_STRCAT(type_str, name);
|
|
XP_STRCPY(get_str, lm_getPrefix_str);
|
|
XP_STRCAT(get_str, name);
|
|
|
|
if (!JS_GetProperty(cx, obj, type_str, &type) ||
|
|
!JSVAL_IS_INT(type) ||
|
|
!JS_GetProperty(cx, obj, get_str, &func))
|
|
return JS_TRUE;
|
|
|
|
JS_free(cx, type_str);
|
|
JS_free(cx, get_str);
|
|
|
|
switch(JSVAL_TO_INT(type)) {
|
|
case ARGTYPE_INT32:
|
|
*vp = INT_TO_JSVAL((int32)ET_moz_CompGetterFunction((ETCompPropGetterFunc)JSVAL_TO_INT(func), name));
|
|
break;
|
|
case ARGTYPE_BOOL:
|
|
*vp = BOOLEAN_TO_JSVAL((JSBool)ET_moz_CompGetterFunction((ETCompPropGetterFunc)JSVAL_TO_INT(func), name));
|
|
break;
|
|
case ARGTYPE_STRING:
|
|
*vp = STRING_TO_JSVAL(JS_NewStringCopyZ(cx,
|
|
(char*)ET_moz_CompGetterFunction((ETCompPropGetterFunc)JSVAL_TO_INT(func), name)));
|
|
break;
|
|
}
|
|
|
|
return JS_TRUE;
|
|
}
|
|
|
|
PR_STATIC_CALLBACK(JSBool)
|
|
component_mozilla_setProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
|
|
{
|
|
char *name, *type_str, *set_str, *prop_val;
|
|
jsval type, func;
|
|
|
|
if (!JSVAL_IS_STRING(id))
|
|
return JS_TRUE;
|
|
|
|
name = JS_GetStringBytes(JSVAL_TO_STRING(id));
|
|
|
|
type_str = JS_malloc(cx, XP_STRLEN(lm_typePrefix_str) + XP_STRLEN(name) + 1);
|
|
set_str = JS_malloc(cx, XP_STRLEN(lm_setPrefix_str) + XP_STRLEN(name) + 1);
|
|
if (!type_str || !set_str)
|
|
return JS_TRUE;
|
|
|
|
XP_STRCPY(type_str, lm_typePrefix_str);
|
|
XP_STRCAT(type_str, name);
|
|
XP_STRCPY(set_str, lm_setPrefix_str);
|
|
XP_STRCAT(set_str, name);
|
|
if (!JS_GetProperty(cx, obj, type_str, &type) ||
|
|
!JSVAL_IS_INT(type) ||
|
|
!JS_GetProperty(cx, obj, set_str, &func))
|
|
return JS_TRUE;
|
|
|
|
JS_free(cx, type_str);
|
|
JS_free(cx, set_str);
|
|
|
|
switch(JSVAL_TO_INT(type)) {
|
|
case ARGTYPE_INT32:
|
|
if (JSVAL_IS_INT(*vp))
|
|
ET_moz_CompSetterFunction((ETCompPropSetterFunc)JSVAL_TO_INT(func), name, (void*)JSVAL_TO_INT(*vp));
|
|
break;
|
|
case ARGTYPE_BOOL:
|
|
if (JSVAL_IS_BOOLEAN(*vp))
|
|
ET_moz_CompSetterFunction((ETCompPropSetterFunc)JSVAL_TO_INT(func), name, (void*)JSVAL_TO_BOOLEAN(*vp));
|
|
break;
|
|
case ARGTYPE_STRING:
|
|
if (JSVAL_IS_STRING(*vp)) {
|
|
prop_val = JS_GetStringBytes(JSVAL_TO_STRING(*vp));
|
|
ET_moz_CompSetterFunction((ETCompPropSetterFunc)JSVAL_TO_INT(func), name, (void*)prop_val);
|
|
}
|
|
break;
|
|
}
|
|
|
|
return JS_TRUE;
|
|
}
|
|
|
|
void
|
|
lm_RegisterComponentProp(const char *comp, const char *targetName,
|
|
uint8 retType, ETCompPropSetterFunc setter,
|
|
ETCompPropGetterFunc getter)
|
|
{
|
|
JSContext *cx;
|
|
JSObject *arrayObj, *obj;
|
|
jsval val;
|
|
char *type, *set, *get;
|
|
MochaDecoder *cd = LM_GetCrippledDecoder();
|
|
|
|
if (!comp || !targetName || !(cx = cd->js_context))
|
|
return;
|
|
|
|
arrayObj = lm_DefineComponents(cd);
|
|
if (!arrayObj)
|
|
return;
|
|
|
|
if (!JS_GetProperty(cx, arrayObj, comp, &val) ||
|
|
!JSVAL_IS_OBJECT(val))
|
|
return;
|
|
|
|
obj = JSVAL_TO_OBJECT(val);
|
|
|
|
if (!JS_DefineProperty(cx, obj, targetName, JSVAL_VOID, component_mozilla_getProperty,
|
|
component_mozilla_setProperty, 0)) {
|
|
}
|
|
|
|
type = JS_malloc(cx, XP_STRLEN(lm_typePrefix_str) + XP_STRLEN(targetName) + 1);
|
|
if (type) {
|
|
XP_STRCPY(type, lm_typePrefix_str);
|
|
XP_STRCAT(type, targetName);
|
|
if (!JS_DefineProperty(cx, obj, type,
|
|
INT_TO_JSVAL((int32)retType), 0, 0, JSPROP_READONLY)) {
|
|
}
|
|
JS_free(cx, type);
|
|
}
|
|
|
|
get = JS_malloc(cx, XP_STRLEN(lm_getPrefix_str) + XP_STRLEN(targetName) + 1);
|
|
if (get) {
|
|
XP_STRCPY(get, lm_getPrefix_str);
|
|
XP_STRCAT(get, targetName);
|
|
if (!JS_DefineProperty(cx, obj, get,
|
|
INT_TO_JSVAL(getter), 0, 0, JSPROP_READONLY)) {
|
|
}
|
|
JS_free(cx, get);
|
|
}
|
|
|
|
set = JS_malloc(cx, XP_STRLEN(lm_setPrefix_str) + XP_STRLEN(targetName) + 1);
|
|
if (set) {
|
|
XP_STRCPY(set, lm_setPrefix_str);
|
|
XP_STRCAT(set, targetName);
|
|
if (!JS_DefineProperty(cx, obj, set,
|
|
INT_TO_JSVAL(setter), 0, 0, JSPROP_READONLY)) {
|
|
}
|
|
JS_free(cx, set);
|
|
}
|
|
}
|
|
|
|
PR_STATIC_CALLBACK(JSBool)
|
|
component_resolve_name(JSContext *cx, JSObject *obj, jsval id)
|
|
{
|
|
return JS_TRUE;
|
|
}
|
|
|
|
PR_STATIC_CALLBACK(void)
|
|
component_finalize(JSContext *cx, JSObject *obj)
|
|
{
|
|
JSComponent* component;
|
|
|
|
component = JS_GetPrivate(cx, obj);
|
|
if (!component)
|
|
return;
|
|
JS_UnlockGCThing(cx, component->name);
|
|
DROP_BACK_COUNT(component->decoder);
|
|
JS_free(cx, component);
|
|
}
|
|
|
|
JSClass lm_component_class =
|
|
{
|
|
"Component", JSCLASS_HAS_PRIVATE,
|
|
JS_PropertyStub, JS_PropertyStub,
|
|
component_getProperty, component_getProperty, JS_EnumerateStub,
|
|
component_resolve_name, JS_ConvertStub, component_finalize
|
|
};
|
|
|
|
PR_STATIC_CALLBACK(JSBool)
|
|
component_activate(JSContext *cx, JSObject *obj, uint argc, jsval *argv, jsval *rval)
|
|
{
|
|
JSComponent *component;
|
|
|
|
component = JS_GetInstancePrivate(cx, obj, &lm_component_class, argv);
|
|
if (!component)
|
|
return JS_FALSE;
|
|
|
|
ET_moz_CallFunctionAsync((ETVoidPtrFunc)component->startup_callback, NULL);
|
|
|
|
return JS_TRUE;
|
|
}
|
|
|
|
static JSFunctionSpec component_methods[] =
|
|
{
|
|
{"activate", component_activate, 0},
|
|
{0}
|
|
};
|
|
|
|
PR_STATIC_CALLBACK(JSBool)
|
|
component_mozilla_method_stub(JSContext *cx, JSObject *obj, uint argc,
|
|
jsval *argv, jsval *rval)
|
|
{
|
|
JSFunction *func;
|
|
JSObject *func_obj;
|
|
jsval type, native;
|
|
uint i;
|
|
JSCompArg *comp_argv;
|
|
|
|
func = JS_ValueToFunction(cx, argv[-2]);
|
|
func_obj = JS_GetFunctionObject(func);
|
|
|
|
if (!JS_GetProperty(cx, func_obj, lm_typePrefix_str, &type) ||
|
|
!JSVAL_IS_INT(type) ||
|
|
!JS_GetProperty(cx, func_obj, lm_methodPrefix_str, &native) ||
|
|
!(comp_argv = JS_malloc(cx, argc * sizeof(JSCompArg))))
|
|
return JS_TRUE;
|
|
|
|
for (i=0; i<argc; i++) {
|
|
if (JSVAL_IS_INT(argv[i])) {
|
|
comp_argv[i].type = ARGTYPE_INT32;
|
|
comp_argv[i].value.intArg = JSVAL_TO_INT(argv[i]);
|
|
}
|
|
else if (JSVAL_IS_BOOLEAN(argv[i])) {
|
|
comp_argv[i].type = ARGTYPE_BOOL;
|
|
comp_argv[i].value.boolArg = JSVAL_TO_BOOLEAN(argv[i]);
|
|
}
|
|
else if (JSVAL_IS_STRING(argv[i])) {
|
|
comp_argv[i].type = ARGTYPE_STRING;
|
|
comp_argv[i].value.stringArg = JS_GetStringBytes(JSVAL_TO_STRING(argv[i]));
|
|
}
|
|
else {
|
|
comp_argv[i].type = ARGTYPE_NULL;
|
|
comp_argv[i].value.intArg = 0;
|
|
}
|
|
}
|
|
|
|
switch(JSVAL_TO_INT(type)) {
|
|
case ARGTYPE_NULL:
|
|
ET_moz_CompMethodFunction((ETCompMethodFunc)JSVAL_TO_INT(native), argc, NULL);
|
|
*rval = 0;
|
|
break;
|
|
case ARGTYPE_INT32:
|
|
*rval = INT_TO_JSVAL((int32)ET_moz_CompMethodFunction((ETCompMethodFunc)JSVAL_TO_INT(native), argc, comp_argv));
|
|
break;
|
|
case ARGTYPE_BOOL:
|
|
*rval = BOOLEAN_TO_JSVAL((JSBool)ET_moz_CompMethodFunction((ETCompMethodFunc)JSVAL_TO_INT(native), argc, comp_argv));
|
|
break;
|
|
case ARGTYPE_STRING:
|
|
*rval = STRING_TO_JSVAL(JS_NewStringCopyZ(cx,
|
|
(char*)ET_moz_CompMethodFunction((ETCompMethodFunc)JSVAL_TO_INT(native), argc, comp_argv)));
|
|
break;
|
|
}
|
|
return JS_TRUE;
|
|
}
|
|
|
|
void
|
|
lm_RegisterComponentMethod(const char *comp, const char *targetName,
|
|
uint8 retType, ETCompMethodFunc method, int32 argc)
|
|
{
|
|
JSContext *cx;
|
|
JSObject *arrayObj, *obj, *func_obj;
|
|
JSFunction *func;
|
|
jsval val;
|
|
MochaDecoder *cd = LM_GetCrippledDecoder();
|
|
|
|
if (!comp || !targetName || !(cx = cd->js_context))
|
|
return;
|
|
|
|
arrayObj = lm_DefineComponents(cd);
|
|
if (!arrayObj)
|
|
return;
|
|
|
|
if (!JS_GetProperty(cx, arrayObj, comp, &val) ||
|
|
!JSVAL_IS_OBJECT(val))
|
|
return;
|
|
|
|
obj = JSVAL_TO_OBJECT(val);
|
|
|
|
if (!(func = JS_DefineFunction(cx, obj, targetName, component_mozilla_method_stub, argc, 0))){
|
|
}
|
|
|
|
func_obj = JS_GetFunctionObject(func);
|
|
|
|
if (!JS_DefineProperty(cx, func_obj, lm_typePrefix_str,
|
|
INT_TO_JSVAL((int32)retType), 0, 0, JSPROP_READONLY))
|
|
return;
|
|
if (!JS_DefineProperty(cx, func_obj, lm_methodPrefix_str,
|
|
INT_TO_JSVAL(method), 0, 0, JSPROP_READONLY))
|
|
return;
|
|
if (!JS_DefineProperty(cx, func_obj, lm_methodArgc_str,
|
|
INT_TO_JSVAL(argc), 0, 0, JSPROP_READONLY))
|
|
return;
|
|
}
|
|
|
|
/* Constructor method for a JSComponent object */
|
|
static JSComponent*
|
|
component_create_self(JSContext *cx, MochaDecoder* decoder, JSComponent *component, const char *name)
|
|
{
|
|
JSObject *obj;
|
|
|
|
/* JSComponent may be malloc'd previous to this to make it easier
|
|
* to fill in the struct with data from the Mozilla thread
|
|
*/
|
|
if (!component) {
|
|
component = JS_malloc(cx, sizeof(JSComponent));
|
|
if (!component)
|
|
return NULL;
|
|
}
|
|
|
|
obj = JS_NewObject(cx, &lm_component_class, NULL, NULL);
|
|
if (!obj || !JS_SetPrivate(cx, obj, component)) {
|
|
JS_free(cx, component);
|
|
return NULL;
|
|
}
|
|
|
|
if (!JS_DefineProperties(cx, obj, component_props))
|
|
return NULL;
|
|
|
|
if (!JS_DefineFunctions(cx, obj, component_methods))
|
|
return NULL;
|
|
|
|
/* Fill out static property fields */
|
|
component->decoder = HOLD_BACK_COUNT(decoder);
|
|
component->obj = obj;
|
|
|
|
component->name = JS_NewStringCopyZ(cx, name);
|
|
if (!component->name || !JS_LockGCThing(cx, component->name))
|
|
return NULL;
|
|
|
|
return component;
|
|
}
|
|
|
|
|
|
/*
|
|
* -----------------------------------------------------------------------
|
|
*
|
|
* Reflection of the list of installed components.
|
|
* The only static property is the array length;
|
|
* the array elements (JSComponents) are added
|
|
* lazily when referenced.
|
|
*
|
|
* -----------------------------------------------------------------------
|
|
*/
|
|
|
|
enum componentarray_slot
|
|
{
|
|
COMPONENTLIST_ARRAY_LENGTH = -1
|
|
};
|
|
|
|
static JSPropertySpec componentarray_props[] =
|
|
{
|
|
{"length", COMPONENTLIST_ARRAY_LENGTH, JSPROP_READONLY},
|
|
{0}
|
|
};
|
|
|
|
/* Look up the component for the specified slot of the plug-in list */
|
|
static JSComponent*
|
|
componentarray_create_component(JSContext *cx, JSComponentArray *array,
|
|
JSComponent *component, const char *targetName, jsint targetSlot)
|
|
{
|
|
component = component_create_self(cx, array->decoder, component, targetName);
|
|
if (component) {
|
|
char *name;
|
|
jsval val;
|
|
|
|
name = JS_GetStringBytes(component->name);
|
|
val = OBJECT_TO_JSVAL(component->obj);
|
|
JS_DefineProperty(cx, array->obj, name, val, NULL, NULL,
|
|
JSPROP_ENUMERATE);
|
|
JS_AliasElement(cx, array->obj, name, targetSlot);
|
|
array->length++;
|
|
return component;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
extern JSClass lm_component_array_class;
|
|
|
|
void
|
|
lm_RegisterComponent(const char *targetName, ETBoolPtrFunc active_callback,
|
|
ETVoidPtrFunc startup_callback)
|
|
{
|
|
JSContext *cx;
|
|
JSObject *arrayObj;
|
|
JSComponentArray *array;
|
|
JSComponent *component;
|
|
jsval val;
|
|
MochaDecoder *cd = LM_GetCrippledDecoder();
|
|
|
|
if (!(cx = cd->js_context) || !targetName)
|
|
return;
|
|
|
|
arrayObj = lm_DefineComponents(cd);
|
|
if (!arrayObj)
|
|
return;
|
|
|
|
array = JS_GetInstancePrivate(cx, arrayObj, &lm_component_array_class, NULL);
|
|
if (!array)
|
|
return;
|
|
|
|
if (JS_GetProperty(cx, arrayObj, targetName, &val) && JSVAL_IS_OBJECT(val)) {
|
|
/* We already have a component by this name. Update the active and
|
|
* startup callback funcs in case ours are out of date
|
|
*/
|
|
component = JS_GetPrivate(cx, JSVAL_TO_OBJECT(val));
|
|
if (!component)
|
|
return;
|
|
|
|
component->active_callback = active_callback;
|
|
component->startup_callback = startup_callback;
|
|
|
|
return;
|
|
}
|
|
|
|
component = JS_malloc(cx, sizeof(JSComponent));
|
|
if (!component)
|
|
return;
|
|
|
|
component->active_callback = active_callback;
|
|
component->startup_callback = startup_callback;
|
|
|
|
componentarray_create_component(cx, array, component, targetName, array->length);
|
|
}
|
|
|
|
|
|
PR_STATIC_CALLBACK(JSBool)
|
|
componentarray_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
|
|
{
|
|
JSComponentArray *array;
|
|
jsint slot;
|
|
|
|
if (!JSVAL_IS_INT(id))
|
|
return JS_TRUE;
|
|
|
|
slot = JSVAL_TO_INT(id);
|
|
|
|
array = JS_GetInstancePrivate(cx, obj, &lm_component_array_class, NULL);
|
|
if (!array)
|
|
return JS_TRUE;
|
|
|
|
switch (slot) {
|
|
case COMPONENTLIST_ARRAY_LENGTH:
|
|
*vp = INT_TO_JSVAL(array->length);
|
|
break;
|
|
|
|
default:
|
|
/* Don't mess with a user-defined property. */
|
|
if (slot >= 0 && slot < (jsint) array->length) {
|
|
|
|
/* Search for an existing JSComponent for this slot */
|
|
JSObject* componentObj = NULL;
|
|
jsval val = *vp;
|
|
|
|
if (JSVAL_IS_OBJECT(val)) {
|
|
componentObj = JSVAL_TO_OBJECT(val);
|
|
}
|
|
else {
|
|
JSComponent* component;
|
|
component = componentarray_create_component(cx, array, NULL,
|
|
NULL, slot);
|
|
if (component)
|
|
componentObj = component->obj;
|
|
}
|
|
|
|
*vp = OBJECT_TO_JSVAL(componentObj);
|
|
break;
|
|
}
|
|
}
|
|
|
|
return JS_TRUE;
|
|
}
|
|
|
|
PR_STATIC_CALLBACK(void)
|
|
componentarray_finalize(JSContext *cx, JSObject *obj)
|
|
{
|
|
JSComponentArray* array;
|
|
|
|
array = JS_GetPrivate(cx, obj);
|
|
if (!array)
|
|
return;
|
|
DROP_BACK_COUNT(array->decoder);
|
|
JS_free(cx, array);
|
|
}
|
|
|
|
JSClass lm_component_array_class =
|
|
{
|
|
"ComponentArray", JSCLASS_HAS_PRIVATE,
|
|
JS_PropertyStub, JS_PropertyStub,
|
|
componentarray_getProperty, componentarray_getProperty, JS_EnumerateStub,
|
|
JS_ResolveStub, JS_ConvertStub, componentarray_finalize
|
|
};
|
|
|
|
|
|
JSObject*
|
|
lm_DefineComponents(MochaDecoder *decoder)
|
|
{
|
|
JSObject *obj;
|
|
JSComponentArray *array;
|
|
JSContext *cx = decoder->js_context;
|
|
JSPreDefComponent def_comps;
|
|
JSComponent *component;
|
|
jsint slot;
|
|
|
|
obj = decoder->components;
|
|
if (obj)
|
|
return obj;
|
|
|
|
array = JS_malloc(cx, sizeof(JSComponentArray));
|
|
if (!array)
|
|
return NULL;
|
|
XP_BZERO(array, sizeof *array);
|
|
|
|
obj = JS_NewObject(cx, &lm_component_array_class, NULL,
|
|
decoder->window_object);
|
|
if (!obj || !JS_SetPrivate(cx, obj, array)) {
|
|
JS_free(cx, array);
|
|
return NULL;
|
|
}
|
|
if (!JS_DefineProperties(cx, obj, componentarray_props))
|
|
return NULL;
|
|
|
|
array->decoder = HOLD_BACK_COUNT(decoder);
|
|
array->obj = obj;
|
|
|
|
/* Components can be added dynamically but some are predefined */
|
|
slot = 0;
|
|
array->length = 0;
|
|
def_comps = predef_components[slot];
|
|
while (def_comps.name) {
|
|
component = JS_malloc(cx, sizeof(JSComponent));
|
|
if (!component)
|
|
return NULL;
|
|
|
|
if (ET_moz_VerifyComponentFunction(def_comps.func, &(component->active_callback),
|
|
&(component->startup_callback))) {
|
|
componentarray_create_component(cx, array, component, def_comps.name, array->length);
|
|
}
|
|
else {
|
|
/*Component call failed somewhere.*/
|
|
JS_free(cx, component);
|
|
}
|
|
def_comps = predef_components[++slot];
|
|
}
|
|
return obj;
|
|
}
|