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