Re-land else-after-returns
[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         unsigned int embedderDataSlot = 0;
39         if (pApp->GetFormFillInfo()->m_pJsPlatform->version >= 2) {
40             embedderDataSlot = pApp->GetFormFillInfo()->m_pJsPlatform->m_v8EmbedderSlot;
41                 }
42         JS_Initial(embedderDataSlot);
43         m_bInit = TRUE;
44     }
45     return new CJS_Runtime(pApp);
46 }
47 void                            CJS_RuntimeFactory::AddRef()
48 {
49     //to do.Should be implemented as atom manipulation.
50     m_nRef++;
51 }
52 void                            CJS_RuntimeFactory::Release()
53 {
54     if(m_bInit)
55     {
56         //to do.Should be implemented as atom manipulation.
57         if (--m_nRef == 0)
58         {
59             JS_Release();
60             ReleaseGlobalData();
61             m_bInit = FALSE;
62         }
63     }
64 }
65
66 void                            CJS_RuntimeFactory::DeleteJSRuntime(IFXJS_Runtime* pRuntime)
67 {
68     delete (CJS_Runtime*)pRuntime;
69 }
70
71 CJS_GlobalData* CJS_RuntimeFactory::NewGlobalData(CPDFDoc_Environment* pApp)
72 {
73     if (m_pGlobalData)
74     {
75         m_nGlobalDataCount++;
76         return m_pGlobalData;
77     }
78     m_nGlobalDataCount = 1;
79     m_pGlobalData = new CJS_GlobalData(pApp);
80     return m_pGlobalData;
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_pFieldEventPath(NULL),
113     m_isolate(NULL)
114 {
115     if (m_pApp->GetFormFillInfo()->m_pJsPlatform->version >= 2) {
116         m_isolate = reinterpret_cast<v8::Isolate*>(m_pApp->GetFormFillInfo()->m_pJsPlatform->m_isolate);
117     }
118     if (!m_isolate) {
119         m_pArrayBufferAllocator.reset(new CJS_ArrayBufferAllocator());
120
121         v8::Isolate::CreateParams params;
122         params.array_buffer_allocator = m_pArrayBufferAllocator.get();
123         m_isolate = v8::Isolate::New(params);
124         }
125
126     InitJSObjects();
127
128     CJS_Context * pContext = (CJS_Context*)NewContext();
129     JS_InitialRuntime(*this, this, pContext, m_context);
130     ReleaseContext(pContext);
131 }
132
133 CJS_Runtime::~CJS_Runtime()
134 {
135     for (int i=0, sz=m_ContextArray.GetSize(); i<sz; i++)
136         delete m_ContextArray.GetAt(i);
137
138     m_ContextArray.RemoveAll();
139
140     JS_ReleaseRuntime(*this, m_context);
141
142     RemoveEventsInLoop(m_pFieldEventPath);
143
144     m_pApp = NULL;
145     m_pDocument = NULL;
146     m_pFieldEventPath = NULL;
147     m_context.Reset();
148
149     //m_isolate->Exit();
150     m_isolate->Dispose();
151 }
152
153 FX_BOOL CJS_Runtime::InitJSObjects()
154 {
155     v8::Isolate::Scope isolate_scope(GetIsolate());
156     v8::HandleScope handle_scope(GetIsolate());
157     v8::Local<v8::Context> context = v8::Context::New(GetIsolate());
158     v8::Context::Scope context_scope(context);
159     //0 - 8
160     if (CJS_Border::Init(*this, JS_STATIC) < 0) return FALSE;
161     if (CJS_Display::Init(*this, JS_STATIC) < 0) return FALSE;
162     if (CJS_Font::Init(*this, JS_STATIC) < 0) return FALSE;
163     if (CJS_Highlight::Init(*this, JS_STATIC) < 0) return FALSE;
164     if (CJS_Position::Init(*this, JS_STATIC) < 0) return FALSE;
165     if (CJS_ScaleHow::Init(*this, JS_STATIC) < 0) return FALSE;
166     if (CJS_ScaleWhen::Init(*this, JS_STATIC) < 0) return FALSE;
167     if (CJS_Style::Init(*this, JS_STATIC) < 0) return FALSE;
168     if (CJS_Zoomtype::Init(*this, JS_STATIC) < 0) return FALSE;
169
170     //9 - 11
171     if (CJS_App::Init(*this, JS_STATIC) < 0) return FALSE;
172     if (CJS_Color::Init(*this, JS_STATIC) < 0) return FALSE;
173     if (CJS_Console::Init(*this, JS_STATIC) < 0) return FALSE;
174
175     //12 - 14
176     if (CJS_Document::Init(*this, JS_DYNAMIC) < 0) return FALSE;
177     if (CJS_Event::Init(*this, JS_STATIC) < 0) return FALSE;
178     if (CJS_Field::Init(*this, JS_DYNAMIC) < 0) return FALSE;
179
180     //15 - 17
181     if (CJS_Global::Init(*this, JS_STATIC) < 0) return FALSE;
182     if (CJS_Icon::Init(*this, JS_DYNAMIC) < 0) return FALSE;
183     if (CJS_Util::Init(*this, JS_STATIC) < 0) return FALSE;
184
185     if (CJS_PublicMethods::Init(*this) < 0) return FALSE;
186     if (CJS_GlobalConsts::Init(*this) < 0) return FALSE;
187     if (CJS_GlobalArrays::Init(*this) < 0) return FALSE;
188
189     if (CJS_TimerObj::Init(*this, JS_DYNAMIC) < 0) return FALSE;
190     if (CJS_PrintParamsObj::Init(*this, JS_DYNAMIC) <0) return FALSE;
191
192     return TRUE;
193 }
194
195 IFXJS_Context* CJS_Runtime::NewContext()
196 {
197     CJS_Context * p = new CJS_Context(this);
198     m_ContextArray.Add(p);
199     return p;
200 }
201
202 void CJS_Runtime::ReleaseContext(IFXJS_Context * pContext)
203 {
204     CJS_Context* pJSContext = (CJS_Context*)pContext;
205
206     for (int i=0, sz=m_ContextArray.GetSize(); i<sz; i++)
207     {
208         if (pJSContext == m_ContextArray.GetAt(i))
209         {
210             delete pJSContext;
211             m_ContextArray.RemoveAt(i);
212             break;
213         }
214     }
215 }
216
217 IFXJS_Context*  CJS_Runtime::GetCurrentContext()
218 {
219     if(!m_ContextArray.GetSize())
220         return NULL;
221     return m_ContextArray.GetAt(m_ContextArray.GetSize()-1);
222 }
223
224 void CJS_Runtime::SetReaderDocument(CPDFSDK_Document* pReaderDoc)
225 {
226     if (m_pDocument != pReaderDoc)
227     {
228         v8::Isolate::Scope isolate_scope(m_isolate);
229         v8::HandleScope handle_scope(m_isolate);
230         v8::Local<v8::Context> context =v8::Local<v8::Context>::New(m_isolate, m_context);
231         v8::Context::Scope context_scope(context);
232
233         m_pDocument = pReaderDoc;
234
235         if (pReaderDoc)
236         {
237             JSObject pThis = JS_GetThisObj(*this);
238             if(!pThis.IsEmpty())
239             {
240                 if (JS_GetObjDefnID(pThis) == JS_GetObjDefnID(*this, L"Document"))
241                 {
242                     if (CJS_Document* pJSDocument = (CJS_Document*)JS_GetPrivate(pThis))
243                     {
244                         if (Document * pDocument = (Document*)pJSDocument->GetEmbedObject())
245                             pDocument->AttachDoc(pReaderDoc);
246                     }
247                 }
248             }
249             JS_SetThisObj(*this, JS_GetObjDefnID(*this, L"Document"));
250         }
251         else
252         {
253             JS_SetThisObj(*this, JS_GetObjDefnID(*this, L"app"));
254         }
255     }
256 }
257
258 FX_BOOL CJS_Runtime::AddEventToLoop(const CFX_WideString& sTargetName, JS_EVENT_T eEventType)
259 {
260     if (m_pFieldEventPath == NULL)
261     {
262         m_pFieldEventPath = new CJS_FieldEvent;
263         m_pFieldEventPath->sTargetName = sTargetName;
264         m_pFieldEventPath->eEventType = eEventType;
265         m_pFieldEventPath->pNext = NULL;
266
267         return TRUE;
268     }
269
270     //to search
271     CJS_FieldEvent* p = m_pFieldEventPath;
272     CJS_FieldEvent* pLast = m_pFieldEventPath;
273     while (p)
274     {
275         if (p->eEventType == eEventType && p->sTargetName == sTargetName)
276             return FALSE;
277
278         pLast = p;
279         p = p->pNext;
280     }
281
282     //to add
283     CJS_FieldEvent* pNew = new CJS_FieldEvent;
284     pNew->sTargetName = sTargetName;
285     pNew->eEventType = eEventType;
286     pNew->pNext = NULL;
287
288     pLast->pNext = pNew;
289
290     return TRUE;
291 }
292
293 void CJS_Runtime::RemoveEventInLoop(const CFX_WideString& sTargetName, JS_EVENT_T eEventType)
294 {
295     FX_BOOL bFind = FALSE;
296
297     CJS_FieldEvent* p = m_pFieldEventPath;
298     CJS_FieldEvent* pLast = NULL;
299     while (p)
300     {
301         if (p->eEventType == eEventType && p->sTargetName == sTargetName)
302         {
303             bFind = TRUE;
304             break;
305         }
306
307         pLast = p;
308         p = p->pNext;
309     }
310
311     if (bFind)
312     {
313         RemoveEventsInLoop(p);
314
315         if (p == m_pFieldEventPath)
316             m_pFieldEventPath = NULL;
317
318         if (pLast)
319             pLast->pNext = NULL;
320     }
321 }
322
323 void CJS_Runtime::RemoveEventsInLoop(CJS_FieldEvent* pStart)
324 {
325     CJS_FieldEvent* p = pStart;
326
327     while (p)
328     {
329         CJS_FieldEvent* pOld = p;
330         p = pOld->pNext;
331
332         delete pOld;
333     }
334 }
335
336 v8::Local<v8::Context>  CJS_Runtime::NewJSContext()
337 {
338     return v8::Local<v8::Context>::New(m_isolate, m_context);
339 }
340
341 CFX_WideString ChangeObjName(const CFX_WideString& str)
342 {
343     CFX_WideString sRet = str;
344     sRet.Replace(L"_", L".");
345     return sRet;
346 }