00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00063 #include <archon/x3d/server/field_type.H>
00064 #include <archon/x3d/server/dump.H>
00065 #include <archon/x3d/server/script_ecma.H>
00066 #include <archon/x3d/server/server.H>
00067
00068 namespace Archon
00069 {
00070 namespace X3D
00071 {
00072 namespace ECMA
00073 {
00074 namespace
00075 {
00076 void printTypeOfJsval(JSContext *c, jsval v)
00077 {
00078 switch(JS_TypeOfValue(c, v))
00079 {
00080 case JSTYPE_VOID: cerr << "VOID\n"; break;
00081 case JSTYPE_OBJECT: cerr << "OBJECT\n"; break;
00082 case JSTYPE_FUNCTION: cerr << "FUNCTION\n"; break;
00083 case JSTYPE_STRING: cerr << "STRING\n"; break;
00084 case JSTYPE_NUMBER: cerr << "NUMBER\n"; break;
00085 case JSTYPE_BOOLEAN: cerr << "BOOLEAN\n"; break;
00086 case JSTYPE_LIMIT: cerr << "LIMIT\n"; break;
00087 }
00088 }
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102 JSBool browser_print(JSContext *c, JSObject *o, uintN n, jsval *v, jsval *r)
00103 {
00104 for(unsigned i=0; i<n; ++i)
00105 {
00106 JSString *s = JS_ValueToString(c, v[i]);
00107 if(!s) return JS_FALSE;
00108 if(i) cerr << " ";
00109 cerr << JS_GetStringBytes(s);
00110 }
00111 return JS_TRUE;
00112 }
00113
00114 JSFunctionSpec globalMethods[] =
00115 {
00116 { "print", browser_print, 0 },
00117 { 0 }
00118 };
00119
00120 JSFunctionSpec browserMethods[] =
00121 {
00122 { "print", browser_print, 0 },
00123 { 0 }
00124 };
00125
00126 JSBool globalResolveOp(JSContext *, JSObject *, jsval);
00127
00128 JSClass globalClass =
00129 {
00130 "Global", 0,
00131 JS_PropertyStub, JS_PropertyStub,JS_PropertyStub, JS_PropertyStub,
00132 JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub
00133 };
00134
00135 JSClass browserClass =
00136 {
00137 "Browser", 0,
00138 JS_PropertyStub, JS_PropertyStub,JS_PropertyStub, JS_PropertyStub,
00139 JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub
00140 };
00141
00142
00143 void toJsval(JSContext *, bool v, jsval *r)
00144 {
00145 *r = v ? JSVAL_TRUE : JSVAL_FALSE;
00146 }
00147
00148 bool fromJsval(JSContext *c, jsval v, bool *r)
00149 {
00150 JSBool w;
00151 if(!JS_ValueToBoolean(c, v, &w)) return false;
00152 *r = w;
00153 return true;
00154 }
00155
00156
00157 void toJsval(JSContext *c, double v, jsval *r)
00158 {
00159 if(!JS_NewDoubleValue(c, v, r))
00160 ARCHON_THROW1(InternalException,
00161 "ECMA::toJsval: Allocation error");
00162 }
00163
00164 bool fromJsval(JSContext *c, jsval v, double *r)
00165 {
00166 jsdouble w;
00167 if(!JS_ValueToNumber(c, v, &w)) return false;
00168 *r = w;
00169 return true;
00170 }
00171
00172
00173 void toJsval(JSContext *c, int v, jsval *r)
00174 {
00175 if(!JS_NewDoubleValue(c, v, r))
00176 ARCHON_THROW1(InternalException,
00177 "ECMA::toJsval: Allocation error");
00178 }
00179
00180 bool fromJsval(JSContext *c, jsval v, int *r)
00181 {
00182 if(!JS_ValueToInt32(c, v, r)) return false;
00183 return true;
00184 }
00185
00186
00187 void toJsval(JSContext *c, string v, jsval *r)
00188 {
00189 JSString *s = JS_NewStringCopyZ(c, v.c_str());
00190 if(!s) ARCHON_THROW1(InternalException,
00191 "ECMA::toJsval: Allocation error");
00192 *r = STRING_TO_JSVAL(s);
00193 }
00194
00195 bool fromJsval(JSContext *c, jsval v, string *r)
00196 {
00197 JSString *s =
00198 JSVAL_IS_STRING(v) ? JSVAL_TO_STRING(v) : JS_ValueToString(c, v);
00199 if(!s) ARCHON_THROW1(InternalException,
00200 "ECMA::fromJsval: Allocation error");
00201 *r = string(JS_GetStringBytes(s));
00202 return true;
00203 }
00204
00205
00206 void toJsval(JSContext *c, Time v, jsval *r)
00207 {
00208 long double w;
00209 v.get(w);
00210 if(!JS_NewDoubleValue(c, w, r))
00211 ARCHON_THROW1(InternalException,
00212 "ECMA::toJsval: Allocation error");
00213 }
00214
00215 bool fromJsval(JSContext *c, jsval v, Time *r)
00216 {
00217 jsdouble w;
00218 if(!JS_ValueToNumber(c, v, &w)) return false;
00219 *r = Time(w);
00220 return true;
00221 }
00222
00223
00224
00225 template<typename T>
00226 struct SimpleValueConverter: Engine::ValueConverterBase
00227 {
00228 bool fieldWrite(JSContext *c, jsval v, NodeBase *n,
00229 const FieldBase *f, Time t) const
00230 {
00231 T w;
00232 if(!fromJsval(c, v, &w)) return false;
00233 Ref<SimpleValue<T> > u = new SimpleValue<T>(f->getType(), w);
00234 Event e(u.get(), t);
00235 f->set(n, &e, true);
00236 return true;
00237 }
00238
00239 void fieldRead(NodeBase *n, const FieldBase *f,
00240 JSContext *c, jsval *r) const
00241 {
00242 Ref<ValueBase> v = f->get(n);
00243 const SimpleValue<T> *w =
00244 dynamic_cast<const SimpleValue<T> *>(v.get());
00245 if(!w) ARCHON_THROW1(InternalException, "Illegal value type");
00246 toJsval(c, w->value, r);
00247 }
00248 };
00249
00250 struct NodeContext
00251 {
00252 Ref<NodeBase> n;
00253 vector<const FieldBase *> fields;
00254 NodeContext(Ref<NodeBase> n): n(n) {}
00255 };
00256
00257 JSBool nodeResolveOp(JSContext *, JSObject *, jsval);
00258 void nodeFinalizeOp(JSContext *, JSObject *);
00259
00260 JSClass nodeClass =
00261 {
00262 "Node", JSCLASS_HAS_PRIVATE,
00263 JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
00264 JS_EnumerateStub, nodeResolveOp, JS_ConvertStub, nodeFinalizeOp
00265 };
00266
00267 struct NodeValueConverter: Engine::ValueConverterBase
00268 {
00269 bool fieldWrite(JSContext *c, jsval v, NodeBase *n,
00270 const FieldBase *f, Time t) const
00271 {
00272 Ref<NodeBase> w;
00273 if(JSVAL_IS_NULL(v));
00274 else if(JSVAL_IS_OBJECT(v))
00275 {
00276 JSObject *o = JSVAL_TO_OBJECT(v);
00277 if(!JS_InstanceOf(c, o, &nodeClass, 0)) return false;
00278 NodeContext *nc = static_cast<NodeContext *>(JS_GetPrivate(c, o));
00279 if(!nc)
00280 ARCHON_THROW1(InternalException,
00281 "ECMA::NodeValueConverter::fieldWrite: "
00282 "Node object had no context");
00283 w = nc->n;
00284 }
00285 else return false;
00286 Ref<NodeValue> u = new NodeValue(SFNode::type, w.get());
00287 Event e(u.get(), t);
00288 f->set(n, &e, true);
00289 return true;
00290 }
00291
00292
00299 void fieldRead(NodeBase *n, const FieldBase *f,
00300 JSContext *c, jsval *r) const
00301 {
00302 Ref<ValueBase> v = f->get(n);
00303 const NodeValue *w = dynamic_cast<const NodeValue *>(v.get());
00304 if(!w) ARCHON_THROW1(InternalException, "Illegal value type");
00305 if(!w->value)
00306 {
00307 *r = JSVAL_NULL;
00308 return;
00309 }
00310 JSObject *o = JS_NewObject(c, &nodeClass, 0, 0);
00311 if(!o)
00312 ARCHON_THROW1(InternalException,
00313 "ECMA::NodeValueConverter::fieldRead: "
00314 "Could not create ECMA object");
00315 NodeContext *nc = new NodeContext(w->value);
00316 if(!JS_SetPrivate(c, o, nc))
00317 {
00318 delete nc;
00319 ARCHON_THROW1(InternalException,
00320 "ECMA::NodeValueConverter::fieldRead: "
00321 "Could not set private object data");
00322 }
00323 *r = OBJECT_TO_JSVAL(o);
00324 }
00325 };
00326
00327 struct ValueConverterMap
00328 {
00329 vector<const Engine::ValueConverterBase *> m;
00330 ValueConverterMap()
00331 {
00332 m.resize(fieldTypeIndexRoof, 0);
00333
00334 m[SFBool::index] = new SimpleValueConverter<bool>;
00335
00336
00337
00338
00339
00340
00341
00342
00343
00344
00345 m[SFDouble::index] = new SimpleValueConverter<double>;
00346
00347
00348 m[SFFloat::index] = new SimpleValueConverter<double>;
00349
00350
00351
00352
00353
00354
00355
00356 m[SFInt32::index] = new SimpleValueConverter<int>;
00357
00358
00359 m[SFNode::index] = new NodeValueConverter;
00360
00361
00362
00363
00364
00365
00366
00367 m[SFString::index] = new SimpleValueConverter<string>;
00368
00369
00370 m[SFTime::index] = new SimpleValueConverter<Time>;
00371
00372
00373
00374
00375
00376
00377
00378
00379
00380
00381
00382
00383
00384
00385
00386 }
00387 };
00388
00389 const Engine::ValueConverterBase *getValueConverter(const FieldType *t)
00390 {
00391 static ValueConverterMap m;
00392 return m.m[t->getIndex()];
00393 }
00394
00395
00396
00397 struct Invocation
00398 {
00399 Engine *engine;
00400 Time timestamp;
00401 Invocation(Engine *engine, Time timestamp):
00402 engine(engine), timestamp(timestamp) {}
00403 };
00404
00405 JSBool sfColorConstructOp(JSContext *c, JSObject *o, uintN n, jsval *v, jsval *r)
00406 {
00407 cerr << "CONSTRUCT(" << n << ")\n";
00408 return JS_TRUE;
00409 }
00410
00411 JSClass sfColorClass =
00412 {
00413 "SFColor", 0,
00414 JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
00415 JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub,
00416 0, 0, 0, sfColorConstructOp
00417 };
00418
00419 JSBool globalResolveOp(JSContext *c, JSObject *o, jsval i)
00420 {
00421 if(!JSVAL_IS_STRING(i))
00422 ARCHON_THROW1(InternalException,
00423 "ECMA::nodeResolveOp: "
00424 "property ID was not a string");
00425 string n = JS_GetStringBytes(JSVAL_TO_STRING(i));
00426 cerr << "(" << n << ")\n";
00427 if(n == "SFColor")
00428 {
00429
00430 JS_DefineObject(c, o, "SFColor", &sfColorClass, 0, JSPROP_ENUMERATE);
00431
00432 }
00433 return true;
00434 }
00435
00436
00437
00438 Ref<CustomFieldBase> fetchCustomField(JSContext *c, jsval i,
00439 Engine::Field **f = 0,
00440 Script **s = 0,
00441 Time *t = 0)
00442 {
00443 const Invocation *invocation =
00444 static_cast<const Invocation *>(JS_GetContextPrivate(c));
00445 if(!invocation)
00446 ARCHON_THROW1(InternalException,
00447 "ECMA::fetchCustomField: "
00448 "No bound invocation");
00449 Engine *engine = invocation->engine;
00450 Script *containingNode = engine->containingNode;
00451 if(!JSVAL_IS_INT(i))
00452 ARCHON_THROW1(InternalException,
00453 "ECMA::fetchCustomField: "
00454 "Unexpected type of property ID");
00455 int j = JSVAL_TO_INT(i);
00456 int n = containingNode->getNumberOfCustomFields();
00457 if(j<0 || j>n)
00458 ARCHON_THROW1(InternalException,
00459 "ECMA::fetchCustomField: "
00460 "Property ID out of range");
00461 if(f) *f = engine->getField(j);
00462 if(s) *s = containingNode;
00463 if(t) *t = invocation->timestamp;
00464 return containingNode->getCustomFieldNoLock(j);
00465 }
00466
00467 void errorReporter(JSContext *context, const char *message,
00468 JSErrorReport *report)
00469 {
00470 const Invocation *invocation =
00471 static_cast<const Invocation *>(JS_GetContextPrivate(context));
00472 if(!invocation)
00473 ARCHON_THROW1(InternalException,
00474 "ECMA::errorReporter: "
00475 "No bound invocation");
00476 Logger *logger =
00477 invocation->engine->containingNode->context->server->getLogger();
00478 if(report)
00479 logger->log(invocation->engine->getSourceName() + ":" +
00480 Text::toString(report->lineno) + ": " + message);
00481 else
00482 logger->log(invocation->engine->getSourceName() + ": " + message);
00483 }
00484
00485 JSBool setPropertyNo(JSContext *c, JSObject *, jsval i, jsval *)
00486 {
00487 Ref<CustomFieldBase> f = fetchCustomField(c, i);
00488 string m = "AccessError: " + f->getName() + " is not writable";
00489 JS_ReportError(c, "%s", m.c_str());
00490 return JS_FALSE;
00491 }
00492
00493 JSBool getPropertyNo(JSContext *c, JSObject *, jsval i, jsval *)
00494 {
00495 Ref<CustomFieldBase> f = fetchCustomField(c, i);
00496 string m = "Access error: " + f->getName() + " is not readable";
00497 JS_ReportError(c, "%s", m.c_str());
00498 return JS_FALSE;
00499 }
00500
00501
00502
00503
00504 const FieldBase *fetchNodeField(JSContext *c, JSObject *o,
00505 jsval i, NodeBase **n)
00506 {
00507 NodeContext *nc = static_cast<NodeContext *>(JS_GetPrivate(c, o));
00508 if(!nc)
00509 ARCHON_THROW1(InternalException,
00510 "ECMA::fetchNodeField: "
00511 "Object had no context");
00512 if(!JSVAL_IS_INT(i))
00513 ARCHON_THROW1(InternalException,
00514 "ECMA::fetchNodeField: "
00515 "Unexpected type of property ID");
00516 int j = JSVAL_TO_INT(i);
00517 if(j < 0 || unsigned(j) > nc->fields.size())
00518 ARCHON_THROW1(InternalException,
00519 "ECMA::fetchNodeField: "
00520 "Property ID out of range");
00521 if(n) *n = nc->n.get();
00522 return nc->fields[j];
00523 }
00524
00525 JSBool getNodeField(JSContext *c, JSObject *o, jsval i, jsval *v)
00526 {
00527 NodeBase *n;
00528 const FieldBase *f = fetchNodeField(c, o, i, &n);
00529 getValueConverter(f->getType())->fieldRead(n, f, c, v);
00530 return JS_TRUE;
00531 }
00532
00533 JSBool setNodeField(JSContext *c, JSObject *o, jsval i, jsval *v)
00534 {
00535 const Invocation *invocation =
00536 static_cast<const Invocation *>(JS_GetContextPrivate(c));
00537 if(!invocation)
00538 ARCHON_THROW1(InternalException,
00539 "ECMA::setNodeField: "
00540 "No bound invocation");
00541 NodeBase *n;
00542 const FieldBase *f = fetchNodeField(c, o, i, &n);
00543 return getValueConverter(f->getType())->
00544 fieldWrite(c, *v, n, f, invocation->timestamp) ?
00545 JS_TRUE : JS_FALSE;
00546 }
00547
00554 JSBool nodeResolveOp(JSContext *c, JSObject *o, jsval i)
00555 {
00556 const Invocation *invocation =
00557 static_cast<const Invocation *>(JS_GetContextPrivate(c));
00558 if(!invocation)
00559 ARCHON_THROW1(InternalException,
00560 "ECMA::nodeResolveOp: "
00561 "No bound invocation");
00562 NodeContext *nc = static_cast<NodeContext *>(JS_GetPrivate(c, o));
00563 if(!nc)
00564 ARCHON_THROW1(InternalException,
00565 "ECMA::nodeResolveOp: "
00566 "Object had no context");
00567 if(!JSVAL_IS_STRING(i))
00568 ARCHON_THROW1(InternalException,
00569 "ECMA::nodeResolveOp: "
00570 "property ID was not a string");
00571 string n = JS_GetStringBytes(JSVAL_TO_STRING(i));
00572 const FieldBase *f = nc->n->getType()->lookupField(n);
00573 if(!f) return true;
00574 int j = nc->fields.size();
00575 if(j==255) ARCHON_THROW1(InternalException,
00576 "ECMA::nodeResolveOp: "
00577 "Too many fields in node");
00578 bool writable =
00579 invocation->engine->containingNode->getDirectOutput() &&
00580 f->getIsEventTarget();
00581 bool readable = f->getIsEventSource();
00582 if(!JS_DefinePropertyWithTinyId(c, o, n.c_str(), j,
00583 JSVAL_NULL,
00584 readable ? getNodeField : getPropertyNo,
00585 writable ? setNodeField : setPropertyNo,
00586 JSPROP_ENUMERATE|JSPROP_PERMANENT))
00587 ARCHON_THROW1(InternalException,
00588 "ECMA::nodeResolveOp: "
00589 "Could not define field as global property");
00590 nc->fields.push_back(f);
00591 return true;
00592 }
00593
00594 void nodeFinalizeOp(JSContext *c, JSObject *o)
00595 {
00596 NodeContext *nc = static_cast<NodeContext *>(JS_GetPrivate(c, o));
00597 if(!nc)
00598 ARCHON_THROW1(InternalException,
00599 "ECMA::nodeFinalizeOp: "
00600 "Object had no context");
00601 delete nc;
00602 }
00603 }
00604
00605 JSBool Engine::getCustomField(JSContext *c, JSObject *, jsval i, jsval *v)
00606 {
00607 Field *g;
00608 Script *s;
00609 Ref<CustomFieldBase> f = fetchCustomField(c, i, &g, &s);
00610 g->valueConverter->fieldRead(s, f.get(), c, v);
00611 return JS_TRUE;
00612 }
00613
00614 JSBool Engine::setCustomField(JSContext *c, JSObject *, jsval i, jsval *v)
00615 {
00616 Field *g;
00617 Script *s;
00618 Time t;
00619 Ref<CustomFieldBase> f = fetchCustomField(c, i, &g, &s, &t);
00620 return g->valueConverter->
00621 fieldWrite(c, *v, s, f.get(), t) ? JS_TRUE : JS_FALSE;
00622 }
00623
00624 Engine::Engine(Script *containingNode, string sourceCode,
00625 string sourceName, int sourceLine):
00626 containingNode(containingNode),
00627 sourceName(sourceName)
00628 {
00629
00630 spiderMonkeyRuntime = JS_Init(1000000L);
00631 if(!spiderMonkeyRuntime)
00632 ARCHON_THROW1(InternalException,
00633 "ECMA::Engine::Engine: Can't create "
00634 "SpiderMonkey runtime");
00635
00636 spiderMonkeyContext = JS_NewContext(spiderMonkeyRuntime, 8192);
00637 if(!spiderMonkeyContext)
00638 ARCHON_THROW1(InternalException,
00639 "ECMA::Engine::Engine: Can't create "
00640 "SpiderMonkey context");
00641
00642
00643 Invocation invocation(this, containingNode->
00644 context->server->getNextTimeStamp());
00645 JS_SetContextPrivate(spiderMonkeyContext, &invocation);
00646
00647 JS_SetErrorReporter(spiderMonkeyContext, errorReporter);
00648
00649
00650 JSObject *globalObject =
00651 JS_NewObject(spiderMonkeyContext, &globalClass, 0, 0);
00652 JS_InitStandardClasses(spiderMonkeyContext, globalObject);
00653 JS_DefineFunctions(spiderMonkeyContext, globalObject, globalMethods);
00654
00655
00656 JSObject *browserObject =
00657 JS_DefineObject(spiderMonkeyContext, globalObject, "Browser",
00658 &browserClass, 0, JSPROP_ENUMERATE);
00659 JS_DefineFunctions(spiderMonkeyContext, browserObject, browserMethods);
00660
00661
00662 unsigned n = containingNode->getNumberOfCustomFields();
00663 if(n>255) ARCHON_THROW1(InternalException,
00664 "ECMA::Engine::Engine: "
00665 "Too many custom fields");
00666 fields.reserve(n);
00667 for(unsigned i=0; i<n; ++i)
00668 {
00669 Ref<CustomFieldBase> f = containingNode->getCustomFieldNoLock(i);
00670 bool writable = f->getIsEventSource() || !f->getIsEventTarget();
00671 bool readable = !f->getIsEventSource() || f->getIsEventTarget();
00672 if(!JS_DefinePropertyWithTinyId(spiderMonkeyContext,
00673 globalObject, f->getName().c_str(),
00674 i, JSVAL_NULL,
00675 readable ? getCustomField : getPropertyNo,
00676 writable ? setCustomField : setPropertyNo,
00677 JSPROP_ENUMERATE|JSPROP_PERMANENT))
00678 ARCHON_THROW1(InternalException,
00679 "ECMA::Engine::Engine: "
00680 "Could not define field as global property");
00681 fields.push_back(Field(getValueConverter(f->getType())));
00682 }
00683
00684
00685 jsval v;
00686 uintN lineno = sourceLine < 1 ? 1 : sourceLine;
00687 JS_EvaluateScript(spiderMonkeyContext, globalObject,
00688 sourceCode.c_str(), sourceCode.size(),
00689 sourceName.c_str(), lineno, &v);
00690
00691
00692
00693
00694
00695
00696 for(unsigned i=0; i<n; ++i)
00697 {
00698 Ref<CustomFieldBase> f = containingNode->getCustomFieldNoLock(i);
00699 if(f->getIsEventSource() && !f->getIsEventTarget()) continue;
00700 if(!JS_LookupProperty(spiderMonkeyContext,
00701 globalObject, f->getName().c_str(), &v))
00702 ARCHON_THROW1(InternalException,
00703 "ECMA::Engine::Engine: "
00704 "JS_LookupProperty failed");
00705 if(JS_TypeOfValue(spiderMonkeyContext, v) != JSTYPE_FUNCTION)
00706 continue;
00707 jsval &h = fields[i].handler;
00708 h = v;
00709
00710
00711
00712
00713
00714 JS_AddRoot(spiderMonkeyContext, &h);
00715 }
00716
00717
00718 if(!JS_LookupProperty(spiderMonkeyContext,
00719 globalObject, "initialize", &v))
00720 ARCHON_THROW1(InternalException,
00721 "ECMA::Engine::Engine: "
00722 "JS_LookupProperty failed");
00723 if(JS_TypeOfValue(spiderMonkeyContext, v) == JSTYPE_FUNCTION)
00724 {
00725 jsval r;
00726 JS_CallFunctionValue(spiderMonkeyContext, globalObject, v, 0, 0, &r);
00727 }
00728
00729
00730 JS_SetContextPrivate(spiderMonkeyContext, 0);
00731 }
00732
00733 Engine::~Engine()
00734 {{
00735 for(unsigned i=0; i<containingNode->getNumberOfCustomFields(); ++i)
00736 {
00737 jsval &h = fields[i].handler;
00738 if(JSVAL_IS_NULL(h)) continue;
00739 JS_RemoveRoot(spiderMonkeyContext, &h);
00740 }
00741
00742 JS_DestroyContext(spiderMonkeyContext);
00743 JS_Finish(spiderMonkeyRuntime);
00744
00745 }}
00746
00752 void Engine::handleEvent(int i, Time timestamp)
00753 {
00754
00755 Invocation invocation(this, containingNode->
00756 context->server->getNextTimeStamp());
00757 JS_SetContextPrivate(spiderMonkeyContext, &invocation);
00758
00759 int n = fields.size();
00760 if(i<0 || i>n)
00761 ARCHON_THROW1(InternalException,
00762 "ECMA::Engine::handleEvent: "
00763 "fieldIndex out of range");
00764 jsval handler = fields[i].handler;
00765 if(JSVAL_IS_NULL(handler)) return;
00766 Ref<CustomFieldBase> f = containingNode->getCustomFieldNoLock(i);
00767 jsval v[2];
00768 fields[i].valueConverter->fieldRead
00769 (containingNode, f.get(), spiderMonkeyContext, &v[0]);
00770 long double t1;
00771 timestamp.get(t1);
00772 jsdouble t2 = t1;
00773 if(!JS_NewDoubleValue(spiderMonkeyContext, t2, &v[1]))
00774 ARCHON_THROW1(InternalException,
00775 "ECMA::Engine::handleEvent: "
00776 "Allocation error");
00777 JSObject *globalObject = JS_GetGlobalObject(spiderMonkeyContext);
00778 jsval r;
00779 JS_CallFunctionValue(spiderMonkeyContext,
00780 globalObject, handler, 2, v, &r);
00781
00782
00783 JS_SetContextPrivate(spiderMonkeyContext, 0);
00784 }
00785 }
00786 }
00787 }