home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / lib / libmocha / lm_init.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  56.2 KB  |  1,965 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.  * JS in the Navigator top-level stuff.
  20.  *
  21.  * Brendan Eich, 9/8/95
  22.  */
  23. #include "lm.h"
  24. #include "xp.h"
  25. #include "net.h"
  26. #include "structs.h"
  27. #include "mkutils.h"    /* XXX for NET_URL_Type() */
  28. #include "layout.h"     /* for lo_FormData */
  29. #include "pa_tags.h"    /* included via -I../libparse */
  30. #include "prmem.h"
  31. #include "prthread.h"
  32. #include "prmon.h"
  33. #ifdef XP_MAC
  34. #include "pprthred.h"   /* for PR_CreateThreadGCAble */
  35. #else
  36. #include "private/pprthred.h"
  37. #endif
  38.  
  39. #include "jri.h"
  40. #include "jriext.h"
  41. #include "java.h"
  42. #include "prefapi.h"
  43. #include "libi18n.h"
  44. #include "intl_csi.h"
  45.  
  46. #define UNICODE /* remove after working everywhere */
  47.  
  48. extern PRThread *mozilla_thread;
  49. extern QueueStackElement    *et_TopQueue;
  50.  
  51. char js_language_name[]  = "JavaScript";
  52. char js_content_type[]   = APPLICATION_JAVASCRIPT;
  53.  
  54. char lm_argc_err_str[]   = "incorrect number of arguments";
  55.  
  56. char lm_onLoad_str[]        = PARAM_ONLOAD;
  57. char lm_onUnload_str[]      = PARAM_ONUNLOAD;
  58. char lm_onAbort_str[]       = PARAM_ONABORT;
  59. char lm_onError_str[]       = PARAM_ONERROR;
  60. char lm_onScroll_str[]      = PARAM_ONSCROLL;
  61. char lm_onFocus_str[]       = PARAM_ONFOCUS;
  62. char lm_onBlur_str[]        = PARAM_ONBLUR;
  63. char lm_onSelect_str[]      = PARAM_ONSELECT;
  64. char lm_onChange_str[]      = PARAM_ONCHANGE;
  65. char lm_onReset_str[]       = PARAM_ONRESET;
  66. char lm_onSubmit_str[]      = PARAM_ONSUBMIT;
  67. char lm_onClick_str[]       = PARAM_ONCLICK;
  68. char lm_onMouseDown_str[]   = PARAM_ONMOUSEDOWN;
  69. char lm_onMouseOver_str[]   = PARAM_ONMOUSEOVER;
  70. char lm_onMouseOut_str[]    = PARAM_ONMOUSEOUT;
  71. char lm_onMouseUp_str[]     = PARAM_ONMOUSEUP;
  72. char lm_onLocate_str[]      = PARAM_ONLOCATE;
  73. char lm_onHelp_str[]        = PARAM_ONHELP;
  74.  
  75. char lm_focus_str[]         = "focus";
  76. char lm_blur_str[]          = "blur";
  77. char lm_select_str[]        = "select";
  78. char lm_click_str[]         = "click";
  79. char lm_scroll_str[]        = "scroll";
  80. char lm_enable_str[]        = "enable";
  81. char lm_disable_str[]       = "disable";
  82.  
  83. char lm_toString_str[]      = "toString";
  84. char lm_length_str[]        = "length";
  85. char lm_document_str[]      = "document";
  86. char lm_forms_str[]         = "forms";
  87. char lm_links_str[]         = "links";
  88. char lm_anchors_str[]       = "anchors";
  89. char lm_plugins_str[]       = "plugins";
  90. char lm_applets_str[]       = "applets";
  91. char lm_embeds_str[]        = "embeds";
  92. char lm_images_str[]        = "images";
  93. char lm_layers_str[]        = "layers";
  94. char lm_location_str[]      = "location";
  95. char lm_navigator_str[]     = "navigator";
  96. char lm_netcaster_str[]     = "netcaster";
  97. char lm_components_str[]    = "components";
  98.  
  99. char lm_parentLayer_str[]   = "parentLayer";
  100. char lm_opener_str[]        = "opener";
  101. char lm_closed_str[]        = "closed";
  102. char lm_assign_str[]        = "assign";
  103. char lm_reload_str[]        = "reload";
  104. char lm_replace_str[]       = "replace";
  105. char lm_event_str[]         = "event";
  106. char lm_methodPrefix_str[]  = "#method";
  107. char lm_methodArgc_str[]    = "#margc";
  108. char lm_methodArgv_str[]    = "#margv";
  109. char lm_getPrefix_str[]     = "#get_";
  110. char lm_setPrefix_str[]     = "#set_";
  111. char lm_typePrefix_str[]    = "#type_";
  112. const char *lm_event_argv[] = {lm_event_str};
  113.  
  114. JSRuntime       *lm_runtime;
  115. static uint32   lm_max_gc_bytes = 4L * 1024L * 1024L;   /* XXX use a pref */
  116.  
  117. MochaDecoder    *lm_crippled_decoder;
  118. JSContext       *lm_crippled_context;   /* exported to jsStubs.c */
  119.  
  120. PRThread        *lm_InterpretThread;    /* interpreter now in its own thread */
  121. JRIEnv          *lm_JSEnv;              /* Java env for lm_InterpretThread */
  122. PREventQueue    *lm_InterpretQueue;     /* for "normal" event messages */
  123. PREventQueue    *lm_PriorityQueue;      /* for stop and death messages */
  124.  
  125. /*
  126.  * This is the big lock that ensures serialization of mocha execution.
  127.  * It must be acquired before executing any mocha code in order to
  128.  * preserve run-to-completion semantics.
  129.  */
  130. static PRThread *lm_owner;        /* the only thread running mocha */
  131. PRMonitor *lm_owner_mon = NULL;   /* lock protecting lm_owner */
  132. static MWContext *lm_owner_context;
  133. static int32      lm_owner_count;
  134.  
  135. #ifdef JAVA
  136. extern LJ_JSJ_Init(void);
  137. #endif
  138.  
  139. static JSClass lm_dummy_class = {
  140.     "Dummy", JSCLASS_HAS_PRIVATE,
  141.     JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
  142.     JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub
  143. };
  144. JSObject *lm_DummyObject;
  145.  
  146. PR_STATIC_CALLBACK(JSBool)
  147. lm_alert(JSContext *cx, JSObject *obj, uint argc, jsval *argv, jsval *rval)
  148. {
  149.     MochaDecoder *decoder;
  150.     MWContext *context;
  151.     JSString *arg;
  152.  
  153.     decoder = JS_GetInstancePrivate(cx, obj, &lm_window_class, argv);
  154.     if (!decoder)
  155.         return JS_TRUE;
  156.     if (!(arg = JS_ValueToString(cx, argv[0])))
  157.         return JS_FALSE;
  158.     context = decoder->window_context;
  159.     if (context) {
  160.     char * message;
  161.     message = lm_StrToLocalEncoding(context, arg);
  162.         ET_PostMessageBox(context, message, JS_FALSE);
  163.     XP_FREEIF(message);
  164.     }
  165.     return JS_TRUE;
  166. }
  167.  
  168. #ifdef DEBUG
  169.  
  170. #include "jscntxt.h"
  171.  
  172. PR_STATIC_CALLBACK(JSBool)
  173. lm_tracing(JSContext *cx, JSObject *obj,
  174.            uint argc, jsval *argv, jsval *rval)
  175. {
  176.     JSBool bval;
  177.  
  178.     if (argc == 0) {
  179.         *rval = BOOLEAN_TO_JSVAL(cx->tracefp != 0);
  180.         return JS_TRUE;
  181.     }
  182.  
  183.     if (JSVAL_IS_INT(argv[0])) {
  184.         if (JSVAL_TO_INT(argv[0]) != 0)
  185.             bval = JS_TRUE;
  186.     } else if (JSVAL_IS_BOOLEAN(argv[0])) {
  187.         bval = JSVAL_TO_BOOLEAN(argv[0]);
  188.     } else {
  189.         return JS_TRUE; /* XXX should be error */
  190.     }
  191.     if (cx->tracefp)
  192.         fclose(cx->tracefp);
  193.     cx->tracefp = bval ? fopen("/dev/tty", "w") : 0;
  194.     return JS_TRUE;
  195. }
  196.  
  197. #endif /* DEBUG */
  198.  
  199. static JSFunctionSpec lm_global_functions[] = {
  200.     {"alert",           lm_alert,       0},
  201. #ifdef DEBUG
  202.     {"tracing",         lm_tracing,     0},
  203. #endif
  204.     {0}
  205. };
  206.  
  207. /*
  208.  * If we don't get passed an object, assume we are supposed to use
  209.  *   the main window object
  210.  */
  211. JSBool
  212. lm_CompileEventHandler(MochaDecoder * decoder, PA_Block id, PA_Block all, 
  213.                        int newline_count, JSObject *object,
  214.                        const char *name, PA_Block block)
  215. {
  216.     JSPrincipals *principals, *registered;
  217.     JSContext *cx;
  218.     char *body, *p;
  219.     JSBool ok;
  220.     JSString *unicode;
  221.  
  222.     cx = decoder->js_context;
  223.     if (object == NULL)
  224.         object = decoder->window_object;
  225.  
  226.     principals = lm_GetCompilationPrincipals(decoder, NULL);
  227.     if (principals == NULL)
  228.         return JS_FALSE;
  229.  
  230.     JSPRINCIPALS_HOLD(cx, principals);
  231.  
  232.     body = (char *) block;
  233.  
  234.     /* Find block in all and subtract newlines in and after block
  235.            from newline_count */
  236.     if (all) {
  237.         /* 
  238.          * XXX - We really should fix it so that "all" is always
  239.          * nonnull.
  240.          */
  241.         for (p=(char *) all; *p; p++) {
  242.             if (*p == '\r' || *p == '\n') {
  243.                 p = XP_STRSTR((char *) all, body);
  244.                 if (p == NULL)
  245.                     break;
  246.                 /* 
  247.                  * XXX - doesn't handle case where there are two 
  248.                  * handlers with the same text
  249.                  */
  250.                 while (*p) {
  251.                     switch (*p) {
  252.                     case '\r':
  253.                         if (p[1] == '\n')
  254.                             p++;
  255.                         /* fall through */
  256.                     case '\n':
  257.                         newline_count--;
  258.                         break;
  259.                     default:
  260.                         break;
  261.                     }
  262.                     p++;
  263.                 }
  264.                 break;
  265.             }
  266.         }
  267.     }
  268.  
  269.     registered = LM_RegisterPrincipals(decoder, principals, 
  270.                                        (char *) id, (char *) all);
  271.  
  272.     unicode = lm_LocalEncodingToStr(decoder->window_context, body);
  273.     JS_LockGCThing(cx, unicode);
  274.     ok = (JSBool)(registered && 
  275.          JS_CompileUCFunctionForPrincipals(cx, object,
  276.             registered,
  277.             name, 1, lm_event_argv,
  278.             JS_GetStringChars(unicode), JS_GetStringLength(unicode), 
  279.             LM_GetSourceURL(decoder),
  280.             newline_count + 1)
  281.          != NULL);
  282.  
  283.     JSPRINCIPALS_DROP(cx, principals);
  284.     JS_UnlockGCThing(cx, unicode);
  285.     return ok;
  286. }
  287.  
  288. #define INTERRUPT_BRANCH_COUNT_MASK     255
  289. #define MAYBE_GC_BRANCH_COUNT_MASK      4095
  290.  
  291. #ifdef XP_UNIX
  292. static uint32 lm_handling_event;
  293. #endif
  294.  
  295. JSBool PR_CALLBACK
  296. lm_BranchCallback(JSContext *cx, JSScript *script)
  297. {
  298.     static uint32 count = 0;
  299.  
  300.     /*
  301.      * If we have been running for a while yield and see if anyone
  302.      *   else is waiting for a time slice or is trying to stop us.
  303.      * At a much less frequent interval, force a GC to catch any garbage
  304.      *   created by long-running or long-resident scripts.
  305.      */
  306.     if ((++count & INTERRUPT_BRANCH_COUNT_MASK) == 0) {
  307.         MochaDecoder *decoder;
  308.     MWContext *context;
  309.  
  310.         PR_Sleep(PR_INTERVAL_NO_WAIT);
  311.  
  312.         /* check to see if we've been stopped */
  313.         decoder = JS_GetPrivate(cx, JS_GetGlobalObject(cx));
  314.     context = decoder->window_context;
  315.         if (!ET_ContinueProcessing(context)) {
  316. #ifdef DEBUG_chouck
  317.             XP_TRACE(("Interrupted in branch callback"));
  318. #endif
  319.             return JS_FALSE;
  320.         }
  321.  
  322.         /* if not stopped, go look for garbage */
  323.         if ((count & MAYBE_GC_BRANCH_COUNT_MASK) == 0) {
  324. #ifdef XP_UNIX
  325.         /* X lacks an idle loop from which to do this opportunistically. */
  326.         if (lm_handling_event && context)
  327.         ET_moz_CallFunction((ETVoidPtrFunc)FE_UpdateStopState, context);
  328. #endif /* XP_UNIX */
  329.  
  330.             JS_MaybeGC(cx);
  331.     }
  332.     }
  333.     return JS_TRUE;
  334. }
  335.  
  336. #define ERROR_REPORT_LIMIT      10
  337.  
  338. static JSBool
  339. lm_lookup_event_handler(JSContext *cx, JSObject *obj, uint32 type, jsval *fvp);
  340.  
  341. void PR_CALLBACK
  342. lm_ErrorReporter(JSContext *cx, const char *message, JSErrorReport *report)
  343. {
  344.     JSObject *obj;
  345.     MochaDecoder *decoder;
  346.     jsval fval, rval, argv[3];
  347.     JSString *str;
  348.     JSBool ok;
  349.     char *last;
  350.     int i, j, k, n;
  351.     const char *s, *t;
  352. #ifdef JAVA
  353.     JSBool java_errors = JS_TRUE;
  354. #else
  355.     JSBool java_errors = JS_FALSE;
  356. #endif /* JAVA */
  357.     MWContext *context;
  358.  
  359. #ifdef XP_WIN16
  360.     java_errors = JS_FALSE;
  361.     return;
  362. #endif
  363.  
  364.     obj = JS_GetGlobalObject(cx);
  365.     decoder = JS_GetPrivate(cx, obj);
  366.     if (!decoder)
  367.         return;
  368.  
  369.     context = decoder->window_context;
  370.     if (context && context->type == MWContextPrint)
  371.     return;
  372.  
  373.     JS_SetErrorReporter(cx, NULL);
  374.     if (lm_lookup_event_handler(cx, obj, EVENT_ERROR, &fval)) {
  375.         if (fval == JSVAL_NULL) {
  376.             /* User has set onerror to null, so cancel this report. */
  377.             goto out;
  378.         }
  379.         if (JS_TypeOfValue(cx, fval) == JSTYPE_FUNCTION) {
  380.             str = JS_NewStringCopyZ(cx, message);
  381.             if (!str)
  382.                 goto out;
  383.             argv[0] = STRING_TO_JSVAL(str);
  384.             str = JS_NewStringCopyZ(cx, report ? report->filename : "");
  385.             if (!str)
  386.                 goto out;
  387.             argv[1] = STRING_TO_JSVAL(str);
  388.             argv[2] = INT_TO_JSVAL(report ? report->lineno : 0);
  389. #ifdef XP_UNIX
  390.         lm_handling_event++;
  391. #endif
  392.             ok = JS_CallFunctionValue(cx, obj, fval, 3, argv, &rval);
  393. #ifdef XP_UNIX
  394.         lm_handling_event--;
  395. #endif
  396.             if (!ok) {
  397.                 /* Error during onerror, message is probably free now. */
  398.                 goto out;
  399.             }
  400.             if (rval == JSVAL_TRUE) {
  401.                 /* True return value means the function reported this error. */
  402.                 goto out;
  403.             }
  404.         }
  405.     }
  406.  
  407.     decoder->error_count++;
  408.     if (decoder->error_count >= ERROR_REPORT_LIMIT) {
  409.         if (decoder->error_count == ERROR_REPORT_LIMIT) {
  410.             last = PR_smprintf("too many %s errors", js_language_name);
  411.         if (last) {
  412.         ET_PostMessageBox(decoder->window_context, last, JS_FALSE);
  413.         XP_FREE(last);
  414.             }
  415.         }
  416.         goto out;
  417.     }
  418.  
  419.     last = PR_sprintf_append(NULL,
  420.                  java_errors
  421.                  ? "java.lang.System.err.println(\"%s Error: "
  422.                  : "<FONT SIZE=4>\\\n<B>%s Error:</B> ",
  423.                  js_language_name);
  424.  
  425.     if (!report) {
  426.         last = PR_sprintf_append(last, 
  427.                  java_errors 
  428.                  ? "%s\\\n"
  429.                  : "<B>%s</B>\n", 
  430.                  message);
  431.     }
  432.     else {
  433.         if (report->filename)
  434.             last = PR_sprintf_append(last, "%s, ", report->filename);
  435.         if (report->lineno) {
  436.         last = PR_sprintf_append(last, 
  437.                      java_errors 
  438.                      ? "line %u:\\\n" 
  439.                      : "<B>line %u:</B>", 
  440.                      report->lineno);
  441.     }
  442.     last = PR_sprintf_append(last,
  443.                  java_errors
  444.                  ? "  %s."
  445.                  : "<BR><BR>%s.</FONT><PRE><FONT SIZE=4>",
  446.                  message);
  447.         if (report->linebuf) {
  448.         if (java_errors)
  449.         last = PR_sprintf_append(last, "\\\n");
  450.             for (s = t = report->linebuf; *s != '\0'; s = t) {
  451.                 for (; t != report->tokenptr && *t != '<' && *t != '\0'; t++)
  452.                     ;
  453.                 last = PR_sprintf_append(last, "%.*s", t - s, s);
  454.                 if (*t == '\0')
  455.                     break;
  456.         if (java_errors) {
  457.             last = PR_sprintf_append(last, (*t == '\"') ? "\\\"" : "%c", *t);
  458.         }
  459.         else {
  460.             if (t == report->tokenptr) {
  461.             last = PR_sprintf_append(last,
  462.                          "</FONT>"
  463.                          "<FONT SIZE=4 COLOR=#ff2020>");
  464.             }
  465.             last = PR_sprintf_append(last, (*t == '<') ? "<" : "%c", *t);
  466.                 }
  467.         t++;
  468.             }
  469.             if (java_errors) {
  470.         last = PR_sprintf_append(last, "\\\n");
  471.         }
  472.         else {
  473.         last = PR_sprintf_append(last, "</FONT><FONT SIZE=4>\n");
  474.         n = report->tokenptr - report->linebuf;
  475.         for (i = j = 0; i < n; i++) {
  476.         if (report->linebuf[i] == '\t') {
  477.             for (k = (j + 8) & ~7; j < k; j++)
  478.             last = PR_sprintf_append(last, ".");
  479.             continue;
  480.         }
  481.             last = PR_sprintf_append(last, ".");
  482.             j++;
  483.         }
  484.         last = PR_sprintf_append(last, java_errors ? "^" : "<B>^</B>");
  485.         }
  486.         }
  487.     if (!java_errors)
  488.         last = PR_sprintf_append(last, "\n</FONT></PRE>");
  489.     }
  490.  
  491.     if (java_errors)
  492.     last = PR_sprintf_append(last, "\");");
  493.  
  494.     if (last) {
  495.     if (java_errors) {
  496.         JS_EvaluateScript(lm_crippled_context, 
  497.                   JS_GetGlobalObject(lm_crippled_context),
  498.                   last, strlen(last), NULL, 0, &rval);
  499.     }
  500.     else {
  501.         if (context)
  502.         ET_MakeHTMLAlert(context, last);
  503.     }
  504.  
  505.     XP_FREE(last);
  506.     }
  507.  
  508. out:
  509.     JS_SetErrorReporter(cx, lm_ErrorReporter);
  510. }
  511.  
  512. static MochaDecoder *
  513. lm_new_decoder(JSRuntime *rt, JSClass *clasp)
  514. {
  515.     JSContext *cx;
  516.     MochaDecoder *decoder;
  517.     JSObject *obj;
  518.  
  519.     decoder = XP_NEW_ZAP(MochaDecoder);
  520.     if (!decoder)
  521.         return NULL;
  522.  
  523. /* XXX begin common */
  524.     cx = JS_NewContext(rt, LM_STACK_SIZE);
  525.     if (!cx) {
  526.         XP_DELETE(decoder);
  527.         return NULL;
  528.     }
  529.  
  530.     decoder->forw_count = 1;
  531.     decoder->js_context = cx;
  532.     JS_SetBranchCallback(cx, lm_BranchCallback);
  533.     JS_SetErrorReporter(cx, lm_ErrorReporter);
  534.  
  535.     obj = JS_NewObject(cx, clasp, NULL, NULL);
  536.     if (!obj || !JS_SetPrivate(cx, obj, decoder)) {
  537.         JS_DestroyContext(cx);
  538.         XP_DELETE(decoder);
  539.         return NULL;
  540.     }
  541.  
  542.     /* If this decoder ever needs to hold anonymous images, then call
  543.        lm_NewImageContext with a NULL context and use IL_SetDisplayMode to
  544.        set the context later. */
  545.     decoder->image_context = 0;
  546.     decoder->window_context = 0;
  547.     decoder->window_object = obj;
  548.     JS_AddNamedRoot(cx, &decoder->window_object, "window_object");
  549.  
  550.     JS_SetGlobalObject(cx, obj);
  551. /* XXX end common */
  552.  
  553.     JS_DefineFunctions(cx, obj, lm_global_functions);
  554.  
  555.     return decoder;
  556. }
  557.  
  558. /*
  559.  * Enable or disable local JS decoding.
  560.  */
  561. static XP_Bool lm_enabled = TRUE;
  562. static XP_Bool lm_enabledMailNews = TRUE;
  563. static XP_Bool lm_enabledSigning = TRUE;
  564. static XP_Bool lm_enabledCrossOrigin = TRUE;
  565.  
  566. /*
  567.  * Is this window enbled to do JS?
  568.  */
  569. JSBool
  570. LM_CanDoJS(MWContext *context)
  571. {
  572.     PRBool forceJSEnabled;
  573.     if (context) {
  574.         forceJSEnabled = (JSBool)context->forceJSEnabled;
  575.     } else {
  576.         forceJSEnabled = PR_FALSE;
  577.     }
  578.     
  579.     if (!forceJSEnabled && !LM_GetMochaEnabled())
  580.         return JS_FALSE;
  581.  
  582.     /* No JS for Editor */
  583.     if( EDT_IS_EDITOR(context) )
  584.         return JS_FALSE;
  585.  
  586.     switch (context->type) {
  587.       case MWContextBrowser:
  588.       case MWContextDialog:
  589.       case MWContextPane:
  590. /* DSR101097 - OS/2 must follow NT w/ this or hangs printing large pages w/ JS */ 
  591. #if defined(XP_WIN) || defined(XP_MAC) || defined(XP_OS2)
  592.       /* only alow JS to run in windows print mode
  593.        * don't know about the safty of other platforms yet
  594.        */
  595.       case MWContextPrint:
  596. #endif /* XP_WIN */
  597.         return JS_TRUE;
  598.       case MWContextMail:
  599.       case MWContextNews:
  600.       case MWContextMailMsg:
  601.       case MWContextNewsMsg:
  602.       case MWContextMessageComposition:
  603.         return (JSBool) lm_enabledMailNews;
  604.       default:
  605.         return JS_FALSE;
  606.     }
  607. }
  608.  
  609. /*
  610.  * Is JS globally enabled?
  611.  */
  612. JSBool
  613. LM_GetMochaEnabled(void)
  614. {
  615.     return (JSBool) lm_enabled;
  616. }
  617.  
  618. /*
  619.  * Is cross-origin access enabled?
  620.  */
  621. JSBool
  622. lm_GetCrossOriginEnabled()
  623. {
  624.     return (JSBool) lm_enabledCrossOrigin;
  625. }
  626.  
  627. static char lm_jsEnabled[] = "javascript.enabled";
  628. static char lm_jsEnabledMN[] = "javascript.allow.mailnews";
  629. static char lm_jsEnabledSigning[] = "javascript.allow.signing";
  630. static char lm_jsEnabledCrossOrigin[] = "javascript.allow.crossOrigin";
  631.  
  632. PR_STATIC_CALLBACK(int)
  633. lm_PrefChangedFunc(const char *pref, void *data)
  634. {
  635.     PREF_GetBoolPref(lm_jsEnabled, &lm_enabled);
  636.     PREF_GetBoolPref(lm_jsEnabledMN, &lm_enabledMailNews);
  637.     PREF_GetBoolPref(lm_jsEnabledSigning, &lm_enabledSigning);
  638.     PREF_GetBoolPref(lm_jsEnabledCrossOrigin, &lm_enabledCrossOrigin);
  639.  
  640.     /*
  641.      * If we started up w/ JS turned off we will have not bothered
  642.      *   the separate thread and event queues, do it now
  643.      */
  644.     if (lm_owner_mon == NULL && lm_enabled)
  645.         LM_InitMocha();
  646.  
  647.     return PREF_NOERROR;
  648. }
  649.  
  650. static JSBool mochaInited = JS_FALSE;
  651.  
  652. /* nix, where is this */
  653. extern void 
  654. JSJ_InitContext(JSContext *context, JSObject *obj); 
  655.  
  656. /*
  657.  * create the mocha thread, event queues, and stream converters
  658.  */
  659. static void
  660. lm_ReallyInitMocha(void)
  661. {
  662.     int priority;
  663.  
  664.     /* register callback incase pref changes while we're running */
  665.     PREF_RegisterCallback(lm_jsEnabled, lm_PrefChangedFunc, NULL);
  666.     PREF_RegisterCallback(lm_jsEnabledMN, lm_PrefChangedFunc, NULL);
  667.     PREF_RegisterCallback(lm_jsEnabledSigning, lm_PrefChangedFunc, NULL);
  668.     PREF_RegisterCallback(lm_jsEnabledCrossOrigin, lm_PrefChangedFunc, NULL);
  669.  
  670.     if ( mochaInited ) {
  671.         return;
  672.     }
  673.     
  674.     lm_runtime = JS_Init(lm_max_gc_bytes);
  675.     if (!lm_runtime)
  676.         return;
  677.  
  678.     mochaInited = JS_TRUE;
  679.     
  680.     /* Initialize a crippled decoder/context for use by Java. */
  681.     lm_crippled_decoder = lm_new_decoder(lm_runtime, &lm_dummy_class);
  682.     lm_crippled_context = lm_crippled_decoder->js_context;
  683.  
  684. #ifdef JAVA
  685.     LJ_JSJ_Init();
  686.  
  687.     /* 
  688.      * Get liveconnect functions defined for the crippled context
  689.      *   so we can pass error messages to the JavaConsole
  690.      */
  691.     JSJ_InitContext(lm_crippled_context, JS_GetGlobalObject(lm_crippled_context));
  692. #endif
  693.  
  694.     /* Initialize a dummy object used for unreflectable applets and embeds. */
  695.     lm_DummyObject = lm_crippled_decoder->window_object;
  696.  
  697.     /* Associate a JS netlib "converter" with our mime type. */
  698.     /* Cool, we are still in the mozilla thread at this point so
  699.        we don't have to make this call into an event passage */
  700.     NET_RegisterContentTypeConverter(js_content_type, FO_PRESENT, 0,
  701.                                      NET_CreateMochaConverter);
  702.     NET_RegisterContentTypeConverter(TEXT_CSS, FO_PRESENT, 0,
  703.                                      NET_CreateMochaConverter);
  704.     NET_RegisterContentTypeConverter(TEXT_JSSS, FO_PRESENT, 0,
  705.                                      NET_CreateMochaConverter);
  706.  
  707.     /* Associate a JS netlib "converter" with our CSS too. */
  708.     NET_RegisterContentTypeConverter(TEXT_CSS, FO_PRESENT, 0,
  709.                                      NET_CreateMochaConverter);
  710.  
  711.     /* Make sure the mozilla event queue is around */
  712.     XP_ASSERT(mozilla_event_queue != NULL);
  713.  
  714.     /* run at slightly lower priority than the mozilla thread */
  715.     priority = PR_GetThreadPriority(PR_CurrentThread());
  716.     PR_ASSERT(priority >= PR_PRIORITY_FIRST && priority <= PR_PRIORITY_LAST);
  717.  
  718.     if (priority == PR_PRIORITY_NORMAL)
  719.     priority = PR_PRIORITY_LOW;
  720.     else if (priority == PR_PRIORITY_HIGH)
  721.     priority = PR_PRIORITY_NORMAL;
  722.     else if (priority == PR_PRIORITY_URGENT)
  723.     priority = PR_PRIORITY_HIGH;
  724.     else
  725.     priority = PR_PRIORITY_LOW;    
  726.  
  727.     /* create the monitor for the owner */
  728.     if (lm_owner_mon == NULL)
  729.         lm_owner_mon = PR_NewMonitor();
  730.  
  731.     /* create the interpreter thread. */
  732.     /*
  733.      * Grab the lm_owner_mon until we are done with thread creation and
  734.      *   initialization.  The thread will immediately try to grab the 
  735.      *   same monitor when it starts up, so if its able to get the monitor
  736.      *   it can be certain that all of the thread state has been initialized
  737.      */
  738.     PR_EnterMonitor(lm_owner_mon);
  739.     lm_InterpretThread = PR_CreateThreadGCAble(PR_USER_THREAD, 
  740.                            lm_wait_for_events, NULL,
  741.                            priority, PR_LOCAL_THREAD, 
  742.                            PR_UNJOINABLE_THREAD,
  743.                            0);  /* default stack size */
  744.  
  745.     lm_InterpretQueue = PR_CreateEventQueue("mocha-event-queue",
  746.                         lm_InterpretThread);
  747.  
  748.     PR_Notify(lm_owner_mon);
  749.     PR_ExitMonitor(lm_owner_mon);
  750.  
  751.     /* AutoInstall trigger functions for JS config object */
  752.     lm_DefineTriggers();
  753.  
  754. #ifdef JSDEBUGGER
  755.     lm_InitJSDebug(lm_runtime);
  756. #endif
  757.  
  758.     return;
  759. }
  760.  
  761. void
  762. LM_ForceJSEnabled(MWContext *cx)
  763. {
  764.     lm_ReallyInitMocha();
  765.     cx->forceJSEnabled = PR_TRUE;
  766.     return;
  767. }
  768.  
  769. /* XXX return boolean to propagate errors. */
  770. void
  771. LM_InitMocha(void)
  772. {
  773.     /* register callback incase pref changes while we're running */
  774.     PREF_RegisterCallback(lm_jsEnabled, lm_PrefChangedFunc, NULL);
  775.     PREF_RegisterCallback(lm_jsEnabledMN, lm_PrefChangedFunc, NULL);
  776.     PREF_RegisterCallback(lm_jsEnabledSigning, lm_PrefChangedFunc, NULL);
  777.     PREF_RegisterCallback(lm_jsEnabledCrossOrigin, lm_PrefChangedFunc, NULL);
  778.  
  779.     /* get our enabled-ness states */
  780.     PREF_GetBoolPref(lm_jsEnabled, &lm_enabled);
  781.     PREF_GetBoolPref(lm_jsEnabledMN, &lm_enabledMailNews);
  782.     PREF_GetBoolPref(lm_jsEnabledSigning, &lm_enabledSigning);
  783.     PREF_GetBoolPref(lm_jsEnabledCrossOrigin, &lm_enabledCrossOrigin);
  784.  
  785.     /* set up the initial queue stack pointers */
  786.     if (!et_TopQueue) {
  787.         et_TopQueue = XP_NEW_ZAP(QueueStackElement);
  788.         if (!et_TopQueue)
  789.             return;
  790.     }
  791.  
  792.     if (!lm_enabled)
  793.         return;
  794.  
  795.     lm_ReallyInitMocha();
  796. }
  797.  
  798. static int lm_moja_initialized = LM_MOJA_UNINITIALIZED;
  799.  
  800. PRLogModuleInfo* Moja;
  801.  
  802. void MojaLogModuleInit()
  803. {
  804.     Moja = PR_NewLogModule("Moja");
  805. }
  806.  
  807. /* returns FALSE if already done or TRUE for success */
  808. int
  809. LM_InitMoja()
  810. {
  811.     /* XXX assert mozilla thread */
  812.     /* this stuff should only be done once.  since it is always
  813.      * called on the moz thread we can do it the easy way */
  814.     if (lm_moja_initialized != LM_MOJA_UNINITIALIZED)
  815.         return lm_moja_initialized;
  816.  
  817. #ifdef JAVA
  818.     /* initialize the java env associated with the mocha thread */
  819.     lm_JSEnv = LJ_EnsureJavaEnv(lm_InterpretThread);
  820.     if (lm_JSEnv == NULL) {
  821.         lm_moja_initialized = LM_MOJA_JAVA_FAILED;
  822.         return lm_moja_initialized;
  823.     }
  824.  
  825.     lm_moja_initialized = LM_MOJA_OK;
  826. #else
  827.     lm_moja_initialized = LM_MOJA_JAVA_FAILED;
  828. #endif
  829.  
  830.     MojaLogModuleInit();
  831.  
  832.     return lm_moja_initialized;
  833. }
  834.  
  835. /* returns FALSE if already done or TRUE for success */
  836. int
  837. LM_IsMojaInitialized()
  838. {
  839.     return lm_moja_initialized;
  840. }
  841.  
  842. void
  843. LM_FinishMoja()
  844. {
  845.     /* XXX write me */
  846. }
  847.  
  848.  
  849. PRBool PR_CALLBACK
  850. LM_HandOffJSLock(PRThread * oldOwner, PRThread *newOwner)
  851. {
  852.         /* XXX note this doesn't worry about the lm_owner_count,
  853.          * assumes it's pushed/popped properly */
  854.         PRBool didHandOff = PR_FALSE;
  855.         PR_EnterMonitor(lm_owner_mon);
  856.         if (lm_owner == oldOwner) {
  857.                 lm_owner = newOwner;
  858.                 didHandOff = PR_TRUE;
  859.         }
  860.         PR_Notify(lm_owner_mon);
  861.         PR_ExitMonitor(lm_owner_mon);
  862.         return didHandOff;
  863. }
  864.  
  865. static PRBool            mozWantsJSLock  = PR_FALSE;
  866. static PRBool            mozGotJSLock    = PR_FALSE;
  867.  
  868. typedef struct lm_lock_waiter {
  869.     JSLockReleaseFunc       fn;
  870.     void                  * data;
  871.     struct lm_lock_waiter * next;
  872. } lm_lock_waiter;
  873.  
  874. static lm_lock_waiter * lm_waiting_list = NULL;
  875.  
  876. /*
  877.  * push the mozilla event loop until the jslock is obtained
  878.  */
  879. static void
  880. LM_WaitForJSLock(void)
  881. {
  882.     PREventQueue *q = mozilla_event_queue;
  883.     PRMonitor *mon = PR_GetEventQueueMonitor(q);
  884.     PRBool hadLayoutLock;
  885.  
  886.     XP_ASSERT(PR_CurrentThread() == mozilla_thread);
  887.  
  888.     hadLayoutLock = (JSBool)(!LO_VerifyUnlockedLayout());
  889.     if (hadLayoutLock)
  890.         LO_UnlockLayout();
  891.     while (!mozGotJSLock) {
  892.         PR_EnterMonitor(mon);
  893.         if (!PR_EventAvailable(q))
  894.             PR_Wait(mon, PR_INTERVAL_NO_TIMEOUT);
  895.         PR_ExitMonitor(mon);
  896.         PR_ProcessPendingEvents(q);
  897.     }
  898.     if (hadLayoutLock)
  899.         LO_LockLayout();
  900. }
  901.  
  902. /*
  903.  * Wait until we get the JSLock
  904.  */
  905. void PR_CALLBACK
  906. LM_LockJS()
  907. {
  908.     PRThread *t = PR_CurrentThread();
  909.  
  910.     XP_ASSERT(lm_owner_mon != NULL);
  911.  
  912.     PR_EnterMonitor(lm_owner_mon);
  913.  
  914.     while (lm_owner != t) {
  915.         if (lm_owner == NULL) {
  916.             lm_owner = t;
  917.             break;
  918.         }
  919.         if (PR_CurrentThread() == mozilla_thread) {
  920.             /* blocking here could deadlock, because the owner
  921.              * of the js thread may make synchronous event calls
  922.              * to the moz thread through et_moz.c or others. */
  923.  
  924.             /* while we wait, run another event loop */
  925.             mozWantsJSLock = PR_TRUE;
  926.             mozGotJSLock = PR_FALSE;
  927.             PR_ExitMonitor(lm_owner_mon);
  928.             LM_WaitForJSLock();
  929.             PR_EnterMonitor(lm_owner_mon);
  930.             XP_ASSERT(lm_owner == mozilla_thread);
  931.             mozWantsJSLock = PR_FALSE;
  932.             mozGotJSLock = PR_FALSE;
  933.         } else {
  934.             PR_Wait(lm_owner_mon, PR_INTERVAL_NO_TIMEOUT);
  935.         }
  936.     }
  937.     lm_owner_count++;
  938.     PR_ExitMonitor(lm_owner_mon);
  939. }
  940.  
  941. /*
  942.  * Try to get the JSLock but just return JS_FALSE if we can't
  943.  *   get it, don't wait since we could deadlock
  944.  */
  945. JSBool PR_CALLBACK
  946. LM_AttemptLockJS(JSLockReleaseFunc fn, void * data)
  947. {
  948.     PRThread *t = PR_CurrentThread();
  949.  
  950.     /*
  951.      * If javascript is disabled this might have never been
  952.      *   created.  In that case its never possible to get the
  953.      *   js lock.
  954.      */
  955.     if (!lm_owner_mon)
  956.        return JS_FALSE;
  957.  
  958.     PR_EnterMonitor(lm_owner_mon);
  959.     if (lm_owner == NULL || lm_owner == t) {
  960.         lm_owner = t;
  961.         lm_owner_count++;
  962.         PR_ExitMonitor(lm_owner_mon);
  963.         return JS_TRUE;
  964.     }
  965.  
  966.     if (fn) {           /* XXX - Only one waitor function allowed at a time */
  967.         lm_lock_waiter ** p;
  968.         lm_lock_waiter * waiter = XP_NEW_ZAP(lm_lock_waiter);
  969.         if (!waiter) {
  970.             PR_ExitMonitor(lm_owner_mon);
  971.             return JS_FALSE;
  972.         }
  973.  
  974.         waiter->fn = fn;
  975.         waiter->data = data;
  976.  
  977.         /* double indirection! */
  978.         for (p = &lm_waiting_list; *p; p = &(*p)->next)
  979.             ;
  980.  
  981.         *p = waiter;
  982.     }
  983.  
  984.     PR_ExitMonitor(lm_owner_mon);
  985.     return JS_FALSE;
  986.  
  987. }
  988.  
  989. JSBool PR_CALLBACK
  990. LM_ClearAttemptLockJS(JSLockReleaseFunc fn, void * data)
  991. {
  992.     lm_lock_waiter ** p;
  993.     lm_lock_waiter * waiter;
  994.  
  995.     for (p = &lm_waiting_list; (waiter = *p) != NULL; p = &waiter->next) {
  996.     if (waiter->fn == fn && waiter->data == data) {
  997.         *p = waiter->next;
  998.             XP_FREE(waiter);
  999.         return JS_TRUE;
  1000.     }
  1001.     }
  1002.     return JS_FALSE;
  1003. }
  1004.  
  1005. PR_STATIC_CALLBACK(void)
  1006. lm_MozGotJSLock(void *data)
  1007. {
  1008.     /* does nothing - signalling is done when the lock
  1009.      * is transferred over.  the event that calls this
  1010.      * function is only sent to wake up the nested event
  1011.      * loop */
  1012. }
  1013.  
  1014. /*
  1015.  * Release the JSLock
  1016.  */
  1017. void PR_CALLBACK
  1018. LM_UnlockJS()
  1019. {
  1020.     XP_ASSERT(PR_CurrentThread() == lm_owner);
  1021.     PR_EnterMonitor(lm_owner_mon);
  1022.     XP_ASSERT(lm_owner_count > 0);
  1023.     if (--lm_owner_count <= 0) {
  1024.         lm_owner_count = 0;
  1025.         lm_owner = NULL;
  1026.         lm_owner_context = NULL;
  1027.  
  1028.         /* was anyone waiting for us to release the JSLock? */
  1029.  
  1030.         /* moz gets priority, and we hand the lock off immediately */
  1031.         if (mozWantsJSLock) {
  1032.             lm_owner = mozilla_thread;
  1033.             lm_owner_count = 0;
  1034.             mozWantsJSLock = PR_FALSE;
  1035.             mozGotJSLock = PR_TRUE;
  1036.             ET_moz_CallFunctionAsync(lm_MozGotJSLock, NULL);
  1037.         } else if (lm_waiting_list) {
  1038.             lm_lock_waiter * waiter = lm_waiting_list;
  1039.             lm_waiting_list = waiter->next;
  1040.             ET_moz_CallFunctionAsync(waiter->fn, waiter->data);
  1041.             XP_FREE(waiter);
  1042.         }
  1043.  
  1044.         PR_Notify(lm_owner_mon);
  1045.     }
  1046.     PR_ExitMonitor(lm_owner_mon);
  1047.  
  1048. }
  1049.  
  1050. /*
  1051.  * keep track of the current context that owns the JS lock in
  1052.  *   case we get an interrupt event and need to decide whether
  1053.  *   to interrupt the current operation or not
  1054.  */
  1055. void
  1056. LM_JSLockSetContext(MWContext * context)
  1057. {
  1058.     XP_ASSERT(lm_owner_mon != NULL);
  1059.     PR_EnterMonitor(lm_owner_mon);
  1060.     XP_ASSERT(lm_owner == PR_CurrentThread());
  1061.     lm_owner_context = context;
  1062.     PR_ExitMonitor(lm_owner_mon);
  1063. }
  1064.  
  1065. /* this could race.  does it matter ? */
  1066. MWContext *
  1067. LM_JSLockGetContext()
  1068. {
  1069.     return lm_owner_context;
  1070. }
  1071.  
  1072.  
  1073. MochaDecoder *
  1074. LM_GetMochaDecoder(MWContext *context)
  1075. {
  1076.     JSContext *cx;
  1077.     MochaDecoder *decoder;
  1078.  
  1079.     if (!LM_CanDoJS(context))
  1080.         return NULL;
  1081.  
  1082.     /* Get the context's JS decoder, creating one if necessary. */
  1083.     cx = context->mocha_context;
  1084.     if (cx) {
  1085.         decoder = JS_GetPrivate(cx, JS_GetGlobalObject(cx));
  1086.     } else {
  1087.         decoder = lm_NewWindow(context);
  1088.         if (!decoder)
  1089.             return NULL;
  1090.         cx = decoder->js_context;
  1091.     }
  1092.     if (!decoder->document && !lm_InitWindowContent(decoder))
  1093.         return NULL;
  1094.     /* The decoder has at least one forward ref from context. */
  1095.     XP_ASSERT(decoder->forw_count > 0);
  1096.     decoder->forw_count++;
  1097.     return decoder;
  1098. }
  1099.  
  1100. void
  1101. LM_PutMochaDecoder(MochaDecoder *decoder)
  1102. {
  1103.     JSContext * cx;
  1104.  
  1105.     XP_ASSERT(decoder->forw_count > 0);
  1106.     if (--decoder->forw_count <= 0) {
  1107.         decoder->forw_count = 0;
  1108.         if (decoder->window_context)
  1109.             decoder->window_context->mocha_context = NULL;
  1110.  
  1111. #define CLEAR(obj)      obj = 0
  1112.  
  1113.         /* Clear all object prototype refs. */
  1114.         CLEAR(decoder->anchor_prototype);
  1115.         CLEAR(decoder->bar_prototype);
  1116.         CLEAR(decoder->document_prototype);
  1117.         CLEAR(decoder->event_prototype);
  1118.         CLEAR(decoder->event_capturer_prototype);
  1119.         CLEAR(decoder->event_receiver_prototype);
  1120.         CLEAR(decoder->form_prototype);
  1121.         CLEAR(decoder->image_prototype);
  1122.         CLEAR(decoder->input_prototype);
  1123.         CLEAR(decoder->layer_prototype);
  1124.         CLEAR(decoder->option_prototype);
  1125.         CLEAR(decoder->rect_prototype);
  1126.         CLEAR(decoder->url_prototype);
  1127.  
  1128.         /* Clear window sub-object refs. */
  1129.         if (decoder->document)
  1130.             lm_CleanUpDocumentRoots(decoder, decoder->document);
  1131.         CLEAR(decoder->document);
  1132.         CLEAR(decoder->history);
  1133.         CLEAR(decoder->location);
  1134.         CLEAR(decoder->navigator);
  1135.         CLEAR(decoder->components);
  1136.         CLEAR(decoder->crypto);
  1137.         CLEAR(decoder->screen);
  1138.         CLEAR(decoder->hardware);
  1139.         CLEAR(decoder->pkcs11);
  1140.  
  1141.         /* Clear ad-hoc GC roots. */
  1142.         CLEAR(decoder->event_receiver);
  1143.         CLEAR(decoder->opener);
  1144.  
  1145.         /* Clear the root of this window's object tree. */
  1146.         CLEAR(decoder->window_object);
  1147.  
  1148. #undef CLEAR
  1149.  
  1150.         /* Don't forget to clear GC roots in the context. */
  1151.         cx = decoder->js_context;
  1152.         JS_ClearRegExpRoots(cx);
  1153.  
  1154.         /* Reset these in case a backward reference to decoder lingers. */
  1155.         decoder->firstVersion = JSVERSION_UNKNOWN;
  1156.         decoder->principals = NULL;
  1157.  
  1158.         /* Hold an extra back ref to keep cx and decoder alive. */
  1159.         HOLD_BACK_COUNT(decoder);
  1160.         JS_SetGlobalObject(cx, NULL);
  1161.         JS_GC(cx);
  1162.  
  1163.         /*
  1164.          * If the finalizer ran, and there are no back refs from private
  1165.          * data of objects held by other windows' properties, then this drop
  1166.          * will destroy the decoder.  Otherwise it must live on until its
  1167.          * runaway kids are all finalized.
  1168.          */
  1169.         DROP_BACK_COUNT(decoder);
  1170.     }
  1171. }
  1172.  
  1173. JSBool
  1174. LM_IsActive(MWContext *context)
  1175. {
  1176.     JSContext *cx = context->mocha_context;
  1177.     if (!cx)
  1178.         return JS_FALSE;
  1179.     
  1180.     return (JSBool)(JS_IsRunning(cx) || (context->js_timeouts_pending > 0));
  1181. }
  1182.  
  1183. const char *
  1184. LM_GetSourceURL(MochaDecoder *decoder)
  1185. {
  1186.     JSContext *cx;
  1187.     const char *originURL;
  1188.  
  1189.     if (decoder->nesting_url)
  1190.         return decoder->nesting_url->str;
  1191.     if (decoder->source_url)
  1192.         return decoder->source_url;
  1193.     cx = decoder->js_context;
  1194.     originURL = lm_GetObjectOriginURL(cx, decoder->window_object);
  1195.     if (!originURL)
  1196.         return NULL;
  1197.     decoder->source_url = JS_strdup(cx, originURL);
  1198.     return decoder->source_url;
  1199. }
  1200.  
  1201. static const char AUTOINSTALL_PREFIX[] = "autoinstall:";
  1202. static size_t AUTOINSTALL_PREFIX_LENGTH = sizeof AUTOINSTALL_PREFIX - 1;
  1203.  
  1204. static JSObject *
  1205. lm_get_scope_from_string(MochaDecoder *decoder, JSContext *cx,
  1206.                          const char *source_url, uint lineno, 
  1207.                          char *scope_to, JSPrincipals *principals)
  1208. {
  1209.     jsval result;
  1210.     JSBool ok;
  1211.     JSObject *scope;
  1212.  
  1213.     if (!scope_to)
  1214.         return NULL;
  1215.  
  1216.     /*
  1217.      * Hack for ASD -- create a new object with environment from scope_to.
  1218.      * If we ever change autoinstall:, change the define MOCHA_CONTEXT_PREFIX
  1219.      * in softupdt.c  XXXbe how about a single definition in a .h file?
  1220.      */
  1221.     if (!XP_STRNCMP(scope_to, AUTOINSTALL_PREFIX, AUTOINSTALL_PREFIX_LENGTH)) {
  1222.         return lm_NewSoftupObject(cx, decoder,
  1223.                                   scope_to + AUTOINSTALL_PREFIX_LENGTH);
  1224.     }
  1225.  
  1226.  
  1227.     if (decoder->active_layer_id == LO_DOCUMENT_LAYER_ID) {
  1228.         scope = decoder->window_object;
  1229.     } else {
  1230.         LO_LockLayout();
  1231.         scope = LO_GetLayerMochaObjectFromId(decoder->window_context,
  1232.                                              decoder->active_layer_id);
  1233.         LO_UnlockLayout();
  1234.     }
  1235.  
  1236.     /* pass the scope as a script to return the scope object */
  1237.     ok = JS_EvaluateScriptForPrincipals(cx,
  1238.                                         scope,
  1239.                                         principals,
  1240.                                         scope_to,
  1241.                                         strlen(scope_to),
  1242.                                         source_url,
  1243.                                         lineno,
  1244.                                         &result);
  1245.  
  1246.     if (ok) {
  1247.         XP_ASSERT(JSVAL_IS_OBJECT(result));
  1248.         if (JSVAL_IS_OBJECT(result))
  1249.             return JSVAL_TO_OBJECT(result);
  1250.     }
  1251.  
  1252.     return NULL;
  1253. }
  1254.  
  1255. JSBool
  1256. LM_EvaluateBuffer(MochaDecoder *decoder, void *base, size_t length,
  1257.                   uint lineno, char *scope_to, JSPrincipals *principals,
  1258.                   JSBool unicode, jsval *result)
  1259. {
  1260.     JSContext *cx;
  1261.     const char *source_url;
  1262.     JSBool ok;
  1263.     JSObject *scope;
  1264.  
  1265.     /* XXX if lineno == 0, do something smart */
  1266.     source_url = LM_GetSourceURL(decoder);
  1267.     if (!source_url)
  1268.         return JS_FALSE;
  1269.     cx = decoder->js_context;
  1270.  
  1271.     principals = LM_RegisterPrincipals(decoder, principals, NULL, base);
  1272.     if (!principals)
  1273.         return JS_FALSE;
  1274.  
  1275.     scope = lm_get_scope_from_string(decoder, cx, source_url, lineno, 
  1276.                                      scope_to, principals);
  1277.     if (!scope) {
  1278.         if (decoder->active_layer_id == LO_DOCUMENT_LAYER_ID) {
  1279.             scope = decoder->window_object;
  1280.         } else {
  1281.             const char *scope_source_url;
  1282.  
  1283.             LO_LockLayout();
  1284.             scope = LO_GetLayerMochaObjectFromId(decoder->window_context,
  1285.                                                  decoder->active_layer_id);
  1286.             LO_UnlockLayout();
  1287.         if (!scope)
  1288.         return JS_FALSE;
  1289.             scope_source_url = lm_GetLayerOriginURL(cx, scope);
  1290.             if (scope_source_url)
  1291.                 source_url = scope_source_url;
  1292.         }
  1293.     }
  1294.  
  1295.     if (unicode)
  1296.     ok = JS_EvaluateUCScriptForPrincipals(cx, scope, principals, base,
  1297.                           length, source_url, lineno, 
  1298.                           result);
  1299.     else
  1300.     ok = JS_EvaluateScriptForPrincipals(cx, scope, principals, base, 
  1301.                         length, source_url, lineno, 
  1302.                         result);
  1303.     return ok;
  1304. }
  1305.  
  1306. char *
  1307. LM_EvaluateAttribute(MWContext *context, char *expr, uint lineno)
  1308. {
  1309.     char *bytes;
  1310.     MochaDecoder *decoder;
  1311.     jsval result;
  1312.     JSContext *cx;
  1313.     JSPrincipals *principals;
  1314.  
  1315.     bytes = 0;
  1316.     if (!expr)
  1317.         return bytes;
  1318.     decoder = LM_GetMochaDecoder(context);
  1319.     if (!decoder)
  1320.         return bytes;
  1321.     
  1322.     /* 
  1323.      * Since this called directly from the mozilla thread, we know that
  1324.      * it's safe to sample the doc_id. In fact, we have to do that,
  1325.      * otherwise the doc_id check could fail for any entities processed.
  1326.      */
  1327.     decoder->doc_id = XP_DOCID(context);
  1328.  
  1329.     cx = decoder->js_context;
  1330.     if (!JS_AddRoot(cx, &result)) {   /* XXX chouck - can we do a lockGCThing here */
  1331.         LM_PutMochaDecoder(decoder);
  1332.         return bytes;
  1333.     }
  1334.     principals = lm_GetCompilationPrincipals(decoder, NULL);
  1335.     if (principals) {
  1336.         JSPRINCIPALS_HOLD(cx, principals);
  1337.         if (LM_EvaluateBuffer(decoder, expr, XP_STRLEN(expr), lineno, NULL,
  1338.                               principals, JS_FALSE, &result)) {
  1339.             bytes = lm_StrToLocalEncoding(context,
  1340.                       JS_ValueToString(cx, result));
  1341.         }
  1342.         JSPRINCIPALS_DROP(cx, principals);
  1343.     }
  1344.     JS_RemoveRoot(cx, &result);
  1345.     LM_PutMochaDecoder(decoder);
  1346.     return bytes;
  1347. }
  1348.  
  1349. static JSObject*
  1350. lm_get_layer_parent(JSContext *cx, JSObject *obj) 
  1351. {
  1352.     JSObject *save = obj;
  1353.     jsval val;
  1354.  
  1355.     if (!JS_InstanceOf(cx, obj, &lm_layer_class, NULL))
  1356.         return NULL;
  1357.  
  1358.     while (obj) {
  1359.         if (JS_InstanceOf(cx, obj, &lm_document_class, NULL)) {
  1360.             return obj;
  1361.         }
  1362.         obj = JS_GetParent(cx, obj);
  1363.     }
  1364.  
  1365.     /* Should only get here if the layer's parent has been severed
  1366.      * Don't want to use this method in general because it could
  1367.      * cause a security violation on the layer container check.
  1368.      */
  1369.     if (!JS_GetProperty(cx, save, lm_parentLayer_str, &val))
  1370.         return NULL;
  1371.     if (val != JSVAL_NULL && JSVAL_IS_OBJECT(val)) {
  1372.         obj = JSVAL_TO_OBJECT(val);
  1373.         if (!JS_GetProperty(cx, obj, lm_document_str, &val))
  1374.             return NULL;
  1375.  
  1376.         if (val != JSVAL_NULL && JSVAL_IS_OBJECT(val))
  1377.             return JSVAL_TO_OBJECT(val);
  1378.     }
  1379.  
  1380.     return NULL;
  1381. }
  1382.  
  1383.  
  1384. static JSBool
  1385. lm_lookup_event_handler(JSContext *cx, JSObject *obj, uint32 type, jsval *fvp)
  1386. {
  1387.     JSEventNames *names;
  1388.     char name[32];
  1389.     JSBool ok;
  1390.  
  1391.     names = lm_GetEventNames(type);
  1392.     if (!names) {
  1393.         *fvp = JSVAL_VOID;
  1394.         return JS_TRUE;
  1395.     }
  1396.     PR_snprintf(name, sizeof name, "on%s", names->lowerName);
  1397.     ok = JS_LookupProperty(cx, obj, name, fvp);
  1398.     if (ok && JSVAL_IS_VOID(*fvp)) {
  1399.         PR_snprintf(name, sizeof name, "on%s", names->mixedName);
  1400.         ok = JS_LookupProperty(cx, obj, name, fvp);
  1401.     }
  1402.     return ok;
  1403. }
  1404.  
  1405. JSBool
  1406. lm_SendEvent(MWContext *context, JSObject *obj, JSEvent *event, jsval *result)
  1407. {
  1408.     JSContext *cx;
  1409.     JSObject *eventObj;
  1410.     MochaDecoder *decoder;
  1411.     JSBool ok = JS_TRUE;
  1412.     jsval funval, argv[1];
  1413.     MWContext *mwcx;
  1414.     uint32 event_capture_bit = 0;
  1415.  
  1416.     decoder = LM_GetMochaDecoder(context);
  1417.     if (!decoder)
  1418.         return JS_FALSE;
  1419.  
  1420.     cx = decoder->js_context;
  1421.  
  1422.     if (!event->object)
  1423.         event->object = obj;
  1424.  
  1425.     event_capture_bit |= context->event_bit;
  1426.  
  1427.     if (context->is_grid_cell) {
  1428.         mwcx = context;
  1429.         while (mwcx->grid_parent) {
  1430.             mwcx = mwcx->grid_parent;
  1431.             event_capture_bit |= mwcx->event_bit;
  1432.         }
  1433.     }
  1434.  
  1435.     ok = lm_lookup_event_handler(cx, obj, event->type, &funval);
  1436.     if (!ok ||
  1437.         (JS_TypeOfValue(cx, funval) != JSTYPE_FUNCTION &&
  1438.          !(event_capture_bit & event->type))) {
  1439.         goto out;
  1440.     }
  1441.  
  1442.     eventObj = lm_NewEventObject(decoder, event);
  1443.     if (!eventObj) {
  1444.         ok = JS_FALSE;
  1445.         goto out;
  1446.     }
  1447.  
  1448.     argv[0] = OBJECT_TO_JSVAL(eventObj);
  1449.     ok = lm_FindEventHandler(context, obj, eventObj, funval, result);
  1450.  
  1451. out:
  1452.     LM_PutMochaDecoder(decoder);
  1453.     return ok;
  1454. }
  1455.  
  1456. JSBool
  1457. lm_FindEventHandler(MWContext *context, JSObject *obj, JSObject *eventObj,
  1458.                     jsval funval, jsval *result)
  1459. {
  1460.  
  1461.     MochaDecoder *decoder;
  1462.     JSContext *cx;
  1463.     JSBool ok, is_window;
  1464.     JSEventCapturer *js_cap;
  1465.     JSEvent *event;
  1466.     MWContext *mwcx;
  1467.     uint32 event_capture_bit = 0;
  1468.  
  1469.     if (!obj)
  1470.         return JS_TRUE;
  1471.     
  1472.     decoder = LM_GetMochaDecoder(context);
  1473.     if (!decoder)
  1474.         return JS_FALSE;
  1475.  
  1476.     cx = decoder->js_context;
  1477.  
  1478.     /*  Fun, fun.  Time for the reverse architecture event capturing.
  1479.      *  First, let's see if we're capturing at all.
  1480.      */
  1481.     event_capture_bit |= context->event_bit;
  1482.  
  1483.     if (context->is_grid_cell) {
  1484.         mwcx = context;
  1485.         while (mwcx->grid_parent) {
  1486.             mwcx = mwcx->grid_parent;
  1487.             event_capture_bit |= mwcx->event_bit;
  1488.         }
  1489.     }
  1490.  
  1491.     if (!(event = JS_GetInstancePrivate(cx, eventObj, &lm_event_class, NULL))) {
  1492.         LM_PutMochaDecoder(decoder);
  1493.         return JS_FALSE;
  1494.     }
  1495.  
  1496.     if (!(event_capture_bit & event->type)) {
  1497.         /*No capturing going on.  Just call the function.*/
  1498.         LM_PutMochaDecoder(decoder);
  1499.         return lm_HandleEvent(cx, obj, eventObj, funval, result);
  1500.  
  1501.     }
  1502.  
  1503.     event->event_handled = JS_FALSE;
  1504.  
  1505.     /*Somebody wants it.  Let's go!  Time for recursion!*/
  1506.  
  1507.     is_window = JS_InstanceOf(cx, obj, &lm_window_class, NULL);
  1508.     if (!is_window || context->grid_parent) {
  1509.         if (is_window && context->is_grid_cell) {
  1510.             if (context->grid_parent->mocha_context) {
  1511.                 ok = lm_FindEventHandler(context->grid_parent, 
  1512.                         JS_GetGlobalObject(context->grid_parent->mocha_context),
  1513.                         eventObj, 0, result);
  1514.             } else {
  1515.                 ok = JS_TRUE;
  1516.             }
  1517.         } else if (JS_InstanceOf(cx, obj, &lm_layer_class, NULL)) {
  1518.             ok = lm_FindEventHandler(context, lm_get_layer_parent(cx, obj), 
  1519.                                      eventObj, 0, result);
  1520.         } else {
  1521.             ok = lm_FindEventHandler(context, JS_GetParent(cx, obj),
  1522.                                      eventObj, 0, result);
  1523.         }
  1524.     }
  1525.     
  1526.     if (!event->event_handled) {
  1527.  
  1528.         /*We unfortunately have to check versus different type here.*/
  1529.         if (JS_InstanceOf(cx, obj, &lm_window_class, NULL)) {
  1530.  
  1531.             if (decoder->event_bit & event->type &&
  1532.                 !(decoder->event_mask & event->type))
  1533.             {
  1534.                 decoder->event_mask |= event->type;
  1535.                 ok = lm_HandleEvent(cx, obj, eventObj, funval, result);
  1536.                 decoder->event_mask &= ~event->type;
  1537.                 LM_PutMochaDecoder(decoder);
  1538.                 event->event_handled = ok;
  1539.                 return ok;
  1540.             }
  1541.         }
  1542.  
  1543.         if (JS_InstanceOf(cx, obj, &lm_document_class, NULL) || 
  1544.             JS_InstanceOf(cx, obj, &lm_layer_class, NULL)) {
  1545.             js_cap = JS_GetPrivate(cx, obj);
  1546.  
  1547.             if (js_cap && js_cap->event_bit & event->type &&
  1548.                     !(js_cap->base.event_mask & event->type))
  1549.             {
  1550.                 XP_ASSERT(cx == event->decoder->js_context);
  1551.                 js_cap->base.event_mask |= event->type;
  1552.                 ok = lm_HandleEvent(cx, obj, eventObj, funval, result);
  1553.                 js_cap->base.event_mask &= ~event->type;
  1554.                 LM_PutMochaDecoder(decoder);
  1555.                 event->event_handled = ok;
  1556.                 return ok;
  1557.             }
  1558.         }
  1559.  
  1560.         /* If we get this far we should be back at the original object and it
  1561.          * needs to have its eventhandler called.
  1562.          */
  1563.         if (obj == event->object) {
  1564.             ok = lm_HandleEvent(cx, obj, eventObj, funval, result);
  1565.         }
  1566.     }
  1567.     LM_PutMochaDecoder(decoder);
  1568.     return ok;
  1569. }
  1570.  
  1571. JSBool
  1572. lm_HandleEvent(JSContext *cx, JSObject *obj, JSObject *eventObj,
  1573.                 jsval funval, jsval *result)
  1574. {
  1575.     JSEvent *event;
  1576.     JSBool ok = JS_TRUE;
  1577.     jsval argv[1];
  1578.     char name[32];
  1579.     JSFunction *fun;
  1580.  
  1581.     if (JS_TypeOfValue(cx, funval) != JSTYPE_FUNCTION) {
  1582.         event = JS_GetPrivate(cx, eventObj);
  1583.         if (!event) {
  1584.             ok = JS_FALSE;
  1585.             goto out;
  1586.         }
  1587.  
  1588.         PR_snprintf(name, sizeof name, "on%s", lm_EventName(event->type));
  1589.         if (!JS_LookupProperty(cx, obj, name, result)) {
  1590.             ok = JS_FALSE;
  1591.             goto out;
  1592.         }
  1593.  
  1594.         ok = lm_lookup_event_handler(cx, obj, event->type, &funval);
  1595.         if (!ok || JS_TypeOfValue(cx, funval) != JSTYPE_FUNCTION)
  1596.             goto out;
  1597.  
  1598.         fun = JS_ValueToFunction(cx, funval);
  1599.         if (fun == NULL) {
  1600.             ok = JS_FALSE;
  1601.             goto out;
  1602.         }
  1603.  
  1604.         if (!lm_CanCaptureEvent(cx, fun, event)) {
  1605.             ok = JS_FALSE;
  1606.             goto out;
  1607.         }
  1608.     }
  1609.  
  1610.  
  1611.     argv[0] = OBJECT_TO_JSVAL(eventObj);
  1612. #ifdef XP_UNIX
  1613.     lm_handling_event++;
  1614. #endif
  1615.     ok = JS_CallFunctionValue(cx, obj, funval, 1, argv, result);
  1616. #ifdef XP_UNIX
  1617.     lm_handling_event--;
  1618. #endif
  1619.  
  1620. out:
  1621.     return ok;
  1622. }
  1623.  
  1624. /*
  1625.  * Wrapper for the common case of decoder's stream being set by code running
  1626.  * on decoder's JS context.
  1627.  */
  1628. JSBool
  1629. LM_SetDecoderStream(MWContext * context, NET_StreamClass *stream,
  1630.                     URL_Struct *url_struct, JSBool free_stream_on_close)
  1631. {
  1632.     MochaDecoder *decoder = LM_GetMochaDecoder(context);
  1633.     JSBool rv;
  1634.  
  1635.     if (!decoder)
  1636.         return (JS_FALSE);
  1637.  
  1638.     rv = lm_SetInputStream(decoder->js_context, decoder, stream,
  1639.                            url_struct, free_stream_on_close);
  1640.  
  1641.     LM_PutMochaDecoder(decoder);
  1642.     return(rv);
  1643.  
  1644. }
  1645.  
  1646. void
  1647. lm_SetActiveForm(MWContext * context, int32 id)
  1648. {
  1649.     MochaDecoder *decoder = LM_GetMochaDecoder(context);
  1650.  
  1651.     if (!decoder)
  1652.         return;
  1653.  
  1654.     decoder->active_form_id = id;
  1655.     LM_PutMochaDecoder(decoder);
  1656.  
  1657. }
  1658.  
  1659. void
  1660. LM_SetActiveLayer(MWContext * context, int32 layer_id)
  1661. {
  1662.     MochaDecoder *decoder = LM_GetMochaDecoder(context);
  1663.     if (!decoder)
  1664.         return;
  1665.  
  1666.     decoder->active_layer_id = layer_id;
  1667.  
  1668.     LM_PutMochaDecoder(decoder);
  1669. }
  1670.  
  1671. int32
  1672. LM_GetActiveLayer(MWContext * context)
  1673. {
  1674.     int32 layer_id;
  1675.     
  1676.     MochaDecoder *decoder = LM_GetMochaDecoder(context);
  1677.     if (!decoder)
  1678.         return LO_DOCUMENT_LAYER_ID;
  1679.  
  1680.     layer_id = decoder->active_layer_id;
  1681.  
  1682.     LM_PutMochaDecoder(decoder);
  1683.  
  1684.     return layer_id;
  1685. }
  1686.  
  1687. JSBool
  1688. lm_SetInputStream(JSContext *cx, MochaDecoder *decoder,
  1689.                   NET_StreamClass *stream, URL_Struct *url_struct,
  1690.                   JSBool free_stream_on_close)
  1691. {
  1692.     const char *origin_url;
  1693.     JSObject *container;
  1694.     JSPrincipals *principals;
  1695.  
  1696.     /*
  1697.      * If the stream is NULL don't clobber the old value
  1698.      */
  1699.     if (stream) {
  1700.         decoder->stream = stream;
  1701.         decoder->free_stream_on_close = free_stream_on_close;
  1702.     }
  1703.     
  1704.     /*
  1705.      * If we're still in the process of loading the main parser stream
  1706.      * (i.e. the window's load event hasn't been sent), the window is the 
  1707.      * owner of the stream.
  1708.      */
  1709.     if (!decoder->load_event_sent)
  1710.         decoder->stream_owner = LO_DOCUMENT_LAYER_ID;
  1711.     decoder->url_struct = NET_HoldURLStruct(url_struct);
  1712.  
  1713.     /* Don't update origin for <SCRIPT SRC="URL"> URLs. */
  1714.     if (decoder->nesting_url)
  1715.         return JS_TRUE;
  1716.  
  1717.     /* Update the origin URL associated with the document in decoder. */
  1718.     if (!decoder->writing_input) {
  1719.         switch (NET_URL_Type(url_struct->address)) {
  1720.           case ABOUT_TYPE_URL:
  1721.           case MOCHA_TYPE_URL:
  1722.             return JS_TRUE;
  1723.         }
  1724.         origin_url = url_struct->address;
  1725.     } else {
  1726.         origin_url = lm_GetSubjectOriginURL(cx);
  1727.     if (!origin_url)
  1728.         return JS_FALSE;
  1729.     }
  1730.  
  1731.     container = lm_GetActiveContainer(decoder);
  1732.     if (container == NULL)
  1733.         return JS_FALSE;
  1734.     principals = lm_GetInnermostPrincipals(cx, container, NULL);
  1735.     if (principals == NULL)
  1736.         return JS_FALSE;
  1737.     if (XP_STRCMP(principals->codebase, origin_url) == 0) {
  1738.     /* XXXbe Don't want to invalidate self-modifying doc's cert principals
  1739.          pessimisticly (for fear of a written unsigned <script> tag).
  1740.          Rather, let LM_RegisterPrincipals handle that case only when
  1741.          it arises.  Note that overwrite of a closed doc drops any old
  1742.          principals via LM_ReleaseDocument/lm_FreeWindowContent.
  1743.     lm_InvalidateCertPrincipals(decoder, principals);
  1744.     */
  1745.     return JS_TRUE;
  1746.     }
  1747.     principals = LM_NewJSPrincipals(NULL, NULL, origin_url);
  1748.     if (principals == NULL)
  1749.     return JS_FALSE;
  1750.     lm_SetContainerPrincipals(cx, container, principals);
  1751.     return JS_TRUE;
  1752. }
  1753.  
  1754. NET_StreamClass *
  1755. lm_ClearDecoderStream(MochaDecoder *decoder, JSBool fromDiscard)
  1756. {
  1757.     NET_StreamClass *stream;
  1758.     URL_Struct *url_struct;
  1759.  
  1760.     stream = decoder->stream;
  1761.     url_struct = decoder->url_struct;
  1762.     decoder->stream = 0;
  1763.     decoder->stream_owner = LO_DOCUMENT_LAYER_ID;
  1764.     decoder->url_struct = 0;
  1765.     if (decoder->writing_input) {
  1766.         decoder->writing_input = JS_FALSE;
  1767.         if (stream) {
  1768.             /*
  1769.              * Complete the stream before freeing the URL struct to which it
  1770.              * may hold a private pointer.
  1771.              */
  1772.             if (!fromDiscard) {
  1773.                 if (decoder->window_context && 
  1774.                     XP_DOCID(decoder->window_context) != -1)
  1775.                     ET_moz_CallFunction( (ETVoidPtrFunc) stream->complete, (void *)stream);
  1776.                 if (decoder->free_stream_on_close)
  1777.                     XP_DELETE(stream);
  1778.             }
  1779.             stream = NULL;
  1780.         }
  1781.         if (url_struct) {
  1782.             /* we should no longer be setting this */
  1783.             XP_ASSERT(url_struct->pre_exit_fn == NULL);
  1784.         }
  1785.     }
  1786.  
  1787.     /*
  1788.      * whether we were writing or not we were holding a reference
  1789.      * to this url_struct.  Let go of it now
  1790.      */ 
  1791.     if (url_struct)
  1792.         NET_DropURLStruct(url_struct);
  1793.     decoder->free_stream_on_close = JS_FALSE;
  1794.     return(stream);
  1795. }
  1796.  
  1797. PRIVATE void
  1798. LM_ClearContextStream(MWContext *context)
  1799. {
  1800.     MochaDecoder *decoder;
  1801.  
  1802.     if (!context->mocha_context) {
  1803.         /* Don't impose cost on non-JS contexts. */
  1804.         return;
  1805.     }
  1806.     decoder = LM_GetMochaDecoder(context);
  1807.     if (!decoder) {
  1808.         /* XXX how can this happen?  If lm_InitWindow fails or if the user
  1809.                turns off JS in the middle of a load.  Return false! */
  1810.         return;
  1811.     }
  1812.     lm_ClearDecoderStream(decoder, JS_FALSE);
  1813.     LM_PutMochaDecoder(decoder);
  1814. }
  1815.  
  1816. JSBool
  1817. lm_SaveParamString(JSContext *cx, PA_Block *bp, const char *str)
  1818. {
  1819.     if (*bp)
  1820.         PA_FREE(*bp);
  1821.  
  1822.     *bp = (PA_Block) strdup(str);
  1823.     if (!*bp) {
  1824.         JS_ReportOutOfMemory(cx);
  1825.         return JS_FALSE;
  1826.     }
  1827.     return JS_TRUE;
  1828. }
  1829.  
  1830. JSObject *
  1831. lm_GetOuterObject(MochaDecoder * decoder)
  1832. {
  1833.     lo_FormData *form_data;
  1834.     JSObject * rv = NULL;
  1835.  
  1836.     if (decoder->active_form_id) {
  1837.         LO_LockLayout();
  1838.         form_data =
  1839.             LO_GetFormDataByID(decoder->window_context,
  1840.                                decoder->active_layer_id,
  1841.                                decoder->active_form_id);
  1842.         if (form_data)
  1843.             rv = form_data->mocha_object;
  1844.  
  1845.         LO_UnlockLayout();
  1846.     }
  1847.     else
  1848.         rv = lm_GetDocumentFromLayerId(decoder, decoder->active_layer_id);
  1849.  
  1850.     return rv;
  1851. }
  1852.  
  1853. /*
  1854.  * Add an object to an array
  1855.  */
  1856. JSBool
  1857. lm_AddObjectToArray(JSContext * cx, JSObject * array_obj,
  1858.                     const char * name, jsint index, JSObject * obj)
  1859. {
  1860.     JSObjectArray *array;
  1861.  
  1862.     array = JS_GetPrivate(cx, array_obj);
  1863.     if (!array)
  1864.         return JS_TRUE;
  1865.  
  1866.     if (name) {
  1867.         if (!JS_DefineProperty(cx, array_obj, name, OBJECT_TO_JSVAL(obj),
  1868.                                NULL, NULL,
  1869.                                JSPROP_ENUMERATE | JSPROP_READONLY)) {
  1870.             return JS_FALSE;
  1871.         }
  1872.     }
  1873.  
  1874.     if (!JS_DefineElement(cx, array_obj, (jsint) index,
  1875.                           OBJECT_TO_JSVAL(obj),
  1876.                           NULL, NULL,
  1877.                           JSPROP_ENUMERATE | JSPROP_READONLY)) {
  1878.         return JS_FALSE;
  1879.     }
  1880.  
  1881.     if (index >= array->length)
  1882.         array->length = index + 1;
  1883.  
  1884.     return JS_TRUE;
  1885.  
  1886. }
  1887.  
  1888. void
  1889. lm_SetVersion(MochaDecoder *decoder, JSVersion version) {
  1890.     if (version == JSVERSION_UNKNOWN) {
  1891.         version = (decoder->firstVersion == JSVERSION_UNKNOWN)
  1892.             ? JSVERSION_DEFAULT
  1893.             : decoder->firstVersion;
  1894.     }
  1895.     if (decoder->firstVersion == JSVERSION_UNKNOWN) {
  1896.         decoder->firstVersion = version;
  1897.     }
  1898.     JS_SetVersion(decoder->js_context, version);
  1899. }
  1900.  
  1901. /*
  1902.  * Convert a locally encoded string into a 16-bit unicode string to pass
  1903.  *   to the JS runtime.  Allow cx to be NULL
  1904.  */
  1905. char *
  1906. lm_StrToLocalEncoding(MWContext * context, JSString * str)
  1907. {
  1908.     INTL_Encoding_ID charset;
  1909.     INTL_Unicode * src = JS_GetStringChars(str);
  1910.     uint32 srclen = JS_GetStringLength(str);
  1911.     uint32 destlen;
  1912.     char * dest;
  1913.  
  1914. #ifdef UNICODE
  1915.     if (!str)
  1916.     return NULL;
  1917. /*    XP_ASSERT(CS_DEFAULT != INTL_GetCSIMetaDocCSID(LO_GetDocumentCharacterSetInfo(context))); */
  1918.     
  1919.     charset = INTL_GetCSIWinCSID(LO_GetDocumentCharacterSetInfo(context));
  1920.     destlen = INTL_UnicodeToStrLen(charset, src, srclen);
  1921.     dest = XP_ALLOC(destlen);
  1922.     if (!dest) {
  1923.     JS_ReportOutOfMemory(context->mocha_context);
  1924.     return NULL;
  1925.     }
  1926.  
  1927.     INTL_UnicodeToStr(charset, src, srclen, (unsigned char *) dest, destlen);
  1928.     return dest;
  1929. #else
  1930.     return strdup(JS_GetStringBytes(str);
  1931. #endif
  1932.  
  1933. }
  1934.  
  1935. JSString *
  1936. lm_LocalEncodingToStr(MWContext * context, char * bytes)
  1937. {
  1938.     uint32 srclen, destlen;
  1939.     uint16 charset;
  1940.     INTL_Unicode * unicode = NULL;
  1941.  
  1942. #ifdef UNICODE
  1943.     /* return NULL or empty string? */
  1944.     if (!bytes)
  1945.     return JS_NewStringCopyZ(context->mocha_context, NULL); 
  1946.  
  1947.     srclen = XP_STRLEN(bytes);
  1948.     charset = INTL_GetCSIWinCSID(LO_GetDocumentCharacterSetInfo(context));
  1949.  
  1950.     /* find out how many unicode characters we'll end up with */
  1951.     destlen = INTL_StrToUnicodeLen(charset, (unsigned char *) bytes);
  1952.     unicode = XP_ALLOC(sizeof(INTL_Unicode) * destlen);
  1953.     if (!unicode)
  1954.     return NULL;
  1955.  
  1956.     /* do the conversion */
  1957.     destlen = INTL_StrToUnicode(charset, (unsigned char *) bytes, 
  1958.                     unicode, destlen);
  1959.     return JS_NewUCString(context->mocha_context, (jschar *) unicode, destlen);
  1960. #else
  1961.     return JS_NewStringCopyZ(context->mocha_context, bytes);
  1962. #endif
  1963.  
  1964. }
  1965.