Home | History | Annotate | Download | only in xfa
      1 // Copyright 2017 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 "fxjs/xfa/cjx_hostpseudomodel.h"
      8 
      9 #include <memory>
     10 #include <vector>
     11 
     12 #include "fxjs/cfxjse_engine.h"
     13 #include "fxjs/cfxjse_value.h"
     14 #include "fxjs/js_resources.h"
     15 #include "xfa/fxfa/cxfa_ffnotify.h"
     16 #include "xfa/fxfa/parser/cscript_hostpseudomodel.h"
     17 #include "xfa/fxfa/parser/cxfa_layoutprocessor.h"
     18 #include "xfa/fxfa/parser/cxfa_node.h"
     19 #include "xfa/fxfa/parser/xfa_resolvenode_rs.h"
     20 
     21 namespace {
     22 
     23 int32_t FilterName(const WideStringView& wsExpression,
     24                    int32_t nStart,
     25                    WideString& wsFilter) {
     26   ASSERT(nStart > -1);
     27   int32_t iLength = wsExpression.GetLength();
     28   if (nStart >= iLength)
     29     return iLength;
     30 
     31   wchar_t* pBuf = wsFilter.GetBuffer(iLength - nStart);
     32   int32_t nCount = 0;
     33   const wchar_t* pSrc = wsExpression.unterminated_c_str();
     34   wchar_t wCur;
     35   while (nStart < iLength) {
     36     wCur = pSrc[nStart++];
     37     if (wCur == ',')
     38       break;
     39 
     40     pBuf[nCount++] = wCur;
     41   }
     42   wsFilter.ReleaseBuffer(nCount);
     43   wsFilter.Trim();
     44   return nStart;
     45 }
     46 
     47 }  // namespace
     48 
     49 const CJX_MethodSpec CJX_HostPseudoModel::MethodSpecs[] = {
     50     {"beep", beep_static},
     51     {"documentCountInBatch", documentCountInBatch_static},
     52     {"documentInBatch", documentInBatch_static},
     53     {"exportData", exportData_static},
     54     {"getFocus", getFocus_static},
     55     {"gotoURL", gotoURL_static},
     56     {"importData", importData_static},
     57     {"messageBox", messageBox_static},
     58     {"openList", openList_static},
     59     {"pageDown", pageDown_static},
     60     {"pageUp", pageUp_static},
     61     {"print", print_static},
     62     {"resetData", resetData_static},
     63     {"response", response_static},
     64     {"setFocus", setFocus_static}};
     65 
     66 CJX_HostPseudoModel::CJX_HostPseudoModel(CScript_HostPseudoModel* model)
     67     : CJX_Object(model) {
     68   DefineMethods(MethodSpecs, FX_ArraySize(MethodSpecs));
     69 }
     70 
     71 CJX_HostPseudoModel::~CJX_HostPseudoModel() {}
     72 
     73 void CJX_HostPseudoModel::appType(CFXJSE_Value* pValue,
     74                                   bool bSetting,
     75                                   XFA_Attribute eAttribute) {
     76   CXFA_FFNotify* pNotify = GetDocument()->GetNotify();
     77   if (!pNotify)
     78     return;
     79 
     80   if (bSetting) {
     81     ThrowInvalidPropertyException();
     82     return;
     83   }
     84   pValue->SetString("Exchange");
     85 }
     86 
     87 void CJX_HostPseudoModel::calculationsEnabled(CFXJSE_Value* pValue,
     88                                               bool bSetting,
     89                                               XFA_Attribute eAttribute) {
     90   CXFA_FFNotify* pNotify = GetDocument()->GetNotify();
     91   if (!pNotify)
     92     return;
     93 
     94   CXFA_FFDoc* hDoc = pNotify->GetHDOC();
     95   if (bSetting) {
     96     pNotify->GetDocEnvironment()->SetCalculationsEnabled(hDoc,
     97                                                          pValue->ToBoolean());
     98     return;
     99   }
    100   pValue->SetBoolean(pNotify->GetDocEnvironment()->IsCalculationsEnabled(hDoc));
    101 }
    102 
    103 void CJX_HostPseudoModel::currentPage(CFXJSE_Value* pValue,
    104                                       bool bSetting,
    105                                       XFA_Attribute eAttribute) {
    106   CXFA_FFNotify* pNotify = GetDocument()->GetNotify();
    107   if (!pNotify)
    108     return;
    109 
    110   CXFA_FFDoc* hDoc = pNotify->GetHDOC();
    111   if (bSetting) {
    112     pNotify->GetDocEnvironment()->SetCurrentPage(hDoc, pValue->ToInteger());
    113     return;
    114   }
    115   pValue->SetInteger(pNotify->GetDocEnvironment()->GetCurrentPage(hDoc));
    116 }
    117 
    118 void CJX_HostPseudoModel::language(CFXJSE_Value* pValue,
    119                                    bool bSetting,
    120                                    XFA_Attribute eAttribute) {
    121   CXFA_FFNotify* pNotify = GetDocument()->GetNotify();
    122   if (!pNotify)
    123     return;
    124 
    125   if (bSetting) {
    126     ThrowException(L"Unable to set language value.");
    127     return;
    128   }
    129   pValue->SetString(
    130       pNotify->GetAppProvider()->GetLanguage().UTF8Encode().AsStringView());
    131 }
    132 
    133 void CJX_HostPseudoModel::numPages(CFXJSE_Value* pValue,
    134                                    bool bSetting,
    135                                    XFA_Attribute eAttribute) {
    136   CXFA_FFNotify* pNotify = GetDocument()->GetNotify();
    137   if (!pNotify)
    138     return;
    139 
    140   CXFA_FFDoc* hDoc = pNotify->GetHDOC();
    141   if (bSetting) {
    142     ThrowException(L"Unable to set numPages value.");
    143     return;
    144   }
    145   pValue->SetInteger(pNotify->GetDocEnvironment()->CountPages(hDoc));
    146 }
    147 
    148 void CJX_HostPseudoModel::platform(CFXJSE_Value* pValue,
    149                                    bool bSetting,
    150                                    XFA_Attribute eAttribute) {
    151   CXFA_FFNotify* pNotify = GetDocument()->GetNotify();
    152   if (!pNotify)
    153     return;
    154 
    155   if (bSetting) {
    156     ThrowException(L"Unable to set platform value.");
    157     return;
    158   }
    159   pValue->SetString(
    160       pNotify->GetAppProvider()->GetPlatform().UTF8Encode().AsStringView());
    161 }
    162 
    163 void CJX_HostPseudoModel::title(CFXJSE_Value* pValue,
    164                                 bool bSetting,
    165                                 XFA_Attribute eAttribute) {
    166   if (!GetDocument()->GetScriptContext()->IsRunAtClient())
    167     return;
    168 
    169   CXFA_FFNotify* pNotify = GetDocument()->GetNotify();
    170   if (!pNotify)
    171     return;
    172 
    173   CXFA_FFDoc* hDoc = pNotify->GetHDOC();
    174   if (bSetting) {
    175     pNotify->GetDocEnvironment()->SetTitle(hDoc, pValue->ToWideString());
    176     return;
    177   }
    178 
    179   WideString wsTitle;
    180   pNotify->GetDocEnvironment()->GetTitle(hDoc, wsTitle);
    181   pValue->SetString(wsTitle.UTF8Encode().AsStringView());
    182 }
    183 
    184 void CJX_HostPseudoModel::validationsEnabled(CFXJSE_Value* pValue,
    185                                              bool bSetting,
    186                                              XFA_Attribute eAttribute) {
    187   CXFA_FFNotify* pNotify = GetDocument()->GetNotify();
    188   if (!pNotify)
    189     return;
    190 
    191   CXFA_FFDoc* hDoc = pNotify->GetHDOC();
    192   if (bSetting) {
    193     pNotify->GetDocEnvironment()->SetValidationsEnabled(hDoc,
    194                                                         pValue->ToBoolean());
    195     return;
    196   }
    197 
    198   bool bEnabled = pNotify->GetDocEnvironment()->IsValidationsEnabled(hDoc);
    199   pValue->SetBoolean(bEnabled);
    200 }
    201 
    202 void CJX_HostPseudoModel::variation(CFXJSE_Value* pValue,
    203                                     bool bSetting,
    204                                     XFA_Attribute eAttribute) {
    205   if (!GetDocument()->GetScriptContext()->IsRunAtClient())
    206     return;
    207 
    208   CXFA_FFNotify* pNotify = GetDocument()->GetNotify();
    209   if (!pNotify)
    210     return;
    211 
    212   if (bSetting) {
    213     ThrowException(L"Unable to set variation value.");
    214     return;
    215   }
    216   pValue->SetString("Full");
    217 }
    218 
    219 void CJX_HostPseudoModel::version(CFXJSE_Value* pValue,
    220                                   bool bSetting,
    221                                   XFA_Attribute eAttribute) {
    222   CXFA_FFNotify* pNotify = GetDocument()->GetNotify();
    223   if (!pNotify)
    224     return;
    225 
    226   if (bSetting) {
    227     ThrowException(L"Unable to set version value.");
    228     return;
    229   }
    230   pValue->SetString("11");
    231 }
    232 
    233 void CJX_HostPseudoModel::name(CFXJSE_Value* pValue,
    234                                bool bSetting,
    235                                XFA_Attribute eAttribute) {
    236   CXFA_FFNotify* pNotify = GetDocument()->GetNotify();
    237   if (!pNotify)
    238     return;
    239 
    240   if (bSetting) {
    241     ThrowInvalidPropertyException();
    242     return;
    243   }
    244   pValue->SetString(
    245       pNotify->GetAppProvider()->GetAppName().UTF8Encode().AsStringView());
    246 }
    247 
    248 CJS_Return CJX_HostPseudoModel::gotoURL(
    249     CJS_V8* runtime,
    250     const std::vector<v8::Local<v8::Value>>& params) {
    251   if (!GetDocument()->GetScriptContext()->IsRunAtClient())
    252     return CJS_Return(true);
    253 
    254   if (params.size() != 1)
    255     return CJS_Return(JSGetStringFromID(JSMessage::kParamError));
    256 
    257   CXFA_FFNotify* pNotify = GetDocument()->GetNotify();
    258   if (!pNotify)
    259     return CJS_Return(true);
    260 
    261   CXFA_FFDoc* hDoc = pNotify->GetHDOC();
    262   WideString URL = runtime->ToWideString(params[0]);
    263   pNotify->GetDocEnvironment()->GotoURL(hDoc, URL);
    264   return CJS_Return(true);
    265 }
    266 
    267 CJS_Return CJX_HostPseudoModel::openList(
    268     CJS_V8* runtime,
    269     const std::vector<v8::Local<v8::Value>>& params) {
    270   if (!GetDocument()->GetScriptContext()->IsRunAtClient())
    271     return CJS_Return(true);
    272 
    273   if (params.size() != 1)
    274     return CJS_Return(JSGetStringFromID(JSMessage::kParamError));
    275 
    276   CXFA_FFNotify* pNotify = GetDocument()->GetNotify();
    277   if (!pNotify)
    278     return CJS_Return(true);
    279 
    280   CXFA_Node* pNode = nullptr;
    281   if (params[0]->IsObject()) {
    282     pNode = ToNode(runtime->ToXFAObject(params[0]));
    283   } else if (params[0]->IsString()) {
    284     CFXJSE_Engine* pScriptContext = GetDocument()->GetScriptContext();
    285     if (!pScriptContext)
    286       return CJS_Return(true);
    287 
    288     CXFA_Object* pObject = pScriptContext->GetThisObject();
    289     if (!pObject)
    290       return CJS_Return(true);
    291 
    292     uint32_t dwFlag = XFA_RESOLVENODE_Children | XFA_RESOLVENODE_Parent |
    293                       XFA_RESOLVENODE_Siblings;
    294     XFA_RESOLVENODE_RS resolveNodeRS;
    295     bool iRet = pScriptContext->ResolveObjects(
    296         pObject, runtime->ToWideString(params[0]).AsStringView(),
    297         &resolveNodeRS, dwFlag, nullptr);
    298     if (!iRet || !resolveNodeRS.objects.front()->IsNode())
    299       return CJS_Return(true);
    300 
    301     pNode = resolveNodeRS.objects.front()->AsNode();
    302   }
    303 
    304   CXFA_LayoutProcessor* pDocLayout = GetDocument()->GetDocLayout();
    305   if (!pDocLayout)
    306     return CJS_Return(true);
    307 
    308   CXFA_FFWidget* hWidget =
    309       pNotify->GetHWidget(pDocLayout->GetLayoutItem(pNode));
    310   if (!hWidget)
    311     return CJS_Return(true);
    312 
    313   pNotify->GetDocEnvironment()->SetFocusWidget(pNotify->GetHDOC(), hWidget);
    314   pNotify->OpenDropDownList(hWidget);
    315   return CJS_Return(true);
    316 }
    317 
    318 CJS_Return CJX_HostPseudoModel::response(
    319     CJS_V8* runtime,
    320     const std::vector<v8::Local<v8::Value>>& params) {
    321   if (params.empty() || params.size() > 4)
    322     return CJS_Return(JSGetStringFromID(JSMessage::kParamError));
    323 
    324   CXFA_FFNotify* pNotify = GetDocument()->GetNotify();
    325   if (!pNotify)
    326     return CJS_Return(true);
    327 
    328   WideString question;
    329   if (params.size() >= 1)
    330     question = runtime->ToWideString(params[0]);
    331 
    332   WideString title;
    333   if (params.size() >= 2)
    334     title = runtime->ToWideString(params[1]);
    335 
    336   WideString defaultAnswer;
    337   if (params.size() >= 3)
    338     defaultAnswer = runtime->ToWideString(params[2]);
    339 
    340   bool mark = false;
    341   if (params.size() >= 4)
    342     mark = runtime->ToInt32(params[3]) != 0;
    343 
    344   WideString answer =
    345       pNotify->GetAppProvider()->Response(question, title, defaultAnswer, mark);
    346   return CJS_Return(runtime->NewString(answer.UTF8Encode().AsStringView()));
    347 }
    348 
    349 CJS_Return CJX_HostPseudoModel::documentInBatch(
    350     CJS_V8* runtime,
    351     const std::vector<v8::Local<v8::Value>>& params) {
    352   return CJS_Return(runtime->NewNumber(0));
    353 }
    354 
    355 CJS_Return CJX_HostPseudoModel::resetData(
    356     CJS_V8* runtime,
    357     const std::vector<v8::Local<v8::Value>>& params) {
    358   if (params.size() > 1)
    359     return CJS_Return(JSGetStringFromID(JSMessage::kParamError));
    360 
    361   CXFA_FFNotify* pNotify = GetDocument()->GetNotify();
    362   if (!pNotify)
    363     return CJS_Return(true);
    364 
    365   WideString expression;
    366   if (params.size() >= 1)
    367     expression = runtime->ToWideString(params[0]);
    368 
    369   if (expression.IsEmpty()) {
    370     pNotify->ResetData();
    371     return CJS_Return(true);
    372   }
    373 
    374   int32_t iStart = 0;
    375   WideString wsName;
    376   CXFA_Node* pNode = nullptr;
    377   int32_t iExpLength = expression.GetLength();
    378   while (iStart < iExpLength) {
    379     iStart = FilterName(expression.AsStringView(), iStart, wsName);
    380     CFXJSE_Engine* pScriptContext = GetDocument()->GetScriptContext();
    381     if (!pScriptContext)
    382       return CJS_Return(true);
    383 
    384     CXFA_Object* pObject = pScriptContext->GetThisObject();
    385     if (!pObject)
    386       return CJS_Return(true);
    387 
    388     uint32_t dwFlag = XFA_RESOLVENODE_Children | XFA_RESOLVENODE_Parent |
    389                       XFA_RESOLVENODE_Siblings;
    390     XFA_RESOLVENODE_RS resolveNodeRS;
    391     bool iRet = pScriptContext->ResolveObjects(pObject, wsName.AsStringView(),
    392                                                &resolveNodeRS, dwFlag, nullptr);
    393     if (!iRet || !resolveNodeRS.objects.front()->IsNode())
    394       continue;
    395 
    396     pNode = resolveNodeRS.objects.front()->AsNode();
    397     pNotify->ResetData(pNode->GetWidgetAcc());
    398   }
    399   if (!pNode)
    400     pNotify->ResetData();
    401 
    402   return CJS_Return(true);
    403 }
    404 
    405 CJS_Return CJX_HostPseudoModel::beep(
    406     CJS_V8* runtime,
    407     const std::vector<v8::Local<v8::Value>>& params) {
    408   if (!GetDocument()->GetScriptContext()->IsRunAtClient())
    409     return CJS_Return(true);
    410 
    411   if (params.size() > 1)
    412     return CJS_Return(JSGetStringFromID(JSMessage::kParamError));
    413 
    414   CXFA_FFNotify* pNotify = GetDocument()->GetNotify();
    415   if (!pNotify)
    416     return CJS_Return(true);
    417 
    418   uint32_t dwType = 4;
    419   if (params.size() >= 1)
    420     dwType = runtime->ToInt32(params[0]);
    421 
    422   pNotify->GetAppProvider()->Beep(dwType);
    423   return CJS_Return(true);
    424 }
    425 
    426 CJS_Return CJX_HostPseudoModel::setFocus(
    427     CJS_V8* runtime,
    428     const std::vector<v8::Local<v8::Value>>& params) {
    429   if (!GetDocument()->GetScriptContext()->IsRunAtClient())
    430     return CJS_Return(true);
    431 
    432   if (params.size() != 1)
    433     return CJS_Return(JSGetStringFromID(JSMessage::kParamError));
    434 
    435   CXFA_FFNotify* pNotify = GetDocument()->GetNotify();
    436   if (!pNotify)
    437     return CJS_Return(true);
    438 
    439   CXFA_Node* pNode = nullptr;
    440   if (params.size() >= 1) {
    441     if (params[0]->IsObject()) {
    442       pNode = ToNode(runtime->ToXFAObject(params[0]));
    443     } else if (params[0]->IsString()) {
    444       CFXJSE_Engine* pScriptContext = GetDocument()->GetScriptContext();
    445       if (!pScriptContext)
    446         return CJS_Return(true);
    447 
    448       CXFA_Object* pObject = pScriptContext->GetThisObject();
    449       if (!pObject)
    450         return CJS_Return(true);
    451 
    452       uint32_t dwFlag = XFA_RESOLVENODE_Children | XFA_RESOLVENODE_Parent |
    453                         XFA_RESOLVENODE_Siblings;
    454       XFA_RESOLVENODE_RS resolveNodeRS;
    455       bool iRet = pScriptContext->ResolveObjects(
    456           pObject, runtime->ToWideString(params[0]).AsStringView(),
    457           &resolveNodeRS, dwFlag, nullptr);
    458       if (!iRet || !resolveNodeRS.objects.front()->IsNode())
    459         return CJS_Return(true);
    460 
    461       pNode = resolveNodeRS.objects.front()->AsNode();
    462     }
    463   }
    464   pNotify->SetFocusWidgetNode(pNode);
    465   return CJS_Return(true);
    466 }
    467 
    468 CJS_Return CJX_HostPseudoModel::getFocus(
    469     CJS_V8* runtime,
    470     const std::vector<v8::Local<v8::Value>>& params) {
    471   CXFA_FFNotify* pNotify = GetDocument()->GetNotify();
    472   if (!pNotify)
    473     return CJS_Return(true);
    474 
    475   CXFA_Node* pNode = pNotify->GetFocusWidgetNode();
    476   if (!pNode)
    477     return CJS_Return(true);
    478 
    479   CFXJSE_Value* value =
    480       GetDocument()->GetScriptContext()->GetJSValueFromMap(pNode);
    481   if (!value)
    482     return CJS_Return(runtime->NewNull());
    483 
    484   return CJS_Return(value->DirectGetValue().Get(runtime->GetIsolate()));
    485 }
    486 
    487 CJS_Return CJX_HostPseudoModel::messageBox(
    488     CJS_V8* runtime,
    489     const std::vector<v8::Local<v8::Value>>& params) {
    490   if (!GetDocument()->GetScriptContext()->IsRunAtClient())
    491     return CJS_Return(true);
    492 
    493   if (params.empty() || params.size() > 4)
    494     return CJS_Return(JSGetStringFromID(JSMessage::kParamError));
    495 
    496   CXFA_FFNotify* pNotify = GetDocument()->GetNotify();
    497   if (!pNotify)
    498     return CJS_Return(true);
    499 
    500   WideString message;
    501   if (params.size() >= 1)
    502     message = runtime->ToWideString(params[0]);
    503 
    504   WideString title;
    505   if (params.size() >= 2)
    506     title = runtime->ToWideString(params[1]);
    507 
    508   uint32_t messageType = XFA_MBICON_Error;
    509   if (params.size() >= 3) {
    510     messageType = runtime->ToInt32(params[2]);
    511     if (messageType > XFA_MBICON_Status)
    512       messageType = XFA_MBICON_Error;
    513   }
    514 
    515   uint32_t buttonType = XFA_MB_OK;
    516   if (params.size() >= 4) {
    517     buttonType = runtime->ToInt32(params[3]);
    518     if (buttonType > XFA_MB_YesNoCancel)
    519       buttonType = XFA_MB_OK;
    520   }
    521 
    522   int32_t iValue = pNotify->GetAppProvider()->MsgBox(message, title,
    523                                                      messageType, buttonType);
    524   return CJS_Return(runtime->NewNumber(iValue));
    525 }
    526 
    527 CJS_Return CJX_HostPseudoModel::documentCountInBatch(
    528     CJS_V8* runtime,
    529     const std::vector<v8::Local<v8::Value>>& params) {
    530   return CJS_Return(runtime->NewNumber(0));
    531 }
    532 
    533 CJS_Return CJX_HostPseudoModel::print(
    534     CJS_V8* runtime,
    535     const std::vector<v8::Local<v8::Value>>& params) {
    536   if (!GetDocument()->GetScriptContext()->IsRunAtClient())
    537     return CJS_Return(true);
    538 
    539   if (params.size() != 8)
    540     return CJS_Return(JSGetStringFromID(JSMessage::kParamError));
    541 
    542   CXFA_FFNotify* pNotify = GetDocument()->GetNotify();
    543   if (!pNotify)
    544     return CJS_Return(true);
    545 
    546   uint32_t dwOptions = 0;
    547   if (runtime->ToBoolean(params[0]))
    548     dwOptions |= XFA_PRINTOPT_ShowDialog;
    549   if (runtime->ToBoolean(params[3]))
    550     dwOptions |= XFA_PRINTOPT_CanCancel;
    551   if (runtime->ToBoolean(params[4]))
    552     dwOptions |= XFA_PRINTOPT_ShrinkPage;
    553   if (runtime->ToBoolean(params[5]))
    554     dwOptions |= XFA_PRINTOPT_AsImage;
    555   if (runtime->ToBoolean(params[6]))
    556     dwOptions |= XFA_PRINTOPT_ReverseOrder;
    557   if (runtime->ToBoolean(params[7]))
    558     dwOptions |= XFA_PRINTOPT_PrintAnnot;
    559 
    560   int32_t nStartPage = runtime->ToInt32(params[1]);
    561   int32_t nEndPage = runtime->ToInt32(params[2]);
    562 
    563   pNotify->GetDocEnvironment()->Print(pNotify->GetHDOC(), nStartPage, nEndPage,
    564                                       dwOptions);
    565   return CJS_Return(true);
    566 }
    567 
    568 CJS_Return CJX_HostPseudoModel::importData(
    569     CJS_V8* runtime,
    570     const std::vector<v8::Local<v8::Value>>& params) {
    571   if (params.empty() || params.size() > 1)
    572     return CJS_Return(JSGetStringFromID(JSMessage::kParamError));
    573 
    574   return CJS_Return(true);
    575 }
    576 
    577 CJS_Return CJX_HostPseudoModel::exportData(
    578     CJS_V8* runtime,
    579     const std::vector<v8::Local<v8::Value>>& params) {
    580   if (params.empty() || params.size() > 2)
    581     return CJS_Return(JSGetStringFromID(JSMessage::kParamError));
    582 
    583   CXFA_FFNotify* pNotify = GetDocument()->GetNotify();
    584   if (!pNotify)
    585     return CJS_Return(true);
    586 
    587   WideString filePath;
    588   if (params.size() >= 1)
    589     filePath = runtime->ToWideString(params[0]);
    590 
    591   bool XDP = true;
    592   if (params.size() >= 2)
    593     XDP = runtime->ToBoolean(params[1]);
    594 
    595   pNotify->GetDocEnvironment()->ExportData(pNotify->GetHDOC(), filePath, XDP);
    596   return CJS_Return(true);
    597 }
    598 
    599 CJS_Return CJX_HostPseudoModel::pageUp(
    600     CJS_V8* runtime,
    601     const std::vector<v8::Local<v8::Value>>& params) {
    602   CXFA_FFNotify* pNotify = GetDocument()->GetNotify();
    603   if (!pNotify)
    604     return CJS_Return(true);
    605 
    606   CXFA_FFDoc* hDoc = pNotify->GetHDOC();
    607   int32_t nCurPage = pNotify->GetDocEnvironment()->GetCurrentPage(hDoc);
    608   int32_t nNewPage = 0;
    609   if (nCurPage <= 1)
    610     return CJS_Return(true);
    611 
    612   nNewPage = nCurPage - 1;
    613   pNotify->GetDocEnvironment()->SetCurrentPage(hDoc, nNewPage);
    614   return CJS_Return(true);
    615 }
    616 
    617 CJS_Return CJX_HostPseudoModel::pageDown(
    618     CJS_V8* runtime,
    619     const std::vector<v8::Local<v8::Value>>& params) {
    620   CXFA_FFNotify* pNotify = GetDocument()->GetNotify();
    621   if (!pNotify)
    622     return CJS_Return(true);
    623 
    624   CXFA_FFDoc* hDoc = pNotify->GetHDOC();
    625   int32_t nCurPage = pNotify->GetDocEnvironment()->GetCurrentPage(hDoc);
    626   int32_t nPageCount = pNotify->GetDocEnvironment()->CountPages(hDoc);
    627   if (!nPageCount || nCurPage == nPageCount)
    628     return CJS_Return(true);
    629 
    630   int32_t nNewPage = 0;
    631   if (nCurPage >= nPageCount)
    632     nNewPage = nPageCount - 1;
    633   else
    634     nNewPage = nCurPage + 1;
    635 
    636   pNotify->GetDocEnvironment()->SetCurrentPage(hDoc, nNewPage);
    637   return CJS_Return(true);
    638 }
    639