Merge XFA to PDFium master at 4dc95e7 on 10/28/2014
[pdfium.git] / fpdfsdk / src / javascript / JS_Runtime.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_EventHandler.h"
10 #include "../../include/javascript/JS_Runtime.h"
11 #include "../../include/javascript/JS_Context.h"
12 #include "../../include/javascript/JS_Define.h"
13 #include "../../include/javascript/JS_Object.h"
14 #include "../../include/javascript/JS_Value.h"
15 #include "../../include/javascript/Document.h"
16 #include "../../include/javascript/app.h"
17 #include "../../include/javascript/color.h"
18 #include "../../include/javascript/Consts.h"
19 #include "../../include/javascript/Document.h"
20 #include "../../include/javascript/event.h"
21 #include "../../include/javascript/Field.h"
22 #include "../../include/javascript/Icon.h"
23 #include "../../include/javascript/PublicMethods.h"
24 #include "../../include/javascript/report.h"
25 #include "../../include/javascript/util.h"
26 #include "../../include/javascript/JS_GlobalData.h"
27 #include "../../include/javascript/global.h"
28 #include "../../include/javascript/console.h"
29 #include "../../include/fpdfxfa/fpdfxfa_app.h"
30 #ifndef FOXIT_CHROME_BUILD
31 #include "../../../fxjse/value.h"
32 #else
33 #include "../../../xfa/src/fxjse/src/value.h"
34 #endif
35
36 #include <libplatform/libplatform.h>
37
38 CJS_RuntimeFactory::~CJS_RuntimeFactory()
39 {
40 }
41
42 IFXJS_Runtime*                                  CJS_RuntimeFactory::NewJSRuntime(CPDFDoc_Environment* pApp)
43 {
44         if (!m_bInit)
45         {
46                 JS_Initial();
47                 m_platform = v8::platform::CreateDefaultPlatform();
48                 v8::V8::InitializePlatform(m_platform);
49                 v8::V8::Initialize();
50                 
51                 m_bInit = TRUE;
52         }
53         return new CJS_Runtime(pApp);
54 }
55 void                                                    CJS_RuntimeFactory::AddRef()
56 {
57         //to do.Should be implemented as atom manipulation.
58         m_nRef++;
59 }
60 void                                                    CJS_RuntimeFactory::Release()
61 {       
62         if(m_bInit)
63         {
64                 //to do.Should be implemented as atom manipulation.
65                 if (--m_nRef == 0)
66                 {
67                         JS_Release();
68                         ReleaseGlobalData();
69                         v8::V8::ShutdownPlatform();
70                         delete m_platform;
71                         m_platform = NULL;
72                         m_bInit = FALSE;
73                 }
74         }
75 }
76
77 void                                                    CJS_RuntimeFactory::DeleteJSRuntime(IFXJS_Runtime* pRuntime)
78 {
79         if(pRuntime)
80                 delete (CJS_Runtime*)pRuntime;
81 }
82
83 CJS_GlobalData* CJS_RuntimeFactory::NewGlobalData(CPDFDoc_Environment* pApp)
84 {
85         if (m_pGlobalData)
86         {
87                 m_nGlobalDataCount++;
88                 return m_pGlobalData;
89         }
90         else
91         {
92                 m_nGlobalDataCount = 1;
93                 m_pGlobalData = new CJS_GlobalData(pApp);
94                 return m_pGlobalData;
95         }
96 }
97
98 void CJS_RuntimeFactory::ReleaseGlobalData()
99 {
100         m_nGlobalDataCount--;
101         
102         if (m_nGlobalDataCount <= 0)
103         {
104                 delete m_pGlobalData;
105                 m_pGlobalData = NULL;
106         }
107 }
108
109 /* ------------------------------ CJS_Runtime ------------------------------ */
110 extern v8::Persistent<v8::ObjectTemplate>& _getGlobalObjectTemplate(IJS_Runtime* pJSRuntime);
111 CJS_Runtime::CJS_Runtime(CPDFDoc_Environment* pApp) :
112         m_pApp(pApp),
113         m_pDocument(NULL),
114         m_bBlocking(FALSE),
115         m_pFieldEventPath(NULL),
116         m_bRegistered(FALSE)
117 {
118         m_isolate = FPDFXFA_GetApp()->GetJSERuntime()?(v8::Isolate*)FPDFXFA_GetApp()->GetJSERuntime():v8::Isolate::New();
119         //m_isolate->Enter();
120         v8::Isolate* isolate = m_isolate;
121         v8::Isolate::Scope isolate_scope(isolate);
122         v8::Locker locker(isolate);
123         v8::HandleScope handle_scope(isolate);
124         if (FPDFXFA_GetApp()->InitRuntime(FALSE)) {
125                 CJS_Context * pContext = (CJS_Context*)NewContext();
126                 JS_InitialRuntime(*this, this, pContext, m_context);
127                 ReleaseContext(pContext);
128                 return;
129         }
130
131         InitJSObjects();
132
133         CJS_Context * pContext = (CJS_Context*)NewContext();
134         JS_InitialRuntime(*this, this, pContext, m_context);
135         ReleaseContext(pContext);
136 }
137
138 CJS_Runtime::~CJS_Runtime()
139 {
140         int size = m_ContextArray.GetSize();
141         for (int i=0;i < size; i++)
142                 delete m_ContextArray.GetAt(i);
143
144         m_ContextArray.RemoveAll();
145
146         //JS_ReleaseRuntime(*this, m_context);
147
148         RemoveEventsInLoop(m_pFieldEventPath);
149
150         m_pApp = NULL;
151         m_pDocument = NULL;
152         m_pFieldEventPath = NULL;
153         m_context.Reset();
154
155         //m_isolate->Exit();
156         //m_isolate->Dispose();
157         m_isolate = NULL;
158 }
159
160 FX_BOOL CJS_Runtime::InitJSObjects()
161 {
162         v8::Isolate::Scope isolate_scope(GetIsolate());
163         v8::Locker locker(GetIsolate());
164         v8::HandleScope handle_scope(GetIsolate());
165         v8::Handle<v8::Context> context = v8::Context::New(GetIsolate());
166         v8::Context::Scope context_scope(context);
167         //0 - 8
168         if (CJS_Border::Init(*this, JS_STATIC) < 0) return FALSE;
169         if (CJS_Display::Init(*this, JS_STATIC) < 0) return FALSE;
170         if (CJS_Font::Init(*this, JS_STATIC) < 0) return FALSE;
171         if (CJS_Highlight::Init(*this, JS_STATIC) < 0) return FALSE;
172         if (CJS_Position::Init(*this, JS_STATIC) < 0) return FALSE;
173         if (CJS_ScaleHow::Init(*this, JS_STATIC) < 0) return FALSE;
174         if (CJS_ScaleWhen::Init(*this, JS_STATIC) < 0) return FALSE;
175         if (CJS_Style::Init(*this, JS_STATIC) < 0) return FALSE;        
176         if (CJS_Zoomtype::Init(*this, JS_STATIC) < 0) return FALSE;     
177
178         //9 - 11
179         if (CJS_App::Init(*this, JS_STATIC) < 0) return FALSE;
180         if (CJS_Color::Init(*this, JS_STATIC) < 0) return FALSE;   
181         if (CJS_Console::Init(*this, JS_STATIC) < 0) return FALSE;
182
183         //12 - 14
184         if (CJS_Document::Init(*this, JS_DYNAMIC) < 0) return FALSE;  
185         if (CJS_Event::Init(*this, JS_STATIC) < 0) return FALSE;                
186         if (CJS_Field::Init(*this, JS_DYNAMIC) < 0) return FALSE;    
187
188         //15 - 17
189         if (CJS_Global::Init(*this, JS_STATIC) < 0) return FALSE;               
190         if (CJS_Icon::Init(*this, JS_DYNAMIC) < 0) return FALSE;
191         if (CJS_Util::Init(*this, JS_STATIC) < 0) return FALSE;
192
193         if (CJS_PublicMethods::Init(*this) < 0) return FALSE;
194         if (CJS_GlobalConsts::Init(*this) < 0) return FALSE;
195         if (CJS_GlobalArrays::Init(*this) < 0) return FALSE;
196
197         if (CJS_TimerObj::Init(*this, JS_DYNAMIC) < 0) return FALSE;
198         if (CJS_PrintParamsObj::Init(*this, JS_DYNAMIC) <0) return FALSE;
199
200         return TRUE;
201 }
202
203 IFXJS_Context* CJS_Runtime::NewContext()
204 {
205         CJS_Context * p = new CJS_Context(this);
206         m_ContextArray.Add(p);
207         return p;
208 }
209
210 void CJS_Runtime::ReleaseContext(IFXJS_Context * pContext)
211 {
212         CJS_Context* pJSContext = (CJS_Context*)pContext;
213
214         for (int i=0, sz=m_ContextArray.GetSize(); i<sz; i++)
215         {
216                 if (pJSContext == m_ContextArray.GetAt(i))
217                 {
218                         delete pJSContext;
219                         m_ContextArray.RemoveAt(i);
220                         break;
221                 }
222         }
223 }
224
225 IFXJS_Context*  CJS_Runtime::GetCurrentContext()
226 {
227         if(!m_ContextArray.GetSize())
228                 return NULL;
229         return m_ContextArray.GetAt(m_ContextArray.GetSize()-1);
230 }
231
232 void CJS_Runtime::SetReaderDocument(CPDFSDK_Document* pReaderDoc)
233 {
234         if (m_pDocument != pReaderDoc)
235         {
236                 v8::Isolate::Scope isolate_scope(m_isolate);
237                 v8::Locker locker(m_isolate);
238                 v8::HandleScope handle_scope(m_isolate);
239                 v8::Local<v8::Context> context =v8::Local<v8::Context>::New(m_isolate, m_context);
240                 v8::Context::Scope context_scope(context);
241
242                 m_pDocument = pReaderDoc;
243
244                 if (pReaderDoc)
245                 {
246                         JSObject pThis = JS_GetThisObj(*this);
247                         if(!pThis.IsEmpty())
248                         {
249                                 if (JS_GetObjDefnID(pThis) == JS_GetObjDefnID(*this, L"Document"))
250                                 {
251                                         if (CJS_Document* pJSDocument = (CJS_Document*)JS_GetPrivate(pThis))
252                                         {
253                                                 if (Document * pDocument = (Document*)pJSDocument->GetEmbedObject())
254                                                         pDocument->AttachDoc(pReaderDoc);
255                                         }
256                                 }
257                         }
258                         JS_SetThisObj(*this, JS_GetObjDefnID(*this, L"Document"));
259                 }
260                 else
261                 {
262                         JS_SetThisObj(*this, JS_GetObjDefnID(*this, L"app"));
263                 }
264         }
265 }
266
267 FX_BOOL CJS_Runtime::AddEventToLoop(const CFX_WideString& sTargetName, JS_EVENT_T eEventType)
268 {
269         if (m_pFieldEventPath == NULL)
270         {
271                 m_pFieldEventPath = new CJS_FieldEvent;
272                 m_pFieldEventPath->sTargetName = sTargetName;
273                 m_pFieldEventPath->eEventType = eEventType;
274                 m_pFieldEventPath->pNext = NULL;
275
276                 return TRUE;
277         }
278
279         //to search
280         CJS_FieldEvent* p = m_pFieldEventPath;
281         CJS_FieldEvent* pLast = m_pFieldEventPath;
282         while (p)
283         {
284                 if (p->eEventType == eEventType && p->sTargetName == sTargetName)
285                         return FALSE;
286
287                 pLast = p;
288                 p = p->pNext;
289         }
290
291         //to add
292         CJS_FieldEvent* pNew = new CJS_FieldEvent;
293         pNew->sTargetName = sTargetName;
294         pNew->eEventType = eEventType;
295         pNew->pNext = NULL;
296
297         pLast->pNext = pNew;
298
299         return TRUE;
300 }
301
302 void CJS_Runtime::RemoveEventInLoop(const CFX_WideString& sTargetName, JS_EVENT_T eEventType)
303 {
304         FX_BOOL bFind = FALSE;
305
306         CJS_FieldEvent* p = m_pFieldEventPath;
307         CJS_FieldEvent* pLast = NULL;
308         while (p)
309         {
310                 if (p->eEventType == eEventType && p->sTargetName == sTargetName)
311                 {
312                         bFind = TRUE;
313                         break;
314                 }
315
316                 pLast = p;
317                 p = p->pNext;
318         }
319
320         if (bFind)
321         {
322                 RemoveEventsInLoop(p);
323
324                 if (p == m_pFieldEventPath)
325                         m_pFieldEventPath = NULL;
326
327                 if (pLast)
328                         pLast->pNext = NULL;
329         }
330 }
331
332 void CJS_Runtime::RemoveEventsInLoop(CJS_FieldEvent* pStart)
333 {
334         CJS_FieldEvent* p = pStart;
335
336         while (p)
337         {
338                 CJS_FieldEvent* pOld = p;
339                 p = pOld->pNext;
340
341                 delete pOld;
342         }
343 }
344
345 v8::Handle<v8::Context> CJS_Runtime::NewJSContext()
346 {
347         return v8::Local<v8::Context>::New(m_isolate, m_context);
348 }
349
350 CFX_WideString ChangeObjName(const CFX_WideString& str)
351 {
352         CFX_WideString sRet = str;
353         sRet.Replace((FX_LPCWSTR)L"_", (FX_LPCWSTR)L".");
354         return sRet;
355 }
356
357 void CJS_Runtime::GetObjectNames(CFX_WideStringArray& array)
358 {
359         array.RemoveAll();
360
361         array.Add(CJS_Border::m_pClassName);
362         array.Add(CJS_Display::m_pClassName);
363         array.Add(CJS_Font::m_pClassName);
364         array.Add(CJS_Highlight::m_pClassName);
365         array.Add(CJS_Position::m_pClassName);
366         array.Add(CJS_ScaleHow::m_pClassName);
367         array.Add(CJS_ScaleWhen::m_pClassName);
368         array.Add(CJS_Style::m_pClassName);
369         array.Add(CJS_Zoomtype::m_pClassName);
370
371         array.Add(CJS_App::m_pClassName);
372         array.Add((FX_LPCWSTR)"this"); 
373         array.Add(CJS_Event::m_pClassName);     
374
375         array.Add(CJS_Global::m_pClassName);    
376         array.Add(CJS_Util::m_pClassName);
377 }
378
379 void CJS_Runtime::GetObjectConsts(const CFX_WideString& sObjName, CFX_WideStringArray& array)
380 {
381         JSConstSpec* pConsts = NULL;
382         int nSize = 0;
383
384         if (sObjName == CJS_Border::m_pClassName)
385                 CJS_Border::GetConsts(pConsts, nSize);
386         else if (sObjName == CJS_Display::m_pClassName)
387                 CJS_Display::GetConsts(pConsts, nSize);
388         else if (sObjName == CJS_Font::m_pClassName)
389                 CJS_Font::GetConsts(pConsts, nSize);
390         else if (sObjName == CJS_Highlight::m_pClassName)
391                 CJS_Highlight::GetConsts(pConsts, nSize);
392         else if (sObjName == CJS_Position::m_pClassName)
393                 CJS_Position::GetConsts(pConsts, nSize);
394         else if (sObjName == CJS_ScaleHow::m_pClassName)
395                 CJS_ScaleHow::GetConsts(pConsts, nSize);
396         else if (sObjName == CJS_ScaleWhen::m_pClassName)
397                 CJS_ScaleWhen::GetConsts(pConsts, nSize);
398         else if (sObjName == CJS_Style::m_pClassName)
399                 CJS_Style::GetConsts(pConsts, nSize);
400         else if (sObjName == CJS_Zoomtype::m_pClassName)
401                 CJS_Zoomtype::GetConsts(pConsts, nSize);
402
403         else if (sObjName == CJS_App::m_pClassName)
404                 CJS_App::GetConsts(pConsts, nSize);
405         else if (sObjName == CJS_Color::m_pClassName)
406                 CJS_Color::GetConsts(pConsts, nSize);   
407
408         else if (sObjName == L"this") 
409         {
410                 if (GetReaderDocument())
411                         CJS_Document::GetConsts(pConsts, nSize);
412                 else 
413                         CJS_App::GetConsts(pConsts, nSize);
414         }
415
416         if (sObjName == CJS_Event::m_pClassName)
417                 CJS_Event::GetConsts(pConsts, nSize);   
418         else if (sObjName == CJS_Field::m_pClassName)
419                 CJS_Field::GetConsts(pConsts, nSize);   
420         else if (sObjName == CJS_Global::m_pClassName)
421                 CJS_Global::GetConsts(pConsts, nSize);  
422         else if (sObjName == CJS_Util::m_pClassName)
423                 CJS_Util::GetConsts(pConsts, nSize);
424
425         for (int i=0; i<nSize; i++)
426                 array.Add(pConsts[i].pName);
427 }
428
429 void CJS_Runtime::GetObjectProps(const CFX_WideString& sObjName, CFX_WideStringArray& array)
430 {
431         JSPropertySpec* pProperties = NULL;
432         int nSize = 0;
433
434         if (sObjName == CJS_App::m_pClassName)
435                 CJS_App::GetProperties(pProperties, nSize);
436         else if (sObjName == CJS_Color::m_pClassName)
437                 CJS_Color::GetProperties(pProperties, nSize); 
438         else if (sObjName == L"this")
439         {
440                 if (GetReaderDocument())
441                         CJS_Document::GetProperties(pProperties, nSize);
442                 else    
443                         CJS_App::GetProperties(pProperties, nSize);
444         }
445         else if (sObjName == CJS_Event::m_pClassName)
446                 CJS_Event::GetProperties(pProperties, nSize);   
447         else if (sObjName == CJS_Field::m_pClassName)
448                 CJS_Field::GetProperties(pProperties, nSize);   
449         else if (sObjName == CJS_Global::m_pClassName)
450                 CJS_Global::GetProperties(pProperties, nSize);  
451         else if (sObjName == CJS_Util::m_pClassName)
452                 CJS_Util::GetProperties(pProperties, nSize);
453
454         for (int i=0; i<nSize; i++)
455                 array.Add(pProperties[i].pName);
456 }
457
458 void CJS_Runtime::GetObjectMethods(const CFX_WideString& sObjName, CFX_WideStringArray& array)
459 {
460         JSMethodSpec* pMethods = NULL;
461         int nSize = 0;
462
463          if (sObjName == CJS_App::m_pClassName)
464                 CJS_App::GetMethods(pMethods, nSize);
465         else if (sObjName == CJS_Color::m_pClassName)
466                 CJS_Color::GetMethods(pMethods, nSize); 
467         else if (sObjName == L"this") 
468         {
469                 if (GetReaderDocument())
470                         CJS_Document::GetMethods(pMethods, nSize);
471                 else    
472                         CJS_App::GetMethods(pMethods, nSize);
473         }
474         else if (sObjName == CJS_Event::m_pClassName)
475                 CJS_Event::GetMethods(pMethods, nSize); 
476         else if (sObjName == CJS_Field::m_pClassName)
477                 CJS_Field::GetMethods(pMethods, nSize); 
478         else if (sObjName == CJS_Global::m_pClassName)
479                 CJS_Global::GetMethods(pMethods, nSize);        
480         else if (sObjName == CJS_Util::m_pClassName)
481                 CJS_Util::GetMethods(pMethods, nSize);
482
483         for (int i=0; i<nSize; i++)
484                 array.Add(pMethods[i].pName);
485 }
486
487 FX_BOOL  CJS_Runtime::IsEntered()
488 {
489         return v8::Isolate::GetCurrent() == m_isolate;
490 }
491 void    CJS_Runtime::Exit()
492 {
493         if(m_isolate) m_isolate->Exit();
494 }
495 void    CJS_Runtime::Enter()
496 {
497         if(m_isolate) m_isolate->Enter();
498 }
499 FX_BOOL CJS_Runtime::GetHValueByName(FX_BSTR utf8Name, FXJSE_HVALUE hValue)
500 {
501         FX_LPCSTR name = utf8Name.GetCStr();
502
503         v8::Locker lock(GetIsolate());
504     v8::Isolate::Scope isolate_scope(GetIsolate());
505     v8::HandleScope handle_scope(GetIsolate());
506     v8::Local<v8::Context> context =
507         v8::Local<v8::Context>::New(GetIsolate(), m_context);
508     v8::Context::Scope context_scope(context);
509
510
511         //v8::Local<v8::Context> tmpCotext = v8::Local<v8::Context>::New(GetIsolate(), m_context);
512         v8::Local<v8::Value> propvalue = context->Global()->Get(v8::String::NewFromUtf8(GetIsolate(), name, v8::String::kNormalString, utf8Name.GetLength()));
513          
514         if (propvalue.IsEmpty()) {
515                 FXJSE_Value_SetUndefined(hValue);
516                 return FALSE;
517         }
518         ((CFXJSE_Value*)hValue)->ForceSetValue(propvalue);
519
520         return TRUE;
521 }
522 FX_BOOL CJS_Runtime::SetHValueByName(FX_BSTR utf8Name, FXJSE_HVALUE hValue)
523 {
524         if (utf8Name.IsEmpty() || hValue == NULL)
525                 return FALSE;
526         FX_LPCSTR name = utf8Name.GetCStr();
527         v8::Isolate* pIsolate = GetIsolate();
528         v8::Locker lock(pIsolate);
529     v8::Isolate::Scope isolate_scope(pIsolate);
530     v8::HandleScope handle_scope(pIsolate);
531     v8::Local<v8::Context> context =
532         v8::Local<v8::Context>::New(pIsolate, m_context);
533     v8::Context::Scope context_scope(context);
534
535         //v8::Local<v8::Context> tmpCotext = v8::Local<v8::Context>::New(GetIsolate(), m_context);
536         v8::Local<v8::Value> propvalue = v8::Local<v8::Value>::New(GetIsolate(),((CFXJSE_Value*)hValue)->DirectGetValue());
537         context->Global()->Set(v8::String::NewFromUtf8(pIsolate, name, v8::String::kNormalString, utf8Name.GetLength()), propvalue);
538          
539         return TRUE;
540 }