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