| // Copyright 2014 The PDFium Authors | 
 | // Use of this source code is governed by a BSD-style license that can be | 
 | // found in the LICENSE file. | 
 |  | 
 | // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com | 
 |  | 
 | #include "fxjs/cjs_app.h" | 
 |  | 
 | #include <stdint.h> | 
 |  | 
 | #include <algorithm> | 
 | #include <utility> | 
 |  | 
 | #include "core/fxcrt/fixed_zeroed_data_vector.h" | 
 | #include "core/fxcrt/stl_util.h" | 
 | #include "fpdfsdk/cpdfsdk_formfillenvironment.h" | 
 | #include "fpdfsdk/cpdfsdk_interactiveform.h" | 
 | #include "fxjs/cjs_document.h" | 
 | #include "fxjs/cjs_timerobj.h" | 
 | #include "fxjs/global_timer.h" | 
 | #include "fxjs/ijs_event_context.h" | 
 | #include "fxjs/js_resources.h" | 
 | #include "v8/include/v8-container.h" | 
 |  | 
 | namespace { | 
 |  | 
 | constexpr wchar_t kStrViewerType[] = L"pdfium"; | 
 | constexpr wchar_t kStrViewerVariation[] = L"Full"; | 
 | constexpr wchar_t kStrPlatform[] = L"WIN"; | 
 | constexpr wchar_t kStrLanguage[] = L"ENU"; | 
 | constexpr int kNumViewerVersion = 8; | 
 | constexpr int kNumViewerVersionXfa = 11; | 
 | constexpr int kNumFormsVersion = 7; | 
 |  | 
 | }  // namespace | 
 |  | 
 | const JSPropertySpec CJS_App::PropertySpecs[] = { | 
 |     {"activeDocs", get_active_docs_static, set_active_docs_static}, | 
 |     {"calculate", get_calculate_static, set_calculate_static}, | 
 |     {"formsVersion", get_forms_version_static, set_forms_version_static}, | 
 |     {"fs", get_fs_static, set_fs_static}, | 
 |     {"fullscreen", get_fullscreen_static, set_fullscreen_static}, | 
 |     {"language", get_language_static, set_language_static}, | 
 |     {"media", get_media_static, set_media_static}, | 
 |     {"platform", get_platform_static, set_platform_static}, | 
 |     {"runtimeHighlight", get_runtime_highlight_static, | 
 |      set_runtime_highlight_static}, | 
 |     {"viewerType", get_viewer_type_static, set_viewer_type_static}, | 
 |     {"viewerVariation", get_viewer_variation_static, | 
 |      set_viewer_variation_static}, | 
 |     {"viewerVersion", get_viewer_version_static, set_viewer_version_static}}; | 
 |  | 
 | const JSMethodSpec CJS_App::MethodSpecs[] = { | 
 |     {"alert", alert_static}, | 
 |     {"beep", beep_static}, | 
 |     {"browseForDoc", browseForDoc_static}, | 
 |     {"clearInterval", clearInterval_static}, | 
 |     {"clearTimeOut", clearTimeOut_static}, | 
 |     {"execDialog", execDialog_static}, | 
 |     {"execMenuItem", execMenuItem_static}, | 
 |     {"findComponent", findComponent_static}, | 
 |     {"goBack", goBack_static}, | 
 |     {"goForward", goForward_static}, | 
 |     {"launchURL", launchURL_static}, | 
 |     {"mailMsg", mailMsg_static}, | 
 |     {"newFDF", newFDF_static}, | 
 |     {"newDoc", newDoc_static}, | 
 |     {"openDoc", openDoc_static}, | 
 |     {"openFDF", openFDF_static}, | 
 |     {"popUpMenuEx", popUpMenuEx_static}, | 
 |     {"popUpMenu", popUpMenu_static}, | 
 |     {"response", response_static}, | 
 |     {"setInterval", setInterval_static}, | 
 |     {"setTimeOut", setTimeOut_static}}; | 
 |  | 
 | uint32_t CJS_App::ObjDefnID = 0; | 
 |  | 
 | const char CJS_App::kName[] = "app"; | 
 |  | 
 | // static | 
 | uint32_t CJS_App::GetObjDefnID() { | 
 |   return ObjDefnID; | 
 | } | 
 |  | 
 | // static | 
 | void CJS_App::DefineJSObjects(CFXJS_Engine* pEngine) { | 
 |   ObjDefnID = pEngine->DefineObj(CJS_App::kName, FXJSOBJTYPE_STATIC, | 
 |                                  JSConstructor<CJS_App>, JSDestructor); | 
 |   DefineProps(pEngine, ObjDefnID, PropertySpecs); | 
 |   DefineMethods(pEngine, ObjDefnID, MethodSpecs); | 
 | } | 
 |  | 
 | CJS_App::CJS_App(v8::Local<v8::Object> pObject, CJS_Runtime* pRuntime) | 
 |     : CJS_Object(pObject, pRuntime) {} | 
 |  | 
 | CJS_App::~CJS_App() = default; | 
 |  | 
 | CJS_Result CJS_App::get_active_docs(CJS_Runtime* pRuntime) { | 
 |   v8::Local<v8::Object> pObj = pRuntime->GetThisObj(); | 
 |   auto pJSDocument = JSGetObject<CJS_Document>(pRuntime->GetIsolate(), pObj); | 
 |   if (!pJSDocument) | 
 |     return CJS_Result::Failure(JSMessage::kObjectTypeError); | 
 |   v8::Local<v8::Array> aDocs = pRuntime->NewArray(); | 
 |   pRuntime->PutArrayElement(aDocs, 0, pJSDocument->ToV8Object()); | 
 |   if (pRuntime->GetArrayLength(aDocs) > 0) | 
 |     return CJS_Result::Success(aDocs); | 
 |  | 
 |   return CJS_Result::Success(pRuntime->NewUndefined()); | 
 | } | 
 |  | 
 | CJS_Result CJS_App::set_active_docs(CJS_Runtime* pRuntime, | 
 |                                     v8::Local<v8::Value> vp) { | 
 |   return CJS_Result::Failure(JSMessage::kNotSupportedError); | 
 | } | 
 |  | 
 | CJS_Result CJS_App::get_calculate(CJS_Runtime* pRuntime) { | 
 |   return CJS_Result::Success(pRuntime->NewBoolean(m_bCalculate)); | 
 | } | 
 |  | 
 | CJS_Result CJS_App::set_calculate(CJS_Runtime* pRuntime, | 
 |                                   v8::Local<v8::Value> vp) { | 
 |   m_bCalculate = pRuntime->ToBoolean(vp); | 
 |   pRuntime->GetFormFillEnv()->GetInteractiveForm()->EnableCalculate( | 
 |       m_bCalculate); | 
 |   return CJS_Result::Success(); | 
 | } | 
 |  | 
 | CJS_Result CJS_App::get_forms_version(CJS_Runtime* pRuntime) { | 
 |   return CJS_Result::Success(pRuntime->NewNumber(kNumFormsVersion)); | 
 | } | 
 |  | 
 | CJS_Result CJS_App::set_forms_version(CJS_Runtime* pRuntime, | 
 |                                       v8::Local<v8::Value> vp) { | 
 |   return CJS_Result::Failure(JSMessage::kNotSupportedError); | 
 | } | 
 |  | 
 | CJS_Result CJS_App::get_viewer_type(CJS_Runtime* pRuntime) { | 
 |   return CJS_Result::Success(pRuntime->NewString(kStrViewerType)); | 
 | } | 
 |  | 
 | CJS_Result CJS_App::set_viewer_type(CJS_Runtime* pRuntime, | 
 |                                     v8::Local<v8::Value> vp) { | 
 |   return CJS_Result::Failure(JSMessage::kNotSupportedError); | 
 | } | 
 |  | 
 | CJS_Result CJS_App::get_viewer_variation(CJS_Runtime* pRuntime) { | 
 |   return CJS_Result::Success(pRuntime->NewString(kStrViewerVariation)); | 
 | } | 
 |  | 
 | CJS_Result CJS_App::set_viewer_variation(CJS_Runtime* pRuntime, | 
 |                                          v8::Local<v8::Value> vp) { | 
 |   return CJS_Result::Failure(JSMessage::kNotSupportedError); | 
 | } | 
 |  | 
 | CJS_Result CJS_App::get_viewer_version(CJS_Runtime* pRuntime) { | 
 |   CPDF_Document::Extension* pContext = | 
 |       pRuntime->GetFormFillEnv()->GetDocExtension(); | 
 |   int version = pContext && pContext->ContainsExtensionForm() | 
 |                     ? kNumViewerVersionXfa | 
 |                     : kNumViewerVersion; | 
 |   return CJS_Result::Success(pRuntime->NewNumber(version)); | 
 | } | 
 |  | 
 | CJS_Result CJS_App::set_viewer_version(CJS_Runtime* pRuntime, | 
 |                                        v8::Local<v8::Value> vp) { | 
 |   return CJS_Result::Failure(JSMessage::kNotSupportedError); | 
 | } | 
 |  | 
 | CJS_Result CJS_App::get_platform(CJS_Runtime* pRuntime) { | 
 |   CPDFSDK_FormFillEnvironment* pFormFillEnv = pRuntime->GetFormFillEnv(); | 
 |   if (pFormFillEnv) { | 
 |     WideString platform = pFormFillEnv->GetPlatform(); | 
 |     if (!platform.IsEmpty()) | 
 |       return CJS_Result::Success(pRuntime->NewString(platform.AsStringView())); | 
 |   } | 
 |   return CJS_Result::Success(pRuntime->NewString(kStrPlatform)); | 
 | } | 
 |  | 
 | CJS_Result CJS_App::set_platform(CJS_Runtime* pRuntime, | 
 |                                  v8::Local<v8::Value> vp) { | 
 |   return CJS_Result::Failure(JSMessage::kNotSupportedError); | 
 | } | 
 |  | 
 | CJS_Result CJS_App::get_language(CJS_Runtime* pRuntime) { | 
 |   CPDFSDK_FormFillEnvironment* pFormFillEnv = pRuntime->GetFormFillEnv(); | 
 |   if (pFormFillEnv) { | 
 |     WideString language = pFormFillEnv->GetLanguage(); | 
 |     if (!language.IsEmpty()) | 
 |       return CJS_Result::Success(pRuntime->NewString(language.AsStringView())); | 
 |   } | 
 |   return CJS_Result::Success(pRuntime->NewString(kStrLanguage)); | 
 | } | 
 |  | 
 | CJS_Result CJS_App::set_language(CJS_Runtime* pRuntime, | 
 |                                  v8::Local<v8::Value> vp) { | 
 |   return CJS_Result::Failure(JSMessage::kNotSupportedError); | 
 | } | 
 |  | 
 | // creates a new fdf object that contains no data | 
 | // comment: need reader support | 
 | // note: | 
 | // CFDF_Document * CPDFSDK_FormFillEnvironment::NewFDF(); | 
 | CJS_Result CJS_App::newFDF(CJS_Runtime* pRuntime, | 
 |                            const std::vector<v8::Local<v8::Value>>& params) { | 
 |   return CJS_Result::Success(); | 
 | } | 
 |  | 
 | // opens a specified pdf document and returns its document object | 
 | // comment:need reader support | 
 | // note: as defined in js reference, the proto of this function's fourth | 
 | // parmeters, how old an fdf document while do not show it. | 
 | // CFDF_Document * CPDFSDK_FormFillEnvironment::OpenFDF(string strPath,bool | 
 | // bUserConv); | 
 |  | 
 | CJS_Result CJS_App::openFDF(CJS_Runtime* pRuntime, | 
 |                             const std::vector<v8::Local<v8::Value>>& params) { | 
 |   return CJS_Result::Success(); | 
 | } | 
 |  | 
 | CJS_Result CJS_App::alert(CJS_Runtime* pRuntime, | 
 |                           const std::vector<v8::Local<v8::Value>>& params) { | 
 |   std::vector<v8::Local<v8::Value>> newParams = ExpandKeywordParams( | 
 |       pRuntime, params, 4, "cMsg", "nIcon", "nType", "cTitle"); | 
 |  | 
 |   if (!IsExpandedParamKnown(newParams[0])) | 
 |     return CJS_Result::Failure(JSMessage::kParamError); | 
 |  | 
 |   CPDFSDK_FormFillEnvironment* pFormFillEnv = pRuntime->GetFormFillEnv(); | 
 |   if (!pFormFillEnv) | 
 |     return CJS_Result::Success(pRuntime->NewNumber(0)); | 
 |  | 
 |   WideString swMsg; | 
 |   if (newParams[0]->IsArray()) { | 
 |     v8::Local<v8::Array> carray = pRuntime->ToArray(newParams[0]); | 
 |     swMsg = L"["; | 
 |     for (size_t i = 0; i < pRuntime->GetArrayLength(carray); ++i) { | 
 |       if (i) | 
 |         swMsg += L", "; | 
 |  | 
 |       swMsg += pRuntime->ToWideString(pRuntime->GetArrayElement(carray, i)); | 
 |     } | 
 |     swMsg += L"]"; | 
 |   } else { | 
 |     swMsg = pRuntime->ToWideString(newParams[0]); | 
 |   } | 
 |  | 
 |   int iIcon = JSPLATFORM_ALERT_ICON_DEFAULT; | 
 |   if (IsExpandedParamKnown(newParams[1])) | 
 |     iIcon = pRuntime->ToInt32(newParams[1]); | 
 |  | 
 |   int iType = JSPLATFORM_ALERT_BUTTON_DEFAULT; | 
 |   if (IsExpandedParamKnown(newParams[2])) | 
 |     iType = pRuntime->ToInt32(newParams[2]); | 
 |  | 
 |   WideString swTitle; | 
 |   if (IsExpandedParamKnown(newParams[3])) | 
 |     swTitle = pRuntime->ToWideString(newParams[3]); | 
 |   else | 
 |     swTitle = JSGetStringFromID(JSMessage::kAlert); | 
 |  | 
 |   pRuntime->BeginBlock(); | 
 |   pFormFillEnv->KillFocusAnnot({}); | 
 |   v8::Local<v8::Value> ret = pRuntime->NewNumber( | 
 |       pFormFillEnv->JS_appAlert(swMsg, swTitle, iType, iIcon)); | 
 |   pRuntime->EndBlock(); | 
 |  | 
 |   return CJS_Result::Success(ret); | 
 | } | 
 |  | 
 | CJS_Result CJS_App::beep(CJS_Runtime* pRuntime, | 
 |                          const std::vector<v8::Local<v8::Value>>& params) { | 
 |   if (params.size() != 1) | 
 |     return CJS_Result::Failure(JSMessage::kParamError); | 
 |  | 
 |   int type = JSPLATFORM_BEEP_DEFAULT; | 
 |   if (IsExpandedParamKnown(params[0])) | 
 |     type = pRuntime->ToInt32(params[0]); | 
 |  | 
 |   pRuntime->GetFormFillEnv()->JS_appBeep(type); | 
 |   return CJS_Result::Success(); | 
 | } | 
 |  | 
 | CJS_Result CJS_App::findComponent( | 
 |     CJS_Runtime* pRuntime, | 
 |     const std::vector<v8::Local<v8::Value>>& params) { | 
 |   return CJS_Result::Success(); | 
 | } | 
 |  | 
 | CJS_Result CJS_App::popUpMenuEx( | 
 |     CJS_Runtime* pRuntime, | 
 |     const std::vector<v8::Local<v8::Value>>& params) { | 
 |   return CJS_Result::Failure(JSMessage::kNotSupportedError); | 
 | } | 
 |  | 
 | CJS_Result CJS_App::get_fs(CJS_Runtime* pRuntime) { | 
 |   return CJS_Result::Failure(JSMessage::kNotSupportedError); | 
 | } | 
 |  | 
 | CJS_Result CJS_App::set_fs(CJS_Runtime* pRuntime, v8::Local<v8::Value> vp) { | 
 |   return CJS_Result::Failure(JSMessage::kNotSupportedError); | 
 | } | 
 |  | 
 | CJS_Result CJS_App::setInterval( | 
 |     CJS_Runtime* pRuntime, | 
 |     const std::vector<v8::Local<v8::Value>>& params) { | 
 |   if (params.size() == 0 || params.size() > 2) | 
 |     return CJS_Result::Failure(JSMessage::kParamError); | 
 |  | 
 |   WideString script = pRuntime->ToWideString(params[0]); | 
 |   if (script.IsEmpty()) | 
 |     return CJS_Result::Failure(JSMessage::kInvalidInputError); | 
 |  | 
 |   uint32_t dwInterval = params.size() > 1 ? pRuntime->ToInt32(params[1]) : 1000; | 
 |   auto timerRef = std::make_unique<GlobalTimer>( | 
 |       this, pRuntime, GlobalTimer::Type::kRepeating, script, dwInterval, 0); | 
 |   GlobalTimer* pTimerRef = timerRef.get(); | 
 |   m_Timers.insert(std::move(timerRef)); | 
 |  | 
 |   v8::Local<v8::Object> pRetObj = pRuntime->NewFXJSBoundObject( | 
 |       CJS_TimerObj::GetObjDefnID(), FXJSOBJTYPE_DYNAMIC); | 
 |   if (pRetObj.IsEmpty()) | 
 |     return CJS_Result::Failure(JSMessage::kBadObjectError); | 
 |  | 
 |   auto* pJS_TimerObj = static_cast<CJS_TimerObj*>( | 
 |       CFXJS_Engine::GetObjectPrivate(pRuntime->GetIsolate(), pRetObj)); | 
 |  | 
 |   pJS_TimerObj->SetTimer(pTimerRef); | 
 |   return CJS_Result::Success(pRetObj); | 
 | } | 
 |  | 
 | CJS_Result CJS_App::setTimeOut( | 
 |     CJS_Runtime* pRuntime, | 
 |     const std::vector<v8::Local<v8::Value>>& params) { | 
 |   if (params.size() == 0 || params.size() > 2) | 
 |     return CJS_Result::Failure(JSMessage::kParamError); | 
 |  | 
 |   WideString script = pRuntime->ToWideString(params[0]); | 
 |   if (script.IsEmpty()) | 
 |     return CJS_Result::Failure(JSMessage::kInvalidInputError); | 
 |  | 
 |   uint32_t dwTimeOut = params.size() > 1 ? pRuntime->ToInt32(params[1]) : 1000; | 
 |   auto timerRef = | 
 |       std::make_unique<GlobalTimer>(this, pRuntime, GlobalTimer::Type::kOneShot, | 
 |                                     script, dwTimeOut, dwTimeOut); | 
 |   GlobalTimer* pTimerRef = timerRef.get(); | 
 |   m_Timers.insert(std::move(timerRef)); | 
 |  | 
 |   v8::Local<v8::Object> pRetObj = pRuntime->NewFXJSBoundObject( | 
 |       CJS_TimerObj::GetObjDefnID(), FXJSOBJTYPE_DYNAMIC); | 
 |   if (pRetObj.IsEmpty()) | 
 |     return CJS_Result::Failure(JSMessage::kBadObjectError); | 
 |  | 
 |   auto* pJS_TimerObj = static_cast<CJS_TimerObj*>( | 
 |       CFXJS_Engine::GetObjectPrivate(pRuntime->GetIsolate(), pRetObj)); | 
 |  | 
 |   pJS_TimerObj->SetTimer(pTimerRef); | 
 |   return CJS_Result::Success(pRetObj); | 
 | } | 
 |  | 
 | CJS_Result CJS_App::clearTimeOut( | 
 |     CJS_Runtime* pRuntime, | 
 |     const std::vector<v8::Local<v8::Value>>& params) { | 
 |   if (params.size() != 1) | 
 |     return CJS_Result::Failure(JSMessage::kParamError); | 
 |  | 
 |   CJS_App::ClearTimerCommon(pRuntime, params[0]); | 
 |   return CJS_Result::Success(); | 
 | } | 
 |  | 
 | CJS_Result CJS_App::clearInterval( | 
 |     CJS_Runtime* pRuntime, | 
 |     const std::vector<v8::Local<v8::Value>>& params) { | 
 |   if (params.size() != 1) | 
 |     return CJS_Result::Failure(JSMessage::kParamError); | 
 |  | 
 |   CJS_App::ClearTimerCommon(pRuntime, params[0]); | 
 |   return CJS_Result::Success(); | 
 | } | 
 |  | 
 | void CJS_App::ClearTimerCommon(CJS_Runtime* pRuntime, | 
 |                                v8::Local<v8::Value> param) { | 
 |   if (!param->IsObject()) | 
 |     return; | 
 |  | 
 |   v8::Local<v8::Object> pObj = pRuntime->ToObject(param); | 
 |   auto pTimer = JSGetObject<CJS_TimerObj>(pRuntime->GetIsolate(), pObj); | 
 |   if (!pTimer) | 
 |     return; | 
 |  | 
 |   GlobalTimer::Cancel(pTimer->GetTimerID()); | 
 | } | 
 |  | 
 | CJS_Result CJS_App::execMenuItem( | 
 |     CJS_Runtime* pRuntime, | 
 |     const std::vector<v8::Local<v8::Value>>& params) { | 
 |   return CJS_Result::Failure(JSMessage::kNotSupportedError); | 
 | } | 
 |  | 
 | void CJS_App::TimerProc(GlobalTimer* pTimer) { | 
 |   CJS_Runtime* pRuntime = pTimer->GetRuntime(); | 
 |   if (pRuntime && (!pTimer->IsOneShot() || pTimer->GetTimeOut() > 0)) | 
 |     RunJsScript(pRuntime, pTimer->GetJScript()); | 
 | } | 
 |  | 
 | void CJS_App::CancelProc(GlobalTimer* pTimer) { | 
 |   m_Timers.erase(fxcrt::MakeFakeUniquePtr(pTimer)); | 
 | } | 
 |  | 
 | void CJS_App::RunJsScript(CJS_Runtime* pRuntime, const WideString& wsScript) { | 
 |   if (pRuntime->IsBlocking()) | 
 |     return; | 
 |  | 
 |   IJS_Runtime::ScopedEventContext pContext(pRuntime); | 
 |   pContext->OnExternal_Exec(); | 
 |   pContext->RunScript(wsScript); | 
 | } | 
 |  | 
 | CJS_Result CJS_App::goBack(CJS_Runtime* pRuntime, | 
 |                            const std::vector<v8::Local<v8::Value>>& params) { | 
 |   // Not supported, but do not return error. | 
 |   return CJS_Result::Success(); | 
 | } | 
 |  | 
 | CJS_Result CJS_App::goForward(CJS_Runtime* pRuntime, | 
 |                               const std::vector<v8::Local<v8::Value>>& params) { | 
 |   // Not supported, but do not return error. | 
 |   return CJS_Result::Success(); | 
 | } | 
 |  | 
 | CJS_Result CJS_App::mailMsg(CJS_Runtime* pRuntime, | 
 |                             const std::vector<v8::Local<v8::Value>>& params) { | 
 |   std::vector<v8::Local<v8::Value>> newParams = ExpandKeywordParams( | 
 |       pRuntime, params, 6, "bUI", "cTo", "cCc", "cBcc", "cSubject", "cMsg"); | 
 |  | 
 |   if (!IsExpandedParamKnown(newParams[0])) | 
 |     return CJS_Result::Failure(JSMessage::kParamError); | 
 |  | 
 |   bool bUI = pRuntime->ToBoolean(newParams[0]); | 
 |   WideString cTo; | 
 |   if (IsExpandedParamKnown(newParams[1])) { | 
 |     cTo = pRuntime->ToWideString(newParams[1]); | 
 |   } else { | 
 |     // cTo parameter required when UI not invoked. | 
 |     if (!bUI) | 
 |       return CJS_Result::Failure(JSMessage::kParamError); | 
 |   } | 
 |  | 
 |   WideString cCc; | 
 |   if (IsExpandedParamKnown(newParams[2])) | 
 |     cCc = pRuntime->ToWideString(newParams[2]); | 
 |  | 
 |   WideString cBcc; | 
 |   if (IsExpandedParamKnown(newParams[3])) | 
 |     cBcc = pRuntime->ToWideString(newParams[3]); | 
 |  | 
 |   WideString cSubject; | 
 |   if (IsExpandedParamKnown(newParams[4])) | 
 |     cSubject = pRuntime->ToWideString(newParams[4]); | 
 |  | 
 |   WideString cMsg; | 
 |   if (IsExpandedParamKnown(newParams[5])) | 
 |     cMsg = pRuntime->ToWideString(newParams[5]); | 
 |  | 
 |   pRuntime->BeginBlock(); | 
 |   pRuntime->GetFormFillEnv()->JS_docmailForm(pdfium::span<const uint8_t>(), bUI, | 
 |                                              cTo, cSubject, cCc, cBcc, cMsg); | 
 |   pRuntime->EndBlock(); | 
 |   return CJS_Result::Success(); | 
 | } | 
 |  | 
 | CJS_Result CJS_App::launchURL(CJS_Runtime* pRuntime, | 
 |                               const std::vector<v8::Local<v8::Value>>& params) { | 
 |   // Unsafe, not supported, but do not return error. | 
 |   return CJS_Result::Success(); | 
 | } | 
 |  | 
 | CJS_Result CJS_App::get_runtime_highlight(CJS_Runtime* pRuntime) { | 
 |   return CJS_Result::Success(pRuntime->NewBoolean(m_bRuntimeHighLight)); | 
 | } | 
 |  | 
 | CJS_Result CJS_App::set_runtime_highlight(CJS_Runtime* pRuntime, | 
 |                                           v8::Local<v8::Value> vp) { | 
 |   m_bRuntimeHighLight = pRuntime->ToBoolean(vp); | 
 |   return CJS_Result::Success(); | 
 | } | 
 |  | 
 | CJS_Result CJS_App::get_fullscreen(CJS_Runtime* pRuntime) { | 
 |   return CJS_Result::Failure(JSMessage::kNotSupportedError); | 
 | } | 
 |  | 
 | CJS_Result CJS_App::set_fullscreen(CJS_Runtime* pRuntime, | 
 |                                    v8::Local<v8::Value> vp) { | 
 |   return CJS_Result::Failure(JSMessage::kNotSupportedError); | 
 | } | 
 |  | 
 | CJS_Result CJS_App::popUpMenu(CJS_Runtime* pRuntime, | 
 |                               const std::vector<v8::Local<v8::Value>>& params) { | 
 |   return CJS_Result::Failure(JSMessage::kNotSupportedError); | 
 | } | 
 |  | 
 | CJS_Result CJS_App::browseForDoc( | 
 |     CJS_Runtime* pRuntime, | 
 |     const std::vector<v8::Local<v8::Value>>& params) { | 
 |   // Unsafe, not supported, but do not return an error. | 
 |   return CJS_Result::Success(); | 
 | } | 
 |  | 
 | WideString CJS_App::SysPathToPDFPath(const WideString& sOldPath) { | 
 |   WideString sRet = L"/"; | 
 |   for (const wchar_t& c : sOldPath) { | 
 |     if (c != L':') | 
 |       sRet += (c == L'\\') ? L'/' : c; | 
 |   } | 
 |   return sRet; | 
 | } | 
 |  | 
 | CJS_Result CJS_App::newDoc(CJS_Runtime* pRuntime, | 
 |                            const std::vector<v8::Local<v8::Value>>& params) { | 
 |   return CJS_Result::Failure(JSMessage::kNotSupportedError); | 
 | } | 
 |  | 
 | CJS_Result CJS_App::openDoc(CJS_Runtime* pRuntime, | 
 |                             const std::vector<v8::Local<v8::Value>>& params) { | 
 |   return CJS_Result::Failure(JSMessage::kNotSupportedError); | 
 | } | 
 |  | 
 | CJS_Result CJS_App::response(CJS_Runtime* pRuntime, | 
 |                              const std::vector<v8::Local<v8::Value>>& params) { | 
 |   std::vector<v8::Local<v8::Value>> newParams = | 
 |       ExpandKeywordParams(pRuntime, params, 5, "cQuestion", "cTitle", | 
 |                           "cDefault", "bPassword", "cLabel"); | 
 |  | 
 |   if (!IsExpandedParamKnown(newParams[0])) | 
 |     return CJS_Result::Failure(JSMessage::kParamError); | 
 |  | 
 |   WideString swQuestion = pRuntime->ToWideString(newParams[0]); | 
 |   WideString swTitle = L"PDF"; | 
 |   if (IsExpandedParamKnown(newParams[1])) | 
 |     swTitle = pRuntime->ToWideString(newParams[1]); | 
 |  | 
 |   WideString swDefault; | 
 |   if (IsExpandedParamKnown(newParams[2])) | 
 |     swDefault = pRuntime->ToWideString(newParams[2]); | 
 |  | 
 |   bool bPassword = false; | 
 |   if (IsExpandedParamKnown(newParams[3])) | 
 |     bPassword = pRuntime->ToBoolean(newParams[3]); | 
 |  | 
 |   WideString swLabel; | 
 |   if (IsExpandedParamKnown(newParams[4])) | 
 |     swLabel = pRuntime->ToWideString(newParams[4]); | 
 |  | 
 |   constexpr int kMaxWideChars = 1024; | 
 |   constexpr int kMaxBytes = kMaxWideChars * sizeof(uint16_t); | 
 |   FixedZeroedDataVector<uint16_t> buffer(kMaxWideChars); | 
 |   pdfium::span<uint16_t> buffer_span = buffer.writable_span(); | 
 |   int byte_length = pRuntime->GetFormFillEnv()->JS_appResponse( | 
 |       swQuestion, swTitle, swDefault, swLabel, bPassword, | 
 |       pdfium::as_writable_bytes(buffer_span)); | 
 |   if (byte_length < 0 || byte_length > kMaxBytes) | 
 |     return CJS_Result::Failure(JSMessage::kParamTooLongError); | 
 |  | 
 |   buffer_span = buffer_span.first( | 
 |       std::min<size_t>(kMaxWideChars, byte_length / sizeof(uint16_t))); | 
 |   return CJS_Result::Success(pRuntime->NewString( | 
 |       WideString::FromUTF16LE(buffer_span.data(), buffer_span.size()) | 
 |           .AsStringView())); | 
 | } | 
 |  | 
 | CJS_Result CJS_App::get_media(CJS_Runtime* pRuntime) { | 
 |   return CJS_Result::Failure(JSMessage::kNotSupportedError); | 
 | } | 
 |  | 
 | CJS_Result CJS_App::set_media(CJS_Runtime* pRuntime, v8::Local<v8::Value> vp) { | 
 |   return CJS_Result::Failure(JSMessage::kNotSupportedError); | 
 | } | 
 |  | 
 | CJS_Result CJS_App::execDialog( | 
 |     CJS_Runtime* pRuntime, | 
 |     const std::vector<v8::Local<v8::Value>>& params) { | 
 |   return CJS_Result::Success(); | 
 | } |