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