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