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