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