• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include "../../include/javascript/JavaScript.h"
8 #include "../../include/javascript/IJavaScript.h"
9 #include "../../include/javascript/JS_Define.h"
10 #include "../../include/javascript/JS_Object.h"
11 #include "../../include/javascript/JS_Value.h"
12 #include "../../include/javascript/JS_GlobalData.h"
13 #include "../../include/javascript/global.h"
14 #include "../../include/javascript/JS_EventHandler.h"
15 #include "../../include/javascript/JS_Context.h"
16 
17 /* ---------------------------- global ---------------------------- */
18 
19 BEGIN_JS_STATIC_CONST(CJS_Global)
20 END_JS_STATIC_CONST()
21 
22 BEGIN_JS_STATIC_PROP(CJS_Global)
23 END_JS_STATIC_PROP()
24 
25 BEGIN_JS_STATIC_METHOD(CJS_Global)
26 	JS_STATIC_METHOD_ENTRY(setPersistent, 2)
27 END_JS_STATIC_METHOD()
28 
29 IMPLEMENT_SPECIAL_JS_CLASS(CJS_Global, global_alternate, global);
30 
InitInstance(IFXJS_Context * cc)31 FX_BOOL	CJS_Global::InitInstance(IFXJS_Context* cc)
32 {
33 	CJS_Context* pContext = (CJS_Context*)cc;
34 	ASSERT(pContext != NULL);
35 
36 	global_alternate* pGlobal = (global_alternate*)GetEmbedObject();
37 	ASSERT(pGlobal != NULL);
38 
39 	pGlobal->Initial(pContext->GetReaderApp());
40 
41 	return TRUE;
42 };
43 
global_alternate(CJS_Object * pJSObject)44 global_alternate::global_alternate(CJS_Object* pJSObject)
45 	: CJS_EmbedObj(pJSObject),
46 	m_pApp(NULL)
47 {
48 }
49 
~global_alternate(void)50 global_alternate::~global_alternate(void)
51 {
52 	ASSERT(m_pApp != NULL);
53 
54 //	CommitGlobalPersisitentVariables();
55 	DestroyGlobalPersisitentVariables();
56 
57 	CJS_RuntimeFactory* pFactory = m_pApp->m_pJSRuntimeFactory;
58 	ASSERT(pFactory);
59 
60 	pFactory->ReleaseGlobalData();
61 }
62 
Initial(CPDFDoc_Environment * pApp)63 void global_alternate::Initial(CPDFDoc_Environment* pApp)
64 {
65 	m_pApp = pApp;
66 
67 	CJS_RuntimeFactory* pFactory = pApp->m_pJSRuntimeFactory;
68 	ASSERT(pFactory);
69 	m_pGlobalData = pFactory->NewGlobalData(pApp);
70 	UpdateGlobalPersistentVariables();
71 }
72 
QueryProperty(FX_LPCWSTR propname)73 FX_BOOL	global_alternate::QueryProperty(FX_LPCWSTR propname)
74 {
75 	return CFX_WideString(propname) != L"setPersistent";
76 }
77 
DelProperty(IFXJS_Context * cc,FX_LPCWSTR propname,JS_ErrorString & sError)78 FX_BOOL	global_alternate::DelProperty(IFXJS_Context* cc, FX_LPCWSTR propname, JS_ErrorString& sError)
79 {
80 	js_global_data* pData = NULL;
81 	CFX_ByteString sPropName = CFX_ByteString::FromUnicode(propname);
82 
83 	if (m_mapGlobal.Lookup(sPropName, (FX_LPVOID&)pData))
84 	{
85 		pData->bDeleted = TRUE;
86 		return TRUE;
87 	}
88 
89 	return FALSE;
90 }
91 
DoProperty(IFXJS_Context * cc,FX_LPCWSTR propname,CJS_PropValue & vp,JS_ErrorString & sError)92 FX_BOOL global_alternate::DoProperty(IFXJS_Context* cc, FX_LPCWSTR propname, CJS_PropValue& vp, JS_ErrorString& sError)
93 {
94 	if (vp.IsSetting())
95 	{
96 		CFX_ByteString sPropName = CFX_ByteString::FromUnicode(propname);
97 		switch (vp.GetType())
98 		{
99 		case VT_number:
100 			{
101 				double dData;
102 				vp >> dData;
103 				return SetGlobalVariables(sPropName, JS_GLOBALDATA_TYPE_NUMBER, dData, false, "", v8::Handle<v8::Object>(), FALSE);
104 			}
105 		case VT_boolean:
106 			{
107 				bool bData;
108 				vp >> bData;
109 				return SetGlobalVariables(sPropName, JS_GLOBALDATA_TYPE_BOOLEAN, 0, (bool)vp, "", v8::Handle<v8::Object>(), FALSE);
110 			}
111 		case VT_string:
112 			{
113 				CFX_ByteString sData;
114 				vp >> sData;
115 				return SetGlobalVariables(sPropName, JS_GLOBALDATA_TYPE_STRING, 0, false, sData, v8::Handle<v8::Object>(), FALSE);
116 			}
117 		case VT_object:
118 			{
119 				JSObject pData = (JSObject)vp;
120 				return SetGlobalVariables(sPropName, JS_GLOBALDATA_TYPE_OBJECT, 0, false, "", pData, FALSE);
121 // 				else
122 // 				{
123 // 					if (vp.IsArrayObject())
124 // 					{
125 // 						CJS_Array array;
126 // 						vp.ConvertToArray(array);
127 // 						return SetGlobalVariables(sPropName, JS_GLOBALDATA_TYPE_OBJECT, 0, false, "",
128 // 							(Dobject*)(Darray*)array, FALSE);
129 // 					}
130 // 					else
131 // 						return FALSE;
132 // 				}
133 			}
134 		case VT_null:
135 			{
136 				return SetGlobalVariables(sPropName, JS_GLOBALDATA_TYPE_NULL, 0, false, "", v8::Handle<v8::Object>(), FALSE);
137 			}
138 		case VT_undefined:
139 			{
140 				DelProperty(cc, propname, sError);
141 				return TRUE;
142 			}
143 		default:
144 			return FALSE;
145 		}
146 	}
147 	else
148 	{
149 		js_global_data* pData = NULL;
150 		CFX_ByteString sPropName = CFX_ByteString::FromUnicode(propname);
151 
152 		if (m_mapGlobal.Lookup(sPropName, (FX_LPVOID&)pData))
153 		{
154 			if (pData)
155 			{
156 				if (!pData->bDeleted)
157 				{
158 					switch (pData->nType)
159 					{
160 					case JS_GLOBALDATA_TYPE_NUMBER:
161 						vp << pData->dData;
162 						break;
163 					case JS_GLOBALDATA_TYPE_BOOLEAN:
164 						vp << pData->bData;
165 						break;
166 					case JS_GLOBALDATA_TYPE_STRING:
167 						vp << pData->sData;
168 						break;
169 					case JS_GLOBALDATA_TYPE_OBJECT:
170 						{
171 							v8::Handle<v8::Object> obj = v8::Local<v8::Object>::New(vp.GetIsolate(),pData->pData);
172 							vp << obj;
173 							break;
174 						}
175 					case JS_GLOBALDATA_TYPE_NULL:
176 						vp.SetNull();
177 						break;
178 					default:
179 						return FALSE;
180 					}
181 					return TRUE;
182 				}
183 				else
184 				{
185 					return TRUE;
186 				}
187 			}
188 			else
189 			{
190 				vp.SetNull();
191 				return TRUE;
192 			}
193 		}
194 		else
195 		{
196 			vp.SetNull();
197 			return TRUE;
198 		}
199 	}
200 
201 	return FALSE;
202 }
203 
setPersistent(OBJ_METHOD_PARAMS)204 FX_BOOL global_alternate::setPersistent(OBJ_METHOD_PARAMS)
205 {
206 	if (params.size() != 2)
207 	{
208 		//sError = JSGetStringFromID(IDS_STRING_JSPARAMERROR);
209 		return FALSE;
210 	}
211 
212 	CFX_ByteString sName = params[0];
213 
214 	js_global_data* pData = NULL;
215 	if (m_mapGlobal.Lookup(sName, (FX_LPVOID&)pData))
216 	{
217 		if (pData && !pData->bDeleted)
218 		{
219 			pData->bPersistent = (bool)params[1];
220 			return TRUE;
221 		}
222 	}
223 
224 	//sError = JSGetStringFromID(IDS_JSPARAM_INCORRECT);
225 	return FALSE;
226 }
227 
UpdateGlobalPersistentVariables()228 void global_alternate::UpdateGlobalPersistentVariables()
229 {
230 	ASSERT(m_pGlobalData != NULL);
231 
232 	for (int i=0,sz=m_pGlobalData->GetSize(); i<sz; i++)
233 	{
234 		CJS_GlobalData_Element* pData = m_pGlobalData->GetAt(i);
235 		ASSERT(pData != NULL);
236 
237 		switch (pData->data.nType)
238 		{
239 		case JS_GLOBALDATA_TYPE_NUMBER:
240 			this->SetGlobalVariables(pData->data.sKey, JS_GLOBALDATA_TYPE_NUMBER, pData->data.dData, false, "", v8::Handle<v8::Object>(), pData->bPersistent == 1);
241 			JS_PutObjectNumber(NULL,(JSFXObject)(*m_pJSObject),
242 				pData->data.sKey.UTF8Decode(), pData->data.dData);
243 			break;
244 		case JS_GLOBALDATA_TYPE_BOOLEAN:
245 			this->SetGlobalVariables(pData->data.sKey, JS_GLOBALDATA_TYPE_BOOLEAN, 0, (bool)(pData->data.bData == 1), "", v8::Handle<v8::Object>(), pData->bPersistent == 1);
246 			JS_PutObjectBoolean(NULL,(JSFXObject)(*m_pJSObject),
247 				pData->data.sKey.UTF8Decode(), (bool)(pData->data.bData == 1));
248 			break;
249 		case JS_GLOBALDATA_TYPE_STRING:
250 			this->SetGlobalVariables(pData->data.sKey, JS_GLOBALDATA_TYPE_STRING, 0, false, pData->data.sData, v8::Handle<v8::Object>(), pData->bPersistent == 1);
251 			JS_PutObjectString(NULL,(JSFXObject)(*m_pJSObject),
252 				pData->data.sKey.UTF8Decode(),
253 				pData->data.sData.UTF8Decode());
254 			break;
255 		case JS_GLOBALDATA_TYPE_OBJECT:
256 			{
257 				IJS_Runtime* pRuntime = JS_GetRuntime((JSFXObject)(*m_pJSObject));
258 				v8::Handle<v8::Object> pObj = JS_NewFxDynamicObj(pRuntime, NULL, -1);
259 
260 				PutObjectProperty(pObj, &pData->data);
261 
262 				this->SetGlobalVariables(pData->data.sKey, JS_GLOBALDATA_TYPE_OBJECT, 0, false, "",
263 					(JSObject)pObj, pData->bPersistent == 1);
264 				JS_PutObjectObject(NULL,(JSFXObject)(*m_pJSObject),
265 					pData->data.sKey.UTF8Decode(), (JSObject)pObj);
266 			}
267 			break;
268 		case JS_GLOBALDATA_TYPE_NULL:
269 			this->SetGlobalVariables(pData->data.sKey, JS_GLOBALDATA_TYPE_NULL, 0, false, "", v8::Handle<v8::Object>(), pData->bPersistent == 1);
270 			JS_PutObjectNull(NULL,(JSFXObject)(*m_pJSObject),
271 				pData->data.sKey.UTF8Decode());
272 			break;
273 		}
274 	}
275 }
276 
CommitGlobalPersisitentVariables()277 void global_alternate::CommitGlobalPersisitentVariables()
278 {
279 	ASSERT(m_pGlobalData != NULL);
280 
281 	FX_POSITION	 pos = m_mapGlobal.GetStartPosition();
282 	while (pos)
283 	{
284 		CFX_ByteString name;
285 		js_global_data* pData = NULL;
286 		m_mapGlobal.GetNextAssoc(pos, name, (FX_LPVOID&)pData);
287 
288 		if (pData)
289 		{
290 			if (pData->bDeleted)
291 			{
292 				m_pGlobalData->DeleteGlobalVariable(name);
293 			}
294 			else
295 			{
296 				switch (pData->nType)
297 				{
298 				case JS_GLOBALDATA_TYPE_NUMBER:
299 					m_pGlobalData->SetGlobalVariableNumber(name, pData->dData);
300 					m_pGlobalData->SetGlobalVariablePersistent(name, pData->bPersistent);
301 					break;
302 				case JS_GLOBALDATA_TYPE_BOOLEAN:
303 					m_pGlobalData->SetGlobalVariableBoolean(name, pData->bData);
304 					m_pGlobalData->SetGlobalVariablePersistent(name, pData->bPersistent);
305 					break;
306 				case JS_GLOBALDATA_TYPE_STRING:
307 					m_pGlobalData->SetGlobalVariableString(name, pData->sData);
308 					m_pGlobalData->SetGlobalVariablePersistent(name, pData->bPersistent);
309 					break;
310 				case JS_GLOBALDATA_TYPE_OBJECT:
311 					//if (pData->pData)
312 					{
313 						CJS_GlobalVariableArray array;
314 						v8::Handle<v8::Object> obj = v8::Local<v8::Object>::New(GetJSObject()->GetIsolate(),pData->pData);
315 						ObjectToArray(obj, array);
316 						m_pGlobalData->SetGlobalVariableObject(name, array);
317 						m_pGlobalData->SetGlobalVariablePersistent(name, pData->bPersistent);
318 					}
319 					break;
320 				case JS_GLOBALDATA_TYPE_NULL:
321 					m_pGlobalData->SetGlobalVariableNull(name);
322 					m_pGlobalData->SetGlobalVariablePersistent(name, pData->bPersistent);
323 					break;
324 				}
325 			}
326 		}
327 	}
328 }
329 
ObjectToArray(v8::Handle<v8::Object> pObj,CJS_GlobalVariableArray & array)330 void global_alternate::ObjectToArray(v8::Handle<v8::Object> pObj, CJS_GlobalVariableArray& array)
331 {
332 	v8::Handle<v8::Array> pKeyList = JS_GetObjectElementNames(pObj);
333 	int	nObjElements = pKeyList->Length();
334 
335 	v8::Local<v8::Context> context = pObj->CreationContext();
336 	v8::Isolate* isolate = context->GetIsolate();
337 
338 	for (int i=0; i<nObjElements; i++)
339 	{
340 
341 		CFX_WideString ws = JS_ToString(JS_GetArrayElemnet(pKeyList, i));
342 		CFX_ByteString sKey = ws.UTF8Encode();
343 
344 		v8::Handle<v8::Value> v = JS_GetObjectElement(isolate, pObj, (const wchar_t*)(FX_LPCWSTR)ws);
345 		FXJSVALUETYPE vt = GET_VALUE_TYPE(v);
346 		switch (vt)
347 		{
348 		case VT_number:
349 			{
350 				CJS_KeyValue* pObjElement = new CJS_KeyValue;
351 				pObjElement->nType = JS_GLOBALDATA_TYPE_NUMBER;
352 				pObjElement->sKey = sKey;
353 				pObjElement->dData = JS_ToNumber(v);
354 				array.Add(pObjElement);
355 			}
356 			break;
357 		case VT_boolean:
358 			{
359 				CJS_KeyValue* pObjElement = new CJS_KeyValue;
360 				pObjElement->nType = JS_GLOBALDATA_TYPE_BOOLEAN;
361 				pObjElement->sKey = sKey;
362 				pObjElement->dData = JS_ToBoolean(v);
363 				array.Add(pObjElement);
364 			}
365 			break;
366 		case VT_string:
367 			{
368 				CFX_ByteString sValue = CJS_Value(isolate, v, VT_string);
369 				CJS_KeyValue* pObjElement = new CJS_KeyValue;
370 				pObjElement->nType = JS_GLOBALDATA_TYPE_STRING;
371 				pObjElement->sKey = sKey;
372 				pObjElement->sData = sValue;
373 				array.Add(pObjElement);
374 			}
375 			break;
376 		case VT_object:
377 			{
378 				CJS_KeyValue* pObjElement = new CJS_KeyValue;
379 				pObjElement->nType = JS_GLOBALDATA_TYPE_OBJECT;
380 				pObjElement->sKey = sKey;
381 				ObjectToArray(JS_ToObject(v), pObjElement->objData);
382 				array.Add(pObjElement);
383 			}
384 			break;
385 		case VT_null:
386 			{
387 				CJS_KeyValue* pObjElement = new CJS_KeyValue;
388 				pObjElement->nType = JS_GLOBALDATA_TYPE_NULL;
389 				pObjElement->sKey = sKey;
390 				array.Add(pObjElement);
391 			}
392 			break;
393 		default:
394 			break;
395 		}
396 	}
397 }
398 
PutObjectProperty(v8::Handle<v8::Object> pObj,CJS_KeyValue * pData)399 void global_alternate::PutObjectProperty(v8::Handle<v8::Object> pObj, CJS_KeyValue* pData)
400 {
401 	ASSERT(pData != NULL);
402 
403 	for (int i=0,sz=pData->objData.Count(); i<sz; i++)
404 	{
405 		CJS_KeyValue* pObjData = pData->objData.GetAt(i);
406 		ASSERT(pObjData != NULL);
407 
408 		switch (pObjData->nType)
409 		{
410 		case JS_GLOBALDATA_TYPE_NUMBER:
411 			JS_PutObjectNumber(NULL,(JSObject)pObj, pObjData->sKey.UTF8Decode(), pObjData->dData);
412 			break;
413 		case JS_GLOBALDATA_TYPE_BOOLEAN:
414 			JS_PutObjectBoolean(NULL,(JSObject)pObj, pObjData->sKey.UTF8Decode(), (bool)(pObjData->bData == 1));
415 			break;
416 		case JS_GLOBALDATA_TYPE_STRING:
417 			JS_PutObjectString(NULL,(JSObject)pObj, pObjData->sKey.UTF8Decode(), pObjData->sData.UTF8Decode());
418 			break;
419 		case JS_GLOBALDATA_TYPE_OBJECT:
420 			{
421 				IJS_Runtime* pRuntime = JS_GetRuntime((JSFXObject)(*m_pJSObject));
422 				v8::Handle<v8::Object> pNewObj = JS_NewFxDynamicObj(pRuntime, NULL, -1);
423 				PutObjectProperty(pNewObj, pObjData);
424 				JS_PutObjectObject(NULL, (JSObject)pObj, pObjData->sKey.UTF8Decode(), (JSObject)pNewObj);
425 			}
426 			break;
427 		case JS_GLOBALDATA_TYPE_NULL:
428 			JS_PutObjectNull(NULL,(JSObject)pObj, pObjData->sKey.UTF8Decode());
429 			break;
430 		}
431 	}
432 }
433 
DestroyGlobalPersisitentVariables()434 void global_alternate::DestroyGlobalPersisitentVariables()
435 {
436 	FX_POSITION	 pos = m_mapGlobal.GetStartPosition();
437 	while (pos)
438 	{
439 		CFX_ByteString name;
440 		js_global_data* pData = NULL;
441 		m_mapGlobal.GetNextAssoc(pos, name, (FX_LPVOID&)pData);
442 		delete pData;
443 	}
444 
445 	m_mapGlobal.RemoveAll();
446 }
447 
448 
SetGlobalVariables(FX_LPCSTR propname,int nType,double dData,bool bData,const CFX_ByteString & sData,JSObject pData,bool bDefaultPersistent)449 FX_BOOL global_alternate::SetGlobalVariables(FX_LPCSTR propname, int nType,
450 				double dData, bool bData, const CFX_ByteString& sData, JSObject pData, bool bDefaultPersistent)
451 {
452 	if (propname == NULL) return FALSE;
453 
454 	js_global_data* pTemp = NULL;
455 	m_mapGlobal.Lookup(propname, (FX_LPVOID&)pTemp);
456 
457 	if (pTemp)
458 	{
459 		if (pTemp->bDeleted || pTemp->nType != nType)
460 		{
461 			pTemp->dData = 0;
462 			pTemp->bData = 0;
463 			pTemp->sData = "";
464 			pTemp->nType = nType;
465 		}
466 
467 		pTemp->bDeleted = FALSE;
468 
469 		switch (nType)
470 		{
471 		case JS_GLOBALDATA_TYPE_NUMBER:
472 			{
473 				pTemp->dData = dData;
474 			}
475 			break;
476 		case JS_GLOBALDATA_TYPE_BOOLEAN:
477 			{
478 				pTemp->bData = bData;
479 			}
480 			break;
481 		case JS_GLOBALDATA_TYPE_STRING:
482 			{
483 				pTemp->sData = sData;
484 			}
485 			break;
486 		case JS_GLOBALDATA_TYPE_OBJECT:
487 			{
488 				pTemp->pData.Reset(JS_GetRuntime(pData), pData);
489 			}
490 			break;
491 		case JS_GLOBALDATA_TYPE_NULL:
492 			break;
493 		default:
494 			return FALSE;
495 		}
496 
497 		return TRUE;
498 	}
499 
500 	js_global_data* pNewData = NULL;
501 
502 	switch (nType)
503 	{
504 	case JS_GLOBALDATA_TYPE_NUMBER:
505 		{
506 			pNewData = new js_global_data;
507 			pNewData->nType = JS_GLOBALDATA_TYPE_NUMBER;
508 			pNewData->dData = dData;
509 			pNewData->bPersistent = bDefaultPersistent;
510 		}
511 		break;
512 	case JS_GLOBALDATA_TYPE_BOOLEAN:
513 		{
514 			pNewData = new js_global_data;
515 			pNewData->nType = JS_GLOBALDATA_TYPE_BOOLEAN;
516 			pNewData->bData = bData;
517 			pNewData->bPersistent = bDefaultPersistent;
518 		}
519 		break;
520 	case JS_GLOBALDATA_TYPE_STRING:
521 		{
522 			pNewData = new js_global_data;
523 			pNewData->nType = JS_GLOBALDATA_TYPE_STRING;
524 			pNewData->sData = sData;
525 			pNewData->bPersistent = bDefaultPersistent;
526 		}
527 		break;
528 	case JS_GLOBALDATA_TYPE_OBJECT:
529 		{
530 			pNewData = new js_global_data;
531 			pNewData->nType = JS_GLOBALDATA_TYPE_OBJECT;
532 			pNewData->pData.Reset(JS_GetRuntime(pData), pData);
533 			pNewData->bPersistent = bDefaultPersistent;
534 		}
535 		break;
536 	case JS_GLOBALDATA_TYPE_NULL:
537 		{
538 			pNewData = new js_global_data;
539 			pNewData->nType = JS_GLOBALDATA_TYPE_NULL;
540 			pNewData->bPersistent = bDefaultPersistent;
541 		}
542 		break;
543 	default:
544 		return FALSE;
545 	}
546 
547 	m_mapGlobal.SetAt(propname, (FX_LPVOID)pNewData);
548 
549 	return TRUE;
550 }
551