1998-04-28 09:16:06 +04:00
|
|
|
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
|
|
|
*
|
|
|
|
* The contents of this file are subject to the Netscape Public License
|
|
|
|
* Version 1.0 (the "NPL"); you may not use this file except in
|
|
|
|
* compliance with the NPL. You may obtain a copy of the NPL at
|
|
|
|
* http://www.mozilla.org/NPL/
|
|
|
|
*
|
|
|
|
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
|
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
|
|
|
* for the specific language governing rights and limitations under the
|
|
|
|
* NPL.
|
|
|
|
*
|
|
|
|
* The Initial Developer of this code under the NPL is Netscape
|
|
|
|
* Communications Corporation. Portions created by Netscape are
|
|
|
|
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
|
|
|
* Reserved.
|
|
|
|
*/
|
|
|
|
/*
|
|
|
|
* JS reflection of the current Navigator Document.
|
|
|
|
*
|
|
|
|
* Brendan Eich, 9/8/95
|
|
|
|
*/
|
1998-06-23 01:21:28 +04:00
|
|
|
#include "rosetta.h"
|
1998-04-28 09:16:06 +04:00
|
|
|
#include "lm.h"
|
|
|
|
#include "prtypes.h"
|
|
|
|
#include "plhash.h"
|
|
|
|
#include "prmem.h"
|
|
|
|
#include "prtime.h"
|
|
|
|
#include "xp.h"
|
|
|
|
#include "lo_ele.h"
|
|
|
|
#include "shist.h"
|
1998-05-12 02:02:46 +04:00
|
|
|
#include "cookies.h"
|
1998-04-28 09:16:06 +04:00
|
|
|
#include "structs.h" /* for MWContext */
|
|
|
|
#include "layout.h" /* included via -I../layout */
|
|
|
|
#include "pa_parse.h" /* included via -I../libparse */
|
|
|
|
#include "pa_tags.h" /* included via -I../libparse */
|
|
|
|
#include "secnav.h"
|
|
|
|
#include "libstyle.h"
|
|
|
|
#include "prthread.h"
|
|
|
|
#include "np.h"
|
1998-08-01 00:19:50 +04:00
|
|
|
#if defined (JAVA)
|
1998-04-28 09:16:06 +04:00
|
|
|
#include "jsjava.h"
|
1998-08-01 00:19:50 +04:00
|
|
|
#elif defined (OJI)
|
|
|
|
#include "jsjava.h"
|
|
|
|
#include "np2.h"
|
1998-04-28 09:16:06 +04:00
|
|
|
#endif
|
1998-09-30 01:23:15 +04:00
|
|
|
#ifdef DOM
|
|
|
|
#include "domstyle.h"
|
|
|
|
#endif
|
1998-04-28 09:16:06 +04:00
|
|
|
|
1998-04-29 14:13:27 +04:00
|
|
|
#ifndef DOM
|
1998-04-28 09:16:06 +04:00
|
|
|
enum doc_slot {
|
|
|
|
DOC_LENGTH = -1,
|
|
|
|
DOC_ELEMENTS = -2,
|
|
|
|
DOC_FORMS = -3,
|
|
|
|
DOC_LINKS = -4,
|
|
|
|
DOC_ANCHORS = -5,
|
|
|
|
DOC_APPLETS = -6,
|
|
|
|
DOC_EMBEDS = -7,
|
|
|
|
DOC_TITLE = -8,
|
|
|
|
DOC_URL = -9,
|
|
|
|
DOC_REFERRER = -10,
|
|
|
|
DOC_LAST_MODIFIED = -11,
|
|
|
|
DOC_COOKIE = -12,
|
|
|
|
DOC_DOMAIN = -13,
|
|
|
|
/* slots below this line are not secured */
|
|
|
|
DOC_IMAGES = -14,
|
|
|
|
DOC_LAYERS = -15,
|
|
|
|
DOC_LOADED_DATE = -16,
|
|
|
|
DOC_BG_COLOR = -17,
|
|
|
|
DOC_FG_COLOR = -18,
|
|
|
|
DOC_LINK_COLOR = -19,
|
|
|
|
DOC_VLINK_COLOR = -20,
|
|
|
|
DOC_ALINK_COLOR = -21,
|
|
|
|
DOC_WIDTH = -22,
|
1998-09-30 04:53:09 +04:00
|
|
|
DOC_HEIGHT = -23,
|
|
|
|
DOC_BUILTINS = -24
|
1998-04-28 09:16:06 +04:00
|
|
|
};
|
1998-04-29 14:13:27 +04:00
|
|
|
#else
|
|
|
|
enum doc_slot {
|
|
|
|
DOC_LENGTH = -1,
|
|
|
|
DOC_ELEMENTS = -2,
|
|
|
|
DOC_FORMS = -3,
|
|
|
|
DOC_LINKS = -4,
|
|
|
|
DOC_ANCHORS = -5,
|
|
|
|
DOC_APPLETS = -6,
|
|
|
|
DOC_EMBEDS = -7,
|
1998-10-20 00:45:03 +04:00
|
|
|
DOC_DOCELEMENT = -8, /* Added for W3C DOM stuff */
|
|
|
|
DOC_TITLE = -9,
|
|
|
|
DOC_URL = -10,
|
|
|
|
DOC_REFERRER = -11,
|
|
|
|
DOC_LAST_MODIFIED = -12,
|
|
|
|
DOC_COOKIE = -13,
|
|
|
|
DOC_DOMAIN = -14,
|
1998-04-29 14:13:27 +04:00
|
|
|
/* slots below this line are not secured */
|
1998-10-20 00:45:03 +04:00
|
|
|
DOC_IMAGES = -15,
|
|
|
|
DOC_LAYERS = -16,
|
|
|
|
DOC_LOADED_DATE = -17,
|
|
|
|
DOC_BG_COLOR = -18,
|
|
|
|
DOC_FG_COLOR = -19,
|
|
|
|
DOC_LINK_COLOR = -20,
|
|
|
|
DOC_VLINK_COLOR = -21,
|
|
|
|
DOC_ALINK_COLOR = -22,
|
|
|
|
DOC_WIDTH = -23,
|
|
|
|
DOC_HEIGHT = -24,
|
|
|
|
DOC_BUILTINS = -25
|
1998-04-29 14:13:27 +04:00
|
|
|
};
|
|
|
|
|
|
|
|
#endif
|
1998-04-28 09:16:06 +04:00
|
|
|
#define IS_SECURE_DOC_SLOT(s) (DOC_DOMAIN <= (s) && (s) <= DOC_LENGTH)
|
|
|
|
|
|
|
|
static JSPropertySpec doc_props[] = {
|
|
|
|
{lm_length_str, DOC_LENGTH, JSPROP_READONLY},
|
|
|
|
{"elements", DOC_ELEMENTS, JSPROP_READONLY},
|
|
|
|
{lm_forms_str, DOC_FORMS, JSPROP_ENUMERATE|JSPROP_READONLY},
|
|
|
|
{lm_links_str, DOC_LINKS, JSPROP_ENUMERATE|JSPROP_READONLY},
|
|
|
|
{lm_anchors_str, DOC_ANCHORS, JSPROP_ENUMERATE|JSPROP_READONLY},
|
|
|
|
{lm_applets_str, DOC_APPLETS, JSPROP_ENUMERATE|JSPROP_READONLY},
|
|
|
|
{lm_embeds_str, DOC_EMBEDS, JSPROP_ENUMERATE|JSPROP_READONLY},
|
|
|
|
{lm_plugins_str, DOC_EMBEDS, JSPROP_READONLY},
|
|
|
|
{lm_images_str, DOC_IMAGES, JSPROP_ENUMERATE|JSPROP_READONLY},
|
|
|
|
{lm_layers_str, DOC_LAYERS, JSPROP_ENUMERATE|JSPROP_READONLY},
|
1998-04-29 14:13:27 +04:00
|
|
|
#ifdef DOM
|
1998-08-27 04:09:43 +04:00
|
|
|
{"documentElement",DOC_DOCELEMENT, JSPROP_ENUMERATE|JSPROP_READONLY},
|
1998-04-29 14:13:27 +04:00
|
|
|
#endif
|
1998-04-28 09:16:06 +04:00
|
|
|
{"title", DOC_TITLE, JSPROP_ENUMERATE|JSPROP_READONLY},
|
|
|
|
{"URL", DOC_URL, JSPROP_ENUMERATE|JSPROP_READONLY},
|
|
|
|
{"referrer", DOC_REFERRER, JSPROP_ENUMERATE|JSPROP_READONLY},
|
|
|
|
{"lastModified", DOC_LAST_MODIFIED, JSPROP_ENUMERATE|JSPROP_READONLY},
|
|
|
|
{"loadedDate", DOC_LOADED_DATE, JSPROP_READONLY},
|
|
|
|
{"cookie", DOC_COOKIE, JSPROP_ENUMERATE},
|
|
|
|
{"domain", DOC_DOMAIN, JSPROP_ENUMERATE},
|
|
|
|
{"bgColor", DOC_BG_COLOR, JSPROP_ENUMERATE},
|
|
|
|
{"fgColor", DOC_FG_COLOR, JSPROP_ENUMERATE},
|
|
|
|
{"linkColor", DOC_LINK_COLOR, JSPROP_ENUMERATE},
|
|
|
|
{"vlinkColor", DOC_VLINK_COLOR, JSPROP_ENUMERATE},
|
|
|
|
{"alinkColor", DOC_ALINK_COLOR, JSPROP_ENUMERATE},
|
|
|
|
{"width", DOC_WIDTH, JSPROP_ENUMERATE},
|
|
|
|
{"height", DOC_HEIGHT, JSPROP_ENUMERATE},
|
1998-09-30 04:53:09 +04:00
|
|
|
{lm_builtins_str,DOC_BUILTINS, JSPROP_ENUMERATE|JSPROP_READONLY},
|
1998-04-28 09:16:06 +04:00
|
|
|
{0}
|
|
|
|
};
|
|
|
|
|
|
|
|
#define LO_COLOR_TYPE(slot) \
|
|
|
|
(((slot) == DOC_BG_COLOR) ? LO_COLOR_BG \
|
|
|
|
: ((slot) == DOC_FG_COLOR) ? LO_COLOR_FG \
|
|
|
|
: ((slot) == DOC_LINK_COLOR) ? LO_COLOR_LINK \
|
|
|
|
: ((slot) == DOC_VLINK_COLOR) ? LO_COLOR_VLINK \
|
|
|
|
: ((slot) == DOC_ALINK_COLOR) ? LO_COLOR_ALINK \
|
|
|
|
: -1)
|
|
|
|
|
|
|
|
|
|
|
|
extern PRThread *mozilla_thread;
|
|
|
|
extern JSClass lm_document_class;
|
|
|
|
extern JSClass lm_form_class;
|
|
|
|
extern JSClass *lm_java_clasp;
|
|
|
|
|
|
|
|
JSContext *lm_writing_context;
|
|
|
|
static int32 writing_context_counter;
|
|
|
|
|
|
|
|
PR_STATIC_CALLBACK(JSBool)
|
|
|
|
doc_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
|
|
|
|
{
|
|
|
|
JSDocument *doc;
|
|
|
|
MochaDecoder *decoder;
|
|
|
|
MWContext *context;
|
|
|
|
History_entry *he = NULL;
|
|
|
|
JSString *str = NULL;
|
|
|
|
int64 prsec, scale, prusec;
|
|
|
|
PRExplodedTime prtime;
|
|
|
|
char *cookie, buf[100];
|
|
|
|
const char *domain, *origin;
|
|
|
|
uint32 type;
|
|
|
|
LO_Color rgb, *bg_color;
|
|
|
|
jsint slot;
|
|
|
|
CL_Layer *layer;
|
|
|
|
int32 active_layer_id;
|
|
|
|
|
|
|
|
doc = JS_GetInstancePrivate(cx, obj, &lm_document_class, NULL);
|
|
|
|
if (!doc)
|
|
|
|
return JS_TRUE;
|
|
|
|
decoder = doc->decoder;
|
|
|
|
|
|
|
|
slot = JSVAL_IS_INT(id) ? JSVAL_TO_INT(id) : 0;
|
|
|
|
|
|
|
|
if (IS_SECURE_DOC_SLOT(slot) ||
|
|
|
|
(slot == 0 &&
|
|
|
|
JSVAL_IS_OBJECT(*vp) &&
|
|
|
|
JSVAL_TO_OBJECT(*vp) &&
|
|
|
|
(JS_InstanceOf(cx, JSVAL_TO_OBJECT(*vp), &lm_form_class, NULL) ||
|
|
|
|
(lm_java_clasp &&
|
|
|
|
JS_InstanceOf(cx, JSVAL_TO_OBJECT(*vp), lm_java_clasp, NULL)))))
|
|
|
|
{
|
|
|
|
if (!lm_CheckPermissions(cx, obj, JSTARGET_UNIVERSAL_BROWSER_READ))
|
|
|
|
return JS_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!JSVAL_IS_INT(id))
|
|
|
|
return JS_TRUE;
|
|
|
|
|
|
|
|
context = decoder->window_context;
|
|
|
|
if (!context)
|
|
|
|
return JS_TRUE;
|
|
|
|
|
|
|
|
LO_LockLayout();
|
|
|
|
if(decoder->doc_id != XP_DOCID(context)) {
|
|
|
|
LO_UnlockLayout();
|
|
|
|
#ifdef DEBUG_chouck
|
|
|
|
XP_TRACE(("DOCID: in doc_getProperty"));
|
|
|
|
#endif
|
|
|
|
return JS_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (slot) {
|
|
|
|
case DOC_FORMS:
|
|
|
|
*vp = OBJECT_TO_JSVAL(lm_GetFormArray(decoder, obj));
|
|
|
|
active_layer_id = LM_GetActiveLayer(context);
|
|
|
|
LM_SetActiveLayer(context, doc->layer_id);
|
|
|
|
(void) LO_EnumerateForms(context, doc->layer_id);
|
|
|
|
LM_SetActiveLayer(context, active_layer_id);
|
|
|
|
LO_UnlockLayout();
|
|
|
|
return JS_TRUE;
|
|
|
|
|
|
|
|
case DOC_LINKS:
|
|
|
|
*vp = OBJECT_TO_JSVAL(lm_GetLinkArray(decoder, obj));
|
|
|
|
active_layer_id = LM_GetActiveLayer(context);
|
|
|
|
LM_SetActiveLayer(context, doc->layer_id);
|
|
|
|
(void) LO_EnumerateLinks(context, doc->layer_id);
|
|
|
|
LM_SetActiveLayer(context, active_layer_id);
|
|
|
|
LO_UnlockLayout();
|
|
|
|
return JS_TRUE;
|
|
|
|
|
|
|
|
case DOC_ANCHORS:
|
|
|
|
*vp = OBJECT_TO_JSVAL(lm_GetNameArray(decoder, obj));
|
|
|
|
active_layer_id = LM_GetActiveLayer(context);
|
|
|
|
LM_SetActiveLayer(context, doc->layer_id);
|
|
|
|
(void) LO_EnumerateNamedAnchors(context,doc->layer_id);
|
|
|
|
LM_SetActiveLayer(context, active_layer_id);
|
|
|
|
LO_UnlockLayout();
|
|
|
|
return JS_TRUE;
|
|
|
|
|
|
|
|
case DOC_APPLETS:
|
1998-08-01 00:19:50 +04:00
|
|
|
#if defined(JAVA) || defined(OJI)
|
1998-04-28 09:16:06 +04:00
|
|
|
if (LM_MOJA_OK != ET_InitMoja(context)) {
|
|
|
|
LO_UnlockLayout();
|
|
|
|
return JS_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
*vp = OBJECT_TO_JSVAL(lm_GetAppletArray(decoder, obj));
|
|
|
|
active_layer_id = LM_GetActiveLayer(context);
|
|
|
|
LM_SetActiveLayer(context, doc->layer_id);
|
|
|
|
(void) LO_EnumerateApplets(context,doc->layer_id);
|
|
|
|
LM_SetActiveLayer(context, active_layer_id);
|
|
|
|
LO_UnlockLayout();
|
|
|
|
return JS_TRUE;
|
|
|
|
#else
|
|
|
|
LO_UnlockLayout();
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
case DOC_EMBEDS:
|
1998-08-01 00:19:50 +04:00
|
|
|
#if defined(JAVA) || defined(OJI)
|
1998-04-28 09:16:06 +04:00
|
|
|
if (LM_MOJA_OK != ET_InitMoja(context)) {
|
|
|
|
LO_UnlockLayout();
|
|
|
|
return JS_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
*vp = OBJECT_TO_JSVAL(lm_GetEmbedArray(decoder, obj));
|
|
|
|
active_layer_id = LM_GetActiveLayer(context);
|
|
|
|
LM_SetActiveLayer(context, doc->layer_id);
|
|
|
|
(void) LO_EnumerateEmbeds(context,doc->layer_id);
|
|
|
|
LM_SetActiveLayer(context, active_layer_id);
|
|
|
|
LO_UnlockLayout();
|
|
|
|
return JS_TRUE;
|
|
|
|
#else
|
|
|
|
LO_UnlockLayout();
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
case DOC_IMAGES:
|
|
|
|
*vp = OBJECT_TO_JSVAL(lm_GetImageArray(decoder, obj));
|
|
|
|
active_layer_id = LM_GetActiveLayer(context);
|
|
|
|
LM_SetActiveLayer(context, doc->layer_id);
|
|
|
|
(void) LO_EnumerateImages(context,doc->layer_id);
|
|
|
|
LM_SetActiveLayer(context, active_layer_id);
|
|
|
|
LO_UnlockLayout();
|
|
|
|
return JS_TRUE;
|
|
|
|
|
1998-09-30 04:53:09 +04:00
|
|
|
case DOC_BUILTINS:
|
|
|
|
*vp = OBJECT_TO_JSVAL(lm_GetBuiltinsArray(decoder, obj));
|
|
|
|
active_layer_id = LM_GetActiveLayer(context);
|
|
|
|
LM_SetActiveLayer(context, doc->layer_id);
|
|
|
|
(void) LO_EnumerateBuiltins(context,doc->layer_id);
|
|
|
|
LM_SetActiveLayer(context, active_layer_id);
|
|
|
|
LO_UnlockLayout();
|
|
|
|
return JS_TRUE;
|
|
|
|
|
1998-04-28 09:16:06 +04:00
|
|
|
case DOC_LAYERS:
|
|
|
|
*vp = OBJECT_TO_JSVAL(lm_GetDocumentLayerArray(decoder, obj));
|
|
|
|
LO_UnlockLayout();
|
|
|
|
return JS_TRUE;
|
|
|
|
|
1998-04-29 14:13:27 +04:00
|
|
|
#ifdef DOM
|
1998-08-27 04:09:43 +04:00
|
|
|
case DOC_DOCELEMENT:
|
|
|
|
*vp = OBJECT_TO_JSVAL(lm_DOMGetDocumentElement(decoder, obj));
|
|
|
|
LO_UnlockLayout();
|
|
|
|
return JS_TRUE;
|
|
|
|
#endif /* DOM */
|
1998-04-29 14:13:27 +04:00
|
|
|
|
1998-04-28 09:16:06 +04:00
|
|
|
/* XXX BUGBUG Need a story for some of these for a layer's document */
|
|
|
|
case DOC_TITLE:
|
|
|
|
he = SHIST_GetCurrent(&context->hist);
|
1998-09-19 04:33:04 +04:00
|
|
|
str = lm_EncodingToStr(context->mocha_context, CS_UTF8, he ? he->title : "");
|
1998-04-28 09:16:06 +04:00
|
|
|
LO_UnlockLayout();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case DOC_URL:
|
|
|
|
he = SHIST_GetCurrent(&context->hist);
|
|
|
|
str = JS_NewStringCopyZ(cx, he ? he->address : "");
|
|
|
|
LO_UnlockLayout();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case DOC_REFERRER:
|
|
|
|
he = SHIST_GetCurrent(&context->hist);
|
|
|
|
str = JS_NewStringCopyZ(cx, he ? he->referer : "");
|
|
|
|
LO_UnlockLayout();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case DOC_LAST_MODIFIED:
|
|
|
|
he = SHIST_GetCurrent(&context->hist);
|
|
|
|
if (he) {
|
|
|
|
LL_I2L(prsec, he->last_modified);
|
|
|
|
LL_I2L(scale, 1000000);
|
|
|
|
LL_MUL(prusec, prsec, scale);
|
|
|
|
PR_ExplodeTime(prusec, PR_LocalTimeParameters, &prtime);
|
1998-10-15 06:49:44 +04:00
|
|
|
PR_FormatTime(buf, sizeof buf,
|
|
|
|
#ifdef _WIN32
|
|
|
|
/* MSVC requires %#c to get a 4-digit date. */
|
|
|
|
"%#c",
|
|
|
|
#else
|
|
|
|
"%c",
|
|
|
|
#endif
|
|
|
|
&prtime);
|
1998-04-28 09:16:06 +04:00
|
|
|
} else {
|
|
|
|
buf[0] = '\0';
|
|
|
|
}
|
|
|
|
str = JS_NewStringCopyZ(cx, buf);
|
|
|
|
LO_UnlockLayout();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case DOC_LOADED_DATE:
|
|
|
|
LO_UnlockLayout();
|
|
|
|
/* XXX todo */
|
|
|
|
str = JSVAL_TO_STRING(JS_GetEmptyStringValue(cx));
|
|
|
|
break;
|
|
|
|
|
|
|
|
case DOC_COOKIE:
|
|
|
|
/* XXX overloaded return - can't distinguish "none" from "error" */
|
|
|
|
he = SHIST_GetCurrent(&context->hist);
|
|
|
|
cookie = NET_GetCookie(context, he ? he->address : "");
|
|
|
|
str = JS_NewStringCopyZ(cx, cookie);
|
|
|
|
XP_FREEIF(cookie);
|
|
|
|
LO_UnlockLayout();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case DOC_DOMAIN:
|
|
|
|
LO_UnlockLayout();
|
|
|
|
origin = lm_GetObjectOriginURL(cx, obj);
|
|
|
|
if (!origin)
|
|
|
|
return JS_FALSE;
|
|
|
|
domain = NET_ParseURL(origin, GET_HOST_PART);
|
|
|
|
if (!domain) {
|
|
|
|
JS_ReportOutOfMemory(cx);
|
|
|
|
return JS_FALSE;
|
|
|
|
}
|
|
|
|
str = JS_NewStringCopyZ(cx, domain);
|
|
|
|
XP_FREE((char *)domain);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case DOC_WIDTH:
|
|
|
|
layer = LO_GetLayerFromId(context, doc->layer_id);
|
|
|
|
*vp = INT_TO_JSVAL(LO_GetLayerScrollWidth(layer));
|
|
|
|
LO_UnlockLayout();
|
|
|
|
return JS_TRUE;
|
|
|
|
|
|
|
|
case DOC_HEIGHT:
|
|
|
|
layer = LO_GetLayerFromId(context, doc->layer_id);
|
|
|
|
*vp = INT_TO_JSVAL(LO_GetLayerScrollHeight(layer));
|
|
|
|
LO_UnlockLayout();
|
|
|
|
return JS_TRUE;
|
|
|
|
|
|
|
|
case DOC_BG_COLOR:
|
|
|
|
layer = LO_GetLayerFromId(context, doc->layer_id);
|
|
|
|
bg_color = LO_GetLayerBgColor(layer);
|
|
|
|
LO_UnlockLayout();
|
|
|
|
if (bg_color) {
|
|
|
|
XP_SPRINTF(buf, "#%02x%02x%02x", bg_color->red, bg_color->green,
|
|
|
|
bg_color->blue);
|
|
|
|
str = JS_NewStringCopyZ(cx, buf);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
*vp = JSVAL_NULL;
|
|
|
|
return JS_TRUE;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
type = LO_COLOR_TYPE(slot);
|
|
|
|
if (type >= LO_NCOLORS) {
|
|
|
|
LO_UnlockLayout();
|
|
|
|
/* Don't mess with a user-defined or method property. */
|
|
|
|
return JS_TRUE;
|
|
|
|
}
|
|
|
|
/* Note: background color handled above */
|
|
|
|
LO_GetDocumentColor(context, type, &rgb);
|
|
|
|
XP_SPRINTF(buf, "#%02x%02x%02x", rgb.red, rgb.green, rgb.blue);
|
|
|
|
str = JS_NewStringCopyZ(cx, buf);
|
|
|
|
LO_UnlockLayout();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Common tail code for string-type properties. */
|
|
|
|
if (!str)
|
|
|
|
return JS_FALSE;
|
|
|
|
*vp = STRING_TO_JSVAL(str);
|
|
|
|
return JS_TRUE;
|
|
|
|
}
|
|
|
|
|
1998-08-18 00:04:23 +04:00
|
|
|
static char *
|
|
|
|
getPortStart(char *host) {
|
|
|
|
char *p, *result;
|
|
|
|
|
|
|
|
result = NULL;
|
|
|
|
for (p=host; *p; p++) {
|
|
|
|
/*
|
|
|
|
* A little paranioia: check that we have only numbers following the
|
|
|
|
* colon
|
|
|
|
*/
|
|
|
|
if (result && (*p < '0' || '9' < *p))
|
|
|
|
result = NULL;
|
|
|
|
if (*p == ':')
|
|
|
|
result = p;
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
1998-04-28 09:16:06 +04:00
|
|
|
|
|
|
|
PR_STATIC_CALLBACK(JSBool)
|
|
|
|
doc_setProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
|
|
|
|
{
|
|
|
|
JSObject *layer_obj;
|
|
|
|
JSDocument *doc;
|
|
|
|
MochaDecoder *decoder;
|
|
|
|
MWContext *context;
|
1998-08-18 00:04:23 +04:00
|
|
|
char *protocol, *pathname, *new_origin_url, *str, *port, *domain;
|
|
|
|
const char *new_domain, *domain_suffix, *prop_name, *origin;
|
1998-04-28 09:16:06 +04:00
|
|
|
size_t domain_len, new_domain_len;
|
|
|
|
JSBool ok;
|
|
|
|
uint32 type;
|
|
|
|
LO_Color *rgb;
|
|
|
|
jsint slot;
|
|
|
|
int32 val;
|
|
|
|
CL_Layer *layer;
|
|
|
|
History_entry *he = NULL;
|
|
|
|
|
|
|
|
doc = JS_GetInstancePrivate(cx, obj, &lm_document_class, NULL);
|
|
|
|
if (!doc)
|
|
|
|
return JS_TRUE;
|
|
|
|
decoder = doc->decoder;
|
|
|
|
|
|
|
|
if (!lm_CheckPermissions(cx, obj, JSTARGET_UNIVERSAL_BROWSER_WRITE))
|
|
|
|
return JS_FALSE;
|
|
|
|
|
|
|
|
if (!JSVAL_IS_INT(id)) {
|
|
|
|
/*
|
|
|
|
* Due to the wonderful world of threads we need to know ahead of
|
|
|
|
* time if someone is setting an onMouseMove event handler here or
|
|
|
|
* in document so that we don't lose messages.
|
|
|
|
*/
|
|
|
|
if (JS_TypeOfValue(cx, *vp) == JSTYPE_FUNCTION) {
|
|
|
|
if (JSVAL_IS_STRING(id)) {
|
|
|
|
prop_name = JS_GetStringBytes(JSVAL_TO_STRING(id));
|
|
|
|
/* XXX use lm_onMouseMove_str etc.*/
|
|
|
|
if (XP_STRCMP(prop_name, "onmousemove") == 0 ||
|
|
|
|
XP_STRCMP(prop_name, "onMouseMove") == 0) {
|
|
|
|
decoder->window_context->js_drag_enabled = TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return JS_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
slot = JSVAL_TO_INT(id);
|
|
|
|
|
|
|
|
context = decoder->window_context;
|
|
|
|
if (!context)
|
|
|
|
return JS_TRUE;
|
|
|
|
|
|
|
|
LO_LockLayout();
|
|
|
|
if(decoder->doc_id != XP_DOCID(context)) {
|
|
|
|
LO_UnlockLayout();
|
|
|
|
#ifdef DEBUG_chouck
|
|
|
|
XP_TRACE(("DOCID: in doc_setProperty"));
|
|
|
|
#endif
|
|
|
|
return JS_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (slot) {
|
|
|
|
case DOC_COOKIE:
|
|
|
|
if (!JSVAL_IS_STRING(*vp) &&
|
|
|
|
!JS_ConvertValue(cx, *vp, JSTYPE_STRING, vp)) {
|
|
|
|
LO_UnlockLayout();
|
|
|
|
return JS_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
he = SHIST_GetCurrent(&context->hist);
|
|
|
|
str = JS_GetStringBytes(JSVAL_TO_STRING(*vp));
|
|
|
|
|
|
|
|
/* will make a copy that netlib can munge */
|
|
|
|
if (str)
|
|
|
|
str = strdup(str);
|
|
|
|
|
|
|
|
LO_UnlockLayout();
|
1998-07-15 04:29:04 +04:00
|
|
|
NET_SetCookieString(context, he ? he->address : "", str);
|
1998-04-28 09:16:06 +04:00
|
|
|
break;
|
|
|
|
|
|
|
|
case DOC_DOMAIN:
|
|
|
|
LO_UnlockLayout();
|
|
|
|
origin = lm_GetObjectOriginURL(cx, obj);
|
|
|
|
if (!origin || XP_STRCMP(origin, lm_unknown_origin_str) == 0)
|
|
|
|
return JS_FALSE;
|
1998-08-18 00:04:23 +04:00
|
|
|
domain = (char *) NET_ParseURL(origin, GET_HOST_PART);
|
1998-04-28 09:16:06 +04:00
|
|
|
if (!domain) {
|
|
|
|
JS_ReportOutOfMemory(cx);
|
|
|
|
return JS_FALSE;
|
|
|
|
}
|
|
|
|
if (!JSVAL_IS_STRING(*vp) &&
|
|
|
|
!JS_ConvertValue(cx, *vp, JSTYPE_STRING, vp)) {
|
|
|
|
XP_FREE((char *)domain);
|
|
|
|
return JS_FALSE;
|
|
|
|
}
|
|
|
|
new_domain = JS_GetStringBytes(JSVAL_TO_STRING(*vp));
|
|
|
|
new_domain_len = JS_GetStringLength(JSVAL_TO_STRING(*vp));
|
1998-08-18 00:04:23 +04:00
|
|
|
|
|
|
|
/* Allow setting document.domain to remove a port */
|
|
|
|
port = getPortStart(domain);
|
|
|
|
if (port != NULL && getPortStart((char *) new_domain) == NULL) {
|
|
|
|
*port = '\0';
|
|
|
|
}
|
|
|
|
|
1998-04-28 09:16:06 +04:00
|
|
|
domain_len = XP_STRLEN(domain);
|
|
|
|
domain_suffix = domain + domain_len - new_domain_len;
|
|
|
|
ok = (JSBool)(!XP_STRCASECMP(domain, new_domain) ||
|
|
|
|
(domain_len > new_domain_len &&
|
|
|
|
!XP_STRCASECMP(domain_suffix, new_domain) &&
|
|
|
|
(domain_suffix[-1] == '.' || domain_suffix[-1] == '/')));
|
|
|
|
if (!ok) {
|
|
|
|
JS_ReportError(cx, "illegal document.domain value %s",
|
|
|
|
new_domain);
|
|
|
|
} else {
|
|
|
|
protocol = NET_ParseURL(origin, GET_PROTOCOL_PART);
|
|
|
|
pathname = NET_ParseURL(origin, GET_PATH_PART | GET_HASH_PART |
|
|
|
|
GET_SEARCH_PART);
|
|
|
|
new_origin_url = PR_smprintf("%s//%s%s",
|
|
|
|
protocol, new_domain, pathname);
|
|
|
|
ok = (JSBool)(protocol && pathname && new_origin_url);
|
|
|
|
if (!ok) {
|
|
|
|
JS_ReportOutOfMemory(cx);
|
|
|
|
} else {
|
|
|
|
JSPrincipals *principals;
|
|
|
|
principals = lm_GetInnermostPrincipals(cx, obj, NULL);
|
|
|
|
if (principals) {
|
|
|
|
ok = lm_SetDocumentDomain(cx, principals, new_origin_url);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
PR_FREEIF(protocol);
|
|
|
|
PR_FREEIF(pathname);
|
|
|
|
PR_FREEIF(new_origin_url);
|
|
|
|
}
|
1998-08-18 00:04:23 +04:00
|
|
|
XP_FREE(domain);
|
1998-04-28 09:16:06 +04:00
|
|
|
return ok;
|
|
|
|
|
|
|
|
case DOC_BG_COLOR:
|
|
|
|
if (doc->layer_id == LO_DOCUMENT_LAYER_ID) {
|
|
|
|
layer = LO_GetLayerFromId(context, LO_DOCUMENT_LAYER_ID);
|
|
|
|
LO_UnlockLayout();
|
|
|
|
if (!lm_jsval_to_rgb(cx, vp, &rgb))
|
|
|
|
return JS_FALSE;
|
|
|
|
ET_TweakLayer(decoder->window_context, layer, 0, 0,
|
|
|
|
rgb, 0, CL_SetBgColor, NULL, decoder->doc_id);
|
|
|
|
} else {
|
|
|
|
layer_obj = LO_GetLayerMochaObjectFromId(context, doc->layer_id);
|
|
|
|
LO_UnlockLayout();
|
|
|
|
if (layer_obj)
|
|
|
|
layer_setBgColorProperty(cx, layer_obj, vp);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case DOC_FG_COLOR:
|
|
|
|
case DOC_LINK_COLOR:
|
|
|
|
case DOC_VLINK_COLOR:
|
|
|
|
case DOC_ALINK_COLOR:
|
|
|
|
type = LO_COLOR_TYPE(slot);
|
|
|
|
if (type >= LO_NCOLORS) {
|
|
|
|
LO_UnlockLayout();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!lm_jsval_to_rgb(cx, vp, &rgb) || !rgb) {
|
|
|
|
LO_UnlockLayout();
|
|
|
|
return JS_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
LO_SetDocumentColor(context, type, rgb);
|
|
|
|
LO_UnlockLayout();
|
|
|
|
if (rgb)
|
|
|
|
XP_FREE(rgb);
|
|
|
|
break;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* XXX BUGBUG These don't do the right thing for a window's document.
|
|
|
|
* Does any of this make sense for a layer's document?
|
|
|
|
*/
|
|
|
|
case DOC_WIDTH:
|
|
|
|
/* Front-ends can't cope with a document dimension less than one. */
|
|
|
|
if (!JS_ValueToInt32(cx, *vp, &val)) {
|
|
|
|
LO_UnlockLayout();
|
|
|
|
return JS_FALSE;
|
|
|
|
}
|
|
|
|
layer = LO_GetLayerFromId(context, doc->layer_id);
|
|
|
|
LO_SetLayerScrollWidth(layer, val <= 1 ? 1 : val);
|
|
|
|
LO_UnlockLayout();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case DOC_HEIGHT:
|
|
|
|
/* Front-ends can't cope with a document dimension less than one. */
|
|
|
|
if (!JS_ValueToInt32(cx, *vp, &val)) {
|
|
|
|
LO_UnlockLayout();
|
|
|
|
return JS_FALSE;
|
|
|
|
}
|
|
|
|
layer = LO_GetLayerFromId(context, doc->layer_id);
|
|
|
|
LO_SetLayerScrollHeight(layer, val <= 1 ? 1 : val);
|
|
|
|
LO_UnlockLayout();
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
LO_UnlockLayout();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return doc_getProperty(cx, obj, id, vp);
|
|
|
|
}
|
|
|
|
|
1998-08-01 00:19:50 +04:00
|
|
|
#if defined(JAVA) || defined(OJI)
|
1998-04-28 09:16:06 +04:00
|
|
|
static void
|
|
|
|
lm_reflect_stuff_eagerly(MWContext * context, int32 layer_id)
|
|
|
|
{
|
|
|
|
|
|
|
|
lo_TopState *top_state;
|
|
|
|
int count, index;
|
|
|
|
LO_JavaAppStruct *applet;
|
|
|
|
LO_EmbedStruct *embed;
|
|
|
|
lo_DocLists *doc_lists;
|
|
|
|
|
|
|
|
LO_LockLayout();
|
|
|
|
|
|
|
|
top_state = lo_GetMochaTopState(context);
|
|
|
|
if (top_state == NULL) {
|
|
|
|
LO_UnlockLayout();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
doc_lists = lo_GetDocListsById(top_state->doc_state, layer_id);
|
|
|
|
|
|
|
|
count = 0;
|
|
|
|
applet = doc_lists->applet_list;
|
|
|
|
while (applet) {
|
|
|
|
applet = applet->nextApplet;
|
|
|
|
count++;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* reflect all applets in reverse order */
|
|
|
|
applet = doc_lists->applet_list;
|
|
|
|
for (index = count-1; index >= 0; index--) {
|
1998-06-03 04:37:20 +04:00
|
|
|
if (applet->objTag.mocha_object == NULL) {
|
1998-04-28 09:16:06 +04:00
|
|
|
LM_ReflectApplet(context, applet, NULL, layer_id, index);
|
|
|
|
}
|
|
|
|
applet = applet->nextApplet;
|
|
|
|
}
|
|
|
|
|
|
|
|
count = 0;
|
|
|
|
embed = doc_lists->embed_list;
|
|
|
|
while (embed) {
|
|
|
|
embed = embed->nextEmbed;
|
|
|
|
count++;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* reflect all embeds in reverse order */
|
|
|
|
embed = doc_lists->embed_list;
|
|
|
|
for (index = count-1; index >= 0; index--) {
|
1998-06-03 04:37:20 +04:00
|
|
|
if (embed->objTag.mocha_object == NULL) {
|
1998-04-28 09:16:06 +04:00
|
|
|
LM_ReflectEmbed(context, embed, NULL, layer_id, index);
|
|
|
|
}
|
|
|
|
embed = embed->nextEmbed;
|
|
|
|
}
|
|
|
|
|
|
|
|
LO_UnlockLayout();
|
|
|
|
}
|
1998-08-01 00:19:50 +04:00
|
|
|
#endif /* JAVA || OJI*/
|
1998-04-28 09:16:06 +04:00
|
|
|
|
|
|
|
PR_STATIC_CALLBACK(JSBool)
|
|
|
|
doc_list_properties(JSContext *cx, JSObject *obj)
|
|
|
|
{
|
1998-08-01 00:19:50 +04:00
|
|
|
#if defined(JAVA) || defined(OJI)
|
1998-04-28 09:16:06 +04:00
|
|
|
/* reflect applets eagerly, anything else? */
|
|
|
|
JSDocument *doc;
|
|
|
|
MWContext *context;
|
|
|
|
JSBool bDoInitMoja = JS_FALSE;
|
|
|
|
lo_TopState *top_state;
|
|
|
|
lo_DocLists *doc_lists;
|
|
|
|
|
|
|
|
doc = JS_GetPrivate(cx, obj);
|
|
|
|
if (!doc)
|
|
|
|
return JS_TRUE;
|
|
|
|
context = doc->decoder->window_context;
|
|
|
|
if (!context)
|
|
|
|
return JS_TRUE;
|
|
|
|
|
|
|
|
LO_LockLayout();
|
|
|
|
|
|
|
|
/* if no embeds or applets don't eagerly start java */
|
|
|
|
top_state = lo_GetMochaTopState(context);
|
|
|
|
if (top_state) {
|
|
|
|
doc_lists = lo_GetDocListsById(top_state->doc_state, doc->layer_id);
|
|
|
|
|
|
|
|
if(doc_lists){
|
|
|
|
if (doc_lists->applet_list)
|
|
|
|
bDoInitMoja = JS_TRUE;
|
|
|
|
else if (doc_lists->embed_list){
|
|
|
|
/* determine if any of these embeds actually require java, are liveconnected. */
|
|
|
|
LO_EmbedStruct *embed;
|
|
|
|
for (embed = doc_lists->embed_list; embed != NULL; embed=embed->nextEmbed){
|
|
|
|
if (NPL_IsLiveConnected(embed)){
|
|
|
|
bDoInitMoja = JS_TRUE;
|
|
|
|
break; /* it only takes one */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
LO_UnlockLayout();
|
|
|
|
|
|
|
|
if(bDoInitMoja) {
|
|
|
|
if (LM_MOJA_OK != ET_InitMoja(context))
|
|
|
|
return JS_FALSE;
|
1998-08-01 00:19:50 +04:00
|
|
|
|
|
|
|
#ifdef OJI
|
1998-09-01 04:23:43 +04:00
|
|
|
if (JVM_IsLiveConnectEnabled())
|
1998-08-01 00:19:50 +04:00
|
|
|
lm_reflect_stuff_eagerly(context, doc->layer_id);
|
|
|
|
#else
|
1998-04-28 09:16:06 +04:00
|
|
|
if (JSJ_IsEnabled())
|
|
|
|
lm_reflect_stuff_eagerly(context, doc->layer_id);
|
1998-08-01 00:19:50 +04:00
|
|
|
#endif /* !OJI */
|
1998-04-28 09:16:06 +04:00
|
|
|
}
|
1998-08-01 00:19:50 +04:00
|
|
|
#endif /* JAVA || OJI */
|
1998-04-28 09:16:06 +04:00
|
|
|
return JS_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
PR_STATIC_CALLBACK(JSBool)
|
|
|
|
doc_resolve_name(JSContext *cx, JSObject *obj, jsval id)
|
|
|
|
{
|
|
|
|
JSDocument *doc;
|
|
|
|
const char * name;
|
|
|
|
JSObject *layer_obj;
|
|
|
|
|
|
|
|
if (!JSVAL_IS_STRING(id))
|
|
|
|
return JS_TRUE;
|
|
|
|
|
|
|
|
name = JS_GetStringBytes(JSVAL_TO_STRING(id));
|
|
|
|
|
|
|
|
doc = JS_GetPrivate(cx, obj);
|
|
|
|
if (!doc)
|
|
|
|
return JS_TRUE;
|
|
|
|
|
|
|
|
layer_obj = lm_GetNamedLayer(doc->decoder, doc->layer_id, name);
|
|
|
|
if (layer_obj)
|
|
|
|
return JS_DefineProperty(cx, obj, name,
|
|
|
|
OBJECT_TO_JSVAL(layer_obj),
|
|
|
|
NULL, NULL,
|
|
|
|
JSPROP_ENUMERATE | JSPROP_READONLY);
|
|
|
|
|
1998-09-30 01:23:15 +04:00
|
|
|
#ifdef DOM
|
|
|
|
if (!DOM_DocObjectResolveStyleProps(cx, obj, id))
|
|
|
|
return JS_FALSE;
|
|
|
|
#else
|
1998-04-28 09:16:06 +04:00
|
|
|
if (!JSS_ResolveDocName(cx, doc->decoder->window_context, obj, id))
|
1998-09-30 01:23:15 +04:00
|
|
|
return JS_FALSE;
|
|
|
|
#endif
|
1998-04-28 09:16:06 +04:00
|
|
|
|
|
|
|
return doc_list_properties(cx, obj);
|
|
|
|
}
|
|
|
|
|
|
|
|
PR_STATIC_CALLBACK(void)
|
|
|
|
doc_finalize(JSContext *cx, JSObject *obj)
|
|
|
|
{
|
|
|
|
JSDocument *doc;
|
|
|
|
|
|
|
|
doc = JS_GetPrivate(cx, obj);
|
|
|
|
if (!doc)
|
|
|
|
return;
|
|
|
|
DROP_BACK_COUNT(doc->decoder);
|
|
|
|
JS_RemoveRoot(cx, &doc->forms);
|
|
|
|
JS_RemoveRoot(cx, &doc->links);
|
|
|
|
JS_RemoveRoot(cx, &doc->anchors);
|
|
|
|
JS_RemoveRoot(cx, &doc->applets);
|
|
|
|
JS_RemoveRoot(cx, &doc->embeds);
|
|
|
|
JS_RemoveRoot(cx, &doc->images);
|
|
|
|
JS_RemoveRoot(cx, &doc->layers);
|
|
|
|
JS_free(cx, doc);
|
|
|
|
}
|
|
|
|
|
|
|
|
JSClass lm_document_class = {
|
|
|
|
"Document", JSCLASS_HAS_PRIVATE,
|
|
|
|
JS_PropertyStub, JS_PropertyStub, doc_getProperty, doc_setProperty,
|
|
|
|
doc_list_properties, doc_resolve_name, JS_ConvertStub, doc_finalize
|
|
|
|
};
|
|
|
|
|
|
|
|
PR_STATIC_CALLBACK(JSBool)
|
|
|
|
Document(JSContext *cx, JSObject *obj,
|
|
|
|
uint argc, jsval *argv, jsval *rval)
|
|
|
|
{
|
|
|
|
return JS_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
PR_STATIC_CALLBACK(JSBool)
|
|
|
|
doc_toString(JSContext *cx, JSObject *obj,
|
|
|
|
uint argc, jsval *argv, jsval *rval)
|
|
|
|
{
|
|
|
|
/* XXX make string of whole doc for trusted scripts */
|
|
|
|
*rval = JS_GetEmptyStringValue(cx);
|
|
|
|
return JS_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
char *
|
|
|
|
LM_GetBaseHrefTag(JSContext *cx, JSPrincipals *principals)
|
|
|
|
{
|
|
|
|
char *new_origin_url;
|
|
|
|
const char *origin_url;
|
|
|
|
const char *cp, *qp, *last_slash;
|
|
|
|
char *tag;
|
|
|
|
|
|
|
|
origin_url = principals ? principals->codebase : lm_unknown_origin_str;
|
|
|
|
if (origin_url == NULL)
|
|
|
|
return NULL;
|
|
|
|
new_origin_url = 0;
|
|
|
|
cp = origin_url;
|
|
|
|
if ((qp = XP_STRCHR(cp, '"')) != 0) {
|
|
|
|
do {
|
|
|
|
new_origin_url = PR_sprintf_append(new_origin_url, "%.*s%%%x",
|
|
|
|
qp - cp, cp, *qp);
|
|
|
|
cp = qp + 1;
|
|
|
|
} while ((qp = XP_STRCHR(cp, '"')) != 0);
|
|
|
|
new_origin_url = PR_sprintf_append(new_origin_url, "%s", cp);
|
|
|
|
if (!new_origin_url) {
|
|
|
|
JS_ReportOutOfMemory(cx);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
origin_url = new_origin_url;
|
|
|
|
}
|
|
|
|
last_slash = XP_STRRCHR(origin_url, '/');
|
|
|
|
if (last_slash) {
|
|
|
|
tag = PR_smprintf("<BASE HREF=\"%.*s/\">\n",
|
|
|
|
last_slash - origin_url, origin_url);
|
|
|
|
} else {
|
|
|
|
tag = PR_smprintf("<BASE HREF=\"%s\">\n", origin_url);
|
|
|
|
}
|
|
|
|
PR_FREEIF(new_origin_url);
|
|
|
|
if (!tag)
|
|
|
|
JS_ReportOutOfMemory(cx);
|
|
|
|
return tag;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
doc_write_stream(JSContext *cx, MochaDecoder *decoder,
|
|
|
|
NET_StreamClass *stream, char *str, size_t len)
|
|
|
|
{
|
|
|
|
ET_lo_DoDocWrite(cx, decoder->window_context, stream, str, len,
|
|
|
|
decoder->doc_id);
|
|
|
|
|
|
|
|
return JS_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static char *
|
|
|
|
context_pathname(JSContext *cx, MWContext *context, int32 layer_id)
|
|
|
|
{
|
|
|
|
MWContext *parent;
|
|
|
|
int count, index;
|
|
|
|
char *name = 0;
|
|
|
|
|
|
|
|
while ((parent = context->grid_parent) != 0) {
|
|
|
|
if (context->name) {
|
|
|
|
name = PR_sprintf_append(name, "%s.", context->name);
|
|
|
|
} else {
|
|
|
|
/* XXX silly xp_cntxt.c puts newer contexts at the front! */
|
|
|
|
count = XP_ListCount(parent->grid_children);
|
|
|
|
index = XP_ListGetNumFromObject(parent->grid_children, context);
|
|
|
|
name = PR_sprintf_append(name, "%u.", count - index);
|
|
|
|
}
|
|
|
|
context = parent;
|
|
|
|
}
|
|
|
|
name = PR_sprintf_append(name, "%ld", (long)XP_DOCID(context));
|
|
|
|
if (layer_id != LO_DOCUMENT_LAYER_ID)
|
|
|
|
name = PR_sprintf_append(name, ".%ld", layer_id);
|
|
|
|
if (!name)
|
|
|
|
JS_ReportOutOfMemory(cx);
|
|
|
|
return name;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Make a wysiwyg: URL containing the context and our origin. */
|
|
|
|
char *
|
|
|
|
lm_MakeWysiwygUrl(JSContext *cx, MochaDecoder *decoder, int32 layer_id,
|
|
|
|
JSPrincipals *principals)
|
|
|
|
{
|
|
|
|
const char *origin;
|
|
|
|
const char *pathname;
|
|
|
|
char *url_string;
|
|
|
|
char *slash;
|
|
|
|
|
|
|
|
origin = principals ? principals->codebase : lm_unknown_origin_str;
|
|
|
|
if (origin == NULL)
|
|
|
|
return NULL;
|
|
|
|
pathname = context_pathname(cx, decoder->window_context, layer_id);
|
|
|
|
if (!pathname)
|
|
|
|
return NULL;
|
|
|
|
while ((slash = XP_STRCHR(pathname, '/')) != NULL) {
|
|
|
|
/* Escape '/' in pathname as "%2f" */
|
|
|
|
char *newPath;
|
|
|
|
*slash = '\0';
|
|
|
|
newPath = PR_smprintf("%s%%2f%s", pathname, slash+1);
|
|
|
|
XP_FREE((char *)pathname);
|
|
|
|
if (!newPath) {
|
|
|
|
JS_ReportOutOfMemory(cx);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
pathname = newPath;
|
|
|
|
}
|
|
|
|
url_string = PR_smprintf("wysiwyg://%s/%s", pathname, origin);
|
|
|
|
XP_FREE((char *)pathname);
|
|
|
|
if (!url_string) {
|
|
|
|
JS_ReportOutOfMemory(cx);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
return url_string;
|
|
|
|
}
|
|
|
|
|
|
|
|
static NET_StreamClass *
|
|
|
|
doc_cache_converter(JSContext *cx, MochaDecoder *decoder,
|
|
|
|
URL_Struct *url_struct, char *wysiwyg_url,
|
|
|
|
int32 layer_id)
|
|
|
|
{
|
|
|
|
NET_StreamClass * rv;
|
|
|
|
|
|
|
|
rv = ET_moz_DocCacheConverter(decoder->window_context,
|
|
|
|
url_struct, wysiwyg_url,
|
|
|
|
layer_id);
|
|
|
|
|
|
|
|
if (!rv)
|
|
|
|
JS_ReportOutOfMemory(cx);
|
|
|
|
|
|
|
|
return rv;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
NET_StreamClass *
|
|
|
|
LM_WysiwygCacheConverter(MWContext *context, URL_Struct *url_struct,
|
|
|
|
const char * wysiwyg_url, const char * base_href)
|
|
|
|
{
|
|
|
|
NET_StreamClass *cache_stream;
|
|
|
|
|
|
|
|
if (!wysiwyg_url) {
|
|
|
|
cache_stream = 0;
|
|
|
|
} else {
|
|
|
|
cache_stream = lm_DocCacheConverter(context, url_struct,
|
|
|
|
wysiwyg_url);
|
|
|
|
if (cache_stream) {
|
|
|
|
/* Wysiwyg files need a base tag that removes that URL prefix. */
|
|
|
|
if (base_href) {
|
|
|
|
(void) cache_stream->put_block(cache_stream,
|
|
|
|
base_href,
|
|
|
|
XP_STRLEN(base_href));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return cache_stream;
|
|
|
|
}
|
|
|
|
|
|
|
|
static char nscp_open_tag[] = "<" PT_NSCP_OPEN ">";
|
|
|
|
|
|
|
|
static NET_StreamClass *
|
|
|
|
doc_open_stream(JSContext *cx, MochaDecoder *decoder, JSObject *doc_obj,
|
|
|
|
const char *mime_type, JSBool replace)
|
|
|
|
{
|
|
|
|
JSDocument *doc;
|
|
|
|
MWContext *context;
|
|
|
|
char *wysiwyg_url, *tag;
|
|
|
|
JSPrincipals *principals;
|
|
|
|
URL_Struct *url_struct, *cached_url;
|
|
|
|
MochaDecoder *running;
|
|
|
|
History_entry *he;
|
|
|
|
NET_StreamClass *stream;
|
|
|
|
JSBool is_text_html;
|
|
|
|
FO_Present_Types present_type;
|
|
|
|
|
|
|
|
context = decoder->window_context;
|
|
|
|
if (!context)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
doc = JS_GetPrivate(cx, doc_obj);
|
|
|
|
if (!doc)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
/* Don't allow a script to replace a message window's contents
|
|
|
|
with its own document.write'ed content, since that would allow
|
|
|
|
them to spoof mail headers. */
|
|
|
|
if ((doc->layer_id == LO_DOCUMENT_LAYER_ID) && IS_MESSAGE_WINDOW(context))
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
/* We must be called after any loading URL has finished. */
|
|
|
|
XP_ASSERT(!decoder->url_struct);
|
|
|
|
principals = lm_GetPrincipalsFromStackFrame(cx);
|
|
|
|
wysiwyg_url = lm_MakeWysiwygUrl(cx, decoder, doc->layer_id, principals);
|
|
|
|
if (!wysiwyg_url)
|
|
|
|
return NULL;
|
|
|
|
url_struct = NET_CreateURLStruct(wysiwyg_url, NET_DONT_RELOAD);
|
|
|
|
if (!url_struct) {
|
|
|
|
XP_FREE(wysiwyg_url);
|
|
|
|
JS_ReportOutOfMemory(cx);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Set content type so it can be cached. */
|
|
|
|
StrAllocCopy(url_struct->content_type, mime_type);
|
|
|
|
url_struct->preset_content_type = TRUE;
|
|
|
|
url_struct->must_cache = TRUE;
|
|
|
|
|
|
|
|
/* Set these to null so we can goto bad from here onward. */
|
|
|
|
stream = 0;
|
|
|
|
cached_url = 0;
|
|
|
|
|
1998-06-23 01:21:28 +04:00
|
|
|
HG99880
|
1998-04-28 09:16:06 +04:00
|
|
|
|
|
|
|
/* If we're opening a stream for the window's document */
|
|
|
|
if (doc->layer_id == LO_DOCUMENT_LAYER_ID) {
|
|
|
|
/* Free any old doc before stream building, which may discard too. */
|
|
|
|
ET_lo_DiscardDocument(context);
|
|
|
|
if (replace) {
|
|
|
|
/* If replacing, flag current entry and url_struct specially. */
|
|
|
|
lm_ReplaceURL(context, url_struct);
|
|
|
|
}
|
|
|
|
present_type = FO_PRESENT;
|
|
|
|
}
|
|
|
|
/* Otherwise, we're dealing with a layer's document */
|
|
|
|
else {
|
|
|
|
const char *referer = lm_GetSubjectOriginURL(cx);
|
|
|
|
|
|
|
|
if (!referer ||
|
|
|
|
!ET_lo_PrepareLayerForWriting(context, doc->layer_id, referer)) {
|
|
|
|
goto bad;
|
|
|
|
}
|
|
|
|
lm_NewLayerDocument(decoder, doc->layer_id);
|
|
|
|
LM_SetActiveLayer(context, doc->layer_id);
|
|
|
|
present_type = FO_PRESENT_INLINE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* We must be called after any open stream has been closed. */
|
|
|
|
XP_ASSERT(!decoder->stream);
|
|
|
|
stream = ET_net_StreamBuilder(present_type, url_struct, context);
|
|
|
|
if (!stream) {
|
|
|
|
JS_ReportError(cx, "cannot open document for %s", mime_type);
|
|
|
|
goto bad;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (doc->layer_id == LO_DOCUMENT_LAYER_ID) {
|
|
|
|
/* Layout discards documents lazily, but we are now eager. */
|
|
|
|
if (!decoder->document && !lm_InitWindowContent(decoder))
|
|
|
|
goto bad;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Reset the doc_id since the context won't have a valid
|
|
|
|
* one set till we start writing out content.
|
|
|
|
*/
|
|
|
|
decoder->doc_id = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
decoder->writing_input = JS_TRUE;
|
|
|
|
if (!lm_SetInputStream(cx, decoder, stream, url_struct, JS_TRUE))
|
|
|
|
goto bad;
|
|
|
|
|
|
|
|
is_text_html = (JSBool)(!XP_STRCMP(mime_type, TEXT_HTML));
|
|
|
|
|
|
|
|
/* Only need to do this for a window's document */
|
|
|
|
if (doc->layer_id == LO_DOCUMENT_LAYER_ID) {
|
|
|
|
if (is_text_html) {
|
|
|
|
/* Feed layout an internal tag so it will create a new top state.*/
|
|
|
|
ET_lo_DoDocWrite(cx, context, stream, nscp_open_tag,
|
|
|
|
sizeof nscp_open_tag - 1, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (is_text_html || !XP_STRCMP(mime_type, TEXT_PLAIN)) {
|
|
|
|
doc_cache_converter(cx, decoder, url_struct,
|
|
|
|
wysiwyg_url, doc->layer_id);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Auto-generate a BASE HREF= tag for generated HTML documents. */
|
|
|
|
if (is_text_html) {
|
|
|
|
tag = LM_GetBaseHrefTag(cx, principals);
|
|
|
|
if (!tag)
|
|
|
|
goto bad;
|
|
|
|
(void) doc_write_stream(cx, decoder, stream, tag, XP_STRLEN(tag));
|
|
|
|
XP_FREE(tag);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (lm_SetLayerSourceURL(decoder, doc->layer_id, wysiwyg_url)) {
|
|
|
|
if ((is_text_html || !XP_STRCMP(mime_type, TEXT_PLAIN)) &&
|
|
|
|
!doc_cache_converter(cx, decoder, url_struct,
|
|
|
|
wysiwyg_url, doc->layer_id)) {
|
|
|
|
lm_SetLayerSourceURL(decoder, doc->layer_id, NULL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Drop our ref on url_struct -- decoder holds its own. */
|
|
|
|
NET_DropURLStruct(url_struct);
|
|
|
|
XP_FREE(wysiwyg_url);
|
|
|
|
return stream;
|
|
|
|
|
|
|
|
bad:
|
|
|
|
decoder->writing_input = JS_FALSE;
|
|
|
|
decoder->free_stream_on_close = JS_FALSE;
|
|
|
|
decoder->stream = 0;
|
|
|
|
decoder->stream_owner = LO_DOCUMENT_LAYER_ID;
|
|
|
|
decoder->url_struct = 0;
|
|
|
|
if (stream) {
|
|
|
|
(*stream->abort)(stream, MK_UNABLE_TO_CONVERT);
|
|
|
|
XP_DELETE(stream);
|
|
|
|
}
|
|
|
|
NET_FreeURLStruct(url_struct);
|
|
|
|
if (cached_url)
|
|
|
|
NET_FreeURLStruct(cached_url);
|
|
|
|
XP_FREE(wysiwyg_url);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static JSBool
|
|
|
|
doc_stream_active(MochaDecoder *decoder)
|
|
|
|
{
|
|
|
|
MWContext *context;
|
|
|
|
lo_TopState *top_state;
|
|
|
|
|
|
|
|
if (!decoder->writing_input)
|
|
|
|
return JS_TRUE;
|
|
|
|
|
|
|
|
context = decoder->window_context;
|
|
|
|
if (context) {
|
|
|
|
LO_LockLayout();
|
|
|
|
top_state = lo_GetMochaTopState(context);
|
|
|
|
if (top_state && top_state->input_write_level) {
|
|
|
|
LO_UnlockLayout();
|
|
|
|
return JS_TRUE;
|
|
|
|
}
|
|
|
|
LO_UnlockLayout();
|
|
|
|
}
|
|
|
|
return JS_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* XXX shared from lm_win.c for compatibility hack */
|
|
|
|
extern JSBool PR_CALLBACK
|
|
|
|
win_open(JSContext *cx, JSObject *obj, uint argc, jsval *argv, jsval *rval);
|
|
|
|
|
|
|
|
PR_STATIC_CALLBACK(JSBool)
|
|
|
|
doc_open(JSContext *cx, JSObject *obj, uint argc, jsval *argv, jsval *rval)
|
|
|
|
{
|
|
|
|
JSDocument *doc;
|
|
|
|
MochaDecoder *decoder;
|
|
|
|
JSString *str, *str2;
|
|
|
|
const char *mime_type, *options;
|
|
|
|
JSBool replace;
|
|
|
|
NET_StreamClass *stream;
|
|
|
|
|
|
|
|
if (!JS_InstanceOf(cx, obj, &lm_document_class, argv))
|
|
|
|
return JS_FALSE;
|
|
|
|
doc = JS_GetPrivate(cx, obj);
|
|
|
|
if (!doc)
|
|
|
|
return JS_TRUE;
|
|
|
|
decoder = doc->decoder;
|
|
|
|
|
|
|
|
if (argc > 2 || argv[0] == JS_GetEmptyStringValue(cx)) {
|
|
|
|
/* XXX hideous compatibility hack to call window.open */
|
|
|
|
return win_open(cx, decoder->window_object, argc, argv, rval);
|
|
|
|
}
|
|
|
|
|
|
|
|
str = str2 = 0;
|
|
|
|
mime_type = TEXT_HTML;
|
|
|
|
replace = JS_FALSE;
|
|
|
|
if (argc >= 1) {
|
|
|
|
if (!(str = JS_ValueToString(cx, argv[0])))
|
|
|
|
return JS_FALSE;
|
|
|
|
mime_type = JS_GetStringBytes(str);
|
|
|
|
if (argc >= 2) {
|
|
|
|
if (!(str2 = JS_ValueToString(cx, argv[1])))
|
|
|
|
return JS_FALSE;
|
|
|
|
options = JS_GetStringBytes(str2);
|
|
|
|
replace = (JSBool)(!XP_STRCASECMP(options, "replace"));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
stream = decoder->stream;
|
|
|
|
if (stream) {
|
|
|
|
if (doc_stream_active(decoder)) {
|
|
|
|
/* Don't close a stream being fed by netlib. */
|
|
|
|
*rval = JSVAL_NULL;
|
|
|
|
return JS_TRUE;
|
|
|
|
}
|
|
|
|
lm_ClearDecoderStream(decoder, JS_FALSE);
|
|
|
|
}
|
|
|
|
stream = doc_open_stream(cx, decoder, obj, mime_type, replace);
|
|
|
|
if (!stream)
|
|
|
|
return JS_FALSE;
|
|
|
|
*rval = OBJECT_TO_JSVAL(doc->object);
|
|
|
|
return JS_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
PR_STATIC_CALLBACK(JSBool)
|
|
|
|
doc_close(JSContext *cx, JSObject *obj, uint argc, jsval *argv, jsval *rval)
|
|
|
|
{
|
|
|
|
JSDocument *doc;
|
|
|
|
MochaDecoder *decoder;
|
|
|
|
|
|
|
|
if (!JS_InstanceOf(cx, obj, &lm_document_class, argv))
|
|
|
|
return JS_FALSE;
|
|
|
|
doc = JS_GetPrivate(cx, obj);
|
|
|
|
if (!doc)
|
|
|
|
return JS_TRUE;
|
|
|
|
decoder = doc->decoder;
|
|
|
|
if (!decoder->stream || doc_stream_active(decoder)) {
|
|
|
|
/* Don't close a closed stream, or a stream being fed by netlib. */
|
|
|
|
*rval = JSVAL_FALSE;
|
|
|
|
return JS_TRUE;
|
|
|
|
}
|
|
|
|
lm_ClearDecoderStream(decoder, JS_FALSE);
|
|
|
|
*rval = JSVAL_TRUE;
|
|
|
|
return JS_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
PR_STATIC_CALLBACK(JSBool)
|
|
|
|
doc_clear(JSContext *cx, JSObject *obj, uint argc, jsval *argv, jsval *rval)
|
|
|
|
{
|
|
|
|
JSDocument *doc;
|
|
|
|
MochaDecoder *decoder;
|
|
|
|
MWContext *context;
|
|
|
|
|
|
|
|
if (!JS_InstanceOf(cx, obj, &lm_document_class, argv))
|
|
|
|
return JS_FALSE;
|
|
|
|
doc = JS_GetPrivate(cx, obj);
|
|
|
|
if (!doc)
|
|
|
|
return JS_TRUE;
|
|
|
|
decoder = doc->decoder;
|
|
|
|
context = decoder->window_context;
|
|
|
|
if (!context)
|
|
|
|
return JS_TRUE;
|
|
|
|
if (!doc_close(cx, obj, argc, argv, rval))
|
|
|
|
return JS_FALSE;
|
|
|
|
/* XXX need to open and push a tag through layout? */
|
|
|
|
ET_PostClearView(context);
|
|
|
|
return JS_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static NET_StreamClass *
|
|
|
|
doc_get_stream(JSContext *cx, MochaDecoder *decoder, JSObject *doc_obj)
|
|
|
|
{
|
|
|
|
NET_StreamClass *stream;
|
|
|
|
JSDocument *doc;
|
|
|
|
|
|
|
|
doc = JS_GetPrivate(cx, doc_obj);
|
|
|
|
if (!doc)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
stream = decoder->stream;
|
|
|
|
if (!stream) {
|
|
|
|
stream = doc_open_stream(cx, decoder, doc_obj, TEXT_HTML, JS_FALSE);
|
|
|
|
/*
|
|
|
|
* If, at document load time, we're trying to get a stream to a layer
|
|
|
|
* that isn't the currently loading layer, then disallow it.
|
|
|
|
*/
|
|
|
|
} else if (doc->layer_id != decoder->active_layer_id &&
|
|
|
|
!decoder->load_event_sent) {
|
|
|
|
return NULL;
|
|
|
|
/*
|
|
|
|
* If we're writing to the main document or before the main document
|
|
|
|
* has completely loaded, make sure that we do all the wysiwyg
|
|
|
|
* nonsense.
|
|
|
|
*/
|
|
|
|
} else if (doc->layer_id == LO_DOCUMENT_LAYER_ID ||
|
|
|
|
!decoder->load_event_sent) {
|
|
|
|
XP_ASSERT(decoder->url_struct);
|
|
|
|
if (decoder->url_struct && !decoder->url_struct->wysiwyg_url)
|
|
|
|
ET_moz_SetMochaWriteStream(decoder);
|
|
|
|
}
|
|
|
|
return stream;
|
|
|
|
}
|
|
|
|
|
|
|
|
static JSBool
|
|
|
|
do_doc_write(JSContext *cx, JSObject *obj,
|
|
|
|
uint argc, jsval *argv, JSBool write_eol,
|
|
|
|
jsval *rval)
|
|
|
|
{
|
|
|
|
JSDocument *doc;
|
|
|
|
MochaDecoder *decoder;
|
|
|
|
MochaDecoder *running;
|
|
|
|
NET_StreamClass *stream;
|
|
|
|
uint i;
|
|
|
|
int status, total_len, len;
|
|
|
|
static char eol[] = "\n";
|
|
|
|
char * buf, * start;
|
|
|
|
JSString * str;
|
|
|
|
|
|
|
|
doc = JS_GetPrivate(cx, obj);
|
|
|
|
if (!doc)
|
|
|
|
return JS_TRUE;
|
|
|
|
|
|
|
|
if (PR_CurrentThread() == mozilla_thread)
|
|
|
|
return JS_FALSE;
|
|
|
|
|
|
|
|
decoder = doc->decoder;
|
|
|
|
stream = doc_get_stream(cx, decoder, obj);
|
|
|
|
if (!stream)
|
|
|
|
return JS_FALSE;
|
|
|
|
|
|
|
|
/* see how much space we need */
|
|
|
|
total_len = 0;
|
|
|
|
for (i = 0; i < argc; i++) {
|
|
|
|
if (JSVAL_IS_STRING(argv[i])) {
|
|
|
|
str = JSVAL_TO_STRING(argv[i]);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
str = JS_ValueToString(cx, argv[i]);
|
|
|
|
if (!str)
|
|
|
|
return JS_FALSE;
|
|
|
|
argv[i] = STRING_TO_JSVAL(str);
|
|
|
|
}
|
|
|
|
|
|
|
|
total_len += JS_GetStringLength(str);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/* see if we need to allocate space for the end of line */
|
|
|
|
if (write_eol)
|
|
|
|
total_len += XP_STRLEN(eol);
|
|
|
|
|
|
|
|
start = buf = XP_ALLOC((total_len + 1) * sizeof(char));
|
|
|
|
if (!buf)
|
|
|
|
return JS_FALSE;
|
|
|
|
|
|
|
|
buf[0] = '\0';
|
|
|
|
|
|
|
|
/* cache these so we don't need to look up each iteration */
|
|
|
|
running = JS_GetPrivate(cx, JS_GetGlobalObject(cx));
|
|
|
|
|
|
|
|
/* build the string for whatever is on the other end of the stream */
|
|
|
|
for (i = 0; i < argc; i++) {
|
|
|
|
|
|
|
|
str = JSVAL_TO_STRING(argv[i]);
|
|
|
|
len = JS_GetStringLength(str);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* JSStrings can contain NUL, not sure how well layout will
|
|
|
|
* deal with that but pass them along in case they're going
|
|
|
|
* to the imglib.
|
|
|
|
*/
|
|
|
|
/* XXXunicode */
|
|
|
|
memcpy(buf, JS_GetStringBytes(str), len);
|
|
|
|
buf += len;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/* generate a new line */
|
|
|
|
if (write_eol)
|
|
|
|
XP_STRCPY(buf, eol);
|
|
|
|
else
|
|
|
|
*buf = '\0';
|
|
|
|
|
|
|
|
if (lm_writing_context == NULL)
|
|
|
|
lm_writing_context = cx;
|
|
|
|
writing_context_counter++;
|
|
|
|
|
|
|
|
/* if we made it to here we must have a valid string */
|
|
|
|
status = ET_lo_DoDocWrite(cx, decoder->window_context, stream, start,
|
|
|
|
total_len, decoder->doc_id);
|
|
|
|
|
|
|
|
if (--writing_context_counter == 0)
|
|
|
|
lm_writing_context = NULL;
|
|
|
|
|
|
|
|
XP_FREE(start);
|
|
|
|
|
|
|
|
if (status < 0) {
|
|
|
|
*rval = JSVAL_FALSE;
|
|
|
|
return JS_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!decoder->document && !lm_InitWindowContent(decoder))
|
|
|
|
return JS_FALSE;
|
|
|
|
*rval = JSVAL_TRUE;
|
|
|
|
return JS_TRUE;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
PR_STATIC_CALLBACK(JSBool)
|
|
|
|
doc_write(JSContext *cx, JSObject *obj,
|
|
|
|
uint argc, jsval *argv, jsval *rval)
|
|
|
|
{
|
|
|
|
if (!JS_InstanceOf(cx, obj, &lm_document_class, argv))
|
|
|
|
return JS_FALSE;
|
|
|
|
|
|
|
|
return do_doc_write(cx, obj, argc, argv, JS_FALSE, rval);
|
|
|
|
}
|
|
|
|
|
|
|
|
PR_STATIC_CALLBACK(JSBool)
|
|
|
|
doc_writeln(JSContext *cx, JSObject *obj,
|
|
|
|
uint argc, jsval *argv, jsval *rval)
|
|
|
|
{
|
|
|
|
if (!JS_InstanceOf(cx, obj, &lm_document_class, argv))
|
|
|
|
return JS_FALSE;
|
|
|
|
|
|
|
|
return do_doc_write(cx, obj, argc, argv, JS_TRUE, rval);
|
|
|
|
}
|
|
|
|
|
|
|
|
PR_STATIC_CALLBACK(JSBool)
|
|
|
|
doc_capture_events(JSContext *cx, JSObject *obj,
|
|
|
|
uint argc, jsval *argv, jsval *rval)
|
|
|
|
{
|
|
|
|
JSDocument *doc;
|
|
|
|
MochaDecoder *decoder;
|
|
|
|
jsdouble d;
|
|
|
|
|
|
|
|
if (!JS_InstanceOf(cx, obj, &lm_document_class, argv))
|
|
|
|
return JS_FALSE;
|
|
|
|
doc = JS_GetPrivate(cx, obj);
|
|
|
|
if (!doc)
|
|
|
|
return JS_FALSE;
|
|
|
|
decoder=doc->decoder;
|
|
|
|
|
|
|
|
if (!decoder->window_context)
|
|
|
|
return JS_TRUE;
|
|
|
|
|
|
|
|
if (argc != 1)
|
|
|
|
return JS_TRUE;
|
|
|
|
|
|
|
|
if (!JS_ValueToNumber(cx, argv[0], &d))
|
|
|
|
return JS_FALSE;
|
|
|
|
|
|
|
|
doc->capturer.event_bit |= (uint32)d;
|
|
|
|
decoder->window_context->event_bit |= (uint32)d;
|
|
|
|
|
|
|
|
return JS_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
PR_STATIC_CALLBACK(JSBool)
|
|
|
|
doc_release_events(JSContext *cx, JSObject *obj,
|
|
|
|
uint argc, jsval *argv, jsval *rval)
|
|
|
|
{
|
|
|
|
JSDocument *doc;
|
|
|
|
JSEventCapturer *cap;
|
|
|
|
MochaDecoder *decoder;
|
|
|
|
jsdouble d;
|
|
|
|
jsint layer_index;
|
|
|
|
jsint max_layer_num;
|
|
|
|
JSObject *cap_obj;
|
|
|
|
|
|
|
|
if (!JS_InstanceOf(cx, obj, &lm_document_class, argv))
|
|
|
|
return JS_FALSE;
|
|
|
|
doc = JS_GetPrivate(cx, obj);
|
|
|
|
if (!doc)
|
|
|
|
return JS_FALSE;
|
|
|
|
decoder=doc->decoder;
|
|
|
|
|
|
|
|
if (!decoder->window_context)
|
|
|
|
return JS_TRUE;
|
|
|
|
|
|
|
|
if (argc != 1)
|
|
|
|
return JS_TRUE;
|
|
|
|
|
|
|
|
if (!JS_ValueToNumber(cx, argv[0], &d))
|
|
|
|
return JS_FALSE;
|
|
|
|
|
|
|
|
doc->capturer.event_bit &= ~(uint32)d;
|
|
|
|
decoder->window_context->event_bit &= ~(uint32)d;
|
|
|
|
|
|
|
|
/*Now we have to see if anyone else wanted that bit set. Joy!*/
|
|
|
|
/*First we check versus window */
|
|
|
|
decoder->window_context->event_bit |= decoder->event_bit;
|
|
|
|
|
|
|
|
/*Now we check versus layers */
|
|
|
|
max_layer_num = LO_GetNumberOfLayers(decoder->window_context);
|
|
|
|
|
|
|
|
for (layer_index=0; layer_index <= max_layer_num; layer_index++) {
|
|
|
|
cap_obj = LO_GetLayerMochaObjectFromId(decoder->window_context, layer_index);
|
|
|
|
if (cap_obj && (cap = JS_GetPrivate(cx, cap_obj)) != NULL)
|
|
|
|
decoder->window_context->event_bit |= cap->event_bit;
|
|
|
|
|
|
|
|
cap_obj = lm_GetDocumentFromLayerId(decoder, layer_index);
|
|
|
|
if (cap_obj && (cap = JS_GetPrivate(cx, cap_obj)) != NULL)
|
|
|
|
decoder->window_context->event_bit |= cap->event_bit;
|
|
|
|
}
|
|
|
|
|
|
|
|
return JS_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
PR_STATIC_CALLBACK(JSBool)
|
|
|
|
doc_get_selection(JSContext *cx, JSObject *obj,
|
|
|
|
uint argc, jsval *argv, jsval *rval)
|
|
|
|
{
|
|
|
|
JSDocument *doc;
|
|
|
|
MWContext *context;
|
|
|
|
JSString *str;
|
|
|
|
char *text;
|
|
|
|
|
|
|
|
if (!JS_InstanceOf(cx, obj, &lm_document_class, argv))
|
|
|
|
return JS_FALSE;
|
|
|
|
|
|
|
|
doc = JS_GetPrivate(cx, obj);
|
|
|
|
if (!doc)
|
|
|
|
return JS_FALSE;
|
|
|
|
context = doc->decoder->window_context;
|
|
|
|
|
|
|
|
text = ET_PostGetSelectedText(context);
|
|
|
|
str = lm_LocalEncodingToStr(context, text);
|
|
|
|
XP_FREE(text);
|
|
|
|
if (!str)
|
|
|
|
return JS_FALSE;
|
|
|
|
|
|
|
|
*rval = STRING_TO_JSVAL(str);
|
|
|
|
return JS_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
PR_STATIC_CALLBACK(JSBool)
|
|
|
|
doc_get_object_at(JSContext *cx, JSObject *obj,
|
|
|
|
uint argc, jsval *argv, jsval *rval)
|
|
|
|
{
|
|
|
|
JSDocument *doc;
|
|
|
|
MochaDecoder *decoder;
|
|
|
|
LO_Element *pElement;
|
|
|
|
CL_Layer *layer;
|
|
|
|
JSObject *xy_obj = 0;
|
|
|
|
LO_AnchorData *anchor;
|
|
|
|
int32 x, y;
|
|
|
|
int16 type;
|
|
|
|
|
|
|
|
if (!JS_InstanceOf(cx, obj, &lm_document_class, argv))
|
|
|
|
return JS_FALSE;
|
|
|
|
|
|
|
|
doc = JS_GetPrivate(cx, obj);
|
|
|
|
if (!doc)
|
|
|
|
return JS_FALSE;
|
|
|
|
|
|
|
|
decoder = doc->decoder;
|
|
|
|
|
|
|
|
if (argc != 2) {
|
|
|
|
JS_ReportError(cx, lm_argc_err_str);
|
|
|
|
return JS_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!decoder->window_context)
|
|
|
|
return JS_TRUE;
|
|
|
|
|
|
|
|
if (!JS_ValueToInt32(cx, argv[0], &x) || !JS_ValueToInt32(cx, argv[1], &y))
|
|
|
|
return JS_FALSE;
|
|
|
|
|
|
|
|
layer = LO_GetLayerFromId(decoder->window_context, doc->layer_id);
|
|
|
|
|
|
|
|
LO_LockLayout();
|
|
|
|
|
|
|
|
pElement = LO_XYToElement(decoder->window_context, x, y, layer);
|
|
|
|
|
|
|
|
type = pElement ? pElement->type : LO_NONE;
|
|
|
|
|
|
|
|
switch (type) {
|
|
|
|
case LO_TEXT:
|
|
|
|
anchor = pElement->lo_text.anchor_href;
|
|
|
|
if (!anchor)
|
|
|
|
*rval = JSVAL_VOID;
|
|
|
|
else
|
|
|
|
*rval = OBJECT_TO_JSVAL(anchor->mocha_object);
|
|
|
|
break;
|
|
|
|
case LO_IMAGE:
|
|
|
|
anchor = pElement->lo_image.anchor_href;
|
|
|
|
if (!anchor)
|
|
|
|
*rval = OBJECT_TO_JSVAL(pElement->lo_image.mocha_object);
|
|
|
|
else
|
|
|
|
*rval = OBJECT_TO_JSVAL(anchor->mocha_object);
|
|
|
|
break;
|
|
|
|
case LO_FORM_ELE:
|
|
|
|
*rval = OBJECT_TO_JSVAL(pElement->lo_form.mocha_object);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
*rval = OBJECT_TO_JSVAL(obj);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
LO_UnlockLayout();
|
|
|
|
|
|
|
|
return JS_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static JSFunctionSpec doc_methods[] = {
|
|
|
|
{"clear", doc_clear, 0},
|
|
|
|
{"close", doc_close, 0},
|
|
|
|
{"open", doc_open, 1},
|
|
|
|
{lm_toString_str, doc_toString, 0},
|
|
|
|
{"write", doc_write, 0},
|
|
|
|
{"writeln", doc_writeln, 0},
|
|
|
|
{"captureEvents", doc_capture_events, 1},
|
|
|
|
{"releaseEvents", doc_release_events, 1},
|
|
|
|
{"getSelection", doc_get_selection, 0},
|
|
|
|
{"getObjectAt", doc_get_object_at, 0},
|
|
|
|
{0}
|
|
|
|
};
|
|
|
|
|
|
|
|
JSObject *
|
|
|
|
lm_DefineDocument(MochaDecoder *decoder, int32 layer_id)
|
|
|
|
{
|
|
|
|
|
|
|
|
JSObject *obj;
|
|
|
|
JSContext *cx;
|
|
|
|
JSDocument *doc;
|
|
|
|
JSObject *parent;
|
|
|
|
|
|
|
|
cx = decoder->js_context;
|
|
|
|
doc = JS_malloc(cx, sizeof *doc);
|
|
|
|
if (!doc)
|
|
|
|
return NULL;
|
|
|
|
XP_BZERO(doc, sizeof *doc);
|
|
|
|
|
|
|
|
obj = lm_GetDocumentFromLayerId(decoder, layer_id);
|
|
|
|
if (obj)
|
|
|
|
return obj;
|
|
|
|
|
|
|
|
if (layer_id == LO_DOCUMENT_LAYER_ID) {
|
|
|
|
parent = decoder->window_object;
|
|
|
|
} else {
|
|
|
|
parent =
|
|
|
|
(JSObject *)LO_GetLayerMochaObjectFromId(decoder->window_context,
|
|
|
|
layer_id);
|
|
|
|
if (!parent)
|
|
|
|
parent = decoder->window_object;
|
|
|
|
}
|
|
|
|
obj = JS_DefineObject(cx, parent, lm_document_str, &lm_document_class,
|
|
|
|
decoder->document_prototype,
|
|
|
|
JSPROP_ENUMERATE|JSPROP_READONLY);
|
|
|
|
|
|
|
|
if (!obj || !JS_SetPrivate(cx, obj, doc)) {
|
|
|
|
JS_free(cx, doc);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!JS_AddNamedRoot(cx, &doc->forms, lm_forms_str) ||
|
|
|
|
!JS_AddNamedRoot(cx, &doc->links, lm_links_str) ||
|
|
|
|
!JS_AddNamedRoot(cx, &doc->anchors, lm_anchors_str) ||
|
|
|
|
!JS_AddNamedRoot(cx, &doc->applets, lm_applets_str) ||
|
|
|
|
!JS_AddNamedRoot(cx, &doc->embeds, lm_embeds_str) ||
|
|
|
|
!JS_AddNamedRoot(cx, &doc->images, lm_images_str) ||
|
1998-10-20 00:45:03 +04:00
|
|
|
!JS_AddNamedRoot(cx, &doc->layers, lm_layers_str)) {
|
1998-04-28 09:16:06 +04:00
|
|
|
/* doc_finalize will clean up the rest. */
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
doc->object = obj;
|
|
|
|
doc->decoder = HOLD_BACK_COUNT(decoder);
|
|
|
|
doc->layer_id = layer_id;
|
|
|
|
if (layer_id == LO_DOCUMENT_LAYER_ID) {
|
|
|
|
decoder->document = obj;
|
|
|
|
XP_ASSERT(decoder->window_context);
|
|
|
|
decoder->doc_id = XP_DOCID(decoder->window_context);
|
|
|
|
}
|
|
|
|
|
|
|
|
return obj;
|
|
|
|
}
|
|
|
|
|
|
|
|
JSBool
|
|
|
|
lm_InitDocumentClass(MochaDecoder *decoder)
|
|
|
|
{
|
|
|
|
JSContext *cx;
|
|
|
|
JSObject *prototype;
|
|
|
|
|
|
|
|
cx = decoder->js_context;
|
|
|
|
prototype = JS_InitClass(cx, decoder->window_object,
|
|
|
|
decoder->event_capturer_prototype,
|
|
|
|
&lm_document_class, Document, 0,
|
|
|
|
doc_props, doc_methods, NULL, NULL);
|
|
|
|
if (!prototype)
|
|
|
|
return JS_FALSE;
|
|
|
|
decoder->document_prototype = prototype;
|
|
|
|
return JS_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
JSObject *
|
|
|
|
lm_GetDocumentFromLayerId(MochaDecoder *decoder, int32 layer_id)
|
|
|
|
{
|
|
|
|
JSObject *layer_obj;
|
|
|
|
JSBool ok;
|
|
|
|
jsval val;
|
|
|
|
JSObject *rv;
|
|
|
|
|
|
|
|
LO_LockLayout();
|
|
|
|
|
|
|
|
if (layer_id == LO_DOCUMENT_LAYER_ID)
|
|
|
|
rv = decoder->document;
|
|
|
|
else {
|
|
|
|
layer_obj = LO_GetLayerMochaObjectFromId(decoder->window_context,
|
|
|
|
layer_id);
|
|
|
|
if (!layer_obj) {
|
|
|
|
LO_UnlockLayout();
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
ok = JS_LookupProperty(decoder->js_context, layer_obj,
|
|
|
|
lm_document_str, &val);
|
|
|
|
if (!ok) {
|
|
|
|
LO_UnlockLayout();
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
rv = JSVAL_IS_OBJECT(val) ? JSVAL_TO_OBJECT(val) : NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
LO_UnlockLayout();
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Clears out object references from the doc private data */
|
|
|
|
void
|
|
|
|
lm_CleanUpDocumentRoots(MochaDecoder *decoder, JSObject *obj)
|
|
|
|
{
|
|
|
|
JSDocument *doc;
|
|
|
|
|
|
|
|
doc = JS_GetPrivate(decoder->js_context, obj);
|
|
|
|
|
|
|
|
if (!doc)
|
|
|
|
return;
|
|
|
|
|
|
|
|
doc->forms = NULL;
|
|
|
|
doc->links = NULL;
|
|
|
|
doc->anchors = NULL;
|
|
|
|
doc->applets = NULL;
|
|
|
|
doc->embeds = NULL;
|
|
|
|
doc->images = NULL;
|
|
|
|
doc->layers = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Called when the content associated with a document is destroyed,
|
|
|
|
* but the document itself may not be. Cleans out object references
|
|
|
|
* from doc private data (so that the objects can be collected). Also
|
|
|
|
* deals with correctly relinquishing event capture.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
lm_CleanUpDocument(MochaDecoder *decoder, JSObject *obj)
|
|
|
|
{
|
|
|
|
JSDocument *doc;
|
|
|
|
MWContext *context;
|
|
|
|
jsint layer_index, max_layer_num;
|
|
|
|
JSObject *cap_obj;
|
|
|
|
JSEventCapturer *cap;
|
|
|
|
|
|
|
|
lm_CleanUpDocumentRoots(decoder, obj);
|
|
|
|
|
|
|
|
doc = JS_GetPrivate(decoder->js_context, obj);
|
|
|
|
if (!doc)
|
|
|
|
return;
|
|
|
|
|
|
|
|
doc->capturer.event_bit = 0;
|
|
|
|
context = decoder->window_context;
|
|
|
|
if (!context)
|
|
|
|
return;
|
|
|
|
context->event_bit = 0;
|
|
|
|
|
|
|
|
/* Now we have to see who still wants events */
|
|
|
|
/* First we check versus window */
|
|
|
|
context->event_bit |= decoder->event_bit;
|
|
|
|
|
|
|
|
/*Now we check versus layers */
|
|
|
|
max_layer_num = LO_GetNumberOfLayers(context);
|
|
|
|
|
|
|
|
for (layer_index=0; layer_index <= max_layer_num; layer_index++) {
|
|
|
|
if (doc->layer_id == layer_index)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
cap_obj = LO_GetLayerMochaObjectFromId(decoder->window_context, layer_index);
|
|
|
|
if (cap_obj && (cap = JS_GetPrivate(decoder->js_context, cap_obj)) != NULL)
|
|
|
|
context->event_bit |= cap->event_bit;
|
|
|
|
|
|
|
|
cap_obj = lm_GetDocumentFromLayerId(decoder, layer_index);
|
|
|
|
if (cap_obj && (cap = JS_GetPrivate(decoder->js_context, cap_obj)) != NULL)
|
|
|
|
context->event_bit |= cap->event_bit;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This routine needs to be callable from either the mocha or
|
|
|
|
* the mozilla threads. The call to lm_FreeWindowContent()
|
|
|
|
* may be problematic since its going to try to post
|
|
|
|
* clearTimeout() messages back to the mozilla thread if any
|
|
|
|
* are pending.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
LM_ReleaseDocument(MWContext *context, JSBool resize_reload)
|
|
|
|
{
|
|
|
|
MochaDecoder *decoder;
|
|
|
|
JSContext *cx;
|
|
|
|
|
|
|
|
if (resize_reload)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* Be defensive about JS-unaware contexts. */
|
|
|
|
cx = context->mocha_context;
|
|
|
|
if (!cx)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* Hold the context's decoder rather than calling LM_GetMochaDecoder. */
|
|
|
|
decoder = JS_GetPrivate(cx, JS_GetGlobalObject(cx));
|
|
|
|
decoder->forw_count++;
|
|
|
|
|
|
|
|
/* Turn of the capture bits for the window and context */
|
|
|
|
decoder->event_bit = 0;
|
|
|
|
decoder->window_context->event_bit = 0;
|
|
|
|
|
|
|
|
/* Set first language version back to unknown for the next document */
|
|
|
|
decoder->firstVersion = JSVERSION_UNKNOWN;
|
|
|
|
|
|
|
|
if (decoder->principals) {
|
|
|
|
/* Drop reference to JSPrincipals object */
|
|
|
|
JSPRINCIPALS_DROP(cx, decoder->principals);
|
|
|
|
decoder->principals = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Free any anonymous images. */
|
|
|
|
if (decoder->image_context)
|
|
|
|
ET_PostFreeAnonImages(context, decoder->image_context);
|
|
|
|
|
|
|
|
/* Free all the HTML-based objects and properties. */
|
|
|
|
lm_FreeWindowContent(decoder, JS_TRUE);
|
|
|
|
JS_GC(cx);
|
|
|
|
|
|
|
|
LM_PutMochaDecoder(decoder);
|
|
|
|
}
|