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