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