1// Copyright 2014 PDFium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6
7#ifndef _JS_DEFINE_H_
8#define _JS_DEFINE_H_
9
10typedef v8::Value			JSValue;
11typedef v8::Handle<v8::Object>	JSObject;
12typedef v8::Handle<v8::Object>	JSFXObject;
13typedef unsigned		JSBool;
14
15struct JSConstSpec
16{
17	const wchar_t* pName;
18	double number;
19	const wchar_t* string;
20	FX_BYTE t; //0:double 1:str
21};
22
23struct JSPropertySpec
24{
25	const wchar_t* pName;
26	v8::AccessorGetterCallback pPropGet;
27	v8::AccessorSetterCallback pPropPut;
28};
29
30struct JSMethodSpec
31{
32	const wchar_t* pName;
33	v8::FunctionCallback pMethodCall;
34	unsigned nParamNum;
35};
36
37typedef CFX_WideString	JS_ErrorString;
38
39#define JS_TRUE			(unsigned)1
40#define JS_FALSE		(unsigned)0
41
42
43#define CJS_PointsArray		CFX_ArrayTemplate<float>
44#define CJS_IntArray		CFX_ArrayTemplate<int>
45
46/* ====================================== PUBLIC DEFINE SPEC ============================================== */
47#ifndef __GNUC__
48#define JS_WIDESTRING(widestring) L#widestring
49#else
50#define JS_WIDESTRING(widestring) L""#widestring
51#endif
52
53#define OBJ_PROP_PARAMS			IFXJS_Context* cc, CJS_PropValue& vp, JS_ErrorString& sError
54#define OBJ_METHOD_PARAMS		IFXJS_Context* cc, const CJS_Parameters& params, CJS_Value& vRet, JS_ErrorString& sError
55#define BEGIN_JS_STATIC_CONST(js_class_name) JSConstSpec js_class_name::JS_Class_Consts[] = {
56#define JS_STATIC_CONST_ENTRY_NUMBER(const_name, pValue) {JS_WIDESTRING(const_name), pValue, L"", 0},
57#define JS_STATIC_CONST_ENTRY_STRING(const_name, pValue) {JS_WIDESTRING(const_name), 0, JS_WIDESTRING(pValue), 1},
58#define END_JS_STATIC_CONST() {0, 0, 0, 0}};
59
60#define BEGIN_JS_STATIC_PROP(js_class_name) JSPropertySpec js_class_name::JS_Class_Properties[] = {
61#define JS_STATIC_PROP_ENTRY(prop_name) {JS_WIDESTRING(prop_name), get_##prop_name##_static, set_##prop_name##_static},
62#define END_JS_STATIC_PROP() {0, 0, 0}};
63
64#define BEGIN_JS_STATIC_METHOD(js_class_name) JSMethodSpec js_class_name::JS_Class_Methods[] = {
65#define JS_STATIC_METHOD_ENTRY(method_name, nargs) {JS_WIDESTRING(method_name), method_name##_static, nargs},
66#define END_JS_STATIC_METHOD() {0, 0, 0}};
67#define MEMLEAKCHECK_1() ((void)0)
68#define MEMLEAKCHECK_2(main_name, sub_name) ((void)0)
69
70
71/*
72#ifdef _DEBUG
73#define MEMLEAKCHECK_1() \
74	_CrtMemState state1;\
75	_CrtMemCheckpoint(&state1);
76
77#define MEMLEAKCHECK_2(main_name,sub_name) \
78	_CrtMemState state2;\
79	_CrtMemCheckpoint(&state2);\
80	_CrtMemState diff;\
81	_CrtMemDifference(&diff,&state1,&state2);\
82	if (diff.lSizes[_NORMAL_BLOCK] > 0)\
83	{\
84		TRACE("Detected normal block memory leaks in JS Module! [%s.%s]\n",#main_name,#sub_name);\
85		_CrtMemDumpStatistics(&diff);\
86	}
87#else
88	#define MEMLEAKCHECK_1() ((void)0)
89	#define MEMLEAKCHECK_2(main_name,sub_name) ((void)0)
90#endif
91*/
92
93/* ======================================== PROP CALLBACK ============================================ */
94
95#define JS_STATIC_PROP_GET(prop_name, class_name)\
96	static void get_##prop_name##_static(JS_PROPGET_ARGS)\
97{\
98	v8::Isolate* isolate = info.GetIsolate();\
99	v8::Local<v8::Context> context = isolate->GetCurrentContext();\
100	v8::Local<v8::Value> v = context->GetEmbedderData(1);\
101	ASSERT(!v.IsEmpty());\
102	if(v.IsEmpty()) return;\
103	v8::Handle<v8::External> field = v8::Handle<v8::External>::Cast(v);\
104	IFXJS_Runtime* pRuntime = (IFXJS_Runtime*)field->Value();\
105	IFXJS_Context* cc = pRuntime->GetCurrentContext();\
106	CJS_PropValue value(isolate);\
107	value.StartGetting();\
108	CJS_Object* pJSObj = (CJS_Object*)JS_GetPrivate(isolate,info.Holder());\
109	ASSERT(pJSObj != NULL);\
110	class_name* pObj = (class_name*)pJSObj->GetEmbedObject();\
111	ASSERT(pObj != NULL);\
112	JS_ErrorString sError;\
113	FX_BOOL bRet = FALSE;\
114	try\
115	{\
116		MEMLEAKCHECK_1();\
117		bRet = pObj->prop_name(cc, value, sError);\
118		MEMLEAKCHECK_2(class_name, prop_name);\
119	}\
120	catch (...)\
121	{\
122		CFX_ByteString cbName;\
123		cbName.Format("%s.%s", #class_name, #prop_name);\
124		JS_Error(NULL,CFX_WideString::FromLocal(cbName), L"Unknown error is catched!");\
125		return ;\
126	}\
127	if (bRet)\
128	{\
129		info.GetReturnValue().Set((v8::Handle<v8::Value>)value);\
130		return ;\
131	}\
132	else\
133	{\
134	CFX_ByteString cbName;\
135		cbName.Format("%s.%s", #class_name, #prop_name);\
136		JS_Error(NULL,CFX_WideString::FromLocal(cbName), sError);\
137		return ;\
138	}\
139}
140
141#define JS_STATIC_PROP_SET(prop_name, class_name)\
142	static void set_##prop_name##_static(JS_PROPPUT_ARGS)\
143{\
144	v8::Isolate* isolate = info.GetIsolate();\
145	v8::Local<v8::Context> context = isolate->GetCurrentContext();\
146	v8::Local<v8::Value> v = context->GetEmbedderData(1);\
147	ASSERT(!v.IsEmpty());\
148	if(v.IsEmpty()) return;\
149	v8::Handle<v8::External> field = v8::Handle<v8::External>::Cast(v);\
150	IFXJS_Runtime* pRuntime = (IFXJS_Runtime*)field->Value();\
151	IFXJS_Context* cc = pRuntime->GetCurrentContext();\
152	CJS_PropValue propValue(CJS_Value(isolate,value,VT_unknown));\
153	propValue.StartSetting();\
154	CJS_Object* pJSObj = (CJS_Object*)JS_GetPrivate(isolate,info.Holder());\
155	ASSERT(pJSObj != NULL);\
156	class_name* pObj = (class_name*)pJSObj->GetEmbedObject();\
157	ASSERT(pObj != NULL);\
158	JS_ErrorString sError;\
159	FX_BOOL bRet = FALSE;\
160	try\
161	{\
162		MEMLEAKCHECK_1();\
163		bRet = pObj->prop_name(cc, propValue, sError);\
164		MEMLEAKCHECK_2(class_name, prop_name);\
165	}\
166	catch (...)\
167	{\
168		CFX_ByteString cbName;\
169		cbName.Format("%s.%s", #class_name, #prop_name);\
170		JS_Error(NULL,CFX_WideString::FromLocal(cbName), L"Unknown error is catched!");\
171		return ;\
172	}\
173	if (bRet)\
174	{\
175		return ;\
176	}\
177	else\
178	{\
179		CFX_ByteString cbName;\
180		cbName.Format("%s.%s", #class_name, #prop_name);\
181		JS_Error(NULL,CFX_WideString::FromLocal(cbName), sError);\
182		return ;\
183	}\
184}
185
186#define JS_STATIC_PROP(prop_name, class_name)\
187JS_STATIC_PROP_GET(prop_name, class_name);\
188JS_STATIC_PROP_SET(prop_name, class_name)
189
190/* ========================================= METHOD CALLBACK =========================================== */
191
192#define JS_STATIC_METHOD(method_name, class_name)\
193	static void method_name##_static(JS_METHOD_ARGS)\
194{\
195	v8::Isolate* isolate = info.GetIsolate();\
196	v8::Local<v8::Context> context = isolate->GetCurrentContext();\
197	v8::Local<v8::Value> v = context->GetEmbedderData(1);\
198	ASSERT(!v.IsEmpty());\
199	if(v.IsEmpty()) return;\
200	v8::Handle<v8::External> field = v8::Handle<v8::External>::Cast(v);\
201	IFXJS_Runtime* pRuntime = (IFXJS_Runtime*)field->Value();\
202	IFXJS_Context* cc = pRuntime->GetCurrentContext();\
203	CJS_Parameters parameters;\
204	for (unsigned int i = 0; i<(unsigned int)info.Length(); i++)\
205    {\
206		parameters.push_back(CJS_Value(isolate, info[i], VT_unknown));\
207	}\
208	CJS_Value valueRes(isolate);\
209	CJS_Object* pJSObj = (CJS_Object *)JS_GetPrivate(isolate,info.Holder());\
210	ASSERT(pJSObj != NULL);\
211	class_name* pObj = (class_name*)pJSObj->GetEmbedObject();\
212	ASSERT(pObj != NULL);\
213	JS_ErrorString sError;\
214	FX_BOOL bRet = FALSE;\
215	try\
216	{\
217		MEMLEAKCHECK_1();\
218		bRet = pObj->method_name(cc, parameters, valueRes, sError);\
219		MEMLEAKCHECK_2(class_name, method_name);\
220	}\
221	catch (...)\
222	{\
223		CFX_ByteString cbName;\
224		cbName.Format("%s.%s", #class_name, #method_name);\
225		JS_Error(NULL, CFX_WideString::FromLocal(cbName), L"Unknown error is catched!");\
226		return ;\
227	}\
228	if (bRet)\
229	{\
230		info.GetReturnValue().Set(valueRes.ToJSValue());\
231		return ;\
232	}\
233	else\
234	{\
235		CFX_ByteString cbName;\
236		cbName.Format("%s.%s", #class_name, #method_name);\
237		JS_Error(NULL, CFX_WideString::FromLocal(cbName), sError);\
238		return ;\
239	}\
240}
241
242/* ===================================== JS CLASS =============================================== */
243
244#define DECLARE_JS_CLASS(js_class_name) \
245	static JSBool JSConstructor(IFXJS_Context* cc, JSFXObject obj,JSFXObject global);\
246	static JSBool JSDestructor(JSFXObject obj);\
247	static int Init(IJS_Runtime* pRuntime, FXJSOBJTYPE eObjType);\
248	static void GetConsts(JSConstSpec*& pConsts, int& nSize);\
249	static void GetProperties(JSPropertySpec*& pProperties, int& nSize);\
250	static void GetMethods(JSMethodSpec*& pMethods, int& nSize);\
251	static JSConstSpec JS_Class_Consts[];\
252	static JSPropertySpec JS_Class_Properties[];\
253	static JSMethodSpec	JS_Class_Methods[];\
254	static const wchar_t* m_pClassName
255
256#define IMPLEMENT_JS_CLASS_RICH(js_class_name, class_alternate, class_name) \
257const wchar_t* js_class_name::m_pClassName = JS_WIDESTRING(class_name);\
258JSBool js_class_name::JSConstructor(IFXJS_Context* cc, JSFXObject obj, JSFXObject global)\
259{\
260	CJS_Object* pObj = FX_NEW js_class_name(obj);\
261	pObj->SetEmbedObject(FX_NEW class_alternate(pObj));\
262	JS_SetPrivate(NULL,obj,(void*)pObj); \
263	pObj->InitInstance(cc);\
264	return JS_TRUE;\
265}\
266\
267JSBool js_class_name::JSDestructor(JSFXObject obj) \
268{\
269	js_class_name* pObj = (js_class_name*)JS_GetPrivate(NULL,obj);\
270	ASSERT(pObj != NULL);\
271	pObj->ExitInstance();\
272	delete pObj;\
273	return JS_TRUE;\
274}\
275\
276int js_class_name::Init(IJS_Runtime* pRuntime, FXJSOBJTYPE eObjType)\
277{\
278	int nObjDefnID = JS_DefineObj(pRuntime, js_class_name::m_pClassName, eObjType, JSConstructor, JSDestructor, 0);\
279	if (nObjDefnID >= 0)\
280	{\
281		for (int j=0, szj=sizeof(JS_Class_Properties)/sizeof(JSPropertySpec)-1; j<szj; j++)\
282		{\
283			if (JS_DefineObjProperty(pRuntime, nObjDefnID, JS_Class_Properties[j].pName, JS_Class_Properties[j].pPropGet, JS_Class_Properties[j].pPropPut) < 0) return -1;\
284		}\
285		for (int k=0, szk=sizeof(JS_Class_Methods)/sizeof(JSMethodSpec)-1; k<szk; k++)\
286		{\
287			if (JS_DefineObjMethod(pRuntime, nObjDefnID,JS_Class_Methods[k].pName, JS_Class_Methods[k].pMethodCall, JS_Class_Methods[k].nParamNum) < 0) return -1;\
288		}\
289		return nObjDefnID;\
290	}\
291	return -1;\
292}\
293void js_class_name::GetConsts(JSConstSpec*& pConsts, int& nSize)\
294{\
295	pConsts = JS_Class_Consts;\
296	nSize = sizeof(JS_Class_Consts) / sizeof(JSConstSpec) - 1;\
297}\
298void js_class_name::GetProperties(JSPropertySpec*& pProperties, int& nSize)\
299{\
300	pProperties = JS_Class_Properties;\
301	nSize = sizeof(JS_Class_Properties) / sizeof(JSPropertySpec) - 1;\
302}\
303void js_class_name::GetMethods(JSMethodSpec*& pMethods, int& nSize)\
304{\
305	pMethods = JS_Class_Methods;\
306	nSize = sizeof(JS_Class_Methods) / sizeof(JSMethodSpec) - 1;\
307}
308
309#define IMPLEMENT_JS_CLASS(js_class_name, class_name) IMPLEMENT_JS_CLASS_RICH(js_class_name, class_name, class_name)
310
311/* ======================================== CONST CLASS ============================================ */
312
313#define DECLARE_JS_CLASS_CONST() \
314	static int Init(IJS_Runtime* pRuntime, FXJSOBJTYPE eObjType);\
315	static void GetConsts(JSConstSpec*& pConsts, int& nSize);\
316	static JSConstSpec JS_Class_Consts[];\
317	static const wchar_t* m_pClassName
318
319#define IMPLEMENT_JS_CLASS_CONST(js_class_name, class_name) \
320const wchar_t* js_class_name::m_pClassName = JS_WIDESTRING(class_name);\
321int js_class_name::Init(IJS_Runtime* pRuntime, FXJSOBJTYPE eObjType)\
322{\
323	int nObjDefnID = JS_DefineObj(pRuntime, js_class_name::m_pClassName, eObjType, NULL, NULL, 0);\
324	if (nObjDefnID >=0)\
325	{\
326		for (int i=0, sz=sizeof(JS_Class_Consts)/sizeof(JSConstSpec)-1; i<sz; i++)\
327		{\
328			if (JS_Class_Consts[i].t == 0)\
329			{\
330				if (JS_DefineObjConst(pRuntime, nObjDefnID, JS_Class_Consts[i].pName, JS_NewNumber(pRuntime,JS_Class_Consts[i].number)) < 0) return -1;\
331			}\
332			else\
333			{\
334			if (JS_DefineObjConst(pRuntime, nObjDefnID, JS_Class_Consts[i].pName, JS_NewString(pRuntime,JS_Class_Consts[i].string)) < 0) return -1;\
335			}\
336		}\
337		return nObjDefnID;\
338	}\
339	return -1;\
340}\
341void js_class_name::GetConsts(JSConstSpec*& pConsts, int& nSize)\
342{\
343	pConsts = JS_Class_Consts;\
344	nSize = sizeof(JS_Class_Consts)/sizeof(JSConstSpec)-1;\
345}
346
347/* ===================================== SPECIAL JS CLASS =============================================== */
348
349#define DECLARE_SPECIAL_JS_CLASS(js_class_name) \
350	static JSBool JSConstructor(IFXJS_Context* cc, JSFXObject obj, JSFXObject global);\
351	static JSBool JSDestructor(JSFXObject obj);\
352	static void GetConsts(JSConstSpec*& pConsts, int& nSize);\
353	static void GetProperties(JSPropertySpec*& pProperties, int& nSize);\
354	static void GetMethods(JSMethodSpec*& pMethods, int& nSize);\
355	static JSConstSpec JS_Class_Consts[];\
356	static JSPropertySpec JS_Class_Properties[];\
357	static JSMethodSpec	JS_Class_Methods[];\
358	static int Init(IJS_Runtime* pRuntime, FXJSOBJTYPE eObjType);\
359	static const wchar_t* m_pClassName;\
360	static void queryprop_##js_class_name##_static(JS_PROPQUERY_ARGS);\
361	static void getprop_##js_class_name##_static(JS_NAMED_PROPGET_ARGS);\
362	static void putprop_##js_class_name##_static(JS_NAMED_PROPPUT_ARGS);\
363	static void delprop_##js_class_name##_static(JS_PROPDEL_ARGS)
364
365#define IMPLEMENT_SPECIAL_JS_CLASS(js_class_name, class_alternate, class_name) \
366const wchar_t * js_class_name::m_pClassName = JS_WIDESTRING(class_name);\
367	void js_class_name::queryprop_##js_class_name##_static(JS_PROPQUERY_ARGS)\
368{\
369	v8::Isolate* isolate = info.GetIsolate();\
370	v8::String::Utf8Value utf8_value(property);\
371	CFX_WideString propname = CFX_WideString::FromUTF8(*utf8_value, utf8_value.length());\
372	CJS_Object* pJSObj = (CJS_Object*)JS_GetPrivate(isolate,info.Holder());\
373	ASSERT(pJSObj != NULL);\
374	class_alternate* pObj = (class_alternate*)pJSObj->GetEmbedObject();\
375	ASSERT(pObj != NULL);\
376	FX_BOOL bRet = FALSE;\
377	try\
378	{\
379		MEMLEAKCHECK_1();\
380		bRet = pObj->QueryProperty((FX_LPCWSTR)propname);\
381		MEMLEAKCHECK_2(class_name, (FX_LPCWSTR)prop_name);\
382	}\
383	catch (...)\
384	{\
385		return ;\
386	}\
387	if (bRet)\
388	{\
389		info.GetReturnValue().Set(0x004);\
390		return ;\
391	}\
392	else\
393	{\
394		info.GetReturnValue().Set(0);\
395		return ;\
396	}\
397	return ;\
398}\
399	void js_class_name::getprop_##js_class_name##_static(JS_NAMED_PROPGET_ARGS)\
400{\
401	v8::Isolate* isolate = info.GetIsolate();\
402	v8::Local<v8::Context> context = isolate->GetCurrentContext();\
403	v8::Local<v8::Value> v = context->GetEmbedderData(1);\
404	ASSERT(!v.IsEmpty());\
405	if(v.IsEmpty()) return;\
406	v8::Handle<v8::External> field = v8::Handle<v8::External>::Cast(v);\
407	IFXJS_Runtime* pRuntime = (IFXJS_Runtime*)field->Value();\
408	IFXJS_Context* cc = pRuntime->GetCurrentContext();\
409	v8::String::Utf8Value utf8_value(property);\
410	CFX_WideString propname = CFX_WideString::FromUTF8(*utf8_value, utf8_value.length());\
411	CJS_PropValue value(isolate);\
412	value.StartGetting();\
413	CJS_Object* pJSObj = (CJS_Object*)JS_GetPrivate(isolate,info.Holder());\
414	ASSERT(pJSObj != NULL);\
415	class_alternate* pObj = (class_alternate*)pJSObj->GetEmbedObject();\
416	ASSERT(pObj != NULL);\
417	JS_ErrorString sError;\
418	FX_BOOL bRet = FALSE;\
419	try\
420	{\
421		MEMLEAKCHECK_1();\
422		bRet = pObj->DoProperty(cc, (FX_LPCWSTR)propname, value, sError);\
423		MEMLEAKCHECK_2(class_name, L"GetProperty");\
424	}\
425	catch (...)\
426	{\
427		CFX_ByteString cbName;\
428		cbName.Format("%s.%s", #class_name, L"GetProperty");\
429		JS_Error(NULL,CFX_WideString::FromLocal(cbName), L"Unknown error is catched!");\
430		return ;\
431	}\
432	if (bRet)\
433	{\
434		info.GetReturnValue().Set((v8::Handle<v8::Value>)value);\
435		return ;\
436	}\
437	else\
438	{\
439		CFX_ByteString cbName;\
440		cbName.Format("%s.%s", #class_name, L"GetProperty");\
441		JS_Error(NULL,CFX_WideString::FromLocal(cbName), sError);\
442		return ;\
443	}\
444	JS_Error(NULL,L"GetProperty", L"Embeded object not found!");\
445	return ;\
446}\
447	void js_class_name::putprop_##js_class_name##_static(JS_NAMED_PROPPUT_ARGS)\
448{\
449	v8::Isolate* isolate = info.GetIsolate();\
450	v8::Local<v8::Context> context = isolate->GetCurrentContext();\
451	v8::Local<v8::Value> v = context->GetEmbedderData(1);\
452	ASSERT(!v.IsEmpty());\
453	if(v.IsEmpty()) return;\
454	v8::Handle<v8::External> field = v8::Handle<v8::External>::Cast(v);\
455	IFXJS_Runtime* pRuntime = (IFXJS_Runtime*)field->Value();\
456	IFXJS_Context* cc = pRuntime->GetCurrentContext();\
457	v8::String::Utf8Value utf8_value(property);\
458	CFX_WideString propname = CFX_WideString::FromUTF8(*utf8_value, utf8_value.length());\
459	CJS_PropValue PropValue(CJS_Value(isolate,value,VT_unknown));\
460	PropValue.StartSetting();\
461	CJS_Object* pJSObj = (CJS_Object*)JS_GetPrivate(isolate,info.Holder());\
462	if(!pJSObj) return;\
463	class_alternate* pObj = (class_alternate*)pJSObj->GetEmbedObject();\
464	ASSERT(pObj != NULL);\
465	JS_ErrorString sError;\
466	FX_BOOL bRet = FALSE;\
467	try\
468	{\
469		MEMLEAKCHECK_1();\
470		bRet = pObj->DoProperty(cc, (FX_LPCWSTR)propname, PropValue, sError);\
471		MEMLEAKCHECK_2(class_name,L"PutProperty");\
472	}\
473	catch (...)\
474	{\
475		CFX_ByteString cbName;\
476		cbName.Format("%s.%s", #class_name, "PutProperty");\
477		JS_Error(NULL,CFX_WideString::FromLocal(cbName), L"Unknown error is catched!");\
478		return ;\
479	}\
480	if (bRet)\
481	{\
482		return ;\
483	}\
484	else\
485	{\
486		CFX_ByteString cbName;\
487		cbName.Format("%s.%s", #class_name, "PutProperty");\
488		JS_Error(NULL,CFX_WideString::FromLocal(cbName), sError);\
489		return ;\
490	}\
491	JS_Error(NULL,L"PutProperty", L"Embeded object not found!");\
492	return ;\
493}\
494	void js_class_name::delprop_##js_class_name##_static(JS_PROPDEL_ARGS)\
495{\
496	v8::Isolate* isolate = info.GetIsolate();\
497	v8::Local<v8::Context> context = isolate->GetCurrentContext();\
498	v8::Local<v8::Value> v = context->GetEmbedderData(1);\
499	ASSERT(!v.IsEmpty());\
500	if(v.IsEmpty()) return;\
501	v8::Handle<v8::External> field = v8::Handle<v8::External>::Cast(v);\
502	IFXJS_Runtime* pRuntime = (IFXJS_Runtime*)field->Value();\
503	IFXJS_Context* cc = pRuntime->GetCurrentContext();\
504	v8::String::Utf8Value utf8_value(property);\
505	CFX_WideString propname = CFX_WideString::FromUTF8(*utf8_value, utf8_value.length());\
506	CJS_Object* pJSObj = (CJS_Object*)JS_GetPrivate(isolate,info.Holder());\
507	ASSERT(pJSObj != NULL);\
508	class_alternate* pObj = (class_alternate*)pJSObj->GetEmbedObject();\
509	ASSERT(pObj != NULL);\
510	JS_ErrorString sError;\
511	FX_BOOL bRet = FALSE;\
512	try\
513	{\
514		MEMLEAKCHECK_1();\
515		bRet = pObj->DelProperty(cc, (FX_LPCWSTR)propname, sError);\
516		MEMLEAKCHECK_2(class_name,L"DelProperty");\
517	}\
518	catch (...)\
519	{\
520		CFX_ByteString cbName;\
521		cbName.Format("%s.%s", #class_name, "DelProperty");\
522		return ;\
523	}\
524	if (bRet)\
525	{\
526		return ;\
527	}\
528	else\
529	{\
530		CFX_ByteString cbName;\
531		cbName.Format("%s.%s", #class_name, "DelProperty");\
532		return ;\
533	}\
534	return ;\
535}\
536JSBool js_class_name::JSConstructor(IFXJS_Context* cc, JSFXObject  obj,JSFXObject  global)\
537{\
538	CJS_Object* pObj = FX_NEW js_class_name(obj);\
539	pObj->SetEmbedObject(FX_NEW class_alternate(pObj));\
540	JS_SetPrivate(NULL,obj, (void*)pObj); \
541	pObj->InitInstance(cc);\
542	return JS_TRUE;\
543}\
544\
545JSBool js_class_name::JSDestructor(JSFXObject obj) \
546{\
547	js_class_name* pObj = (js_class_name*)JS_GetPrivate(NULL,obj);\
548	ASSERT(pObj != NULL);\
549	pObj->ExitInstance();\
550	delete pObj;\
551	return JS_TRUE;\
552}\
553\
554int js_class_name::Init(IJS_Runtime* pRuntime, FXJSOBJTYPE eObjType)\
555{\
556\
557	int nObjDefnID = JS_DefineObj(pRuntime, js_class_name::m_pClassName, eObjType, JSConstructor, JSDestructor, 0);\
558\
559	if (nObjDefnID >= 0)\
560	{\
561		for (int j=0, szj=sizeof(JS_Class_Properties)/sizeof(JSPropertySpec)-1; j<szj; j++)\
562		{\
563			if (JS_DefineObjProperty(pRuntime, nObjDefnID, JS_Class_Properties[j].pName, JS_Class_Properties[j].pPropGet,JS_Class_Properties[j].pPropPut)<0)return -1;\
564		}\
565\
566		for (int k=0, szk=sizeof(JS_Class_Methods)/sizeof(JSMethodSpec)-1; k<szk; k++)\
567		{\
568			if (JS_DefineObjMethod(pRuntime, nObjDefnID,JS_Class_Methods[k].pName,JS_Class_Methods[k].pMethodCall,JS_Class_Methods[k].nParamNum)<0)return -1;\
569		}\
570		if (JS_DefineObjAllProperties(pRuntime, nObjDefnID, js_class_name::queryprop_##js_class_name##_static, js_class_name::getprop_##js_class_name##_static,js_class_name::putprop_##js_class_name##_static,js_class_name::delprop_##js_class_name##_static)<0) return -1;\
571\
572		return nObjDefnID;\
573	}\
574\
575	return -1;\
576}\
577void js_class_name::GetConsts(JSConstSpec*& pConsts, int& nSize)\
578{\
579	pConsts = JS_Class_Consts;\
580	nSize = sizeof(JS_Class_Consts)/sizeof(JSConstSpec)-1;\
581}\
582void js_class_name::GetProperties(JSPropertySpec*& pProperties, int& nSize)\
583{\
584	pProperties = JS_Class_Properties;\
585	nSize = sizeof(JS_Class_Properties)/sizeof(JSPropertySpec)-1;\
586}\
587void js_class_name::GetMethods(JSMethodSpec*& pMethods, int& nSize)\
588{\
589	pMethods = JS_Class_Methods;\
590	nSize = sizeof(JS_Class_Methods)/sizeof(JSMethodSpec)-1;\
591}
592
593#define JS_SPECIAL_STATIC_METHOD(method_name, class_alternate, class_name)\
594	static void method_name##_static(JS_METHOD_ARGS)\
595{\
596	v8::Isolate* isolate = info.GetIsolate();\
597	v8::Local<v8::Context> context = isolate->GetCurrentContext();\
598	v8::Local<v8::Value> v = context->GetEmbedderData(1);\
599	ASSERT(!v.IsEmpty());\
600	if(v.IsEmpty()) return;\
601	v8::Handle<v8::External> field = v8::Handle<v8::External>::Cast(v);\
602	IFXJS_Runtime* pRuntime = (IFXJS_Runtime*)field->Value();\
603	IFXJS_Context* cc = pRuntime->GetCurrentContext();\
604	CJS_Parameters parameters;\
605	for (unsigned int i = 0; i<(unsigned int)info.Length(); i++)\
606	{\
607	parameters.push_back(CJS_Value(isolate, info[i], VT_unknown));\
608	}\
609	CJS_Value valueRes(isolate);\
610	CJS_Object* pJSObj = (CJS_Object *)JS_GetPrivate(isolate, info.Holder());\
611	ASSERT(pJSObj != NULL);\
612	class_alternate* pObj = (class_alternate*)pJSObj->GetEmbedObject();\
613	ASSERT(pObj != NULL);\
614	JS_ErrorString sError;\
615	FX_BOOL bRet = FALSE;\
616	try\
617	{\
618		MEMLEAKCHECK_1();\
619		bRet = pObj->method_name(cc, parameters, valueRes, sError);\
620		MEMLEAKCHECK_2(class_name, method_name);\
621	}\
622	catch (...)\
623	{\
624		CFX_ByteString cbName;\
625		cbName.Format("%s.%s", #class_name, #method_name);\
626		JS_Error(NULL, CFX_WideString::FromLocal(cbName), L"Unknown error is catched!");\
627		return ;\
628	}\
629	if (bRet)\
630	{\
631		info.GetReturnValue().Set(valueRes.ToJSValue());\
632		return ;\
633	}\
634	else\
635	{\
636		CFX_ByteString cbName;\
637		cbName.Format("%s.%s", #class_name, #method_name);\
638		JS_Error(NULL, CFX_WideString::FromLocal(cbName), sError);\
639		return ;\
640	}\
641	JS_Error(NULL,  JS_WIDESTRING(method_name), L"Embeded object not found!");\
642    return ;\
643}
644
645/* ======================================== GLOBAL METHODS ============================================ */
646#define JS_STATIC_GLOBAL_FUN(fun_name) \
647static void fun_name##_static(JS_METHOD_ARGS)\
648{\
649	v8::Isolate* isolate = info.GetIsolate();\
650	v8::Local<v8::Context> context = isolate->GetCurrentContext();\
651	v8::Local<v8::Value> v = context->GetEmbedderData(1);\
652	ASSERT(!v.IsEmpty());\
653	if(v.IsEmpty()) return;\
654	v8::Handle<v8::External> field = v8::Handle<v8::External>::Cast(v);\
655	IFXJS_Runtime* pRuntime = (IFXJS_Runtime*)field->Value();\
656	IFXJS_Context* cc = pRuntime->GetCurrentContext();\
657	CJS_Parameters parameters;\
658	for (unsigned int i = 0; i<(unsigned int)info.Length(); i++)\
659	{\
660	parameters.push_back(CJS_Value(isolate, info[i], VT_unknown));\
661	}\
662	CJS_Value valueRes(isolate);\
663	JS_ErrorString sError;\
664	if (!fun_name(cc, parameters, valueRes, sError))\
665	{\
666		JS_Error(NULL, JS_WIDESTRING(fun_name), sError);\
667		return ;\
668	}\
669	info.GetReturnValue().Set(valueRes.ToJSValue());\
670	return ;\
671}
672
673#define JS_STATIC_DECLARE_GLOBAL_FUN() \
674static JSMethodSpec	global_methods[]; \
675static int Init(IJS_Runtime* pRuntime)
676
677#define BEGIN_JS_STATIC_GLOBAL_FUN(js_class_name) \
678JSMethodSpec js_class_name::global_methods[] = {
679
680#define JS_STATIC_GLOBAL_FUN_ENTRY(method_name,nargs) JS_STATIC_METHOD_ENTRY(method_name,nargs)
681
682#define END_JS_STATIC_GLOBAL_FUN() END_JS_STATIC_METHOD()
683
684#define IMPLEMENT_JS_STATIC_GLOBAL_FUN(js_class_name) \
685int js_class_name::Init(IJS_Runtime* pRuntime)\
686{\
687	for (int i=0, sz=sizeof(js_class_name::global_methods)/sizeof(JSMethodSpec)-1; i<sz; i++)\
688	{\
689		if (JS_DefineGlobalMethod(pRuntime,\
690				js_class_name::global_methods[i].pName,\
691				js_class_name::global_methods[i].pMethodCall,\
692				js_class_name::global_methods[i].nParamNum\
693				) < 0\
694			)return -1;\
695	}\
696	return 0;\
697}
698
699/* ======================================== GLOBAL CONSTS ============================================ */
700#define DEFINE_GLOBAL_CONST(pRuntime, const_name , const_value)\
701if (JS_DefineGlobalConst(pRuntime,JS_WIDESTRING(const_name),JS_NewString(pRuntime,JS_WIDESTRING(const_value)))) return -1
702
703/* ======================================== GLOBAL ARRAYS ============================================ */
704
705#define DEFINE_GLOBAL_ARRAY(pRuntime)\
706int size = sizeof(ArrayContent) / sizeof(FX_LPCWSTR);\
707\
708CJS_Array array(pRuntime);\
709for (int i=0; i<size; i++) array.SetElement(i,CJS_Value(pRuntime,(FX_LPCWSTR)ArrayContent[i]));\
710\
711CJS_PropValue prop(pRuntime);\
712prop << array;\
713if (JS_DefineGlobalConst(pRuntime, (const wchar_t*)ArrayName, prop.ToJSValue()) < 0)\
714	return -1
715
716/* ============================================================ */
717
718#define VALUE_NAME_STRING		L"string"
719#define VALUE_NAME_NUMBER		L"number"
720#define VALUE_NAME_BOOLEAN		L"boolean"
721#define VALUE_NAME_DATE			L"date"
722#define VALUE_NAME_OBJECT		L"object"
723#define VALUE_NAME_FXOBJ		L"fxobj"
724#define VALUE_NAME_NULL			L"null"
725#define VALUE_NAME_UNDEFINED	L"undefined"
726
727#define CLASSNAME_ARRAY			L"Array"
728#define CLASSNAME_DATE			L"Date"
729#define CLASSNAME_STRING		L"v8::String"
730
731const unsigned int JSCONST_nStringHash = JS_CalcHash(VALUE_NAME_STRING,wcslen(VALUE_NAME_STRING));
732const unsigned int JSCONST_nNumberHash = JS_CalcHash(VALUE_NAME_NUMBER,wcslen(VALUE_NAME_NUMBER));
733const unsigned int JSCONST_nBoolHash = JS_CalcHash(VALUE_NAME_BOOLEAN,wcslen(VALUE_NAME_BOOLEAN));
734const unsigned int JSCONST_nDateHash = JS_CalcHash(VALUE_NAME_DATE,wcslen(VALUE_NAME_DATE));
735const unsigned int JSCONST_nObjectHash = JS_CalcHash(VALUE_NAME_OBJECT,wcslen(VALUE_NAME_OBJECT));
736const unsigned int JSCONST_nFXobjHash = JS_CalcHash(VALUE_NAME_FXOBJ,wcslen(VALUE_NAME_FXOBJ));
737const unsigned int JSCONST_nNullHash = JS_CalcHash(VALUE_NAME_NULL,wcslen(VALUE_NAME_NULL));
738const unsigned int JSCONST_nUndefHash = JS_CalcHash(VALUE_NAME_UNDEFINED,wcslen(VALUE_NAME_UNDEFINED));
739
740static FXJSVALUETYPE GET_VALUE_TYPE(v8::Handle<v8::Value> p)
741{
742
743		const unsigned int nHash = JS_CalcHash(JS_GetTypeof(p));
744
745		if (nHash == JSCONST_nUndefHash)
746			return VT_undefined;
747		else if (nHash == JSCONST_nNullHash)
748			return VT_null;
749		else if (nHash == JSCONST_nStringHash)
750			return VT_string;
751		else if (nHash == JSCONST_nNumberHash)
752			return VT_number;
753		else if (nHash == JSCONST_nBoolHash)
754			return VT_boolean;
755		else if (nHash == JSCONST_nDateHash)
756			return VT_date;
757		else if (nHash == JSCONST_nObjectHash)
758			return VT_object;
759		else if (nHash == JSCONST_nFXobjHash)
760			return VT_fxobject;
761
762		/*
763		const char * sType = p->getTypeof()->toDchars();
764		if (strcmp(sType,VALUE_NAME_STRING) == 0)
765			return VT_string;
766		else if (strcmp(sType,VALUE_NAME_NUMBER) == 0)
767			return VT_number;
768		else if (strcmp(sType,VALUE_NAME_BOOLEAN) == 0)
769			return VT_boolean;
770		else if (strcmp(sType,VALUE_NAME_DATE) == 0)
771			return VT_date;
772		else if (strcmp(sType,VALUE_NAME_OBJECT) == 0)
773			return VT_object;
774		else if (strcmp(sType,VALUE_NAME_FXOBJ) == 0)
775			return VT_object;
776		else if (strcmp(sType,VALUE_NAME_NULL) == 0)
777			return VT_null;
778		else if (strcmp(sType,VALUE_NAME_UNDEFINED) == 0)
779			return VT_undefined;
780			*/
781
782	return VT_unknown;
783}
784
785#endif //_JS_DEFINE_H_
786