Clean up CPDF_AnnotList.
[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     return FALSE;
199
200   vp << JS_NUM_VIEWERVERSION;
201   return TRUE;
202 }
203
204 FX_BOOL app::platform(IJS_Context* cc,
205                       CJS_PropValue& vp,
206                       CFX_WideString& sError) {
207   if (vp.IsGetting()) {
208     vp << JS_STR_PLATFORM;
209     return TRUE;
210   }
211
212   return FALSE;
213 }
214
215 FX_BOOL app::language(IJS_Context* cc,
216                       CJS_PropValue& vp,
217                       CFX_WideString& sError) {
218   if (vp.IsGetting()) {
219     vp << JS_STR_LANGUANGE;
220     return TRUE;
221   }
222
223   return FALSE;
224 }
225
226 // creates a new fdf object that contains no data
227 // comment: need reader support
228 // note:
229 // CFDF_Document * CPDFDoc_Environment::NewFDF();
230 FX_BOOL app::newFDF(IJS_Context* cc,
231                     const CJS_Parameters& params,
232                     CJS_Value& vRet,
233                     CFX_WideString& sError) {
234   return TRUE;
235 }
236 // opens a specified pdf document and returns its document object
237 // comment:need reader support
238 // note: as defined in js reference, the proto of this function's fourth
239 // parmeters, how old an fdf document while do not show it.
240 // CFDF_Document * CPDFDoc_Environment::OpenFDF(string strPath,bool bUserConv);
241
242 FX_BOOL app::openFDF(IJS_Context* cc,
243                      const CJS_Parameters& params,
244                      CJS_Value& vRet,
245                      CFX_WideString& sError) {
246   return TRUE;
247 }
248
249 FX_BOOL app::alert(IJS_Context* cc,
250                    const CJS_Parameters& params,
251                    CJS_Value& vRet,
252                    CFX_WideString& sError) {
253   int iSize = params.size();
254   if (iSize < 1)
255     return FALSE;
256
257   CFX_WideString swMsg = L"";
258   CFX_WideString swTitle = L"";
259   int iIcon = 0;
260   int iType = 0;
261
262   CJS_Runtime* pRuntime = CJS_Runtime::FromContext(cc);
263   v8::Isolate* isolate = pRuntime->GetIsolate();
264
265   if (iSize == 1) {
266     if (params[0].GetType() == CJS_Value::VT_object) {
267       v8::Local<v8::Object> pObj = params[0].ToV8Object();
268       {
269         v8::Local<v8::Value> pValue =
270             FXJS_GetObjectElement(isolate, pObj, L"cMsg");
271         swMsg = CJS_Value(pRuntime, pValue, CJS_Value::VT_unknown)
272                     .ToCFXWideString();
273
274         pValue = FXJS_GetObjectElement(isolate, pObj, L"cTitle");
275         swTitle = CJS_Value(pRuntime, pValue, CJS_Value::VT_unknown)
276                       .ToCFXWideString();
277
278         pValue = FXJS_GetObjectElement(isolate, pObj, L"nIcon");
279         iIcon = CJS_Value(pRuntime, pValue, CJS_Value::VT_unknown).ToInt();
280
281         pValue = FXJS_GetObjectElement(isolate, pObj, L"nType");
282         iType = CJS_Value(pRuntime, pValue, CJS_Value::VT_unknown).ToInt();
283       }
284
285       if (swMsg == L"") {
286         CJS_Array carray(pRuntime);
287         if (params[0].ConvertToArray(carray)) {
288           int iLength = carray.GetLength();
289           CJS_Value* pValue = new CJS_Value(pRuntime);
290           for (int i = 0; i < iLength; ++i) {
291             carray.GetElement(i, *pValue);
292             swMsg += (*pValue).ToCFXWideString();
293             if (i < iLength - 1)
294               swMsg += L",  ";
295           }
296
297           delete pValue;
298         }
299       }
300
301       if (swTitle == L"")
302         swTitle = JSGetStringFromID((CJS_Context*)cc, IDS_STRING_JSALERT);
303     } else if (params[0].GetType() == CJS_Value::VT_boolean) {
304       FX_BOOL bGet = params[0].ToBool();
305       if (bGet)
306         swMsg = L"true";
307       else
308         swMsg = L"false";
309
310       swTitle = JSGetStringFromID((CJS_Context*)cc, IDS_STRING_JSALERT);
311     } else {
312       swMsg = params[0].ToCFXWideString();
313       swTitle = JSGetStringFromID((CJS_Context*)cc, IDS_STRING_JSALERT);
314     }
315   } else {
316     if (params[0].GetType() == CJS_Value::VT_boolean) {
317       FX_BOOL bGet = params[0].ToBool();
318       if (bGet)
319         swMsg = L"true";
320       else
321         swMsg = L"false";
322     } else {
323       swMsg = params[0].ToCFXWideString();
324     }
325     swTitle = JSGetStringFromID((CJS_Context*)cc, IDS_STRING_JSALERT);
326
327     for (int i = 1; i < iSize; i++) {
328       if (i == 1)
329         iIcon = params[i].ToInt();
330       if (i == 2)
331         iType = params[i].ToInt();
332       if (i == 3)
333         swTitle = params[i].ToCFXWideString();
334     }
335   }
336
337   pRuntime->BeginBlock();
338   vRet = MsgBox(pRuntime->GetReaderApp(), swMsg.c_str(), swTitle.c_str(), iType,
339                 iIcon);
340   pRuntime->EndBlock();
341   return TRUE;
342 }
343
344 FX_BOOL app::beep(IJS_Context* cc,
345                   const CJS_Parameters& params,
346                   CJS_Value& vRet,
347                   CFX_WideString& sError) {
348   if (params.size() == 1) {
349     CJS_Context* pContext = (CJS_Context*)cc;
350     CJS_Runtime* pRuntime = pContext->GetJSRuntime();
351     CPDFDoc_Environment* pEnv = pRuntime->GetReaderApp();
352     pEnv->JS_appBeep(params[0].ToInt());
353     return TRUE;
354   }
355
356   sError = JSGetStringFromID((CJS_Context*)cc, IDS_STRING_JSPARAMERROR);
357   return FALSE;
358 }
359
360 FX_BOOL app::findComponent(IJS_Context* cc,
361                            const CJS_Parameters& params,
362                            CJS_Value& vRet,
363                            CFX_WideString& sError) {
364   return TRUE;
365 }
366
367 FX_BOOL app::popUpMenuEx(IJS_Context* cc,
368                          const CJS_Parameters& params,
369                          CJS_Value& vRet,
370                          CFX_WideString& sError) {
371   return FALSE;
372 }
373
374 FX_BOOL app::fs(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError) {
375   return FALSE;
376 }
377
378 FX_BOOL app::setInterval(IJS_Context* cc,
379                          const CJS_Parameters& params,
380                          CJS_Value& vRet,
381                          CFX_WideString& sError) {
382   CJS_Context* pContext = (CJS_Context*)cc;
383   if (params.size() > 2 || params.size() == 0) {
384     sError = JSGetStringFromID(pContext, IDS_STRING_JSPARAMERROR);
385     return FALSE;
386   }
387
388   CFX_WideString script = params.size() > 0 ? params[0].ToCFXWideString() : L"";
389   if (script.IsEmpty()) {
390     sError = JSGetStringFromID(pContext, IDS_STRING_JSAFNUMBER_KEYSTROKE);
391     return TRUE;
392   }
393
394   CJS_Runtime* pRuntime = pContext->GetJSRuntime();
395   FX_DWORD dwInterval = params.size() > 1 ? params[1].ToInt() : 1000;
396
397   CPDFDoc_Environment* pApp = pRuntime->GetReaderApp();
398   ASSERT(pApp);
399   CJS_Timer* pTimer =
400       new CJS_Timer(this, pApp, pRuntime, 0, script, dwInterval, 0);
401   m_aTimer.Add(pTimer);
402
403   v8::Local<v8::Object> pRetObj = FXJS_NewFxDynamicObj(
404       pRuntime->GetIsolate(), pRuntime, CJS_TimerObj::g_nObjDefnID);
405   CJS_TimerObj* pJS_TimerObj =
406       (CJS_TimerObj*)FXJS_GetPrivate(pRuntime->GetIsolate(), pRetObj);
407   TimerObj* pTimerObj = (TimerObj*)pJS_TimerObj->GetEmbedObject();
408   pTimerObj->SetTimer(pTimer);
409
410   vRet = pRetObj;
411   return TRUE;
412 }
413
414 FX_BOOL app::setTimeOut(IJS_Context* cc,
415                         const CJS_Parameters& params,
416                         CJS_Value& vRet,
417                         CFX_WideString& sError) {
418   if (params.size() > 2 || params.size() == 0) {
419     sError = JSGetStringFromID((CJS_Context*)cc, IDS_STRING_JSPARAMERROR);
420     return FALSE;
421   }
422
423   CJS_Context* pContext = (CJS_Context*)cc;
424   ASSERT(pContext != NULL);
425   CJS_Runtime* pRuntime = pContext->GetJSRuntime();
426   ASSERT(pRuntime != NULL);
427
428   CFX_WideString script = params.size() > 0 ? params[0].ToCFXWideString() : L"";
429   if (script.IsEmpty()) {
430     sError =
431         JSGetStringFromID((CJS_Context*)cc, IDS_STRING_JSAFNUMBER_KEYSTROKE);
432     return TRUE;
433   }
434
435   FX_DWORD dwTimeOut = params.size() > 1 ? params[1].ToInt() : 1000;
436
437   CPDFDoc_Environment* pApp = pRuntime->GetReaderApp();
438   ASSERT(pApp);
439
440   CJS_Timer* pTimer =
441       new CJS_Timer(this, pApp, pRuntime, 1, script, dwTimeOut, dwTimeOut);
442   m_aTimer.Add(pTimer);
443
444   v8::Local<v8::Object> pRetObj = FXJS_NewFxDynamicObj(
445       pRuntime->GetIsolate(), pRuntime, CJS_TimerObj::g_nObjDefnID);
446   CJS_TimerObj* pJS_TimerObj =
447       (CJS_TimerObj*)FXJS_GetPrivate(pRuntime->GetIsolate(), pRetObj);
448   TimerObj* pTimerObj = (TimerObj*)pJS_TimerObj->GetEmbedObject();
449   pTimerObj->SetTimer(pTimer);
450
451   vRet = pRetObj;
452   return TRUE;
453 }
454
455 FX_BOOL app::clearTimeOut(IJS_Context* cc,
456                           const CJS_Parameters& params,
457                           CJS_Value& vRet,
458                           CFX_WideString& sError) {
459   CJS_Context* pContext = (CJS_Context*)cc;
460   if (params.size() != 1) {
461     sError = JSGetStringFromID(pContext, IDS_STRING_JSPARAMERROR);
462     return FALSE;
463   }
464
465   if (params[0].GetType() == CJS_Value::VT_fxobject) {
466     v8::Local<v8::Object> pObj = params[0].ToV8Object();
467     if (FXJS_GetObjDefnID(pObj) == CJS_TimerObj::g_nObjDefnID) {
468       if (CJS_Object* pJSObj = params[0].ToCJSObject()) {
469         if (TimerObj* pTimerObj = (TimerObj*)pJSObj->GetEmbedObject()) {
470           if (CJS_Timer* pTimer = pTimerObj->GetTimer()) {
471             pTimer->KillJSTimer();
472
473             for (int i = 0, sz = m_aTimer.GetSize(); i < sz; i++) {
474               if (m_aTimer[i] == pTimer) {
475                 m_aTimer.RemoveAt(i);
476                 break;
477               }
478             }
479
480             delete pTimer;
481             pTimerObj->SetTimer(NULL);
482           }
483         }
484       }
485     }
486   }
487
488   return TRUE;
489 }
490
491 FX_BOOL app::clearInterval(IJS_Context* cc,
492                            const CJS_Parameters& params,
493                            CJS_Value& vRet,
494                            CFX_WideString& sError) {
495   CJS_Context* pContext = (CJS_Context*)cc;
496   if (params.size() != 1) {
497     sError = JSGetStringFromID(pContext, IDS_STRING_JSPARAMERROR);
498     return FALSE;
499   }
500
501   if (params[0].GetType() == CJS_Value::VT_fxobject) {
502     v8::Local<v8::Object> pObj = params[0].ToV8Object();
503     if (FXJS_GetObjDefnID(pObj) == CJS_TimerObj::g_nObjDefnID) {
504       if (CJS_Object* pJSObj = params[0].ToCJSObject()) {
505         if (TimerObj* pTimerObj = (TimerObj*)pJSObj->GetEmbedObject()) {
506           if (CJS_Timer* pTimer = pTimerObj->GetTimer()) {
507             pTimer->KillJSTimer();
508
509             for (int i = 0, sz = m_aTimer.GetSize(); i < sz; i++) {
510               if (m_aTimer[i] == pTimer) {
511                 m_aTimer.RemoveAt(i);
512                 break;
513               }
514             }
515
516             delete pTimer;
517             pTimerObj->SetTimer(NULL);
518           }
519         }
520       }
521     }
522   }
523
524   return TRUE;
525 }
526
527 FX_BOOL app::execMenuItem(IJS_Context* cc,
528                           const CJS_Parameters& params,
529                           CJS_Value& vRet,
530                           CFX_WideString& sError) {
531   return FALSE;
532 }
533
534 void app::TimerProc(CJS_Timer* pTimer) {
535   ASSERT(pTimer != NULL);
536
537   CJS_Runtime* pRuntime = pTimer->GetRuntime();
538
539   switch (pTimer->GetType()) {
540     case 0:  // interval
541       if (pRuntime)
542         RunJsScript(pRuntime, pTimer->GetJScript());
543       break;
544     case 1:
545       if (pTimer->GetTimeOut() > 0) {
546         if (pRuntime)
547           RunJsScript(pRuntime, pTimer->GetJScript());
548         pTimer->KillJSTimer();
549       }
550       break;
551   }
552 }
553
554 void app::RunJsScript(CJS_Runtime* pRuntime, const CFX_WideString& wsScript) {
555   if (!pRuntime->IsBlocking()) {
556     IJS_Context* pContext = pRuntime->NewContext();
557     pContext->OnExternal_Exec();
558     CFX_WideString wtInfo;
559     pContext->RunScript(wsScript, &wtInfo);
560     pRuntime->ReleaseContext(pContext);
561   }
562 }
563
564 FX_BOOL app::goBack(IJS_Context* cc,
565                     const CJS_Parameters& params,
566                     CJS_Value& vRet,
567                     CFX_WideString& sError) {
568   // Not supported.
569   return TRUE;
570 }
571
572 FX_BOOL app::goForward(IJS_Context* cc,
573                        const CJS_Parameters& params,
574                        CJS_Value& vRet,
575                        CFX_WideString& sError) {
576   // Not supported.
577   return TRUE;
578 }
579
580 FX_BOOL app::mailMsg(IJS_Context* cc,
581                      const CJS_Parameters& params,
582                      CJS_Value& vRet,
583                      CFX_WideString& sError) {
584   if (params.size() < 1)
585     return FALSE;
586
587   FX_BOOL bUI = TRUE;
588   CFX_WideString cTo = L"";
589   CFX_WideString cCc = L"";
590   CFX_WideString cBcc = L"";
591   CFX_WideString cSubject = L"";
592   CFX_WideString cMsg = L"";
593
594   CJS_Context* pContext = static_cast<CJS_Context*>(cc);
595   CJS_Runtime* pRuntime = pContext->GetJSRuntime();
596   v8::Isolate* isolate = pRuntime->GetIsolate();
597
598   if (params[0].GetType() == CJS_Value::VT_object) {
599     v8::Local<v8::Object> pObj = params[0].ToV8Object();
600
601     v8::Local<v8::Value> pValue = FXJS_GetObjectElement(isolate, pObj, L"bUI");
602     bUI = CJS_Value(pRuntime, pValue, GET_VALUE_TYPE(pValue)).ToBool();
603
604     pValue = FXJS_GetObjectElement(isolate, pObj, L"cTo");
605     cTo = CJS_Value(pRuntime, pValue, GET_VALUE_TYPE(pValue)).ToCFXWideString();
606
607     pValue = FXJS_GetObjectElement(isolate, pObj, L"cCc");
608     cCc = CJS_Value(pRuntime, pValue, GET_VALUE_TYPE(pValue)).ToCFXWideString();
609
610     pValue = FXJS_GetObjectElement(isolate, pObj, L"cBcc");
611     cBcc =
612         CJS_Value(pRuntime, pValue, GET_VALUE_TYPE(pValue)).ToCFXWideString();
613
614     pValue = FXJS_GetObjectElement(isolate, pObj, L"cSubject");
615     cSubject =
616         CJS_Value(pRuntime, pValue, GET_VALUE_TYPE(pValue)).ToCFXWideString();
617
618     pValue = FXJS_GetObjectElement(isolate, pObj, L"cMsg");
619     cMsg =
620         CJS_Value(pRuntime, pValue, GET_VALUE_TYPE(pValue)).ToCFXWideString();
621   } else {
622     if (params.size() < 2)
623       return FALSE;
624
625     bUI = params[0].ToBool();
626     cTo = params[1].ToCFXWideString();
627
628     if (params.size() >= 3)
629       cCc = params[2].ToCFXWideString();
630     if (params.size() >= 4)
631       cBcc = params[3].ToCFXWideString();
632     if (params.size() >= 5)
633       cSubject = params[4].ToCFXWideString();
634     if (params.size() >= 6)
635       cMsg = params[5].ToCFXWideString();
636   }
637
638   pRuntime->BeginBlock();
639   pContext->GetReaderApp()->JS_docmailForm(NULL, 0, bUI, cTo.c_str(),
640                                            cSubject.c_str(), cCc.c_str(),
641                                            cBcc.c_str(), cMsg.c_str());
642   pRuntime->EndBlock();
643
644   return FALSE;
645 }
646
647 FX_BOOL app::launchURL(IJS_Context* cc,
648                        const CJS_Parameters& params,
649                        CJS_Value& vRet,
650                        CFX_WideString& sError) {
651   // Unsafe, not supported.
652   return TRUE;
653 }
654
655 FX_BOOL app::runtimeHighlight(IJS_Context* cc,
656                               CJS_PropValue& vp,
657                               CFX_WideString& sError) {
658   if (vp.IsSetting()) {
659     vp >> m_bRuntimeHighLight;
660   } else {
661     vp << m_bRuntimeHighLight;
662   }
663
664   return TRUE;
665 }
666
667 FX_BOOL app::fullscreen(IJS_Context* cc,
668                         CJS_PropValue& vp,
669                         CFX_WideString& sError) {
670   return FALSE;
671 }
672
673 FX_BOOL app::popUpMenu(IJS_Context* cc,
674                        const CJS_Parameters& params,
675                        CJS_Value& vRet,
676                        CFX_WideString& sError) {
677   return FALSE;
678 }
679
680 FX_BOOL app::browseForDoc(IJS_Context* cc,
681                           const CJS_Parameters& params,
682                           CJS_Value& vRet,
683                           CFX_WideString& sError) {
684   // Unsafe, not supported.
685   return TRUE;
686 }
687
688 CFX_WideString app::SysPathToPDFPath(const CFX_WideString& sOldPath) {
689   CFX_WideString sRet = L"/";
690
691   for (int i = 0, sz = sOldPath.GetLength(); i < sz; i++) {
692     wchar_t c = sOldPath.GetAt(i);
693     if (c == L':') {
694     } else {
695       if (c == L'\\') {
696         sRet += L"/";
697       } else {
698         sRet += c;
699       }
700     }
701   }
702
703   return sRet;
704 }
705
706 FX_BOOL app::newDoc(IJS_Context* cc,
707                     const CJS_Parameters& params,
708                     CJS_Value& vRet,
709                     CFX_WideString& sError) {
710   return FALSE;
711 }
712
713 FX_BOOL app::openDoc(IJS_Context* cc,
714                      const CJS_Parameters& params,
715                      CJS_Value& vRet,
716                      CFX_WideString& sError) {
717   return FALSE;
718 }
719
720 FX_BOOL app::response(IJS_Context* cc,
721                       const CJS_Parameters& params,
722                       CJS_Value& vRet,
723                       CFX_WideString& sError) {
724   CFX_WideString swQuestion = L"";
725   CFX_WideString swLabel = L"";
726   CFX_WideString swTitle = L"PDF";
727   CFX_WideString swDefault = L"";
728   bool bPassWord = false;
729
730   CJS_Runtime* pRuntime = CJS_Runtime::FromContext(cc);
731   v8::Isolate* isolate = pRuntime->GetIsolate();
732
733   int iLength = params.size();
734   if (iLength > 0 && params[0].GetType() == CJS_Value::VT_object) {
735     v8::Local<v8::Object> pObj = params[0].ToV8Object();
736     v8::Local<v8::Value> pValue =
737         FXJS_GetObjectElement(isolate, pObj, L"cQuestion");
738     swQuestion =
739         CJS_Value(pRuntime, pValue, GET_VALUE_TYPE(pValue)).ToCFXWideString();
740
741     pValue = FXJS_GetObjectElement(isolate, pObj, L"cTitle");
742     swTitle =
743         CJS_Value(pRuntime, pValue, GET_VALUE_TYPE(pValue)).ToCFXWideString();
744
745     pValue = FXJS_GetObjectElement(isolate, pObj, L"cDefault");
746     swDefault =
747         CJS_Value(pRuntime, pValue, GET_VALUE_TYPE(pValue)).ToCFXWideString();
748
749     pValue = FXJS_GetObjectElement(isolate, pObj, L"cLabel");
750     swLabel =
751         CJS_Value(pRuntime, pValue, GET_VALUE_TYPE(pValue)).ToCFXWideString();
752
753     pValue = FXJS_GetObjectElement(isolate, pObj, L"bPassword");
754     bPassWord = CJS_Value(pRuntime, pValue, GET_VALUE_TYPE(pValue)).ToBool();
755   } else {
756     switch (iLength) {
757       case 5:
758         swLabel = params[4].ToCFXWideString();
759       // FALLTHROUGH
760       case 4:
761         bPassWord = params[3].ToBool();
762       // FALLTHROUGH
763       case 3:
764         swDefault = params[2].ToCFXWideString();
765       // FALLTHROUGH
766       case 2:
767         swTitle = params[1].ToCFXWideString();
768       // FALLTHROUGH
769       case 1:
770         swQuestion = params[0].ToCFXWideString();
771       // FALLTHROUGH
772       default:
773         break;
774     }
775   }
776
777   CJS_Context* pContext = (CJS_Context*)cc;
778   ASSERT(pContext != NULL);
779
780   CPDFDoc_Environment* pApp = pContext->GetReaderApp();
781   ASSERT(pApp != NULL);
782
783   const int MAX_INPUT_BYTES = 2048;
784   nonstd::unique_ptr<char[]> pBuff(new char[MAX_INPUT_BYTES + 2]);
785   memset(pBuff.get(), 0, MAX_INPUT_BYTES + 2);
786   int nLengthBytes = pApp->JS_appResponse(
787       swQuestion.c_str(), swTitle.c_str(), swDefault.c_str(), swLabel.c_str(),
788       bPassWord, pBuff.get(), MAX_INPUT_BYTES);
789   if (nLengthBytes <= 0) {
790     vRet.SetNull();
791     return FALSE;
792   }
793   nLengthBytes = std::min(nLengthBytes, MAX_INPUT_BYTES);
794
795   CFX_WideString ret_string = CFX_WideString::FromUTF16LE(
796       (unsigned short*)pBuff.get(), nLengthBytes / sizeof(unsigned short));
797   vRet = ret_string.c_str();
798   return TRUE;
799 }
800
801 FX_BOOL app::media(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError) {
802   return FALSE;
803 }
804
805 FX_BOOL app::execDialog(IJS_Context* cc,
806                         const CJS_Parameters& params,
807                         CJS_Value& vRet,
808                         CFX_WideString& sError) {
809   return TRUE;
810 }