a2e1af4dca8cb72a25e40cb0907a1dae44f6ad8e
[pdfium.git] / fpdfsdk / src / javascript / app.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 "app.h"
8
9 #include "../../../third_party/base/nonstd_unique_ptr.h"
10 #include "../../include/fsdk_mgr.h"  // For CPDFDoc_Environment.
11 #include "../../include/javascript/IJavaScript.h"
12 #include "Document.h"
13 #include "JS_Context.h"
14 #include "JS_Define.h"
15 #include "JS_EventHandler.h"
16 #include "JS_Object.h"
17 #include "JS_Runtime.h"
18 #include "JS_Value.h"
19 #include "resource.h"
20
21 static v8::Isolate* GetIsolate(IFXJS_Context* cc) {
22   CJS_Context* pContext = (CJS_Context*)cc;
23   CJS_Runtime* pRuntime = pContext->GetJSRuntime();
24   return pRuntime->GetIsolate();
25 }
26
27 BEGIN_JS_STATIC_CONST(CJS_TimerObj)
28 END_JS_STATIC_CONST()
29
30 BEGIN_JS_STATIC_PROP(CJS_TimerObj)
31 END_JS_STATIC_PROP()
32
33 BEGIN_JS_STATIC_METHOD(CJS_TimerObj)
34 END_JS_STATIC_METHOD()
35
36 IMPLEMENT_JS_CLASS(CJS_TimerObj, TimerObj)
37
38 TimerObj::TimerObj(CJS_Object* pJSObject)
39     : CJS_EmbedObj(pJSObject), m_pTimer(NULL) {}
40
41 TimerObj::~TimerObj() {}
42
43 void TimerObj::SetTimer(CJS_Timer* pTimer) {
44   m_pTimer = pTimer;
45 }
46
47 CJS_Timer* TimerObj::GetTimer() const {
48   return m_pTimer;
49 }
50
51 #define JS_STR_VIEWERTYPE L"pdfium"
52 #define JS_STR_VIEWERVARIATION L"Full"
53 #define JS_STR_PLATFORM L"WIN"
54 #define JS_STR_LANGUANGE L"ENU"
55 #define JS_NUM_VIEWERVERSION 8
56 #define JS_NUM_FORMSVERSION 7
57
58 BEGIN_JS_STATIC_CONST(CJS_App)
59 END_JS_STATIC_CONST()
60
61 BEGIN_JS_STATIC_PROP(CJS_App)
62 JS_STATIC_PROP_ENTRY(activeDocs)
63 JS_STATIC_PROP_ENTRY(calculate)
64 JS_STATIC_PROP_ENTRY(formsVersion)
65 JS_STATIC_PROP_ENTRY(fs)
66 JS_STATIC_PROP_ENTRY(fullscreen)
67 JS_STATIC_PROP_ENTRY(language)
68 JS_STATIC_PROP_ENTRY(media)
69 JS_STATIC_PROP_ENTRY(platform)
70 JS_STATIC_PROP_ENTRY(runtimeHighlight)
71 JS_STATIC_PROP_ENTRY(viewerType)
72 JS_STATIC_PROP_ENTRY(viewerVariation)
73 JS_STATIC_PROP_ENTRY(viewerVersion)
74 END_JS_STATIC_PROP()
75
76 BEGIN_JS_STATIC_METHOD(CJS_App)
77 JS_STATIC_METHOD_ENTRY(alert)
78 JS_STATIC_METHOD_ENTRY(beep)
79 JS_STATIC_METHOD_ENTRY(browseForDoc)
80 JS_STATIC_METHOD_ENTRY(clearInterval)
81 JS_STATIC_METHOD_ENTRY(clearTimeOut)
82 JS_STATIC_METHOD_ENTRY(execDialog)
83 JS_STATIC_METHOD_ENTRY(execMenuItem)
84 JS_STATIC_METHOD_ENTRY(findComponent)
85 JS_STATIC_METHOD_ENTRY(goBack)
86 JS_STATIC_METHOD_ENTRY(goForward)
87 JS_STATIC_METHOD_ENTRY(launchURL)
88 JS_STATIC_METHOD_ENTRY(mailMsg)
89 JS_STATIC_METHOD_ENTRY(newFDF)
90 JS_STATIC_METHOD_ENTRY(newDoc)
91 JS_STATIC_METHOD_ENTRY(openDoc)
92 JS_STATIC_METHOD_ENTRY(openFDF)
93 JS_STATIC_METHOD_ENTRY(popUpMenuEx)
94 JS_STATIC_METHOD_ENTRY(popUpMenu)
95 JS_STATIC_METHOD_ENTRY(response)
96 JS_STATIC_METHOD_ENTRY(setInterval)
97 JS_STATIC_METHOD_ENTRY(setTimeOut)
98 END_JS_STATIC_METHOD()
99
100 IMPLEMENT_JS_CLASS(CJS_App, app)
101
102 app::app(CJS_Object* pJSObject)
103     : CJS_EmbedObj(pJSObject), m_bCalculate(true), m_bRuntimeHighLight(false) {}
104
105 app::~app() {
106   for (int i = 0, sz = m_aTimer.GetSize(); i < sz; i++)
107     delete m_aTimer[i];
108
109   m_aTimer.RemoveAll();
110 }
111
112 FX_BOOL app::activeDocs(IFXJS_Context* cc,
113                         CJS_PropValue& vp,
114                         CFX_WideString& sError) {
115   if (!vp.IsGetting())
116     return FALSE;
117
118   CJS_Context* pContext = (CJS_Context*)cc;
119   CPDFDoc_Environment* pApp = pContext->GetReaderApp();
120   CJS_Runtime* pRuntime = pContext->GetJSRuntime();
121   CPDFSDK_Document* pCurDoc = pContext->GetReaderDocument();
122   CJS_Array aDocs(pRuntime->GetIsolate());
123   if (CPDFSDK_Document* pDoc = pApp->GetSDKDocument()) {
124     CJS_Document* pJSDocument = NULL;
125     if (pDoc == pCurDoc) {
126       v8::Local<v8::Object> pObj = FXJS_GetThisObj(pRuntime->GetIsolate());
127       if (FXJS_GetObjDefnID(pObj) ==
128           FXJS_GetObjDefnID(pRuntime->GetIsolate(), L"Document"))
129         pJSDocument =
130             (CJS_Document*)FXJS_GetPrivate(pRuntime->GetIsolate(), pObj);
131     } else {
132       v8::Local<v8::Object> pObj = FXJS_NewFxDynamicObj(
133           pRuntime->GetIsolate(), pContext,
134           FXJS_GetObjDefnID(pRuntime->GetIsolate(), L"Document"));
135       pJSDocument =
136           (CJS_Document*)FXJS_GetPrivate(pRuntime->GetIsolate(), pObj);
137       ASSERT(pJSDocument != NULL);
138     }
139     aDocs.SetElement(0, CJS_Value(pRuntime->GetIsolate(), pJSDocument));
140   }
141   if (aDocs.GetLength() > 0)
142     vp << aDocs;
143   else
144     vp.SetNull();
145
146   return TRUE;
147 }
148
149 FX_BOOL app::calculate(IFXJS_Context* cc,
150                        CJS_PropValue& vp,
151                        CFX_WideString& sError) {
152   if (vp.IsSetting()) {
153     bool bVP;
154     vp >> bVP;
155     m_bCalculate = (FX_BOOL)bVP;
156
157     CJS_Context* pContext = (CJS_Context*)cc;
158     CPDFDoc_Environment* pApp = pContext->GetReaderApp();
159     CJS_Runtime* pRuntime = pContext->GetJSRuntime();
160     CJS_Array aDocs(pRuntime->GetIsolate());
161     if (CPDFSDK_Document* pDoc = pApp->GetSDKDocument())
162       pDoc->GetInterForm()->EnableCalculate((FX_BOOL)m_bCalculate);
163   } else {
164     vp << (bool)m_bCalculate;
165   }
166   return TRUE;
167 }
168
169 FX_BOOL app::formsVersion(IFXJS_Context* cc,
170                           CJS_PropValue& vp,
171                           CFX_WideString& sError) {
172   if (vp.IsGetting()) {
173     vp << JS_NUM_FORMSVERSION;
174     return TRUE;
175   }
176
177   return FALSE;
178 }
179
180 FX_BOOL app::viewerType(IFXJS_Context* cc,
181                         CJS_PropValue& vp,
182                         CFX_WideString& sError) {
183   if (vp.IsGetting()) {
184     vp << JS_STR_VIEWERTYPE;
185     return TRUE;
186   }
187
188   return FALSE;
189 }
190
191 FX_BOOL app::viewerVariation(IFXJS_Context* cc,
192                              CJS_PropValue& vp,
193                              CFX_WideString& sError) {
194   if (vp.IsGetting()) {
195     vp << JS_STR_VIEWERVARIATION;
196     return TRUE;
197   }
198
199   return FALSE;
200 }
201
202 FX_BOOL app::viewerVersion(IFXJS_Context* cc,
203                            CJS_PropValue& vp,
204                            CFX_WideString& sError) {
205   if (vp.IsGetting()) {
206     vp << JS_NUM_VIEWERVERSION;
207     return TRUE;
208   }
209
210   return FALSE;
211 }
212
213 FX_BOOL app::platform(IFXJS_Context* cc,
214                       CJS_PropValue& vp,
215                       CFX_WideString& sError) {
216   if (vp.IsGetting()) {
217     vp << JS_STR_PLATFORM;
218     return TRUE;
219   }
220
221   return FALSE;
222 }
223
224 FX_BOOL app::language(IFXJS_Context* cc,
225                       CJS_PropValue& vp,
226                       CFX_WideString& sError) {
227   if (vp.IsGetting()) {
228     vp << JS_STR_LANGUANGE;
229     return TRUE;
230   }
231
232   return FALSE;
233 }
234
235 // creates a new fdf object that contains no data
236 // comment: need reader support
237 // note:
238 // CFDF_Document * CPDFDoc_Environment::NewFDF();
239 FX_BOOL app::newFDF(IFXJS_Context* cc,
240                     const CJS_Parameters& params,
241                     CJS_Value& vRet,
242                     CFX_WideString& sError) {
243   return TRUE;
244 }
245 // opens a specified pdf document and returns its document object
246 // comment:need reader support
247 // note: as defined in js reference, the proto of this function's fourth
248 // parmeters, how old an fdf document while do not show it.
249 // CFDF_Document * CPDFDoc_Environment::OpenFDF(string strPath,bool bUserConv);
250
251 FX_BOOL app::openFDF(IFXJS_Context* cc,
252                      const CJS_Parameters& params,
253                      CJS_Value& vRet,
254                      CFX_WideString& sError) {
255   return TRUE;
256 }
257
258 FX_BOOL app::alert(IFXJS_Context* cc,
259                    const CJS_Parameters& params,
260                    CJS_Value& vRet,
261                    CFX_WideString& sError) {
262   int iSize = params.size();
263   if (iSize < 1)
264     return FALSE;
265
266   CFX_WideString swMsg = L"";
267   CFX_WideString swTitle = L"";
268   int iIcon = 0;
269   int iType = 0;
270
271   v8::Isolate* isolate = GetIsolate(cc);
272
273   if (iSize == 1) {
274     if (params[0].GetType() == CJS_Value::VT_object) {
275       v8::Local<v8::Object> pObj = params[0].ToV8Object();
276       {
277         v8::Local<v8::Value> pValue =
278             FXJS_GetObjectElement(isolate, pObj, L"cMsg");
279         swMsg =
280             CJS_Value(isolate, pValue, CJS_Value::VT_unknown).ToCFXWideString();
281
282         pValue = FXJS_GetObjectElement(isolate, pObj, L"cTitle");
283         swTitle =
284             CJS_Value(isolate, pValue, CJS_Value::VT_unknown).ToCFXWideString();
285
286         pValue = FXJS_GetObjectElement(isolate, pObj, L"nIcon");
287         iIcon = CJS_Value(isolate, pValue, CJS_Value::VT_unknown).ToInt();
288
289         pValue = FXJS_GetObjectElement(isolate, pObj, L"nType");
290         iType = CJS_Value(isolate, pValue, CJS_Value::VT_unknown).ToInt();
291       }
292
293       if (swMsg == L"") {
294         CJS_Array carray(isolate);
295         if (params[0].ConvertToArray(carray)) {
296           int iLength = carray.GetLength();
297           CJS_Value* pValue = new CJS_Value(isolate);
298           for (int i = 0; i < iLength; ++i) {
299             carray.GetElement(i, *pValue);
300             swMsg += (*pValue).ToCFXWideString();
301             if (i < iLength - 1)
302               swMsg += L",  ";
303           }
304
305           delete pValue;
306         }
307       }
308
309       if (swTitle == L"")
310         swTitle = JSGetStringFromID((CJS_Context*)cc, IDS_STRING_JSALERT);
311     } else if (params[0].GetType() == CJS_Value::VT_boolean) {
312       FX_BOOL bGet = params[0].ToBool();
313       if (bGet)
314         swMsg = L"true";
315       else
316         swMsg = L"false";
317
318       swTitle = JSGetStringFromID((CJS_Context*)cc, IDS_STRING_JSALERT);
319     } else {
320       swMsg = params[0].ToCFXWideString();
321       swTitle = JSGetStringFromID((CJS_Context*)cc, IDS_STRING_JSALERT);
322     }
323   } else {
324     if (params[0].GetType() == CJS_Value::VT_boolean) {
325       FX_BOOL bGet = params[0].ToBool();
326       if (bGet)
327         swMsg = L"true";
328       else
329         swMsg = L"false";
330     } else {
331       swMsg = params[0].ToCFXWideString();
332     }
333     swTitle = JSGetStringFromID((CJS_Context*)cc, IDS_STRING_JSALERT);
334
335     for (int i = 1; i < iSize; i++) {
336       if (i == 1)
337         iIcon = params[i].ToInt();
338       if (i == 2)
339         iType = params[i].ToInt();
340       if (i == 3)
341         swTitle = params[i].ToCFXWideString();
342     }
343   }
344
345   CJS_Context* pContext = (CJS_Context*)cc;
346   ASSERT(pContext != NULL);
347   CJS_Runtime* pRuntime = pContext->GetJSRuntime();
348   ASSERT(pRuntime != NULL);
349   pRuntime->BeginBlock();
350   vRet = MsgBox(pRuntime->GetReaderApp(), swMsg.c_str(), swTitle.c_str(), iType,
351                 iIcon);
352   pRuntime->EndBlock();
353
354   return TRUE;
355 }
356
357 FX_BOOL app::beep(IFXJS_Context* cc,
358                   const CJS_Parameters& params,
359                   CJS_Value& vRet,
360                   CFX_WideString& sError) {
361   if (params.size() == 1) {
362     CJS_Context* pContext = (CJS_Context*)cc;
363     CJS_Runtime* pRuntime = pContext->GetJSRuntime();
364     CPDFDoc_Environment* pEnv = pRuntime->GetReaderApp();
365     pEnv->JS_appBeep(params[0].ToInt());
366     return TRUE;
367   }
368
369   sError = JSGetStringFromID((CJS_Context*)cc, IDS_STRING_JSPARAMERROR);
370   return FALSE;
371 }
372
373 FX_BOOL app::findComponent(IFXJS_Context* cc,
374                            const CJS_Parameters& params,
375                            CJS_Value& vRet,
376                            CFX_WideString& sError) {
377   return TRUE;
378 }
379
380 FX_BOOL app::popUpMenuEx(IFXJS_Context* cc,
381                          const CJS_Parameters& params,
382                          CJS_Value& vRet,
383                          CFX_WideString& sError) {
384   return FALSE;
385 }
386
387 FX_BOOL app::fs(IFXJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError) {
388   return FALSE;
389 }
390
391 FX_BOOL app::setInterval(IFXJS_Context* cc,
392                          const CJS_Parameters& params,
393                          CJS_Value& vRet,
394                          CFX_WideString& sError) {
395   CJS_Context* pContext = (CJS_Context*)cc;
396   if (params.size() > 2 || params.size() == 0) {
397     sError = JSGetStringFromID(pContext, IDS_STRING_JSPARAMERROR);
398     return FALSE;
399   }
400
401   CFX_WideString script = params.size() > 0 ? params[0].ToCFXWideString() : L"";
402   if (script.IsEmpty()) {
403     sError = JSGetStringFromID(pContext, IDS_STRING_JSAFNUMBER_KEYSTROKE);
404     return TRUE;
405   }
406
407   CJS_Runtime* pRuntime = pContext->GetJSRuntime();
408   FX_DWORD dwInterval = params.size() > 1 ? params[1].ToInt() : 1000;
409
410   CPDFDoc_Environment* pApp = pRuntime->GetReaderApp();
411   ASSERT(pApp);
412   CJS_Timer* pTimer =
413       new CJS_Timer(this, pApp, pRuntime, 0, script, dwInterval, 0);
414   m_aTimer.Add(pTimer);
415
416   v8::Local<v8::Object> pRetObj = FXJS_NewFxDynamicObj(
417       pRuntime->GetIsolate(), pContext,
418       FXJS_GetObjDefnID(pRuntime->GetIsolate(), L"TimerObj"));
419
420   CJS_TimerObj* pJS_TimerObj =
421       (CJS_TimerObj*)FXJS_GetPrivate(pRuntime->GetIsolate(), pRetObj);
422   ASSERT(pJS_TimerObj != NULL);
423
424   TimerObj* pTimerObj = (TimerObj*)pJS_TimerObj->GetEmbedObject();
425   ASSERT(pTimerObj != NULL);
426
427   pTimerObj->SetTimer(pTimer);
428
429   vRet = pRetObj;
430
431   return TRUE;
432 }
433
434 FX_BOOL app::setTimeOut(IFXJS_Context* cc,
435                         const CJS_Parameters& params,
436                         CJS_Value& vRet,
437                         CFX_WideString& sError) {
438   if (params.size() > 2 || params.size() == 0) {
439     sError = JSGetStringFromID((CJS_Context*)cc, IDS_STRING_JSPARAMERROR);
440     return FALSE;
441   }
442
443   CJS_Context* pContext = (CJS_Context*)cc;
444   ASSERT(pContext != NULL);
445   CJS_Runtime* pRuntime = pContext->GetJSRuntime();
446   ASSERT(pRuntime != NULL);
447
448   CFX_WideString script = params.size() > 0 ? params[0].ToCFXWideString() : L"";
449   if (script.IsEmpty()) {
450     sError =
451         JSGetStringFromID((CJS_Context*)cc, IDS_STRING_JSAFNUMBER_KEYSTROKE);
452     return TRUE;
453   }
454
455   FX_DWORD dwTimeOut = params.size() > 1 ? params[1].ToInt() : 1000;
456
457   CPDFDoc_Environment* pApp = pRuntime->GetReaderApp();
458   ASSERT(pApp);
459
460   CJS_Timer* pTimer =
461       new CJS_Timer(this, pApp, pRuntime, 1, script, dwTimeOut, dwTimeOut);
462   m_aTimer.Add(pTimer);
463
464   v8::Local<v8::Object> pRetObj = FXJS_NewFxDynamicObj(
465       pRuntime->GetIsolate(), pContext,
466       FXJS_GetObjDefnID(pRuntime->GetIsolate(), L"TimerObj"));
467
468   CJS_TimerObj* pJS_TimerObj =
469       (CJS_TimerObj*)FXJS_GetPrivate(pRuntime->GetIsolate(), pRetObj);
470   ASSERT(pJS_TimerObj != NULL);
471
472   TimerObj* pTimerObj = (TimerObj*)pJS_TimerObj->GetEmbedObject();
473   ASSERT(pTimerObj != NULL);
474
475   pTimerObj->SetTimer(pTimer);
476
477   vRet = pRetObj;
478
479   return TRUE;
480 }
481
482 FX_BOOL app::clearTimeOut(IFXJS_Context* cc,
483                           const CJS_Parameters& params,
484                           CJS_Value& vRet,
485                           CFX_WideString& sError) {
486   CJS_Context* pContext = (CJS_Context*)cc;
487   ASSERT(pContext != NULL);
488   CJS_Runtime* pRuntime = pContext->GetJSRuntime();
489   ASSERT(pRuntime != NULL);
490
491   if (params.size() != 1) {
492     sError = JSGetStringFromID((CJS_Context*)cc, IDS_STRING_JSPARAMERROR);
493     return FALSE;
494   }
495
496   if (params[0].GetType() == CJS_Value::VT_fxobject) {
497     v8::Local<v8::Object> pObj = params[0].ToV8Object();
498     {
499       if (FXJS_GetObjDefnID(pObj) ==
500           FXJS_GetObjDefnID(pRuntime->GetIsolate(), L"TimerObj")) {
501         if (CJS_Object* pJSObj = params[0].ToCJSObject()) {
502           if (TimerObj* pTimerObj = (TimerObj*)pJSObj->GetEmbedObject()) {
503             if (CJS_Timer* pTimer = pTimerObj->GetTimer()) {
504               pTimer->KillJSTimer();
505
506               for (int i = 0, sz = m_aTimer.GetSize(); i < sz; i++) {
507                 if (m_aTimer[i] == pTimer) {
508                   m_aTimer.RemoveAt(i);
509                   break;
510                 }
511               }
512
513               delete pTimer;
514               pTimerObj->SetTimer(NULL);
515             }
516           }
517         }
518       }
519     }
520   }
521
522   return TRUE;
523 }
524
525 FX_BOOL app::clearInterval(IFXJS_Context* cc,
526                            const CJS_Parameters& params,
527                            CJS_Value& vRet,
528                            CFX_WideString& sError) {
529   CJS_Context* pContext = (CJS_Context*)cc;
530   ASSERT(pContext != NULL);
531   CJS_Runtime* pRuntime = pContext->GetJSRuntime();
532   ASSERT(pRuntime != NULL);
533
534   if (params.size() != 1) {
535     sError = JSGetStringFromID((CJS_Context*)cc, IDS_STRING_JSPARAMERROR);
536     return FALSE;
537   }
538
539   if (params[0].GetType() == CJS_Value::VT_fxobject) {
540     v8::Local<v8::Object> pObj = params[0].ToV8Object();
541     {
542       if (FXJS_GetObjDefnID(pObj) ==
543           FXJS_GetObjDefnID(pRuntime->GetIsolate(), L"TimerObj")) {
544         if (CJS_Object* pJSObj = params[0].ToCJSObject()) {
545           if (TimerObj* pTimerObj = (TimerObj*)pJSObj->GetEmbedObject()) {
546             if (CJS_Timer* pTimer = pTimerObj->GetTimer()) {
547               pTimer->KillJSTimer();
548
549               for (int i = 0, sz = m_aTimer.GetSize(); i < sz; i++) {
550                 if (m_aTimer[i] == pTimer) {
551                   m_aTimer.RemoveAt(i);
552                   break;
553                 }
554               }
555
556               delete pTimer;
557               pTimerObj->SetTimer(NULL);
558             }
559           }
560         }
561       }
562     }
563   }
564
565   return TRUE;
566 }
567
568 FX_BOOL app::execMenuItem(IFXJS_Context* cc,
569                           const CJS_Parameters& params,
570                           CJS_Value& vRet,
571                           CFX_WideString& sError) {
572   return FALSE;
573 }
574
575 void app::TimerProc(CJS_Timer* pTimer) {
576   ASSERT(pTimer != NULL);
577
578   CJS_Runtime* pRuntime = pTimer->GetRuntime();
579
580   switch (pTimer->GetType()) {
581     case 0:  // interval
582       if (pRuntime)
583         RunJsScript(pRuntime, pTimer->GetJScript());
584       break;
585     case 1:
586       if (pTimer->GetTimeOut() > 0) {
587         if (pRuntime)
588           RunJsScript(pRuntime, pTimer->GetJScript());
589         pTimer->KillJSTimer();
590       }
591       break;
592   }
593 }
594
595 void app::RunJsScript(CJS_Runtime* pRuntime, const CFX_WideString& wsScript) {
596   ASSERT(pRuntime != NULL);
597
598   if (!pRuntime->IsBlocking()) {
599     IFXJS_Context* pContext = pRuntime->NewContext();
600     ASSERT(pContext != NULL);
601     pContext->OnExternal_Exec();
602     CFX_WideString wtInfo;
603     pContext->RunScript(wsScript, wtInfo);
604     pRuntime->ReleaseContext(pContext);
605   }
606 }
607
608 FX_BOOL app::goBack(IFXJS_Context* cc,
609                     const CJS_Parameters& params,
610                     CJS_Value& vRet,
611                     CFX_WideString& sError) {
612   // Not supported.
613   return TRUE;
614 }
615
616 FX_BOOL app::goForward(IFXJS_Context* cc,
617                        const CJS_Parameters& params,
618                        CJS_Value& vRet,
619                        CFX_WideString& sError) {
620   // Not supported.
621   return TRUE;
622 }
623
624 FX_BOOL app::mailMsg(IFXJS_Context* cc,
625                      const CJS_Parameters& params,
626                      CJS_Value& vRet,
627                      CFX_WideString& sError) {
628   CJS_Context* pContext = (CJS_Context*)cc;
629   v8::Isolate* isolate = GetIsolate(cc);
630
631   FX_BOOL bUI = TRUE;
632   CFX_WideString cTo = L"";
633   CFX_WideString cCc = L"";
634   CFX_WideString cBcc = L"";
635   CFX_WideString cSubject = L"";
636   CFX_WideString cMsg = L"";
637
638   if (params.size() < 1)
639     return FALSE;
640
641   if (params[0].GetType() == CJS_Value::VT_object) {
642     v8::Local<v8::Object> pObj = params[0].ToV8Object();
643
644     v8::Local<v8::Value> pValue = FXJS_GetObjectElement(isolate, pObj, L"bUI");
645     bUI = CJS_Value(isolate, pValue, GET_VALUE_TYPE(pValue)).ToBool();
646
647     pValue = FXJS_GetObjectElement(isolate, pObj, L"cTo");
648     cTo = CJS_Value(isolate, pValue, GET_VALUE_TYPE(pValue)).ToCFXWideString();
649
650     pValue = FXJS_GetObjectElement(isolate, pObj, L"cCc");
651     cCc = CJS_Value(isolate, pValue, GET_VALUE_TYPE(pValue)).ToCFXWideString();
652
653     pValue = FXJS_GetObjectElement(isolate, pObj, L"cBcc");
654     cBcc = CJS_Value(isolate, pValue, GET_VALUE_TYPE(pValue)).ToCFXWideString();
655
656     pValue = FXJS_GetObjectElement(isolate, pObj, L"cSubject");
657     cSubject =
658         CJS_Value(isolate, pValue, GET_VALUE_TYPE(pValue)).ToCFXWideString();
659
660     pValue = FXJS_GetObjectElement(isolate, pObj, L"cMsg");
661     cMsg = CJS_Value(isolate, pValue, GET_VALUE_TYPE(pValue)).ToCFXWideString();
662   } else {
663     if (params.size() < 2)
664       return FALSE;
665
666     bUI = params[0].ToBool();
667     cTo = params[1].ToCFXWideString();
668
669     if (params.size() >= 3)
670       cCc = params[2].ToCFXWideString();
671     if (params.size() >= 4)
672       cBcc = params[3].ToCFXWideString();
673     if (params.size() >= 5)
674       cSubject = params[4].ToCFXWideString();
675     if (params.size() >= 6)
676       cMsg = params[5].ToCFXWideString();
677   }
678
679   CJS_Runtime* pRuntime = pContext->GetJSRuntime();
680   ASSERT(pRuntime != NULL);
681
682   CPDFDoc_Environment* pApp = pContext->GetReaderApp();
683   ASSERT(pApp != NULL);
684
685   pRuntime->BeginBlock();
686   pApp->JS_docmailForm(NULL, 0, bUI, cTo.c_str(), cSubject.c_str(), cCc.c_str(),
687                        cBcc.c_str(), cMsg.c_str());
688   pRuntime->EndBlock();
689
690   return FALSE;
691 }
692
693 FX_BOOL app::launchURL(IFXJS_Context* cc,
694                        const CJS_Parameters& params,
695                        CJS_Value& vRet,
696                        CFX_WideString& sError) {
697   // Unsafe, not supported.
698   return TRUE;
699 }
700
701 FX_BOOL app::runtimeHighlight(IFXJS_Context* cc,
702                               CJS_PropValue& vp,
703                               CFX_WideString& sError) {
704   if (vp.IsSetting()) {
705     vp >> m_bRuntimeHighLight;
706   } else {
707     vp << m_bRuntimeHighLight;
708   }
709
710   return TRUE;
711 }
712
713 FX_BOOL app::fullscreen(IFXJS_Context* cc,
714                         CJS_PropValue& vp,
715                         CFX_WideString& sError) {
716   return FALSE;
717 }
718
719 FX_BOOL app::popUpMenu(IFXJS_Context* cc,
720                        const CJS_Parameters& params,
721                        CJS_Value& vRet,
722                        CFX_WideString& sError) {
723   return FALSE;
724 }
725
726 FX_BOOL app::browseForDoc(IFXJS_Context* cc,
727                           const CJS_Parameters& params,
728                           CJS_Value& vRet,
729                           CFX_WideString& sError) {
730   // Unsafe, not supported.
731   return TRUE;
732 }
733
734 CFX_WideString app::SysPathToPDFPath(const CFX_WideString& sOldPath) {
735   CFX_WideString sRet = L"/";
736
737   for (int i = 0, sz = sOldPath.GetLength(); i < sz; i++) {
738     wchar_t c = sOldPath.GetAt(i);
739     if (c == L':') {
740     } else {
741       if (c == L'\\') {
742         sRet += L"/";
743       } else {
744         sRet += c;
745       }
746     }
747   }
748
749   return sRet;
750 }
751
752 FX_BOOL app::newDoc(IFXJS_Context* cc,
753                     const CJS_Parameters& params,
754                     CJS_Value& vRet,
755                     CFX_WideString& sError) {
756   return FALSE;
757 }
758
759 FX_BOOL app::openDoc(IFXJS_Context* cc,
760                      const CJS_Parameters& params,
761                      CJS_Value& vRet,
762                      CFX_WideString& sError) {
763   return FALSE;
764 }
765
766 FX_BOOL app::response(IFXJS_Context* cc,
767                       const CJS_Parameters& params,
768                       CJS_Value& vRet,
769                       CFX_WideString& sError) {
770   CFX_WideString swQuestion = L"";
771   CFX_WideString swLabel = L"";
772   CFX_WideString swTitle = L"PDF";
773   CFX_WideString swDefault = L"";
774   bool bPassWord = false;
775
776   v8::Isolate* isolate = GetIsolate(cc);
777
778   int iLength = params.size();
779   if (iLength > 0 && params[0].GetType() == CJS_Value::VT_object) {
780     v8::Local<v8::Object> pObj = params[0].ToV8Object();
781     v8::Local<v8::Value> pValue =
782         FXJS_GetObjectElement(isolate, pObj, L"cQuestion");
783     swQuestion =
784         CJS_Value(isolate, pValue, GET_VALUE_TYPE(pValue)).ToCFXWideString();
785
786     pValue = FXJS_GetObjectElement(isolate, pObj, L"cTitle");
787     swTitle =
788         CJS_Value(isolate, pValue, GET_VALUE_TYPE(pValue)).ToCFXWideString();
789
790     pValue = FXJS_GetObjectElement(isolate, pObj, L"cDefault");
791     swDefault =
792         CJS_Value(isolate, pValue, GET_VALUE_TYPE(pValue)).ToCFXWideString();
793
794     pValue = FXJS_GetObjectElement(isolate, pObj, L"cLabel");
795     swLabel =
796         CJS_Value(isolate, pValue, GET_VALUE_TYPE(pValue)).ToCFXWideString();
797
798     pValue = FXJS_GetObjectElement(isolate, pObj, L"bPassword");
799     bPassWord = CJS_Value(isolate, pValue, GET_VALUE_TYPE(pValue)).ToBool();
800   } else {
801     switch (iLength) {
802       case 5:
803         swLabel = params[4].ToCFXWideString();
804       // FALLTHROUGH
805       case 4:
806         bPassWord = params[3].ToBool();
807       // FALLTHROUGH
808       case 3:
809         swDefault = params[2].ToCFXWideString();
810       // FALLTHROUGH
811       case 2:
812         swTitle = params[1].ToCFXWideString();
813       // FALLTHROUGH
814       case 1:
815         swQuestion = params[0].ToCFXWideString();
816       // FALLTHROUGH
817       default:
818         break;
819     }
820   }
821
822   CJS_Context* pContext = (CJS_Context*)cc;
823   ASSERT(pContext != NULL);
824
825   CPDFDoc_Environment* pApp = pContext->GetReaderApp();
826   ASSERT(pApp != NULL);
827
828   const int MAX_INPUT_BYTES = 2048;
829   nonstd::unique_ptr<char[]> pBuff(new char[MAX_INPUT_BYTES + 2]);
830   memset(pBuff.get(), 0, MAX_INPUT_BYTES + 2);
831   int nLengthBytes = pApp->JS_appResponse(
832       swQuestion.c_str(), swTitle.c_str(), swDefault.c_str(), swLabel.c_str(),
833       bPassWord, pBuff.get(), MAX_INPUT_BYTES);
834   if (nLengthBytes <= 0) {
835     vRet.SetNull();
836     return FALSE;
837   }
838   nLengthBytes = std::min(nLengthBytes, MAX_INPUT_BYTES);
839
840   CFX_WideString ret_string = CFX_WideString::FromUTF16LE(
841       (unsigned short*)pBuff.get(), nLengthBytes / sizeof(unsigned short));
842   vRet = ret_string.c_str();
843   return TRUE;
844 }
845
846 FX_BOOL app::media(IFXJS_Context* cc,
847                    CJS_PropValue& vp,
848                    CFX_WideString& sError) {
849   return FALSE;
850 }
851
852 FX_BOOL app::execDialog(IFXJS_Context* cc,
853                         const CJS_Parameters& params,
854                         CJS_Value& vRet,
855                         CFX_WideString& sError) {
856   return TRUE;
857 }