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