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