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