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