home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / lib / libmocha / lm_doc.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  53.9 KB  |  1,784 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 reflection of the current Navigator Document.
  20.  *
  21.  * Brendan Eich, 9/8/95
  22.  */
  23. #include "lm.h"
  24. #include "prtypes.h"
  25. #include "plhash.h"
  26. #include "prmem.h"
  27. #include "prtime.h"
  28. #include "xp.h"
  29. #include "lo_ele.h"
  30. #include "shist.h"
  31. #include "structs.h"            /* for MWContext */
  32. #include "layout.h"             /* included via -I../layout */
  33. #include "mkaccess.h"           /* from ../libnet */
  34. #include "mkcache.h"            /* from ../libnet */
  35. #include "pa_parse.h"           /* included via -I../libparse */
  36. #include "pa_tags.h"            /* included via -I../libparse */
  37. #include "cert.h"               /* for CERT_DupCertificate */
  38. #include "libstyle.h"
  39. #include "prthread.h"
  40. #include "np.h"
  41. #ifdef JAVA
  42. #include "jsjava.h"
  43. #endif
  44.  
  45. enum doc_slot {
  46.     DOC_LENGTH          = -1,
  47.     DOC_ELEMENTS        = -2,
  48.     DOC_FORMS           = -3,
  49.     DOC_LINKS           = -4,
  50.     DOC_ANCHORS         = -5,
  51.     DOC_APPLETS         = -6,
  52.     DOC_EMBEDS          = -7,
  53.     DOC_TITLE           = -8,
  54.     DOC_URL             = -9,
  55.     DOC_REFERRER        = -10,
  56.     DOC_LAST_MODIFIED   = -11,
  57.     DOC_COOKIE          = -12,
  58.     DOC_DOMAIN          = -13,
  59.     /* slots below this line are not secured */
  60.     DOC_IMAGES          = -14,
  61.     DOC_LAYERS          = -15,
  62.     DOC_LOADED_DATE     = -16,
  63.     DOC_BG_COLOR        = -17,
  64.     DOC_FG_COLOR        = -18,
  65.     DOC_LINK_COLOR      = -19,
  66.     DOC_VLINK_COLOR     = -20,
  67.     DOC_ALINK_COLOR     = -21,
  68.     DOC_WIDTH           = -22,
  69.     DOC_HEIGHT          = -23
  70. };
  71.  
  72. #define IS_SECURE_DOC_SLOT(s) (DOC_DOMAIN <= (s) && (s) <= DOC_LENGTH) 
  73.  
  74. static JSPropertySpec doc_props[] = {
  75.     {lm_length_str,  DOC_LENGTH,        JSPROP_READONLY},
  76.     {"elements",     DOC_ELEMENTS,      JSPROP_READONLY},
  77.     {lm_forms_str,   DOC_FORMS,         JSPROP_ENUMERATE|JSPROP_READONLY},
  78.     {lm_links_str,   DOC_LINKS,         JSPROP_ENUMERATE|JSPROP_READONLY},
  79.     {lm_anchors_str, DOC_ANCHORS,       JSPROP_ENUMERATE|JSPROP_READONLY},
  80.     {lm_applets_str, DOC_APPLETS,       JSPROP_ENUMERATE|JSPROP_READONLY},
  81.     {lm_embeds_str,  DOC_EMBEDS,        JSPROP_ENUMERATE|JSPROP_READONLY},
  82.     {lm_plugins_str, DOC_EMBEDS,        JSPROP_READONLY},
  83.     {lm_images_str,  DOC_IMAGES,        JSPROP_ENUMERATE|JSPROP_READONLY},
  84.     {lm_layers_str,  DOC_LAYERS,        JSPROP_ENUMERATE|JSPROP_READONLY},
  85.     {"title",        DOC_TITLE,         JSPROP_ENUMERATE|JSPROP_READONLY},
  86.     {"URL",          DOC_URL,           JSPROP_ENUMERATE|JSPROP_READONLY},
  87.     {"referrer",     DOC_REFERRER,      JSPROP_ENUMERATE|JSPROP_READONLY},
  88.     {"lastModified", DOC_LAST_MODIFIED, JSPROP_ENUMERATE|JSPROP_READONLY},
  89.     {"loadedDate",   DOC_LOADED_DATE,   JSPROP_READONLY},
  90.     {"cookie",       DOC_COOKIE,        JSPROP_ENUMERATE},
  91.     {"domain",       DOC_DOMAIN,        JSPROP_ENUMERATE},
  92.     {"bgColor",      DOC_BG_COLOR,      JSPROP_ENUMERATE},
  93.     {"fgColor",      DOC_FG_COLOR,      JSPROP_ENUMERATE},
  94.     {"linkColor",    DOC_LINK_COLOR,    JSPROP_ENUMERATE},
  95.     {"vlinkColor",   DOC_VLINK_COLOR,   JSPROP_ENUMERATE},
  96.     {"alinkColor",   DOC_ALINK_COLOR,   JSPROP_ENUMERATE},
  97.     {"width",        DOC_WIDTH,         JSPROP_ENUMERATE},
  98.     {"height",       DOC_HEIGHT,        JSPROP_ENUMERATE},
  99.     {0}
  100. };
  101.  
  102. #define LO_COLOR_TYPE(slot)                             \
  103.     (((slot) == DOC_BG_COLOR) ? LO_COLOR_BG             \
  104.      : ((slot) == DOC_FG_COLOR) ? LO_COLOR_FG           \
  105.      : ((slot) == DOC_LINK_COLOR) ? LO_COLOR_LINK       \
  106.      : ((slot) == DOC_VLINK_COLOR) ? LO_COLOR_VLINK     \
  107.      : ((slot) == DOC_ALINK_COLOR) ? LO_COLOR_ALINK     \
  108.      : -1)
  109.  
  110.  
  111. extern PRThread *mozilla_thread;
  112. extern JSClass lm_document_class;
  113. extern JSClass lm_form_class;
  114. extern JSClass *lm_java_clasp;
  115.  
  116. JSContext *lm_writing_context;
  117. static int32 writing_context_counter;
  118.  
  119. PR_STATIC_CALLBACK(JSBool)
  120. doc_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
  121. {
  122.     JSDocument *doc;
  123.     MochaDecoder *decoder;
  124.     MWContext *context;
  125.     History_entry *he = NULL;
  126.     JSString *str = NULL;
  127.     int64 prsec, scale, prusec;
  128.     PRExplodedTime prtime;
  129.     char *cookie, buf[100];
  130.     const char *domain, *origin;
  131.     uint32 type;
  132.     LO_Color rgb, *bg_color;
  133.     jsint slot;
  134.     CL_Layer *layer;
  135.     int32 active_layer_id;
  136.  
  137.     doc = JS_GetInstancePrivate(cx, obj, &lm_document_class, NULL);
  138.     if (!doc)
  139.         return JS_TRUE;
  140.     decoder = doc->decoder;
  141.  
  142.     slot = JSVAL_IS_INT(id) ? JSVAL_TO_INT(id) : 0;
  143.  
  144.     if (IS_SECURE_DOC_SLOT(slot) ||
  145.         (slot == 0 &&
  146.          JSVAL_IS_OBJECT(*vp) && 
  147.          JSVAL_TO_OBJECT(*vp) && 
  148.          (JS_InstanceOf(cx, JSVAL_TO_OBJECT(*vp), &lm_form_class, NULL) ||
  149.           (lm_java_clasp &&
  150.        JS_InstanceOf(cx, JSVAL_TO_OBJECT(*vp), lm_java_clasp, NULL)))))
  151.     {
  152.         if (!lm_CheckPermissions(cx, obj, JSTARGET_UNIVERSAL_BROWSER_READ))
  153.             return JS_FALSE;
  154.     }
  155.  
  156.     if (!JSVAL_IS_INT(id))
  157.         return JS_TRUE;
  158.  
  159.     context = decoder->window_context;
  160.     if (!context)
  161.         return JS_TRUE;
  162.  
  163.     LO_LockLayout();
  164.     if(decoder->doc_id != XP_DOCID(context)) {
  165.         LO_UnlockLayout();
  166. #ifdef DEBUG_chouck
  167.         XP_TRACE(("DOCID: in doc_getProperty"));
  168. #endif
  169.         return JS_FALSE;
  170.     }
  171.  
  172.     switch (slot) {
  173.       case DOC_FORMS:
  174.         *vp = OBJECT_TO_JSVAL(lm_GetFormArray(decoder, obj));
  175.         active_layer_id = LM_GetActiveLayer(context);
  176.         LM_SetActiveLayer(context, doc->layer_id);
  177.         (void) LO_EnumerateForms(context, doc->layer_id);
  178.         LM_SetActiveLayer(context, active_layer_id);
  179.         LO_UnlockLayout();
  180.         return JS_TRUE;
  181.  
  182.       case DOC_LINKS:
  183.         *vp = OBJECT_TO_JSVAL(lm_GetLinkArray(decoder, obj));
  184.         active_layer_id = LM_GetActiveLayer(context);
  185.         LM_SetActiveLayer(context, doc->layer_id);
  186.         (void) LO_EnumerateLinks(context, doc->layer_id);
  187.         LM_SetActiveLayer(context, active_layer_id);
  188.         LO_UnlockLayout();
  189.         return JS_TRUE;
  190.  
  191.       case DOC_ANCHORS:
  192.         *vp = OBJECT_TO_JSVAL(lm_GetNameArray(decoder, obj));
  193.         active_layer_id = LM_GetActiveLayer(context);
  194.         LM_SetActiveLayer(context, doc->layer_id);
  195.         (void) LO_EnumerateNamedAnchors(context,doc->layer_id);
  196.         LM_SetActiveLayer(context, active_layer_id);
  197.         LO_UnlockLayout();
  198.         return JS_TRUE;
  199.  
  200.       case DOC_APPLETS:
  201. #ifdef JAVA
  202.         if (LM_MOJA_OK != ET_InitMoja(context)) {
  203.             LO_UnlockLayout();
  204.             return JS_FALSE;
  205.         }
  206.         
  207.         *vp = OBJECT_TO_JSVAL(lm_GetAppletArray(decoder, obj));
  208.         active_layer_id = LM_GetActiveLayer(context);
  209.         LM_SetActiveLayer(context, doc->layer_id);
  210.         (void) LO_EnumerateApplets(context,doc->layer_id);
  211.         LM_SetActiveLayer(context, active_layer_id);
  212.         LO_UnlockLayout();
  213.         return JS_TRUE;
  214. #else
  215.         LO_UnlockLayout();
  216.         break;
  217. #endif
  218.  
  219.       case DOC_EMBEDS:
  220. #ifdef JAVA
  221.         if (LM_MOJA_OK != ET_InitMoja(context)) {
  222.             LO_UnlockLayout();
  223.             return JS_FALSE;
  224.         }
  225.  
  226.         *vp = OBJECT_TO_JSVAL(lm_GetEmbedArray(decoder, obj));
  227.         active_layer_id = LM_GetActiveLayer(context);
  228.         LM_SetActiveLayer(context, doc->layer_id);
  229.         (void) LO_EnumerateEmbeds(context,doc->layer_id);
  230.         LM_SetActiveLayer(context, active_layer_id);
  231.         LO_UnlockLayout();
  232.         return JS_TRUE;
  233. #else
  234.         LO_UnlockLayout();
  235.         break;
  236. #endif
  237.  
  238.       case DOC_IMAGES:
  239.         *vp = OBJECT_TO_JSVAL(lm_GetImageArray(decoder, obj));
  240.         active_layer_id = LM_GetActiveLayer(context);
  241.         LM_SetActiveLayer(context, doc->layer_id);
  242.         (void) LO_EnumerateImages(context,doc->layer_id);
  243.         LM_SetActiveLayer(context, active_layer_id);
  244.         LO_UnlockLayout();
  245.         return JS_TRUE;
  246.  
  247.       case DOC_LAYERS:
  248.         *vp = OBJECT_TO_JSVAL(lm_GetDocumentLayerArray(decoder, obj));
  249.         LO_UnlockLayout();
  250.         return JS_TRUE;
  251.  
  252.         /* XXX BUGBUG Need a story for some of these for a layer's document */
  253.       case DOC_TITLE:
  254.         he = SHIST_GetCurrent(&context->hist);
  255.         str = lm_LocalEncodingToStr(context, he ? he->title : "");
  256.         LO_UnlockLayout();
  257.         break;
  258.  
  259.       case DOC_URL:
  260.         he = SHIST_GetCurrent(&context->hist);
  261.         str = JS_NewStringCopyZ(cx, he ? he->address : "");
  262.         LO_UnlockLayout();
  263.         break;
  264.  
  265.       case DOC_REFERRER:
  266.         he = SHIST_GetCurrent(&context->hist);
  267.         str = JS_NewStringCopyZ(cx, he ? he->referer : "");
  268.         LO_UnlockLayout();
  269.         break;
  270.  
  271.       case DOC_LAST_MODIFIED:
  272.         he = SHIST_GetCurrent(&context->hist);
  273.         if (he) {
  274.             LL_I2L(prsec, he->last_modified);
  275.             LL_I2L(scale, 1000000);
  276.             LL_MUL(prusec, prsec, scale);
  277.             PR_ExplodeTime(prusec, PR_LocalTimeParameters, &prtime);
  278.             PR_FormatTime(buf, sizeof buf, "%c", &prtime);
  279.         } else {
  280.             buf[0] = '\0';
  281.         }
  282.         str = JS_NewStringCopyZ(cx, buf);
  283.         LO_UnlockLayout();
  284.         break;
  285.  
  286.       case DOC_LOADED_DATE:
  287.         LO_UnlockLayout();
  288.         /* XXX todo */
  289.         str = JSVAL_TO_STRING(JS_GetEmptyStringValue(cx));
  290.         break;
  291.  
  292.       case DOC_COOKIE:
  293.         /* XXX overloaded return - can't distinguish "none" from "error" */
  294.         he = SHIST_GetCurrent(&context->hist);
  295.     cookie = NET_GetCookie(context, he ? he->address : "");
  296.         str = JS_NewStringCopyZ(cx, cookie);
  297.     XP_FREEIF(cookie);
  298.         LO_UnlockLayout();
  299.         break;
  300.  
  301.       case DOC_DOMAIN:
  302.         LO_UnlockLayout();
  303.         origin = lm_GetObjectOriginURL(cx, obj);
  304.         if (!origin)
  305.             return JS_FALSE;
  306.         domain = NET_ParseURL(origin, GET_HOST_PART);
  307.         if (!domain) {
  308.             JS_ReportOutOfMemory(cx);
  309.             return JS_FALSE;
  310.         }
  311.         str = JS_NewStringCopyZ(cx, domain);
  312.         XP_FREE((char *)domain);
  313.         break;
  314.  
  315.       case DOC_WIDTH:
  316.         layer = LO_GetLayerFromId(context, doc->layer_id);
  317.         *vp = INT_TO_JSVAL(LO_GetLayerScrollWidth(layer));
  318.         LO_UnlockLayout();
  319.         return JS_TRUE;
  320.           
  321.       case DOC_HEIGHT:
  322.         layer = LO_GetLayerFromId(context, doc->layer_id);
  323.         *vp = INT_TO_JSVAL(LO_GetLayerScrollHeight(layer));
  324.         LO_UnlockLayout();
  325.         return JS_TRUE;
  326.  
  327.       case DOC_BG_COLOR:
  328.         layer = LO_GetLayerFromId(context, doc->layer_id);
  329.         bg_color = LO_GetLayerBgColor(layer);
  330.         LO_UnlockLayout();
  331.         if (bg_color) {
  332.             XP_SPRINTF(buf, "#%02x%02x%02x", bg_color->red, bg_color->green, 
  333.                        bg_color->blue);
  334.             str = JS_NewStringCopyZ(cx, buf);
  335.         } 
  336.         else {
  337.             *vp = JSVAL_NULL;
  338.             return JS_TRUE;
  339.         }
  340.         break;
  341.          
  342.       default:
  343.         type = LO_COLOR_TYPE(slot);
  344.         if (type >= LO_NCOLORS) {
  345.             LO_UnlockLayout();
  346.             /* Don't mess with a user-defined or method property. */
  347.             return JS_TRUE;
  348.         }
  349.         /* Note: background color handled above */
  350.         LO_GetDocumentColor(context, type, &rgb);
  351.         XP_SPRINTF(buf, "#%02x%02x%02x", rgb.red, rgb.green, rgb.blue);
  352.         str = JS_NewStringCopyZ(cx, buf);
  353.         LO_UnlockLayout();
  354.         break;
  355.     }
  356.  
  357.     /* Common tail code for string-type properties. */
  358.     if (!str)
  359.         return JS_FALSE;
  360.     *vp = STRING_TO_JSVAL(str);
  361.     return JS_TRUE;
  362. }
  363.  
  364.  
  365. PR_STATIC_CALLBACK(JSBool)
  366. doc_setProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
  367. {
  368.     JSObject *layer_obj;
  369.     JSDocument *doc;
  370.     MochaDecoder *decoder;
  371.     MWContext *context;
  372.     char *protocol, *pathname, *new_origin_url, *str;
  373.     const char *domain, *new_domain, *domain_suffix, *prop_name, *origin;
  374.     size_t domain_len, new_domain_len;
  375.     JSBool ok;
  376.     uint32 type;
  377.     LO_Color *rgb;
  378.     jsint slot;
  379.     int32 val;
  380.     CL_Layer *layer;
  381.     History_entry *he = NULL;
  382.  
  383.     doc = JS_GetInstancePrivate(cx, obj, &lm_document_class, NULL);
  384.     if (!doc)
  385.         return JS_TRUE;
  386.     decoder = doc->decoder;
  387.  
  388.     if (!lm_CheckPermissions(cx, obj, JSTARGET_UNIVERSAL_BROWSER_WRITE))
  389.         return JS_FALSE;
  390.  
  391.     if (!JSVAL_IS_INT(id)) {
  392.         /*
  393.          * Due to the wonderful world of threads we need to know ahead of
  394.          * time if someone is setting an onMouseMove event handler here or
  395.          * in document so that we don't lose messages.
  396.          */
  397.         if (JS_TypeOfValue(cx, *vp) == JSTYPE_FUNCTION) {
  398.             if (JSVAL_IS_STRING(id)) {
  399.                 prop_name = JS_GetStringBytes(JSVAL_TO_STRING(id));
  400.                 /* XXX use lm_onMouseMove_str etc.*/
  401.                 if (XP_STRCMP(prop_name, "onmousemove") == 0 ||
  402.                     XP_STRCMP(prop_name, "onMouseMove") == 0) {
  403.                     decoder->window_context->js_drag_enabled = TRUE;
  404.                 }
  405.             }
  406.         }
  407.         return JS_TRUE;
  408.     }
  409.  
  410.     slot = JSVAL_TO_INT(id);
  411.  
  412.     context = decoder->window_context;
  413.     if (!context)
  414.         return JS_TRUE;
  415.  
  416.     LO_LockLayout();
  417.     if(decoder->doc_id != XP_DOCID(context)) {
  418.         LO_UnlockLayout();
  419. #ifdef DEBUG_chouck
  420.         XP_TRACE(("DOCID: in doc_setProperty"));
  421. #endif
  422.         return JS_FALSE;
  423.     }
  424.  
  425.     switch (slot) {
  426.       case DOC_COOKIE:
  427.         if (!JSVAL_IS_STRING(*vp) &&
  428.             !JS_ConvertValue(cx, *vp, JSTYPE_STRING, vp)) {
  429.         LO_UnlockLayout();
  430.             return JS_FALSE;
  431.         }
  432.  
  433.     he = SHIST_GetCurrent(&context->hist);
  434.     str = JS_GetStringBytes(JSVAL_TO_STRING(*vp));
  435.  
  436.         /* will make a copy that netlib can munge */
  437.     if (str)
  438.         str = strdup(str);
  439.  
  440.         NET_SetCookieString(context, he ? he->address : "", str);
  441.         LO_UnlockLayout();
  442.         break;
  443.  
  444.       case DOC_DOMAIN:
  445.         LO_UnlockLayout();
  446.         origin = lm_GetObjectOriginURL(cx, obj);
  447.         if (!origin || XP_STRCMP(origin, lm_unknown_origin_str) == 0)
  448.             return JS_FALSE;
  449.         domain = NET_ParseURL(origin, GET_HOST_PART);
  450.         if (!domain) {
  451.             JS_ReportOutOfMemory(cx);
  452.             return JS_FALSE;
  453.         }
  454.         if (!JSVAL_IS_STRING(*vp) &&
  455.             !JS_ConvertValue(cx, *vp, JSTYPE_STRING, vp)) {
  456.             XP_FREE((char *)domain);
  457.             return JS_FALSE;
  458.         }
  459.         new_domain = JS_GetStringBytes(JSVAL_TO_STRING(*vp));
  460.         new_domain_len = JS_GetStringLength(JSVAL_TO_STRING(*vp));
  461.         domain_len = XP_STRLEN(domain);
  462.         domain_suffix = domain + domain_len - new_domain_len;
  463.         ok = (JSBool)(!XP_STRCASECMP(domain, new_domain) ||
  464.              (domain_len > new_domain_len &&
  465.               !XP_STRCASECMP(domain_suffix, new_domain) &&
  466.               (domain_suffix[-1] == '.' || domain_suffix[-1] == '/')));
  467.         if (!ok) {
  468.             JS_ReportError(cx, "illegal document.domain value %s",
  469.                               new_domain);
  470.         } else {
  471.             protocol = NET_ParseURL(origin, GET_PROTOCOL_PART);
  472.             pathname = NET_ParseURL(origin, GET_PATH_PART | GET_HASH_PART |
  473.                                             GET_SEARCH_PART);
  474.             new_origin_url = PR_smprintf("%s//%s%s",
  475.                                          protocol, new_domain, pathname);
  476.             ok = (JSBool)(protocol && pathname && new_origin_url);
  477.             if (!ok) {
  478.                 JS_ReportOutOfMemory(cx);
  479.             } else {
  480.                 JSPrincipals *principals;
  481.                 principals = lm_GetInnermostPrincipals(cx, obj, NULL);
  482.                 if (principals) {
  483.                     ok = lm_SetDocumentDomain(cx, principals, new_origin_url);
  484.                 } 
  485.             }
  486.             PR_FREEIF(protocol);
  487.             PR_FREEIF(pathname);
  488.             PR_FREEIF(new_origin_url);
  489.         }
  490.         XP_FREE((char *)domain);
  491.         return ok;
  492.  
  493.       case DOC_BG_COLOR:
  494.         if (doc->layer_id == LO_DOCUMENT_LAYER_ID) {
  495.             layer = LO_GetLayerFromId(context, LO_DOCUMENT_LAYER_ID);
  496.             LO_UnlockLayout();
  497.             if (!lm_jsval_to_rgb(cx, vp, &rgb))
  498.                 return JS_FALSE;
  499.             ET_TweakLayer(decoder->window_context, layer, 0, 0,
  500.                           rgb, 0, CL_SetBgColor, NULL, decoder->doc_id);
  501.         } else {
  502.             layer_obj = LO_GetLayerMochaObjectFromId(context, doc->layer_id);
  503.             LO_UnlockLayout();
  504.             if (layer_obj)
  505.                 layer_setBgColorProperty(cx, layer_obj, vp);
  506.         }
  507.         break;
  508.  
  509.       case DOC_FG_COLOR:
  510.       case DOC_LINK_COLOR:
  511.       case DOC_VLINK_COLOR:
  512.       case DOC_ALINK_COLOR:
  513.         type = LO_COLOR_TYPE(slot);
  514.         if (type >= LO_NCOLORS) {
  515.             LO_UnlockLayout();
  516.             break;
  517.         }
  518.  
  519.         if (!lm_jsval_to_rgb(cx, vp, &rgb) || !rgb) {
  520.             LO_UnlockLayout();
  521.             return JS_FALSE;
  522.         }
  523.         
  524.         LO_SetDocumentColor(context, type, rgb);
  525.         LO_UnlockLayout();
  526.         if (rgb)
  527.             XP_FREE(rgb);
  528.         break;
  529.  
  530.         /* 
  531.          * XXX BUGBUG These don't do the right thing for a window's document.
  532.          * Does any of this make sense for a layer's document?
  533.          */
  534.       case DOC_WIDTH:
  535.         /* Front-ends can't cope with a document dimension less than one. */
  536.         if (!JS_ValueToInt32(cx, *vp, &val)) {
  537.             LO_UnlockLayout();
  538.             return JS_FALSE;
  539.         }
  540.         layer = LO_GetLayerFromId(context, doc->layer_id);
  541.         LO_SetLayerScrollWidth(layer, val <= 1 ? 1 : val);
  542.         LO_UnlockLayout();
  543.         break;
  544.           
  545.       case DOC_HEIGHT:
  546.         /* Front-ends can't cope with a document dimension less than one. */
  547.         if (!JS_ValueToInt32(cx, *vp, &val)) {
  548.             LO_UnlockLayout();
  549.             return JS_FALSE;
  550.         }
  551.         layer = LO_GetLayerFromId(context, doc->layer_id);
  552.         LO_SetLayerScrollHeight(layer, val <= 1 ? 1 : val);
  553.         LO_UnlockLayout();
  554.         break;
  555.  
  556.       default:
  557.         LO_UnlockLayout();
  558.         break;
  559.     }
  560.  
  561.     return doc_getProperty(cx, obj, id, vp);
  562. }
  563.  
  564. #ifdef JAVA
  565. static void 
  566. lm_reflect_stuff_eagerly(MWContext * context, int32 layer_id)
  567. {
  568.  
  569.     lo_TopState *top_state;
  570.     int count, index;
  571.     LO_JavaAppStruct *applet;
  572.     LO_EmbedStruct *embed;
  573.     lo_DocLists *doc_lists;
  574.  
  575.     LO_LockLayout();
  576.  
  577.     top_state = lo_GetMochaTopState(context);
  578.     if (top_state == NULL) {
  579.         LO_UnlockLayout();
  580.         return;
  581.     }
  582.     doc_lists = lo_GetDocListsById(top_state->doc_state, layer_id);
  583.  
  584.     count = 0;
  585.     applet = doc_lists->applet_list;
  586.     while (applet) {
  587.         applet = applet->nextApplet;
  588.         count++;
  589.     }
  590.  
  591.     /* reflect all applets in reverse order */
  592.     applet = doc_lists->applet_list;
  593.     for (index = count-1; index >= 0; index--) {
  594.         if (applet->mocha_object == NULL) {
  595.             LM_ReflectApplet(context, applet, NULL, layer_id, index);
  596.         }
  597.         applet = applet->nextApplet;
  598.     }
  599.  
  600.     count = 0;
  601.     embed = doc_lists->embed_list;
  602.     while (embed) {
  603.         embed = embed->nextEmbed;
  604.         count++;
  605.     }
  606.  
  607.     /* reflect all embeds in reverse order */
  608.     embed = doc_lists->embed_list;
  609.     for (index = count-1; index >= 0; index--) {
  610.         if (embed->mocha_object == NULL) {
  611.             LM_ReflectEmbed(context, embed, NULL, layer_id, index);
  612.         }
  613.         embed = embed->nextEmbed;
  614.     }
  615.  
  616.     LO_UnlockLayout();
  617. }
  618. #endif /* JAVA */
  619.  
  620. PR_STATIC_CALLBACK(JSBool)
  621. doc_list_properties(JSContext *cx, JSObject *obj)
  622. {
  623. #ifdef JAVA
  624.  
  625.     /* reflect applets eagerly, anything else? */
  626.     JSDocument *doc;
  627.     MWContext *context;
  628.     JSBool bDoInitMoja = JS_FALSE;
  629.     lo_TopState *top_state;
  630.     lo_DocLists *doc_lists;
  631.  
  632.     doc = JS_GetPrivate(cx, obj);
  633.     if (!doc)
  634.         return JS_TRUE;
  635.     context = doc->decoder->window_context;
  636.     if (!context)
  637.         return JS_TRUE;
  638.  
  639.     LO_LockLayout();
  640.  
  641.     /* if no embeds or applets don't eagerly start java */
  642.     top_state = lo_GetMochaTopState(context);
  643.     if (top_state) {
  644.         doc_lists = lo_GetDocListsById(top_state->doc_state, doc->layer_id);
  645.  
  646.         if(doc_lists){
  647.             if (doc_lists->applet_list)
  648.                 bDoInitMoja = JS_TRUE;
  649.             else if (doc_lists->embed_list){
  650.                 /* determine if any of these embeds actually require java, are liveconnected. */
  651.                 LO_EmbedStruct *embed;
  652.                 for (embed = doc_lists->embed_list; embed != NULL; embed=embed->nextEmbed){
  653.                     if (NPL_IsLiveConnected(embed)){
  654.                         bDoInitMoja = JS_TRUE;
  655.                         break; /* it only takes one  */
  656.                     }
  657.                 }
  658.             }
  659.         }
  660.  
  661.     }
  662.     LO_UnlockLayout();
  663.  
  664.     if(bDoInitMoja) {
  665.         if (LM_MOJA_OK != ET_InitMoja(context))
  666.             return JS_FALSE;
  667.         if (JSJ_IsEnabled())
  668.             lm_reflect_stuff_eagerly(context, doc->layer_id);
  669.     }
  670.  
  671. #endif
  672.     return JS_TRUE;
  673. }
  674.  
  675. PR_STATIC_CALLBACK(JSBool)
  676. doc_resolve_name(JSContext *cx, JSObject *obj, jsval id)
  677. {
  678.     JSDocument *doc;
  679.     const char * name;
  680.     JSObject *layer_obj;
  681.  
  682.     if (!JSVAL_IS_STRING(id))
  683.         return JS_TRUE;
  684.  
  685.     name = JS_GetStringBytes(JSVAL_TO_STRING(id));
  686.  
  687.     doc = JS_GetPrivate(cx, obj);
  688.     if (!doc)
  689.         return JS_TRUE;
  690.  
  691.     layer_obj = lm_GetNamedLayer(doc->decoder, doc->layer_id, name);
  692.     if (layer_obj)
  693.         return JS_DefineProperty(cx, obj, name,
  694.                                  OBJECT_TO_JSVAL(layer_obj),
  695.                                  NULL, NULL,
  696.                                  JSPROP_ENUMERATE | JSPROP_READONLY);
  697.  
  698.     if (!JSS_ResolveDocName(cx, doc->decoder->window_context, obj, id))
  699.         return JS_FALSE;
  700.  
  701.     return doc_list_properties(cx, obj);
  702. }
  703.  
  704. PR_STATIC_CALLBACK(void)
  705. doc_finalize(JSContext *cx, JSObject *obj)
  706. {
  707.     JSDocument *doc;
  708.  
  709.     doc = JS_GetPrivate(cx, obj);
  710.     if (!doc)
  711.         return;
  712.     DROP_BACK_COUNT(doc->decoder);
  713.     JS_RemoveRoot(cx, &doc->forms);
  714.     JS_RemoveRoot(cx, &doc->links);
  715.     JS_RemoveRoot(cx, &doc->anchors);
  716.     JS_RemoveRoot(cx, &doc->applets);
  717.     JS_RemoveRoot(cx, &doc->embeds);
  718.     JS_RemoveRoot(cx, &doc->images);
  719.     JS_RemoveRoot(cx, &doc->layers);
  720.     JS_free(cx, doc);
  721. }
  722.  
  723. JSClass lm_document_class = {
  724.     "Document", JSCLASS_HAS_PRIVATE,
  725.     JS_PropertyStub, JS_PropertyStub, doc_getProperty, doc_setProperty,
  726.     doc_list_properties, doc_resolve_name, JS_ConvertStub, doc_finalize
  727. };
  728.  
  729. PR_STATIC_CALLBACK(JSBool)
  730. Document(JSContext *cx, JSObject *obj,
  731.          uint argc, jsval *argv, jsval *rval)
  732. {
  733.     return JS_TRUE;
  734. }
  735.  
  736. PR_STATIC_CALLBACK(JSBool)
  737. doc_toString(JSContext *cx, JSObject *obj,
  738.               uint argc, jsval *argv, jsval *rval)
  739. {
  740.     /* XXX make string of whole doc for trusted scripts */
  741.     *rval = JS_GetEmptyStringValue(cx); 
  742.     return JS_TRUE;
  743. }
  744.  
  745. char *
  746. LM_GetBaseHrefTag(JSContext *cx, JSPrincipals *principals)
  747. {
  748.     char *new_origin_url;
  749.     const char *origin_url;
  750.     const char *cp, *qp, *last_slash;
  751.     char *tag;
  752.  
  753.     origin_url = principals ? principals->codebase : lm_unknown_origin_str;
  754.     if (origin_url == NULL)
  755.         return NULL;
  756.     new_origin_url = 0;
  757.     cp = origin_url;
  758.     if ((qp = XP_STRCHR(cp, '"')) != 0) {
  759.         do {
  760.             new_origin_url = PR_sprintf_append(new_origin_url, "%.*s%%%x",
  761.                                                 qp - cp, cp, *qp);
  762.             cp = qp + 1;
  763.         } while ((qp = XP_STRCHR(cp, '"')) != 0);
  764.         new_origin_url = PR_sprintf_append(new_origin_url, "%s", cp);
  765.         if (!new_origin_url) {
  766.             JS_ReportOutOfMemory(cx);
  767.             return NULL;
  768.         }
  769.         origin_url = new_origin_url;
  770.     }
  771.     last_slash = XP_STRRCHR(origin_url, '/');
  772.     if (last_slash) {
  773.         tag = PR_smprintf("<BASE HREF=\"%.*s/\">\n",
  774.                           last_slash - origin_url, origin_url);
  775.     } else {
  776.         tag = PR_smprintf("<BASE HREF=\"%s\">\n", origin_url);
  777.     }
  778.     PR_FREEIF(new_origin_url);
  779.     if (!tag)
  780.         JS_ReportOutOfMemory(cx);
  781.     return tag;
  782. }
  783.  
  784. static int
  785. doc_write_stream(JSContext *cx, MochaDecoder *decoder,
  786.                  NET_StreamClass *stream, char *str, size_t len)
  787. {    
  788.     ET_lo_DoDocWrite(cx, decoder->window_context, stream, str, len,
  789.                      decoder->doc_id);
  790.  
  791.     return JS_TRUE;
  792. }
  793.  
  794. static char *
  795. context_pathname(JSContext *cx, MWContext *context, int32 layer_id)
  796. {
  797.     MWContext *parent;
  798.     int count, index;
  799.     char *name = 0;
  800.  
  801.     while ((parent = context->grid_parent) != 0) {
  802.         if (context->name) {
  803.             name = PR_sprintf_append(name, "%s.", context->name);
  804.         } else {
  805.             /* XXX silly xp_cntxt.c puts newer contexts at the front! */
  806.             count = XP_ListCount(parent->grid_children);
  807.             index = XP_ListGetNumFromObject(parent->grid_children, context);
  808.             name = PR_sprintf_append(name, "%u.", count - index);
  809.         }
  810.         context = parent;
  811.     }
  812.     name = PR_sprintf_append(name, "%ld", (long)XP_DOCID(context));
  813.     if (layer_id != LO_DOCUMENT_LAYER_ID)
  814.         name = PR_sprintf_append(name, ".%ld", layer_id);
  815.     if (!name)
  816.         JS_ReportOutOfMemory(cx);
  817.     return name;
  818. }
  819.  
  820. /* Make a wysiwyg: URL containing the context and our origin. */
  821. char *
  822. lm_MakeWysiwygUrl(JSContext *cx, MochaDecoder *decoder, int32 layer_id,
  823.                   JSPrincipals *principals)
  824. {
  825.     const char *origin;
  826.     const char *pathname;
  827.     char *url_string;
  828.     char *slash;
  829.  
  830.     origin = principals ? principals->codebase : lm_unknown_origin_str;
  831.     if (origin == NULL)
  832.         return NULL;
  833.     pathname = context_pathname(cx, decoder->window_context, layer_id);
  834.     if (!pathname)
  835.         return NULL;
  836.     while ((slash = XP_STRCHR(pathname, '/')) != NULL) {
  837.         /* Escape '/' in pathname as "%2f" */
  838.         char *newPath;
  839.         *slash = '\0';
  840.         newPath = PR_smprintf("%s%%2f%s", pathname, slash+1);
  841.         XP_FREE((char *)pathname);
  842.         if (!newPath) {
  843.             JS_ReportOutOfMemory(cx);
  844.             return NULL;
  845.         }
  846.         pathname = newPath;
  847.     }
  848.     url_string = PR_smprintf("wysiwyg://%s/%s", pathname, origin);
  849.     XP_FREE((char *)pathname);
  850.     if (!url_string) {
  851.         JS_ReportOutOfMemory(cx);
  852.         return NULL;
  853.     }
  854.     return url_string;
  855. }
  856.  
  857. static NET_StreamClass *
  858. doc_cache_converter(JSContext *cx, MochaDecoder *decoder,
  859.                     URL_Struct *url_struct, char *wysiwyg_url,
  860.                     int32 layer_id)
  861. {
  862.     NET_StreamClass * rv;
  863.  
  864.     rv = ET_moz_DocCacheConverter(decoder->window_context, 
  865.                                   url_struct, wysiwyg_url,
  866.                                   layer_id);
  867.  
  868.     if (!rv)
  869.         JS_ReportOutOfMemory(cx);
  870.  
  871.     return rv;
  872.  
  873. }
  874.  
  875. NET_StreamClass *
  876. LM_WysiwygCacheConverter(MWContext *context, URL_Struct *url_struct,
  877.                          const char * wysiwyg_url, const char * base_href)
  878. {
  879.     NET_StreamClass *cache_stream;
  880.  
  881.     if (!wysiwyg_url) {
  882.         cache_stream = 0;
  883.     } else {
  884.         cache_stream = lm_DocCacheConverter(context, url_struct,
  885.                                             wysiwyg_url);
  886.         if (cache_stream) {
  887.             /* Wysiwyg files need a base tag that removes that URL prefix. */
  888.             if (base_href) {
  889.                 (void) cache_stream->put_block(cache_stream, 
  890.                                                base_href,
  891.                                                XP_STRLEN(base_href));
  892.             }
  893.         }
  894.     }
  895.     return cache_stream;
  896. }
  897.  
  898. static char nscp_open_tag[] = "<" PT_NSCP_OPEN ">";
  899.  
  900. static NET_StreamClass *
  901. doc_open_stream(JSContext *cx, MochaDecoder *decoder, JSObject *doc_obj,
  902.                 const char *mime_type, JSBool replace)
  903. {
  904.     JSDocument *doc;
  905.     MWContext *context;
  906.     char *wysiwyg_url, *tag;
  907.     JSPrincipals *principals;
  908.     URL_Struct *url_struct, *cached_url;
  909.     MochaDecoder *running;
  910.     History_entry *he;
  911.     NET_StreamClass *stream;
  912.     JSBool is_text_html;
  913.     FO_Present_Types present_type;
  914.  
  915.     context = decoder->window_context;
  916.     if (!context)
  917.         return NULL;
  918.  
  919.     doc = JS_GetPrivate(cx, doc_obj);
  920.     if (!doc)
  921.         return NULL;
  922.     
  923.     /* Don't allow a script to replace a message window's contents
  924.        with its own document.write'ed content, since that would allow
  925.        them to spoof mail headers. */
  926.     if ((doc->layer_id == LO_DOCUMENT_LAYER_ID) && IS_MESSAGE_WINDOW(context))
  927.         return NULL;
  928.  
  929.     /* We must be called after any loading URL has finished. */
  930.     XP_ASSERT(!decoder->url_struct);
  931.     principals = lm_GetPrincipalsFromStackFrame(cx);
  932.     wysiwyg_url = lm_MakeWysiwygUrl(cx, decoder, doc->layer_id, principals);
  933.     if (!wysiwyg_url)
  934.         return NULL;
  935.     url_struct = NET_CreateURLStruct(wysiwyg_url, NET_DONT_RELOAD);
  936.     if (!url_struct) {
  937.         XP_FREE(wysiwyg_url);
  938.         JS_ReportOutOfMemory(cx);
  939.         return NULL;
  940.     }
  941.  
  942.     /* Set content type so it can be cached. */
  943.     StrAllocCopy(url_struct->content_type, mime_type);
  944.     url_struct->preset_content_type = TRUE;
  945.     url_struct->must_cache = TRUE;
  946.  
  947.     /* Set these to null so we can goto bad from here onward. */
  948.     stream = 0;
  949.     cached_url = 0;
  950.  
  951.     /* If the writer is secure, pass its security info into the cache. */
  952.     running = JS_GetPrivate(cx, JS_GetGlobalObject(cx));
  953.     he = SHIST_GetCurrent(&running->window_context->hist);
  954.     if (he && he->security_on) {
  955.         /* Copy security stuff (checking for malloc failure) */
  956.         url_struct->security_on = he->security_on;
  957.         StrAllocCopy(url_struct->key_cipher, he->key_cipher);
  958.         if (he->key_cipher && !url_struct->key_cipher)
  959.             goto bad;
  960.         url_struct->key_size = he->key_size;
  961.         url_struct->key_secret_size = he->key_secret_size;
  962.  
  963.         /* Make a url struct just to lookup a cached certificate. */
  964.         cached_url = NET_CreateURLStruct(he->address, NET_DONT_RELOAD);
  965.         if (!cached_url)
  966.             goto bad;
  967.         (void) ET_net_FindURLInCache(cached_url, running->window_context);
  968.         if (cached_url->certificate) {
  969.             url_struct->certificate
  970.                 = CERT_DupCertificate(cached_url->certificate);
  971.             if (!url_struct->certificate)
  972.                 goto bad;
  973.         }
  974.         NET_FreeURLStruct(cached_url);
  975.         cached_url = 0;
  976.     }
  977.  
  978.     /* If we're opening a stream for the window's document */
  979.     if (doc->layer_id == LO_DOCUMENT_LAYER_ID) {
  980.         /* Free any old doc before stream building, which may discard too. */
  981.         ET_lo_DiscardDocument(context);
  982.         if (replace) {
  983.             /* If replacing, flag current entry and url_struct specially. */
  984.             lm_ReplaceURL(context, url_struct);
  985.         }
  986.         present_type = FO_PRESENT;
  987.     }
  988.     /* Otherwise, we're dealing with a layer's document */
  989.     else {
  990.     const char *referer = lm_GetSubjectOriginURL(cx);
  991.  
  992.     if (!referer ||
  993.         !ET_lo_PrepareLayerForWriting(context, doc->layer_id, referer)) {
  994.         goto bad;
  995.     }
  996.     lm_NewLayerDocument(decoder, doc->layer_id);
  997.     LM_SetActiveLayer(context, doc->layer_id);
  998.         present_type = FO_PRESENT_INLINE;
  999.     }
  1000.  
  1001.     /* We must be called after any open stream has been closed. */
  1002.     XP_ASSERT(!decoder->stream);
  1003.     stream = ET_net_StreamBuilder(present_type, url_struct, context);
  1004.     if (!stream) {
  1005.         JS_ReportError(cx, "cannot open document for %s", mime_type);
  1006.         goto bad;
  1007.     }
  1008.  
  1009.     if (doc->layer_id == LO_DOCUMENT_LAYER_ID) {
  1010.         /* Layout discards documents lazily, but we are now eager. */
  1011.         if (!decoder->document && !lm_InitWindowContent(decoder))
  1012.             goto bad;
  1013.  
  1014.         /* 
  1015.          * Reset the doc_id since the context won't have a valid 
  1016.          * one set till we start writing out content.
  1017.          */
  1018.         decoder->doc_id = 0;
  1019.     }
  1020.     
  1021.     decoder->writing_input = JS_TRUE;
  1022.     if (!lm_SetInputStream(cx, decoder, stream, url_struct, JS_TRUE))
  1023.         goto bad;
  1024.     
  1025.     is_text_html =  (JSBool)(!XP_STRCMP(mime_type, TEXT_HTML));
  1026.     
  1027.     /* Only need to do this for a window's document */
  1028.     if (doc->layer_id == LO_DOCUMENT_LAYER_ID) {
  1029.         if (is_text_html) {
  1030.             /* Feed layout an internal tag so it will create a new top state.*/
  1031.             ET_lo_DoDocWrite(cx, context, stream, nscp_open_tag,
  1032.                              sizeof nscp_open_tag - 1, 0);
  1033.         }
  1034.  
  1035.         if (is_text_html || !XP_STRCMP(mime_type, TEXT_PLAIN)) {
  1036.             doc_cache_converter(cx, decoder, url_struct, 
  1037.                                 wysiwyg_url, doc->layer_id);
  1038.         }
  1039.  
  1040.         /* Auto-generate a BASE HREF= tag for generated HTML documents. */
  1041.         if (is_text_html) {
  1042.             tag = LM_GetBaseHrefTag(cx, principals);
  1043.             if (!tag)
  1044.                 goto bad;
  1045.             (void) doc_write_stream(cx, decoder, stream, tag, XP_STRLEN(tag));
  1046.             XP_FREE(tag);
  1047.         }
  1048.     }
  1049.     else {
  1050.         if (lm_SetLayerSourceURL(decoder, doc->layer_id, wysiwyg_url)) {
  1051.             if ((is_text_html || !XP_STRCMP(mime_type, TEXT_PLAIN)) &&
  1052.                 !doc_cache_converter(cx, decoder, url_struct, 
  1053.                                      wysiwyg_url, doc->layer_id)) {
  1054.                 lm_SetLayerSourceURL(decoder, doc->layer_id, NULL);
  1055.             }
  1056.         }
  1057.     }
  1058.  
  1059.     /* Drop our ref on url_struct -- decoder holds its own. */
  1060.     NET_DropURLStruct(url_struct);
  1061.     XP_FREE(wysiwyg_url);
  1062.     return stream;
  1063.  
  1064. bad:
  1065.     decoder->writing_input = JS_FALSE;
  1066.     decoder->free_stream_on_close = JS_FALSE;
  1067.     decoder->stream = 0;
  1068.     decoder->stream_owner = LO_DOCUMENT_LAYER_ID;
  1069.     decoder->url_struct = 0;
  1070.     if (stream) {
  1071.         (*stream->abort)(stream, MK_UNABLE_TO_CONVERT);
  1072.         XP_DELETE(stream);
  1073.     }
  1074.     NET_FreeURLStruct(url_struct);
  1075.     if (cached_url)
  1076.         NET_FreeURLStruct(cached_url);
  1077.     XP_FREE(wysiwyg_url);
  1078.     return NULL;
  1079. }
  1080.  
  1081. static JSBool
  1082. doc_stream_active(MochaDecoder *decoder)
  1083. {
  1084.     MWContext *context;
  1085.     lo_TopState *top_state;
  1086.  
  1087.     if (!decoder->writing_input)
  1088.         return JS_TRUE;
  1089.  
  1090.     context = decoder->window_context;
  1091.     if (context) {
  1092.         LO_LockLayout();
  1093.         top_state = lo_GetMochaTopState(context);
  1094.         if (top_state && top_state->input_write_level) {
  1095.             LO_UnlockLayout();
  1096.             return JS_TRUE;
  1097.         }
  1098.         LO_UnlockLayout();
  1099.     }
  1100.     return JS_FALSE;
  1101. }
  1102.  
  1103. /* XXX shared from lm_win.c for compatibility hack */
  1104. extern JSBool PR_CALLBACK
  1105. win_open(JSContext *cx, JSObject *obj, uint argc, jsval *argv, jsval *rval);
  1106.  
  1107. PR_STATIC_CALLBACK(JSBool)
  1108. doc_open(JSContext *cx, JSObject *obj, uint argc, jsval *argv, jsval *rval)
  1109. {
  1110.     JSDocument *doc;
  1111.     MochaDecoder *decoder;
  1112.     JSString *str, *str2;
  1113.     const char *mime_type, *options;
  1114.     JSBool replace;
  1115.     NET_StreamClass *stream;
  1116.  
  1117.     if (!JS_InstanceOf(cx, obj, &lm_document_class, argv))
  1118.         return JS_FALSE;
  1119.     doc = JS_GetPrivate(cx, obj);
  1120.     if (!doc)
  1121.         return JS_TRUE;
  1122.     decoder = doc->decoder;
  1123.  
  1124.     if (argc > 2 || argv[0] == JS_GetEmptyStringValue(cx)) {
  1125.         /* XXX hideous compatibility hack to call window.open */
  1126.         return win_open(cx, decoder->window_object, argc, argv, rval);
  1127.     }
  1128.  
  1129.     str = str2 = 0;
  1130.     mime_type = TEXT_HTML;
  1131.     replace = JS_FALSE;
  1132.     if (argc >= 1) {
  1133.         if (!(str = JS_ValueToString(cx, argv[0])))
  1134.             return JS_FALSE;
  1135.         mime_type = JS_GetStringBytes(str);
  1136.         if (argc >= 2) {
  1137.             if (!(str2 = JS_ValueToString(cx, argv[1])))
  1138.                 return JS_FALSE;
  1139.             options = JS_GetStringBytes(str2);
  1140.             replace = (JSBool)(!XP_STRCASECMP(options, "replace"));
  1141.         }
  1142.     }
  1143.     stream = decoder->stream;
  1144.     if (stream) {
  1145.         if (doc_stream_active(decoder)) {
  1146.             /* Don't close a stream being fed by netlib. */
  1147.             *rval = JSVAL_NULL;
  1148.             return JS_TRUE;
  1149.         }
  1150.         lm_ClearDecoderStream(decoder, JS_FALSE);
  1151.     }
  1152.     stream = doc_open_stream(cx, decoder, obj, mime_type, replace);
  1153.     if (!stream)
  1154.         return JS_FALSE;
  1155.     *rval = OBJECT_TO_JSVAL(doc->object);
  1156.     return JS_TRUE;
  1157. }
  1158.  
  1159. PR_STATIC_CALLBACK(JSBool)
  1160. doc_close(JSContext *cx, JSObject *obj, uint argc, jsval *argv, jsval *rval)
  1161. {
  1162.     JSDocument *doc;
  1163.     MochaDecoder *decoder;
  1164.  
  1165.     if (!JS_InstanceOf(cx, obj, &lm_document_class, argv))
  1166.         return JS_FALSE;
  1167.     doc = JS_GetPrivate(cx, obj);
  1168.     if (!doc)
  1169.         return JS_TRUE;
  1170.     decoder = doc->decoder;
  1171.     if (!decoder->stream || doc_stream_active(decoder)) {
  1172.         /* Don't close a closed stream, or a stream being fed by netlib. */
  1173.         *rval = JSVAL_FALSE;
  1174.         return JS_TRUE;
  1175.     }
  1176.     lm_ClearDecoderStream(decoder, JS_FALSE);
  1177.     *rval = JSVAL_TRUE;
  1178.     return JS_TRUE;
  1179. }
  1180.  
  1181. PR_STATIC_CALLBACK(JSBool)
  1182. doc_clear(JSContext *cx, JSObject *obj, uint argc, jsval *argv, jsval *rval)
  1183. {
  1184.     JSDocument *doc;
  1185.     MochaDecoder *decoder;
  1186.     MWContext *context;
  1187.  
  1188.     if (!JS_InstanceOf(cx, obj, &lm_document_class, argv))
  1189.         return JS_FALSE;
  1190.     doc = JS_GetPrivate(cx, obj);
  1191.     if (!doc)
  1192.         return JS_TRUE;
  1193.     decoder = doc->decoder;
  1194.     context = decoder->window_context;
  1195.     if (!context)
  1196.         return JS_TRUE;
  1197.     if (!doc_close(cx, obj, argc, argv, rval))
  1198.         return JS_FALSE;
  1199.     /* XXX need to open and push a tag through layout? */
  1200.     ET_PostClearView(context);
  1201.     return JS_TRUE;
  1202. }
  1203.  
  1204. static NET_StreamClass *
  1205. doc_get_stream(JSContext *cx, MochaDecoder *decoder, JSObject *doc_obj)
  1206. {
  1207.     NET_StreamClass *stream;
  1208.     JSDocument *doc;
  1209.  
  1210.     doc = JS_GetPrivate(cx, doc_obj);
  1211.     if (!doc)
  1212.         return NULL;
  1213.     
  1214.     stream = decoder->stream;
  1215.     if (!stream) {
  1216.         stream = doc_open_stream(cx, decoder, doc_obj, TEXT_HTML, JS_FALSE);
  1217.     /*
  1218.      * If, at document load time, we're trying to get a stream to a layer
  1219.      * that isn't the currently loading layer, then disallow it.
  1220.      */
  1221.     } else if (doc->layer_id != decoder->active_layer_id &&
  1222.            !decoder->load_event_sent) {
  1223.         return NULL;
  1224.     /*
  1225.      * If we're writing to the main document or before the main document
  1226.      * has completely loaded, make sure that we do all the wysiwyg
  1227.      * nonsense.
  1228.      */
  1229.     } else if (doc->layer_id == LO_DOCUMENT_LAYER_ID ||
  1230.                !decoder->load_event_sent) { 
  1231.         XP_ASSERT(decoder->url_struct);
  1232.         if (decoder->url_struct && !decoder->url_struct->wysiwyg_url)
  1233.             ET_moz_SetMochaWriteStream(decoder);
  1234.     }
  1235.     return stream;
  1236. }
  1237.  
  1238. static JSBool
  1239. do_doc_write(JSContext *cx, JSObject *obj,
  1240.              uint argc, jsval *argv, JSBool write_eol, 
  1241.              jsval *rval)
  1242. {
  1243.     JSDocument *doc;
  1244.     MochaDecoder *decoder;
  1245.     MochaDecoder *running;
  1246.     NET_StreamClass *stream;
  1247.     uint i;
  1248.     int status, total_len, len;
  1249.     static char eol[] = "\n";
  1250.     char * buf, * start;
  1251.     JSString * str;
  1252.  
  1253.     doc = JS_GetPrivate(cx, obj);
  1254.     if (!doc)
  1255.         return JS_TRUE;
  1256.  
  1257.     if (PR_CurrentThread() == mozilla_thread)
  1258.         return JS_FALSE;
  1259.  
  1260.     decoder = doc->decoder;
  1261.     stream = doc_get_stream(cx, decoder, obj);
  1262.     if (!stream)
  1263.         return JS_FALSE;
  1264.  
  1265.     /* see how much space we need */
  1266.     total_len = 0;
  1267.     for (i = 0; i < argc; i++) {
  1268.         if (JSVAL_IS_STRING(argv[i])) {
  1269.             str = JSVAL_TO_STRING(argv[i]);
  1270.         }
  1271.         else {
  1272.             str = JS_ValueToString(cx, argv[i]);
  1273.             if (!str)
  1274.                 return JS_FALSE;
  1275.             argv[i] = STRING_TO_JSVAL(str);
  1276.         }
  1277.  
  1278.         total_len += JS_GetStringLength(str);
  1279.  
  1280.     }
  1281.  
  1282.     /* see if we need to allocate space for the end of line */
  1283.     if (write_eol)
  1284.         total_len += XP_STRLEN(eol);
  1285.  
  1286.     start = buf = XP_ALLOC((total_len + 1) * sizeof(char));
  1287.     if (!buf)
  1288.         return JS_FALSE;
  1289.  
  1290.     buf[0] = '\0';
  1291.  
  1292.     /* cache these so we don't need to look up each iteration */
  1293.     running = JS_GetPrivate(cx, JS_GetGlobalObject(cx));
  1294.  
  1295.     /* build the string for whatever is on the other end of the stream */
  1296.     for (i = 0; i < argc; i++) {
  1297.  
  1298.         str = JSVAL_TO_STRING(argv[i]);
  1299.         len = JS_GetStringLength(str);
  1300.  
  1301.         /* 
  1302.          * JSStrings can contain NUL, not sure how well layout will
  1303.          *   deal with that but pass them along in case they're going
  1304.          *   to the imglib.
  1305.          */
  1306.     /* XXXunicode */
  1307.         memcpy(buf, JS_GetStringBytes(str), len);
  1308.         buf += len;
  1309.  
  1310.     }
  1311.  
  1312.     /* generate a new line */
  1313.     if (write_eol)
  1314.         XP_STRCPY(buf, eol);
  1315.     else
  1316.         *buf = '\0';
  1317.  
  1318.     if (lm_writing_context == NULL)
  1319.         lm_writing_context = cx;
  1320.     writing_context_counter++;
  1321.  
  1322.     /* if we made it to here we must have a valid string */
  1323.     status = ET_lo_DoDocWrite(cx, decoder->window_context, stream, start,
  1324.                               total_len, decoder->doc_id);
  1325.  
  1326.     if (--writing_context_counter == 0)
  1327.         lm_writing_context = NULL;
  1328.  
  1329.     XP_FREE(start);
  1330.  
  1331.     if (status < 0) {
  1332.         *rval = JSVAL_FALSE;
  1333.         return JS_TRUE;
  1334.     }
  1335.     
  1336.     if (!decoder->document && !lm_InitWindowContent(decoder))
  1337.         return JS_FALSE;
  1338.     *rval = JSVAL_TRUE;
  1339.     return JS_TRUE;
  1340.  
  1341. }
  1342.  
  1343. PR_STATIC_CALLBACK(JSBool)
  1344. doc_write(JSContext *cx, JSObject *obj,
  1345.           uint argc, jsval *argv, jsval *rval)
  1346. {
  1347.     if (!JS_InstanceOf(cx, obj, &lm_document_class, argv))
  1348.         return JS_FALSE;
  1349.  
  1350.     return do_doc_write(cx, obj, argc, argv, JS_FALSE, rval);
  1351. }
  1352.  
  1353. PR_STATIC_CALLBACK(JSBool)
  1354. doc_writeln(JSContext *cx, JSObject *obj,
  1355.             uint argc, jsval *argv, jsval *rval)
  1356. {
  1357.     if (!JS_InstanceOf(cx, obj, &lm_document_class, argv))
  1358.         return JS_FALSE;
  1359.  
  1360.     return do_doc_write(cx, obj, argc, argv, JS_TRUE, rval);
  1361. }
  1362.  
  1363. PR_STATIC_CALLBACK(JSBool)
  1364. doc_capture_events(JSContext *cx, JSObject *obj,
  1365.             uint argc, jsval *argv, jsval *rval)
  1366. {
  1367.     JSDocument *doc;
  1368.     MochaDecoder *decoder;
  1369.     jsdouble d;
  1370.  
  1371.     if (!JS_InstanceOf(cx, obj, &lm_document_class, argv))
  1372.         return JS_FALSE;
  1373.     doc = JS_GetPrivate(cx, obj);
  1374.     if (!doc)
  1375.         return JS_FALSE;
  1376.     decoder=doc->decoder;
  1377.  
  1378.     if (!decoder->window_context)
  1379.         return JS_TRUE;
  1380.  
  1381.     if (argc != 1)
  1382.         return JS_TRUE;
  1383.  
  1384.     if (!JS_ValueToNumber(cx, argv[0], &d)) 
  1385.         return JS_FALSE;
  1386.  
  1387.     doc->capturer.event_bit |= (uint32)d;
  1388.     decoder->window_context->event_bit |= (uint32)d;
  1389.  
  1390.     return JS_TRUE;
  1391. }
  1392.  
  1393. PR_STATIC_CALLBACK(JSBool)
  1394. doc_release_events(JSContext *cx, JSObject *obj,
  1395.             uint argc, jsval *argv, jsval *rval)
  1396. {
  1397.     JSDocument *doc;
  1398.     JSEventCapturer *cap;
  1399.     MochaDecoder *decoder;
  1400.     jsdouble d;
  1401.     jsint layer_index;
  1402.     jsint max_layer_num;
  1403.     JSObject *cap_obj;
  1404.  
  1405.     if (!JS_InstanceOf(cx, obj, &lm_document_class, argv))
  1406.         return JS_FALSE;
  1407.     doc = JS_GetPrivate(cx, obj);
  1408.     if (!doc)
  1409.         return JS_FALSE;
  1410.     decoder=doc->decoder;
  1411.  
  1412.     if (!decoder->window_context)
  1413.         return JS_TRUE;
  1414.  
  1415.     if (argc != 1)
  1416.         return JS_TRUE;
  1417.  
  1418.     if (!JS_ValueToNumber(cx, argv[0], &d)) 
  1419.         return JS_FALSE;
  1420.  
  1421.     doc->capturer.event_bit &= ~(uint32)d;
  1422.     decoder->window_context->event_bit &= ~(uint32)d;
  1423.  
  1424.     /*Now we have to see if anyone else wanted that bit set.  Joy!*/
  1425.     /*First we check versus window */
  1426.     decoder->window_context->event_bit |= decoder->event_bit;
  1427.  
  1428.     /*Now we check versus layers */
  1429.     max_layer_num = LO_GetNumberOfLayers(decoder->window_context);
  1430.     
  1431.     for (layer_index=0; layer_index <= max_layer_num; layer_index++) {
  1432.         cap_obj = LO_GetLayerMochaObjectFromId(decoder->window_context, layer_index);
  1433.         if (cap_obj && (cap = JS_GetPrivate(cx, cap_obj)) != NULL)
  1434.             decoder->window_context->event_bit |= cap->event_bit;
  1435.         
  1436.         cap_obj = lm_GetDocumentFromLayerId(decoder, layer_index);
  1437.         if (cap_obj && (cap = JS_GetPrivate(cx, cap_obj)) != NULL)
  1438.             decoder->window_context->event_bit |= cap->event_bit;
  1439.     }
  1440.     
  1441.     return JS_TRUE;
  1442. }
  1443.  
  1444. PR_STATIC_CALLBACK(JSBool)
  1445. doc_get_selection(JSContext *cx, JSObject *obj,
  1446.             uint argc, jsval *argv, jsval *rval)
  1447. {
  1448.     JSDocument *doc;
  1449.     MWContext *context;
  1450.     JSString *str;
  1451.     char *text;
  1452.     
  1453.     if (!JS_InstanceOf(cx, obj, &lm_document_class, argv))
  1454.         return JS_FALSE;
  1455.  
  1456.     doc = JS_GetPrivate(cx, obj);
  1457.     if (!doc)
  1458.         return JS_FALSE;
  1459.     context = doc->decoder->window_context;
  1460.  
  1461.     text = ET_PostGetSelectedText(context);
  1462.     str = lm_LocalEncodingToStr(context, text);
  1463.     XP_FREE(text);
  1464.     if (!str)
  1465.         return JS_FALSE;
  1466.  
  1467.     *rval = STRING_TO_JSVAL(str);
  1468.     return JS_TRUE;
  1469. }
  1470.  
  1471. PR_STATIC_CALLBACK(JSBool)
  1472. doc_get_object_at(JSContext *cx, JSObject *obj,
  1473.             uint argc, jsval *argv, jsval *rval)
  1474. {
  1475.     JSDocument *doc;
  1476.     MochaDecoder *decoder;
  1477.     LO_Element *pElement;
  1478.     CL_Layer *layer;
  1479.     JSObject *xy_obj = 0;
  1480.     LO_AnchorData *anchor;
  1481.     int32 x, y;
  1482.     int16 type;
  1483.  
  1484.     if (!JS_InstanceOf(cx, obj, &lm_document_class, argv))
  1485.         return JS_FALSE;
  1486.  
  1487.     doc = JS_GetPrivate(cx, obj);
  1488.     if (!doc)
  1489.         return JS_FALSE;
  1490.     
  1491.     decoder = doc->decoder;
  1492.  
  1493.     if (argc != 2) {
  1494.         JS_ReportError(cx, lm_argc_err_str);
  1495.         return JS_FALSE;
  1496.     }
  1497.  
  1498.     if (!decoder->window_context)
  1499.         return JS_TRUE;
  1500.  
  1501.     if (!JS_ValueToInt32(cx, argv[0], &x) || !JS_ValueToInt32(cx, argv[1], &y))
  1502.         return JS_FALSE;    
  1503.  
  1504.     layer = LO_GetLayerFromId(decoder->window_context, doc->layer_id);
  1505.         
  1506.     LO_LockLayout();
  1507.  
  1508.     pElement = LO_XYToElement(decoder->window_context, x, y, layer);
  1509.  
  1510.     type = pElement ? pElement->type : LO_NONE;
  1511.  
  1512.     switch (type) {
  1513.       case LO_TEXT:
  1514.         anchor = pElement->lo_text.anchor_href;
  1515.         if (!anchor)
  1516.             *rval = JSVAL_VOID;
  1517.         else
  1518.             *rval = OBJECT_TO_JSVAL(anchor->mocha_object);
  1519.         break;
  1520.       case LO_IMAGE:
  1521.         anchor = pElement->lo_image.anchor_href;
  1522.         if (!anchor)
  1523.             *rval = OBJECT_TO_JSVAL(pElement->lo_image.mocha_object);
  1524.         else 
  1525.             *rval = OBJECT_TO_JSVAL(anchor->mocha_object);
  1526.         break;
  1527.       case LO_FORM_ELE:
  1528.         *rval = OBJECT_TO_JSVAL(pElement->lo_form.mocha_object);
  1529.         break;
  1530.       default:
  1531.         *rval = OBJECT_TO_JSVAL(obj);
  1532.         break;
  1533.     }
  1534.  
  1535.     LO_UnlockLayout();
  1536.  
  1537.     return JS_TRUE;
  1538. }
  1539.  
  1540. static JSFunctionSpec doc_methods[] = {
  1541.     {"clear",           doc_clear,              0},
  1542.     {"close",           doc_close,              0},
  1543.     {"open",            doc_open,               1},
  1544.     {lm_toString_str,   doc_toString,           0},
  1545.     {"write",           doc_write,              0},
  1546.     {"writeln",         doc_writeln,            0},
  1547.     {"captureEvents",   doc_capture_events,     1}, 
  1548.     {"releaseEvents",   doc_release_events,     1},
  1549.     {"getSelection",    doc_get_selection,      0},
  1550.     {"getObjectAt",     doc_get_object_at,      0},
  1551.     {0}
  1552. };
  1553.  
  1554. JSObject *
  1555. lm_DefineDocument(MochaDecoder *decoder, int32 layer_id)
  1556. {
  1557.  
  1558.     JSObject *obj;
  1559.     JSContext *cx;
  1560.     JSDocument *doc;
  1561.     JSObject *parent;
  1562.  
  1563.     cx = decoder->js_context;
  1564.     doc = JS_malloc(cx, sizeof *doc);
  1565.     if (!doc)
  1566.         return NULL;
  1567.     XP_BZERO(doc, sizeof *doc);
  1568.  
  1569.     obj = lm_GetDocumentFromLayerId(decoder, layer_id);
  1570.     if (obj)
  1571.         return obj;
  1572.     
  1573.     if (layer_id == LO_DOCUMENT_LAYER_ID) {
  1574.         parent = decoder->window_object;
  1575.     } else {
  1576.         parent = 
  1577.             (JSObject *)LO_GetLayerMochaObjectFromId(decoder->window_context, 
  1578.                                                      layer_id);    
  1579.     if (!parent)
  1580.         parent = decoder->window_object;
  1581.     }
  1582.     obj = JS_DefineObject(cx, parent, lm_document_str, &lm_document_class, 
  1583.                           decoder->document_prototype, 
  1584.                           JSPROP_ENUMERATE|JSPROP_READONLY);
  1585.  
  1586.     if (!obj || !JS_SetPrivate(cx, obj, doc)) {
  1587.         JS_free(cx, doc);
  1588.         return NULL;
  1589.     }
  1590.  
  1591.     if (!JS_AddNamedRoot(cx, &doc->forms,   lm_forms_str) ||
  1592.         !JS_AddNamedRoot(cx, &doc->links,   lm_links_str) ||
  1593.         !JS_AddNamedRoot(cx, &doc->anchors, lm_anchors_str) ||
  1594.         !JS_AddNamedRoot(cx, &doc->applets, lm_applets_str) ||
  1595.         !JS_AddNamedRoot(cx, &doc->embeds,  lm_embeds_str) ||
  1596.         !JS_AddNamedRoot(cx, &doc->images,  lm_images_str) ||
  1597.         !JS_AddNamedRoot(cx, &doc->layers,  lm_layers_str)) {
  1598.         /* doc_finalize will clean up the rest. */
  1599.         return NULL;
  1600.     }
  1601.  
  1602.     doc->object = obj;
  1603.     doc->decoder = HOLD_BACK_COUNT(decoder);
  1604.     doc->layer_id = layer_id;
  1605.     if (layer_id == LO_DOCUMENT_LAYER_ID) {
  1606.         decoder->document = obj;
  1607.         XP_ASSERT(decoder->window_context);
  1608.         decoder->doc_id = XP_DOCID(decoder->window_context);
  1609.     }
  1610.  
  1611.     return obj;
  1612. }
  1613.  
  1614. JSBool
  1615. lm_InitDocumentClass(MochaDecoder *decoder)
  1616. {
  1617.     JSContext *cx;
  1618.     JSObject *prototype;
  1619.  
  1620.     cx = decoder->js_context;
  1621.     prototype = JS_InitClass(cx, decoder->window_object, 
  1622.                              decoder->event_capturer_prototype,
  1623.                              &lm_document_class, Document, 0,
  1624.                              doc_props, doc_methods, NULL, NULL);
  1625.     if (!prototype)
  1626.         return JS_FALSE;
  1627.     decoder->document_prototype = prototype;
  1628.     return JS_TRUE;
  1629. }
  1630.  
  1631. JSObject *
  1632. lm_GetDocumentFromLayerId(MochaDecoder *decoder, int32 layer_id)
  1633. {
  1634.     JSObject *layer_obj;
  1635.     JSBool ok;
  1636.     jsval val;
  1637.     JSObject *rv;
  1638.  
  1639.     LO_LockLayout();
  1640.  
  1641.     if (layer_id == LO_DOCUMENT_LAYER_ID)
  1642.         rv = decoder->document;
  1643.     else {
  1644.         layer_obj = LO_GetLayerMochaObjectFromId(decoder->window_context, 
  1645.                                                  layer_id);
  1646.         if (!layer_obj) {
  1647.             LO_UnlockLayout();
  1648.             return NULL;
  1649.         }
  1650.         
  1651.         ok = JS_LookupProperty(decoder->js_context, layer_obj, 
  1652.                                lm_document_str, &val);
  1653.         if (!ok) {
  1654.             LO_UnlockLayout();
  1655.             return NULL;
  1656.         }
  1657.  
  1658.         rv = JSVAL_IS_OBJECT(val) ? JSVAL_TO_OBJECT(val) : NULL;
  1659.     }
  1660.  
  1661.     LO_UnlockLayout();
  1662.     return rv;
  1663. }
  1664.  
  1665. /* Clears out object references from the doc private data */
  1666. void
  1667. lm_CleanUpDocumentRoots(MochaDecoder *decoder, JSObject *obj)
  1668. {
  1669.     JSDocument *doc;
  1670.  
  1671.     doc = JS_GetPrivate(decoder->js_context, obj);
  1672.  
  1673.     if (!doc)
  1674.         return;
  1675.  
  1676.     doc->forms = NULL;
  1677.     doc->links = NULL;
  1678.     doc->anchors = NULL;
  1679.     doc->applets = NULL;
  1680.     doc->embeds = NULL;
  1681.     doc->images = NULL;
  1682.     doc->layers = NULL;
  1683. }
  1684.  
  1685. /* 
  1686.  * Called when the content associated with a document is destroyed,
  1687.  * but the document itself may not be. Cleans out object references
  1688.  * from doc private data (so that the objects can be collected). Also
  1689.  * deals with correctly relinquishing event capture.
  1690.  */
  1691. void
  1692. lm_CleanUpDocument(MochaDecoder *decoder, JSObject *obj)
  1693. {
  1694.     JSDocument *doc;
  1695.     MWContext *context;
  1696.     jsint layer_index, max_layer_num;
  1697.     JSObject *cap_obj;
  1698.     JSEventCapturer *cap;
  1699.  
  1700.     lm_CleanUpDocumentRoots(decoder, obj);
  1701.     
  1702.     doc = JS_GetPrivate(decoder->js_context, obj);
  1703.     if (!doc)
  1704.         return;
  1705.  
  1706.     doc->capturer.event_bit = 0;
  1707.     context = decoder->window_context;
  1708.     if (!context)
  1709.         return;
  1710.     context->event_bit = 0;
  1711.  
  1712.     /* Now we have to see who still wants events */
  1713.     /* First we check versus window */
  1714.     context->event_bit |= decoder->event_bit;
  1715.  
  1716.     /*Now we check versus layers */
  1717.     max_layer_num = LO_GetNumberOfLayers(context);
  1718.  
  1719.     for (layer_index=0; layer_index <= max_layer_num; layer_index++) {
  1720.         if (doc->layer_id == layer_index)
  1721.             continue;
  1722.  
  1723.         cap_obj = LO_GetLayerMochaObjectFromId(decoder->window_context, layer_index);
  1724.         if (cap_obj && (cap = JS_GetPrivate(decoder->js_context, cap_obj)) != NULL)
  1725.             context->event_bit |= cap->event_bit;
  1726.         
  1727.         cap_obj = lm_GetDocumentFromLayerId(decoder, layer_index);
  1728.         if (cap_obj && (cap = JS_GetPrivate(decoder->js_context, cap_obj)) != NULL)
  1729.             context->event_bit |= cap->event_bit;
  1730.     }
  1731.  
  1732. }
  1733.  
  1734.  
  1735.  
  1736. /*
  1737.  * This routine needs to be callable from either the mocha or
  1738.  *   the mozilla threads.  The call to lm_FreeWindowContent()
  1739.  *   may be problematic since its going to try to post
  1740.  *   clearTimeout() messages back to the mozilla thread if any
  1741.  *   are pending.
  1742.  */
  1743. void
  1744. LM_ReleaseDocument(MWContext *context, JSBool resize_reload)
  1745. {
  1746.     MochaDecoder *decoder;
  1747.     JSContext *cx;
  1748.  
  1749.     if (resize_reload)
  1750.         return;
  1751.  
  1752.     /* Be defensive about JS-unaware contexts. */
  1753.     cx = context->mocha_context;
  1754.     if (!cx)
  1755.         return;
  1756.  
  1757.     /* Hold the context's decoder rather than calling LM_GetMochaDecoder. */
  1758.     decoder = JS_GetPrivate(cx, JS_GetGlobalObject(cx));
  1759.     decoder->forw_count++;
  1760.  
  1761.     /* Turn of the capture bits for the window and context */
  1762.     decoder->event_bit = 0;
  1763.     decoder->window_context->event_bit = 0;
  1764.     
  1765.     /* Set first language version back to unknown for the next document */
  1766.     decoder->firstVersion = JSVERSION_UNKNOWN;
  1767.  
  1768.     if (decoder->principals) {
  1769.         /* Drop reference to JSPrincipals object */
  1770.         JSPRINCIPALS_DROP(cx, decoder->principals);
  1771.         decoder->principals = NULL;
  1772.     }
  1773.  
  1774.     /* Free any anonymous images. */
  1775.     if (decoder->image_context)
  1776.         ET_PostFreeAnonImages(context, decoder->image_context);
  1777.  
  1778.     /* Free all the HTML-based objects and properties. */
  1779.     lm_FreeWindowContent(decoder, JS_TRUE);
  1780.     JS_GC(cx);
  1781.  
  1782.     LM_PutMochaDecoder(decoder);
  1783. }
  1784.