Plumb in an externally created v8::Isolate
[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 void* CJS_ArrayBufferAllocator::Allocate(size_t length) {
95     return calloc(1, length);
96 }
97
98 void* CJS_ArrayBufferAllocator::AllocateUninitialized(size_t length) {
99     return malloc(length);
100 }
101
102 void CJS_ArrayBufferAllocator::Free(void* data, size_t length) {
103     free(data);
104 }
105
106 /* ------------------------------ CJS_Runtime ------------------------------ */
107
108 CJS_Runtime::CJS_Runtime(CPDFDoc_Environment * pApp) :
109         m_pApp(pApp),
110         m_pDocument(NULL),
111         m_bBlocking(FALSE),
112         m_bRegistered(FALSE),
113         m_pFieldEventPath(NULL),
114         m_isolate(NULL)
115 {
116         if (m_pApp->GetFormFillInfo()->m_pJsPlatform->version >= 2) {
117                 m_isolate = m_pApp->GetFormFillInfo()->m_pJsPlatform->m_isolate;
118         }
119         if (!m_isolate) {
120                 m_pArrayBufferAllocator.reset(new CJS_ArrayBufferAllocator());
121
122                 v8::Isolate::CreateParams params;
123                 params.array_buffer_allocator = m_pArrayBufferAllocator.get();
124                 m_isolate = v8::Isolate::New(params);
125         }
126
127         InitJSObjects();
128
129         CJS_Context * pContext = (CJS_Context*)NewContext();
130         JS_InitialRuntime(*this, this, pContext, m_context);
131         ReleaseContext(pContext);
132 }
133
134 CJS_Runtime::~CJS_Runtime()
135 {
136         for (int i=0, sz=m_ContextArray.GetSize(); i<sz; i++)
137                 delete m_ContextArray.GetAt(i);
138
139         m_ContextArray.RemoveAll();
140
141         JS_ReleaseRuntime(*this, m_context);
142
143         RemoveEventsInLoop(m_pFieldEventPath);
144
145         m_pApp = NULL;
146         m_pDocument = NULL;
147         m_pFieldEventPath = NULL;
148         m_context.Reset();
149
150         //m_isolate->Exit();
151         m_isolate->Dispose();
152 }
153
154 FX_BOOL CJS_Runtime::InitJSObjects()
155 {
156         v8::Isolate::Scope isolate_scope(GetIsolate());
157         v8::HandleScope handle_scope(GetIsolate());
158         v8::Local<v8::Context> context = v8::Context::New(GetIsolate());
159         v8::Context::Scope context_scope(context);
160         //0 - 8
161         if (CJS_Border::Init(*this, JS_STATIC) < 0) return FALSE;
162         if (CJS_Display::Init(*this, JS_STATIC) < 0) return FALSE;
163         if (CJS_Font::Init(*this, JS_STATIC) < 0) return FALSE;
164         if (CJS_Highlight::Init(*this, JS_STATIC) < 0) return FALSE;
165         if (CJS_Position::Init(*this, JS_STATIC) < 0) return FALSE;
166         if (CJS_ScaleHow::Init(*this, JS_STATIC) < 0) return FALSE;
167         if (CJS_ScaleWhen::Init(*this, JS_STATIC) < 0) return FALSE;
168         if (CJS_Style::Init(*this, JS_STATIC) < 0) return FALSE;
169         if (CJS_Zoomtype::Init(*this, JS_STATIC) < 0) return FALSE;
170
171         //9 - 11
172         if (CJS_App::Init(*this, JS_STATIC) < 0) return FALSE;
173         if (CJS_Color::Init(*this, JS_STATIC) < 0) return FALSE;
174         if (CJS_Console::Init(*this, JS_STATIC) < 0) return FALSE;
175
176         //12 - 14
177         if (CJS_Document::Init(*this, JS_DYNAMIC) < 0) return FALSE;
178         if (CJS_Event::Init(*this, JS_STATIC) < 0) return FALSE;
179         if (CJS_Field::Init(*this, JS_DYNAMIC) < 0) return FALSE;
180
181         //15 - 17
182         if (CJS_Global::Init(*this, JS_STATIC) < 0) return FALSE;
183         if (CJS_Icon::Init(*this, JS_DYNAMIC) < 0) return FALSE;
184         if (CJS_Util::Init(*this, JS_STATIC) < 0) return FALSE;
185
186         if (CJS_PublicMethods::Init(*this) < 0) return FALSE;
187         if (CJS_GlobalConsts::Init(*this) < 0) return FALSE;
188         if (CJS_GlobalArrays::Init(*this) < 0) return FALSE;
189
190         if (CJS_TimerObj::Init(*this, JS_DYNAMIC) < 0) return FALSE;
191         if (CJS_PrintParamsObj::Init(*this, JS_DYNAMIC) <0) return FALSE;
192
193         return TRUE;
194 }
195
196 IFXJS_Context* CJS_Runtime::NewContext()
197 {
198         CJS_Context * p = new CJS_Context(this);
199         m_ContextArray.Add(p);
200         return p;
201 }
202
203 void CJS_Runtime::ReleaseContext(IFXJS_Context * pContext)
204 {
205         CJS_Context* pJSContext = (CJS_Context*)pContext;
206
207         for (int i=0, sz=m_ContextArray.GetSize(); i<sz; i++)
208         {
209                 if (pJSContext == m_ContextArray.GetAt(i))
210                 {
211                         delete pJSContext;
212                         m_ContextArray.RemoveAt(i);
213                         break;
214                 }
215         }
216 }
217
218 IFXJS_Context*  CJS_Runtime::GetCurrentContext()
219 {
220         if(!m_ContextArray.GetSize())
221                 return NULL;
222         return m_ContextArray.GetAt(m_ContextArray.GetSize()-1);
223 }
224
225 void CJS_Runtime::SetReaderDocument(CPDFSDK_Document* pReaderDoc)
226 {
227         if (m_pDocument != pReaderDoc)
228         {
229                 v8::Isolate::Scope isolate_scope(m_isolate);
230                 v8::HandleScope handle_scope(m_isolate);
231                 v8::Local<v8::Context> context =v8::Local<v8::Context>::New(m_isolate, m_context);
232                 v8::Context::Scope context_scope(context);
233
234                 m_pDocument = pReaderDoc;
235
236                 if (pReaderDoc)
237                 {
238                         JSObject pThis = JS_GetThisObj(*this);
239                         if(!pThis.IsEmpty())
240                         {
241                                 if (JS_GetObjDefnID(pThis) == JS_GetObjDefnID(*this, L"Document"))
242                                 {
243                                         if (CJS_Document* pJSDocument = (CJS_Document*)JS_GetPrivate(pThis))
244                                         {
245                                                 if (Document * pDocument = (Document*)pJSDocument->GetEmbedObject())
246                                                         pDocument->AttachDoc(pReaderDoc);
247                                         }
248                                 }
249                         }
250                         JS_SetThisObj(*this, JS_GetObjDefnID(*this, L"Document"));
251                 }
252                 else
253                 {
254                         JS_SetThisObj(*this, JS_GetObjDefnID(*this, L"app"));
255                 }
256         }
257 }
258
259 FX_BOOL CJS_Runtime::AddEventToLoop(const CFX_WideString& sTargetName, JS_EVENT_T eEventType)
260 {
261         if (m_pFieldEventPath == NULL)
262         {
263                 m_pFieldEventPath = new CJS_FieldEvent;
264                 m_pFieldEventPath->sTargetName = sTargetName;
265                 m_pFieldEventPath->eEventType = eEventType;
266                 m_pFieldEventPath->pNext = NULL;
267
268                 return TRUE;
269         }
270
271         //to search
272         CJS_FieldEvent* p = m_pFieldEventPath;
273         CJS_FieldEvent* pLast = m_pFieldEventPath;
274         while (p)
275         {
276                 if (p->eEventType == eEventType && p->sTargetName == sTargetName)
277                         return FALSE;
278
279                 pLast = p;
280                 p = p->pNext;
281         }
282
283         //to add
284         CJS_FieldEvent* pNew = new CJS_FieldEvent;
285         pNew->sTargetName = sTargetName;
286         pNew->eEventType = eEventType;
287         pNew->pNext = NULL;
288
289         pLast->pNext = pNew;
290
291         return TRUE;
292 }
293
294 void CJS_Runtime::RemoveEventInLoop(const CFX_WideString& sTargetName, JS_EVENT_T eEventType)
295 {
296         FX_BOOL bFind = FALSE;
297
298         CJS_FieldEvent* p = m_pFieldEventPath;
299         CJS_FieldEvent* pLast = NULL;
300         while (p)
301         {
302                 if (p->eEventType == eEventType && p->sTargetName == sTargetName)
303                 {
304                         bFind = TRUE;
305                         break;
306                 }
307
308                 pLast = p;
309                 p = p->pNext;
310         }
311
312         if (bFind)
313         {
314                 RemoveEventsInLoop(p);
315
316                 if (p == m_pFieldEventPath)
317                         m_pFieldEventPath = NULL;
318
319                 if (pLast)
320                         pLast->pNext = NULL;
321         }
322 }
323
324 void CJS_Runtime::RemoveEventsInLoop(CJS_FieldEvent* pStart)
325 {
326         CJS_FieldEvent* p = pStart;
327
328         while (p)
329         {
330                 CJS_FieldEvent* pOld = p;
331                 p = pOld->pNext;
332
333                 delete pOld;
334         }
335 }
336
337 v8::Local<v8::Context>  CJS_Runtime::NewJSContext()
338 {
339         return v8::Local<v8::Context>::New(m_isolate, m_context);
340 }
341
342 CFX_WideString ChangeObjName(const CFX_WideString& str)
343 {
344         CFX_WideString sRet = str;
345         sRet.Replace(L"_", L".");
346         return sRet;
347 }