Removing unnecessary casts from wchar_t* to wchar_t*, by various names.
[pdfium.git] / fpdfsdk / src / javascript / global.cpp
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
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
44 global_alternate::global_alternate(CJS_Object* pJSObject)
45         : CJS_EmbedObj(pJSObject),
46         m_pApp(NULL)
47 {
48 }
49
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   
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
73 FX_BOOL global_alternate::QueryProperty(FX_LPCWSTR propname)
74 {
75         return CFX_WideString(propname) != L"setPersistent";
76 }
77
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
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
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
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
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
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, (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
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
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
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 }