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