/* -*- 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 named SPANS in the current document. * * Chris Toshok, 26-Feb-1998 */ #ifdef DOM #include "lm.h" #include "lo_ele.h" #include "prtypes.h" #include "pa_tags.h" #include "layout.h" enum span_array_slot { SPAN_ARRAY_LENGTH = -1 }; static JSPropertySpec span_array_props[] = { { lm_length_str, SPAN_ARRAY_LENGTH, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT}, { 0 } }; extern JSClass lm_span_array_class; PR_STATIC_CALLBACK(JSBool) span_array_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) { JSObjectArray *array; MochaDecoder *decoder; MWContext *context; jsint count, slot; lo_NameList *span; int32 active_layer_id; /* XP_TRACE (("span_array_getProperty called\n")); */ if (!JSVAL_IS_INT(id)) return JS_TRUE; slot = JSVAL_TO_INT(id); array = JS_GetInstancePrivate(cx, obj, &lm_span_array_class, NULL); if (!array) return JS_TRUE; decoder = array->decoder; context = decoder->window_context; if (!context) return JS_TRUE; LO_LockLayout(); switch (slot) { case SPAN_ARRAY_LENGTH: active_layer_id = LM_GetActiveLayer(context); LM_SetActiveLayer(context, array->layer_id); count = LO_EnumerateSpans(context, array->layer_id); LM_SetActiveLayer(context, active_layer_id); if (count > array->length) array->length = count; *vp = INT_TO_JSVAL(count); break; default: if (slot < 0) { /* Don't mess with user-defined or method properties. */ LO_UnlockLayout(); return JS_TRUE; } if (slot >= array->length) array->length = slot + 1; span = LO_GetSpanByIndex(context, array->layer_id, (uint)slot); XP_TRACE (("span = %p\n", span)); if (span) { *vp = OBJECT_TO_JSVAL(LM_ReflectSpan(context, span, NULL, array->layer_id, (uint)slot)); } break; } LO_UnlockLayout(); return JS_TRUE; } PR_STATIC_CALLBACK(void) span_array_finalize(JSContext *cx, JSObject *obj) { JSObjectArray *array; array = JS_GetPrivate(cx, obj); if (!array) return; DROP_BACK_COUNT(array->decoder); JS_free(cx, array); } JSClass lm_span_array_class = { "SpanArray", JSCLASS_HAS_PRIVATE, JS_PropertyStub, JS_PropertyStub, span_array_getProperty, span_array_getProperty, JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, span_array_finalize }; PR_STATIC_CALLBACK(JSBool) SpanArray(JSContext *cx, JSObject *obj, uint argc, jsval *argv, jsval *rval) { return JS_TRUE; } static JSObject * reflect_span_array(MochaDecoder *decoder, JSClass *clasp, JSNative constructor, JSObject *document) { JSContext *cx; JSObject *obj, *prototype; JSObjectArray *array; JSDocument *doc; cx = decoder->js_context; doc = JS_GetPrivate(cx, document); if (!doc) return NULL; prototype = JS_InitClass(cx, decoder->window_object, NULL, clasp, constructor, 0, span_array_props, NULL, NULL, NULL); if (!prototype) return NULL; array = JS_malloc(cx, sizeof *array); if (!array) return NULL; XP_BZERO(array, sizeof *array); obj = JS_NewObject(cx, clasp, prototype, document); if (!obj || !JS_SetPrivate(cx, obj, array)) { JS_free(cx, array); return NULL; } array->decoder = HOLD_BACK_COUNT(decoder); array->layer_id = doc->layer_id; return obj; } JSObject * lm_GetSpanArray(MochaDecoder *decoder, JSObject *document) { JSObject *obj; JSDocument *doc; doc = JS_GetPrivate(decoder->js_context, document); if (!doc) return NULL; obj = doc->spans; if (obj) return obj; obj = reflect_span_array(decoder, &lm_span_array_class, SpanArray, document); doc->spans = obj; return obj; } JSBool PR_CALLBACK span_setProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp); JSBool PR_CALLBACK span_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp); void PR_CALLBACK span_Finalize(JSContext *cx, JSObject *obj); enum { SPAN_NAME = -1, SPAN_FONTFAMILY = -2, SPAN_FONTWEIGHT = -3, SPAN_FONTSIZE = -4, SPAN_FONTSLANT = -5, SPAN_COLOR = -6, SPAN_BGCOLOR = -7 }; static JSPropertySpec span_props[] = { {"name", SPAN_NAME, JSPROP_ENUMERATE | JSPROP_READONLY }, {"fontFamily", SPAN_FONTFAMILY, JSPROP_ENUMERATE }, {"fontWeight", SPAN_FONTWEIGHT, JSPROP_ENUMERATE }, {"fontSize", SPAN_FONTSIZE, JSPROP_ENUMERATE }, {"fontSlant", SPAN_FONTSLANT, JSPROP_ENUMERATE }, {"color", SPAN_COLOR, JSPROP_ENUMERATE }, {"bgcolor", SPAN_BGCOLOR, JSPROP_ENUMERATE }, { 0 } }; static JSClass lm_span_class = { "Span", JSCLASS_HAS_PRIVATE, JS_PropertyStub, JS_PropertyStub, span_getProperty, span_setProperty, JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, span_Finalize }; /* Base span element type. */ typedef struct JSSpan { MochaDecoder *decoder; int32 layer_id; uint index; JSString *text; JSString *name; } JSSpan; PR_STATIC_CALLBACK(JSBool) Span(JSContext *cx, JSObject *obj, uint argc, jsval *argv, jsval *rval) { return JS_TRUE; } JSObject * LM_ReflectSpan(MWContext *context, lo_NameList *name_rec, PA_Tag * tag, int32 layer_id, uint index) { JSObject *obj, *array_obj, *document; MochaDecoder *decoder; JSContext *cx; JSObjectArray *array; JSSpan *named_span; lo_TopState *top_state; PRHashTable *map; JSString *str; obj = name_rec->mocha_object; if (obj) return obj; decoder = LM_GetMochaDecoder(context); if (!decoder) return NULL; cx = decoder->js_context; top_state = lo_GetMochaTopState(context); if (top_state->resize_reload) { map = lm_GetIdToObjectMap(decoder); if (map) obj = (JSObject *)PR_HashTableLookup(map, LM_GET_MAPPING_KEY(LM_SPANS, layer_id, index)); if (obj) { name_rec->mocha_object = obj; LM_PutMochaDecoder(decoder); return obj; } } /* Get the document object that will hold this span */ document = lm_GetDocumentFromLayerId(decoder, layer_id); if (!document) { LM_PutMochaDecoder(decoder); return NULL; } array_obj = lm_GetSpanArray(decoder, document); if (!array_obj) { LM_PutMochaDecoder(decoder); return NULL; } array = JS_GetPrivate(cx, array_obj); if (!array) { LM_PutMochaDecoder(decoder); return NULL; } named_span = JS_malloc(cx, sizeof *named_span); if (!named_span) { LM_PutMochaDecoder(decoder); return NULL; } XP_BZERO(named_span, sizeof *named_span); obj = JS_NewObject(cx, &lm_span_class, decoder->span_prototype, document); if (!obj || !JS_SetPrivate(cx, obj, named_span)) { JS_free(cx, named_span); LM_PutMochaDecoder(decoder); return NULL; } /* Put obj into the document.spans array. */ JS_DefineProperty(cx, array_obj, (char *) name_rec->name, OBJECT_TO_JSVAL(obj), NULL, NULL, JSPROP_ENUMERATE|JSPROP_READONLY); JS_AliasElement(cx, array_obj, (char *) name_rec->name, index); /* Put it in the index to object hash table */ map = lm_GetIdToObjectMap(decoder); if (map) { PR_HashTableAdd(map, LM_GET_MAPPING_KEY(LM_SPANS, layer_id, index), obj); } if ((jsint) index >= array->length) array->length = index + 1; named_span->decoder = HOLD_BACK_COUNT(decoder); named_span->layer_id = layer_id; named_span->index = index; if (name_rec->element && name_rec->element->type == LO_TEXT) { str = lm_LocalEncodingToStr(context, (char *) name_rec->element->lo_text.text); if (!str || !JS_LockGCThing(cx, str)) { LM_PutMochaDecoder(decoder); return NULL; } named_span->text = str; } str = JS_NewStringCopyZ(cx, (char *) name_rec->name); if (!str || !JS_LockGCThing(cx, str)) { LM_PutMochaDecoder(decoder); return NULL; } named_span->name = str; name_rec->mocha_object = obj; /* see if there are any attributes for event handlers */ if(tag) { PA_Block onclick, onmouseover, onmouseout, onmousedown, onmouseup, ondblclick, id; /* don't hold the layout lock across compiles */ LO_UnlockLayout(); onclick = lo_FetchParamValue(context, tag, PARAM_ONCLICK); onmouseover = lo_FetchParamValue(context, tag, PARAM_ONMOUSEOVER); onmouseout = lo_FetchParamValue(context, tag, PARAM_ONMOUSEOUT); onmousedown = lo_FetchParamValue(context, tag, PARAM_ONMOUSEDOWN); onmouseup = lo_FetchParamValue(context, tag, PARAM_ONMOUSEUP); ondblclick = lo_FetchParamValue(context, tag, PARAM_ONDBLCLICK); id = lo_FetchParamValue(context, tag, PARAM_ID); if (onclick) { (void) lm_CompileEventHandler(decoder, id, tag->data, tag->newline_count, obj, PARAM_ONCLICK, onclick); PA_FREE(onclick); #if 0 anchor_data->event_handler_present = TRUE; #endif } if (onmouseover) { (void) lm_CompileEventHandler(decoder, id, tag->data, tag->newline_count, obj, PARAM_ONMOUSEOVER, onmouseover); PA_FREE(onmouseover); #if 0 anchor_data->event_handler_present = TRUE; #endif } if (onmouseout) { (void) lm_CompileEventHandler(decoder, id, tag->data, tag->newline_count, obj, PARAM_ONMOUSEOUT, onmouseout); PA_FREE(onmouseout); #if 0 anchor_data->event_handler_present = TRUE; #endif } if (onmousedown) { (void) lm_CompileEventHandler(decoder, id, tag->data, tag->newline_count, obj, PARAM_ONMOUSEDOWN, onmousedown); PA_FREE(onmousedown); #if 0 anchor_data->event_handler_present = TRUE; #endif } if (onmouseup) { (void) lm_CompileEventHandler(decoder, id, tag->data, tag->newline_count, obj, PARAM_ONMOUSEUP, onmouseup); PA_FREE(onmouseup); #if 0 anchor_data->event_handler_present = TRUE; #endif } if (ondblclick) { (void) lm_CompileEventHandler(decoder, id, tag->data, tag->newline_count, obj, PARAM_ONDBLCLICK, ondblclick); PA_FREE(ondblclick); #if 0 anchor_data->event_handler_present = TRUE; #endif } if (id) PA_FREE(id); LO_LockLayout(); } LM_PutMochaDecoder(decoder); return obj; } JSBool PR_CALLBACK span_setProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) { JSSpan *span; lo_NameList *name_rec; jsint slot; JSBool ok; LO_Color *rgb; char *font_family, *font_weight, *font_slant; int32 font_size; if (!JSVAL_IS_INT(id)) { return JS_TRUE; } slot = JSVAL_TO_INT(id); span = JS_GetInstancePrivate(cx, obj, &lm_span_class, NULL); if (!span) { return JS_TRUE; } LO_LockLayout(); name_rec = LO_GetSpanByIndex(span->decoder->window_context, span->layer_id, span->index); if (!name_rec) { LO_UnlockLayout(); return JS_TRUE; /* Try to handle this case gracefully. */ } ok = JS_TRUE; switch (slot) { case SPAN_COLOR: LO_UnlockLayout(); if (!lm_jsval_to_rgb(cx, vp, &rgb)) return JS_FALSE; ET_TweakSpan(span->decoder->window_context, name_rec, rgb, 0, SP_SetColor, span->decoder->doc_id); break; case SPAN_BGCOLOR: LO_UnlockLayout(); if (!lm_jsval_to_rgb(cx, vp, &rgb)) return JS_FALSE; ET_TweakSpan(span->decoder->window_context, name_rec, rgb, 0, SP_SetBackground, span->decoder->doc_id); break; case SPAN_FONTFAMILY: LO_UnlockLayout(); font_family = JS_GetStringBytes(JSVAL_TO_STRING(*vp)); ET_TweakSpan(span->decoder->window_context, name_rec, font_family, 0, SP_SetFontFamily, span->decoder->doc_id); break; case SPAN_FONTWEIGHT: LO_UnlockLayout(); font_weight = JS_GetStringBytes(JSVAL_TO_STRING(*vp)); ET_TweakSpan(span->decoder->window_context, name_rec, font_weight, 0, SP_SetFontWeight, span->decoder->doc_id); break; case SPAN_FONTSIZE: LO_UnlockLayout(); font_size = JSVAL_TO_INT(*vp); ET_TweakSpan(span->decoder->window_context, name_rec, NULL, font_size, SP_SetFontSize, span->decoder->doc_id); break; case SPAN_FONTSLANT: LO_UnlockLayout(); font_slant = JS_GetStringBytes(JSVAL_TO_STRING(*vp)); ET_TweakSpan(span->decoder->window_context, name_rec, font_slant, 0, SP_SetFontSlant, span->decoder->doc_id); break; default: ok = JS_FALSE; break; } return ok; } JSBool PR_CALLBACK span_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) { XP_TRACE (("Span get property called...\n")); return JS_FALSE; } void PR_CALLBACK span_Finalize(JSContext *cx, JSObject *obj) { JSSpan *span; MochaDecoder *decoder; MWContext *context; lo_NameList *name_rec; span = JS_GetPrivate(cx, obj); if (!span) return; decoder = span->decoder; context = decoder->window_context; if (context) { LO_LockLayout(); name_rec = LO_GetSpanByIndex(context, span->layer_id, span->index); if (name_rec && name_rec->mocha_object == obj) name_rec->mocha_object = NULL; LO_UnlockLayout(); } DROP_BACK_COUNT(decoder); JS_UnlockGCThing(cx, span->text); JS_UnlockGCThing(cx, span->name); JS_free(cx, span); } JSBool lm_InitSpanClass(MochaDecoder *decoder) { JSContext *cx; JSObject *prototype; cx = decoder->js_context; prototype = JS_InitClass(cx, decoder->window_object, decoder->event_receiver_prototype, &lm_span_class, Span, 0, span_props, NULL, NULL, NULL); if (!prototype) return JS_FALSE; decoder->span_prototype = prototype; return JS_TRUE; } #endif /* DOM */