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