home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / lib / libmocha / lm_cmpnt.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  17.9 KB  |  673 lines

  1. /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  2.  *
  3.  * The contents of this file are subject to the Netscape Public License
  4.  * Version 1.0 (the "NPL"); you may not use this file except in
  5.  * compliance with the NPL.  You may obtain a copy of the NPL at
  6.  * http://www.mozilla.org/NPL/
  7.  *
  8.  * Software distributed under the NPL is distributed on an "AS IS" basis,
  9.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
  10.  * for the specific language governing rights and limitations under the
  11.  * NPL.
  12.  *
  13.  * The Initial Developer of this code under the NPL is Netscape
  14.  * Communications Corporation.  Portions created by Netscape are
  15.  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
  16.  * Reserved.
  17.  */
  18.  
  19.  
  20. /*
  21.  * JS reflection of Navigator Components.
  22.  *
  23.  * Created: Tom Pixley, 4/22/97
  24.  *
  25.  */
  26.  
  27. #include "lm.h"
  28. #include "prmem.h"
  29. #include "np.h"
  30. #include "net.h"
  31. #include "fe_proto.h"
  32.  
  33. /*
  34.  * -----------------------------------------------------------------------
  35.  *
  36.  * Data types
  37.  *
  38.  * -----------------------------------------------------------------------
  39.  */
  40.  
  41. typedef struct JSComponent
  42. {
  43.     MochaDecoder    *decoder;
  44.     JSObject        *obj;
  45.     JSString            *name;
  46.     ETBoolPtrFunc     active_callback;
  47.     ETVoidPtrFunc     startup_callback;
  48. } JSComponent;
  49.  
  50. typedef struct JSComponentArray
  51. {
  52.     MochaDecoder       *decoder;
  53.     JSObject           *obj;
  54.     jsint        length;
  55. } JSComponentArray;
  56.  
  57. typedef struct JSPreDefComponent
  58. {
  59.     const char *name;
  60.     ETVerifyComponentFunc func;
  61. } JSPreDefComponent;
  62.  
  63. static JSPreDefComponent predef_components[] =
  64. {
  65.     {0}
  66. };
  67.  
  68. /*
  69.  * -----------------------------------------------------------------------
  70.  *
  71.  * Reflection of an installed component.
  72.  *
  73.  * -----------------------------------------------------------------------
  74.  */
  75.  
  76. enum component_slot
  77. {
  78.     COMPONENT_NAME        = -1,
  79.     COMPONENT_ACTIVE      = -2
  80. };
  81.  
  82.  
  83. static JSPropertySpec component_props[] =
  84. {
  85.     {"name",        COMPONENT_NAME,    JSPROP_ENUMERATE | JSPROP_READONLY},
  86.     {"active",        COMPONENT_ACTIVE,    JSPROP_ENUMERATE | JSPROP_READONLY},
  87.     {0}
  88. };
  89.  
  90. extern JSClass lm_component_class;
  91.  
  92. PR_STATIC_CALLBACK(JSBool)
  93. component_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
  94. {
  95.     JSComponent *component;
  96.     JSString *str;
  97.     jsint slot;
  98.  
  99.     if (!JSVAL_IS_INT(id))
  100.     return JS_TRUE;
  101.  
  102.     slot = JSVAL_TO_INT(id);
  103.  
  104.     component = JS_GetInstancePrivate(cx, obj, &lm_component_class, NULL);
  105.     if (!component)
  106.     return JS_TRUE;
  107.  
  108.     switch (slot) {
  109.       case COMPONENT_NAME:
  110.         str = component->name;
  111.     if (str)
  112.         *vp = STRING_TO_JSVAL(str);
  113.     else
  114.         *vp = JS_GetEmptyStringValue(cx);
  115.         break;
  116.  
  117.       case COMPONENT_ACTIVE:
  118.     *vp = JSVAL_FALSE;
  119.     if (ET_moz_CallFunctionBool((ETBoolPtrFunc)component->active_callback, NULL))
  120.         *vp = JSVAL_TRUE;
  121.         break;
  122.  
  123.       default:
  124.     break;
  125.     }
  126.  
  127.     return JS_TRUE;
  128. }
  129.  
  130. PR_STATIC_CALLBACK(JSBool)
  131. component_mozilla_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
  132. {
  133.     char *name, *type_str, *get_str;
  134.     jsval type, func;
  135.  
  136.     if (!JSVAL_IS_STRING(id))
  137.     return JS_TRUE;
  138.  
  139.     name = JS_GetStringBytes(JSVAL_TO_STRING(id));
  140.  
  141.     type_str = JS_malloc(cx, XP_STRLEN(lm_typePrefix_str) + XP_STRLEN(name) + 1);
  142.     get_str = JS_malloc(cx, XP_STRLEN(lm_getPrefix_str) + XP_STRLEN(name) + 1);
  143.     if (!type_str || !get_str)
  144.     return JS_TRUE;
  145.  
  146.     XP_STRCPY(type_str, lm_typePrefix_str);
  147.     XP_STRCAT(type_str, name);
  148.     XP_STRCPY(get_str, lm_getPrefix_str);
  149.     XP_STRCAT(get_str, name);
  150.  
  151.     if (!JS_GetProperty(cx, obj, type_str, &type) ||
  152.     !JSVAL_IS_INT(type) ||
  153.     !JS_GetProperty(cx, obj, get_str, &func))
  154.     return JS_TRUE;
  155.  
  156.     JS_free(cx, type_str);
  157.     JS_free(cx, get_str);
  158.  
  159.     switch(JSVAL_TO_INT(type)) {
  160.     case ARGTYPE_INT32:
  161.     *vp = INT_TO_JSVAL((int32)ET_moz_CompGetterFunction((ETCompPropGetterFunc)JSVAL_TO_INT(func), name));
  162.     break;
  163.     case ARGTYPE_BOOL:
  164.     *vp = BOOLEAN_TO_JSVAL((JSBool)ET_moz_CompGetterFunction((ETCompPropGetterFunc)JSVAL_TO_INT(func), name));
  165.     break;
  166.     case ARGTYPE_STRING:
  167.     *vp = STRING_TO_JSVAL(JS_NewStringCopyZ(cx, 
  168.         (char*)ET_moz_CompGetterFunction((ETCompPropGetterFunc)JSVAL_TO_INT(func), name)));
  169.     break;
  170.     }
  171.  
  172.     return JS_TRUE;
  173. }
  174.  
  175. PR_STATIC_CALLBACK(JSBool)
  176. component_mozilla_setProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
  177. {
  178.     char *name, *type_str, *set_str, *prop_val;
  179.     jsval type, func;
  180.  
  181.     if (!JSVAL_IS_STRING(id))
  182.     return JS_TRUE;
  183.  
  184.     name = JS_GetStringBytes(JSVAL_TO_STRING(id));
  185.  
  186.     type_str = JS_malloc(cx, XP_STRLEN(lm_typePrefix_str) + XP_STRLEN(name) + 1);
  187.     set_str = JS_malloc(cx, XP_STRLEN(lm_setPrefix_str) + XP_STRLEN(name) + 1);
  188.     if (!type_str || !set_str)
  189.     return JS_TRUE;
  190.  
  191.     XP_STRCPY(type_str, lm_typePrefix_str);
  192.     XP_STRCAT(type_str, name);
  193.     XP_STRCPY(set_str, lm_setPrefix_str);
  194.     XP_STRCAT(set_str, name);
  195.     if (!JS_GetProperty(cx, obj, type_str, &type) ||
  196.     !JSVAL_IS_INT(type) ||
  197.     !JS_GetProperty(cx, obj, set_str, &func))
  198.     return JS_TRUE;
  199.  
  200.     JS_free(cx, type_str);
  201.     JS_free(cx, set_str);
  202.   
  203.     switch(JSVAL_TO_INT(type)) {
  204.     case ARGTYPE_INT32:
  205.     if (JSVAL_IS_INT(*vp))
  206.         ET_moz_CompSetterFunction((ETCompPropSetterFunc)JSVAL_TO_INT(func), name, (void*)JSVAL_TO_INT(*vp));
  207.     break;
  208.     case ARGTYPE_BOOL:
  209.     if (JSVAL_IS_BOOLEAN(*vp))
  210.         ET_moz_CompSetterFunction((ETCompPropSetterFunc)JSVAL_TO_INT(func), name, (void*)JSVAL_TO_BOOLEAN(*vp));
  211.     break;
  212.     case ARGTYPE_STRING:
  213.     if (JSVAL_IS_STRING(*vp)) {
  214.         prop_val = JS_GetStringBytes(JSVAL_TO_STRING(*vp));
  215.         ET_moz_CompSetterFunction((ETCompPropSetterFunc)JSVAL_TO_INT(func), name, (void*)prop_val);
  216.     }
  217.     break;
  218.     }
  219.  
  220.     return JS_TRUE;
  221. }
  222.  
  223. void
  224. lm_RegisterComponentProp(const char *comp, const char *targetName, 
  225.              uint8 retType, ETCompPropSetterFunc setter, 
  226.              ETCompPropGetterFunc getter)
  227. {
  228.     JSContext *cx;
  229.     JSObject *arrayObj, *obj;
  230.     jsval val;
  231.     char *type, *set, *get;
  232.     
  233.     if (!comp || !targetName || !(cx = lm_crippled_decoder->js_context))
  234.     return;
  235.  
  236.     arrayObj = lm_DefineComponents(lm_crippled_decoder);
  237.     if (!arrayObj)
  238.     return;
  239.  
  240.     if (!JS_GetProperty(cx, arrayObj, comp, &val) ||
  241.         !JSVAL_IS_OBJECT(val))
  242.     return;
  243.  
  244.     obj = JSVAL_TO_OBJECT(val);
  245.  
  246.     if (!JS_DefineProperty(cx, obj, targetName, JSVAL_VOID, component_mozilla_getProperty, 
  247.                component_mozilla_setProperty, 0)) {
  248.     }
  249.  
  250.     type = JS_malloc(cx, XP_STRLEN(lm_typePrefix_str) + XP_STRLEN(targetName) + 1);
  251.     if (type) {
  252.     XP_STRCPY(type, lm_typePrefix_str);
  253.     XP_STRCAT(type, targetName);
  254.     if (!JS_DefineProperty(cx, obj, type,
  255.                INT_TO_JSVAL((int32)retType), 0, 0, JSPROP_READONLY)) {
  256.     }
  257.     JS_free(cx, type);
  258.     }
  259.  
  260.     get = JS_malloc(cx, XP_STRLEN(lm_getPrefix_str) + XP_STRLEN(targetName) + 1);
  261.     if (get) {
  262.     XP_STRCPY(get, lm_getPrefix_str);
  263.     XP_STRCAT(get, targetName);
  264.     if (!JS_DefineProperty(cx, obj, get,
  265.                INT_TO_JSVAL(getter), 0, 0, JSPROP_READONLY)) {
  266.     }
  267.     JS_free(cx, get);
  268.     }
  269.  
  270.     set = JS_malloc(cx, XP_STRLEN(lm_setPrefix_str) + XP_STRLEN(targetName) + 1);
  271.     if (set) {
  272.     XP_STRCPY(set, lm_setPrefix_str);
  273.     XP_STRCAT(set, targetName);
  274.     if (!JS_DefineProperty(cx, obj, set,
  275.                INT_TO_JSVAL(setter), 0, 0, JSPROP_READONLY)) {
  276.     }
  277.     JS_free(cx, set);
  278.     }
  279. }
  280.  
  281. PR_STATIC_CALLBACK(JSBool)
  282. component_resolve_name(JSContext *cx, JSObject *obj, jsval id)
  283. {
  284.     return JS_TRUE;
  285. }
  286.  
  287. PR_STATIC_CALLBACK(void)
  288. component_finalize(JSContext *cx, JSObject *obj)
  289. {
  290.     JSComponent* component;
  291.  
  292.     component = JS_GetPrivate(cx, obj);
  293.     if (!component)
  294.     return;
  295.     JS_UnlockGCThing(cx, component->name);
  296.     DROP_BACK_COUNT(component->decoder);
  297.     JS_free(cx, component);
  298. }
  299.  
  300. JSClass lm_component_class =
  301. {
  302.     "Component", JSCLASS_HAS_PRIVATE,
  303.     JS_PropertyStub, JS_PropertyStub,
  304.     component_getProperty, component_getProperty, JS_EnumerateStub,
  305.     component_resolve_name, JS_ConvertStub, component_finalize
  306. };
  307.  
  308. PR_STATIC_CALLBACK(JSBool)
  309. component_activate(JSContext *cx, JSObject *obj, uint argc, jsval *argv, jsval *rval)
  310. {
  311.     JSComponent *component;
  312.  
  313.     component = JS_GetInstancePrivate(cx, obj, &lm_component_class, argv);
  314.     if (!component)
  315.     return JS_FALSE;
  316.  
  317.     ET_moz_CallFunctionAsync((ETVoidPtrFunc)component->startup_callback, NULL);
  318.  
  319.     return JS_TRUE;
  320. }
  321.  
  322. static JSFunctionSpec component_methods[] =
  323. {
  324.     {"activate", component_activate, 0},
  325.     {0}
  326. };
  327.  
  328. PR_STATIC_CALLBACK(JSBool)
  329. component_mozilla_method_stub(JSContext *cx, JSObject *obj, uint argc, 
  330.                   jsval *argv, jsval *rval)
  331. {
  332.     JSFunction *func;
  333.     JSObject *func_obj;
  334.     jsval type, native;
  335.     uint i;
  336.     JSCompArg *comp_argv;
  337.  
  338.     func = JS_ValueToFunction(cx, argv[-2]);
  339.     func_obj = JS_GetFunctionObject(func);
  340.  
  341.     if (!JS_GetProperty(cx, func_obj, lm_typePrefix_str, &type) ||
  342.     !JSVAL_IS_INT(type) ||
  343.     !JS_GetProperty(cx, func_obj, lm_methodPrefix_str, &native) ||
  344.     !(comp_argv = JS_malloc(cx, argc * sizeof(JSCompArg))))
  345.     return JS_TRUE;
  346.   
  347.     for (i=0; i<argc; i++) {
  348.     if (JSVAL_IS_INT(argv[i])) {
  349.         comp_argv[i].type = ARGTYPE_INT32;
  350.         comp_argv[i].value.intArg = JSVAL_TO_INT(argv[i]);
  351.     }
  352.     else if (JSVAL_IS_BOOLEAN(argv[i])) {
  353.         comp_argv[i].type = ARGTYPE_BOOL;
  354.         comp_argv[i].value.boolArg = JSVAL_TO_BOOLEAN(argv[i]);
  355.     }
  356.     else if (JSVAL_IS_STRING(argv[i])) {
  357.         comp_argv[i].type = ARGTYPE_STRING;
  358.         comp_argv[i].value.stringArg = JS_GetStringBytes(JSVAL_TO_STRING(argv[i]));
  359.     }
  360.     else {
  361.         comp_argv[i].type = ARGTYPE_NULL;
  362.         comp_argv[i].value.intArg = 0;
  363.     }
  364.     }
  365.  
  366.     switch(JSVAL_TO_INT(type)) {
  367.     case ARGTYPE_NULL:
  368.     ET_moz_CompMethodFunction((ETCompMethodFunc)JSVAL_TO_INT(native), argc, NULL);
  369.     *rval = 0;
  370.     break;
  371.     case ARGTYPE_INT32:
  372.     *rval = INT_TO_JSVAL((int32)ET_moz_CompMethodFunction((ETCompMethodFunc)JSVAL_TO_INT(native), argc, comp_argv));
  373.     break;
  374.     case ARGTYPE_BOOL:
  375.     *rval = BOOLEAN_TO_JSVAL((JSBool)ET_moz_CompMethodFunction((ETCompMethodFunc)JSVAL_TO_INT(native), argc, comp_argv));
  376.     break;
  377.     case ARGTYPE_STRING:
  378.     *rval = STRING_TO_JSVAL(JS_NewStringCopyZ(cx, 
  379.         (char*)ET_moz_CompMethodFunction((ETCompMethodFunc)JSVAL_TO_INT(native), argc, comp_argv)));
  380.     break;
  381.     }
  382.     return JS_TRUE;
  383. }
  384.  
  385. void
  386. lm_RegisterComponentMethod(const char *comp, const char *targetName, 
  387.                uint8 retType, ETCompMethodFunc method, int32 argc)
  388. {
  389.     JSContext *cx;
  390.     JSObject *arrayObj, *obj, *func_obj;
  391.     JSFunction *func;
  392.     jsval val;
  393.     
  394.     if (!comp || !targetName || !(cx = lm_crippled_decoder->js_context))
  395.     return;
  396.  
  397.     arrayObj = lm_DefineComponents(lm_crippled_decoder);
  398.     if (!arrayObj)
  399.     return;
  400.  
  401.     if (!JS_GetProperty(cx, arrayObj, comp, &val) ||
  402.         !JSVAL_IS_OBJECT(val))
  403.     return;
  404.  
  405.     obj = JSVAL_TO_OBJECT(val);
  406.  
  407.     if (!(func = JS_DefineFunction(cx, obj, targetName, component_mozilla_method_stub, argc, 0))){
  408.     }
  409.  
  410.     func_obj = JS_GetFunctionObject(func);
  411.  
  412.     if (!JS_DefineProperty(cx, func_obj, lm_typePrefix_str,
  413.                INT_TO_JSVAL((int32)retType), 0, 0, JSPROP_READONLY))
  414.     return;
  415.     if (!JS_DefineProperty(cx, func_obj, lm_methodPrefix_str,
  416.                INT_TO_JSVAL(method), 0, 0, JSPROP_READONLY))
  417.     return;
  418.     if (!JS_DefineProperty(cx, func_obj, lm_methodArgc_str,
  419.                INT_TO_JSVAL(argc), 0, 0, JSPROP_READONLY))
  420.     return;
  421. }
  422.  
  423. /* Constructor method for a JSComponent object */
  424. static JSComponent*
  425. component_create_self(JSContext *cx, MochaDecoder* decoder, JSComponent *component, const char *name)
  426. {
  427.     JSObject *obj;
  428.  
  429.     /* JSComponent may be malloc'd previous to this to make it easier
  430.      * to fill in the struct with data from the Mozilla thread
  431.      */
  432.     if (!component) {
  433.     component = JS_malloc(cx, sizeof(JSComponent));
  434.     if (!component)
  435.         return NULL;
  436.     }
  437.  
  438.     obj = JS_NewObject(cx, &lm_component_class, NULL, NULL);
  439.     if (!obj || !JS_SetPrivate(cx, obj, component)) {
  440.     JS_free(cx, component);
  441.     return NULL;
  442.     }
  443.  
  444.     if (!JS_DefineProperties(cx, obj, component_props))
  445.     return NULL;
  446.  
  447.     if (!JS_DefineFunctions(cx, obj, component_methods))
  448.     return NULL;
  449.  
  450.     /* Fill out static property fields */
  451.     component->decoder = HOLD_BACK_COUNT(decoder);
  452.     component->obj = obj;
  453.  
  454.     component->name = JS_NewStringCopyZ(cx, name);
  455.     if (!component->name || !JS_LockGCThing(cx, component->name))
  456.     return NULL;
  457.  
  458.     return component;
  459. }
  460.  
  461.  
  462. /*
  463.  * -----------------------------------------------------------------------
  464.  *
  465.  * Reflection of the list of installed components.
  466.  * The only static property is the array length;
  467.  * the array elements (JSComponents) are added
  468.  * lazily when referenced.
  469.  *
  470.  * -----------------------------------------------------------------------
  471.  */
  472.  
  473. enum componentarray_slot
  474. {
  475.     COMPONENTLIST_ARRAY_LENGTH = -1
  476. };
  477.  
  478. static JSPropertySpec componentarray_props[] =
  479. {
  480.     {"length",  COMPONENTLIST_ARRAY_LENGTH,    JSPROP_READONLY},
  481.     {0}
  482. };
  483.  
  484. /* Look up the component for the specified slot of the plug-in list */
  485. static JSComponent*
  486. componentarray_create_component(JSContext *cx, JSComponentArray *array,
  487.                 JSComponent *component, const char *targetName, jsint targetSlot)
  488. {
  489.     component = component_create_self(cx, array->decoder, component, targetName);
  490.     if (component) {
  491.     char *name;
  492.     jsval val;
  493.  
  494.     name = JS_GetStringBytes(component->name);
  495.     val = OBJECT_TO_JSVAL(component->obj);
  496.     JS_DefineProperty(cx, array->obj, name, val, NULL, NULL,
  497.               JSPROP_ENUMERATE);
  498.     JS_AliasElement(cx, array->obj, name, targetSlot);
  499.     array->length++;
  500.     return component;
  501.     }
  502.     return NULL;
  503. }
  504.  
  505. extern JSClass lm_component_array_class;
  506.  
  507. void
  508. lm_RegisterComponent(const char *targetName, ETBoolPtrFunc active_callback, 
  509.              ETVoidPtrFunc startup_callback) 
  510. {
  511.     JSContext *cx;
  512.     JSObject *arrayObj;
  513.     JSComponentArray *array;
  514.     JSComponent *component;
  515.     jsval val;
  516.  
  517.     if (!(cx = lm_crippled_decoder->js_context) || !targetName)
  518.     return;
  519.     
  520.     arrayObj = lm_DefineComponents(lm_crippled_decoder);
  521.     if (!arrayObj)
  522.     return;
  523.  
  524.     array = JS_GetInstancePrivate(cx, arrayObj, &lm_component_array_class, NULL);
  525.     if (!array)
  526.     return;
  527.  
  528.     if (JS_GetProperty(cx, arrayObj, targetName, &val) && JSVAL_IS_OBJECT(val)) {
  529.     /* We already have a component by this name.  Update the active and
  530.      * startup callback funcs in case ours are out of date 
  531.      */
  532.     component = JS_GetPrivate(cx, JSVAL_TO_OBJECT(val));
  533.     if (!component)
  534.         return;
  535.  
  536.     component->active_callback = active_callback;
  537.     component->startup_callback = startup_callback;
  538.  
  539.     return;
  540.     }
  541.  
  542.     component = JS_malloc(cx, sizeof(JSComponent));
  543.     if (!component)
  544.     return;
  545.  
  546.     component->active_callback = active_callback;
  547.     component->startup_callback = startup_callback;
  548.  
  549.     componentarray_create_component(cx, array, component, targetName, array->length);
  550. }
  551.  
  552.  
  553. PR_STATIC_CALLBACK(JSBool)
  554. componentarray_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
  555. {
  556.     JSComponentArray *array;
  557.     jsint slot;
  558.  
  559.     if (!JSVAL_IS_INT(id))
  560.     return JS_TRUE;
  561.  
  562.     slot = JSVAL_TO_INT(id);
  563.  
  564.     array = JS_GetInstancePrivate(cx, obj, &lm_component_array_class, NULL);
  565.     if (!array)
  566.     return JS_TRUE;
  567.  
  568.     switch (slot) {
  569.       case COMPONENTLIST_ARRAY_LENGTH:
  570.         *vp = INT_TO_JSVAL(array->length);
  571.         break;
  572.  
  573.       default:
  574.         /* Don't mess with a user-defined property. */
  575.         if (slot >= 0 && slot < (jsint) array->length) {
  576.  
  577.         /* Search for an existing JSComponent for this slot */
  578.         JSObject* componentObj = NULL;
  579.         jsval val = *vp;
  580.  
  581.         if (JSVAL_IS_OBJECT(val)) {
  582.             componentObj = JSVAL_TO_OBJECT(val);
  583.         }
  584.         else {
  585.         JSComponent* component;
  586.         component = componentarray_create_component(cx, array, NULL,
  587.                                                     NULL, slot);
  588.         if (component)
  589.                 componentObj = component->obj;
  590.         }
  591.  
  592.         *vp = OBJECT_TO_JSVAL(componentObj);
  593.         break;
  594.     }
  595.     }
  596.  
  597.     return JS_TRUE;
  598. }
  599.  
  600. PR_STATIC_CALLBACK(void)
  601. componentarray_finalize(JSContext *cx, JSObject *obj)
  602. {
  603.     JSComponentArray* array;
  604.  
  605.     array = JS_GetPrivate(cx, obj);
  606.     if (!array)
  607.     return;
  608.     DROP_BACK_COUNT(array->decoder);
  609.     JS_free(cx, array);
  610. }
  611.  
  612. JSClass lm_component_array_class =
  613. {
  614.     "ComponentArray", JSCLASS_HAS_PRIVATE,
  615.     JS_PropertyStub, JS_PropertyStub,
  616.     componentarray_getProperty, componentarray_getProperty, JS_EnumerateStub,
  617.     JS_ResolveStub, JS_ConvertStub, componentarray_finalize
  618. };
  619.  
  620.  
  621. JSObject*
  622. lm_DefineComponents(MochaDecoder *decoder)
  623. {
  624.     JSObject *obj;
  625.     JSComponentArray *array;
  626.     JSContext *cx = decoder->js_context;
  627.     JSPreDefComponent def_comps;   
  628.     JSComponent *component;
  629.     jsint slot;
  630.  
  631.     obj = decoder->components;
  632.     if (obj)
  633.         return obj;
  634.  
  635.     array = JS_malloc(cx, sizeof(JSComponentArray));
  636.     if (!array)
  637.         return NULL;
  638.     XP_BZERO(array, sizeof *array);
  639.  
  640.     obj = JS_NewObject(cx, &lm_component_array_class, NULL,
  641.                decoder->window_object);
  642.     if (!obj || !JS_SetPrivate(cx, obj, array)) {
  643.         JS_free(cx, array);
  644.         return NULL;
  645.     }
  646.     if (!JS_DefineProperties(cx, obj, componentarray_props))
  647.     return NULL; 
  648.  
  649.     array->decoder = HOLD_BACK_COUNT(decoder);
  650.     array->obj = obj;
  651.  
  652.     /* Components can be added dynamically but some are predefined */
  653.     slot = 0;
  654.     array->length = 0;
  655.     def_comps = predef_components[slot];
  656.     while (def_comps.name) {
  657.     component = JS_malloc(cx, sizeof(JSComponent));
  658.     if (!component)
  659.         return NULL;
  660.  
  661.     if (ET_moz_VerifyComponentFunction(def_comps.func, &(component->active_callback), 
  662.                        &(component->startup_callback))) {
  663.         componentarray_create_component(cx, array, component, def_comps.name, array->length);
  664.     }
  665.     else {
  666.         /*Component call failed somewhere.*/
  667.         JS_free(cx, component);
  668.     }
  669.     def_comps = predef_components[++slot];
  670.     }
  671.     return obj;
  672. }
  673.