Home | History | Annotate | Download | only in javascript
      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 "fpdfsdk/javascript/Document.h"
      8 
      9 #include <algorithm>
     10 #include <utility>
     11 #include <vector>
     12 
     13 #include "core/fpdfapi/font/cpdf_font.h"
     14 #include "core/fpdfapi/page/cpdf_page.h"
     15 #include "core/fpdfapi/parser/cpdf_array.h"
     16 #include "core/fpdfapi/parser/cpdf_document.h"
     17 #include "core/fpdfapi/parser/cpdf_string.h"
     18 #include "core/fpdfapi/parser/fpdf_parser_decode.h"
     19 #include "core/fpdfdoc/cpdf_interform.h"
     20 #include "core/fpdfdoc/cpdf_nametree.h"
     21 #include "fpdfsdk/cpdfsdk_annotiteration.h"
     22 #include "fpdfsdk/cpdfsdk_formfillenvironment.h"
     23 #include "fpdfsdk/cpdfsdk_interform.h"
     24 #include "fpdfsdk/cpdfsdk_pageview.h"
     25 #include "fpdfsdk/cpdfsdk_widget.h"
     26 #include "fpdfsdk/javascript/Annot.h"
     27 #include "fpdfsdk/javascript/Field.h"
     28 #include "fpdfsdk/javascript/Icon.h"
     29 #include "fpdfsdk/javascript/JS_Define.h"
     30 #include "fpdfsdk/javascript/JS_EventHandler.h"
     31 #include "fpdfsdk/javascript/JS_Object.h"
     32 #include "fpdfsdk/javascript/JS_Value.h"
     33 #include "fpdfsdk/javascript/app.h"
     34 #include "fpdfsdk/javascript/cjs_event_context.h"
     35 #include "fpdfsdk/javascript/cjs_runtime.h"
     36 #include "fpdfsdk/javascript/resource.h"
     37 #include "third_party/base/numerics/safe_math.h"
     38 #include "third_party/base/ptr_util.h"
     39 
     40 JSConstSpec CJS_PrintParamsObj::ConstSpecs[] = {{0, JSConstSpec::Number, 0, 0}};
     41 
     42 JSPropertySpec CJS_PrintParamsObj::PropertySpecs[] = {{0, 0, 0}};
     43 
     44 JSMethodSpec CJS_PrintParamsObj::MethodSpecs[] = {{0, 0}};
     45 
     46 IMPLEMENT_JS_CLASS(CJS_PrintParamsObj, PrintParamsObj)
     47 
     48 PrintParamsObj::PrintParamsObj(CJS_Object* pJSObject)
     49     : CJS_EmbedObj(pJSObject) {
     50   bUI = true;
     51   nStart = 0;
     52   nEnd = 0;
     53   bSilent = false;
     54   bShrinkToFit = false;
     55   bPrintAsImage = false;
     56   bReverse = false;
     57   bAnnotations = true;
     58 }
     59 
     60 #define MINWIDTH 5.0f
     61 #define MINHEIGHT 5.0f
     62 
     63 JSConstSpec CJS_Document::ConstSpecs[] = {{0, JSConstSpec::Number, 0, 0}};
     64 
     65 JSPropertySpec CJS_Document::PropertySpecs[] = {
     66     {"ADBE", get_ADBE_static, set_ADBE_static},
     67     {"author", get_author_static, set_author_static},
     68     {"baseURL", get_baseURL_static, set_baseURL_static},
     69     {"bookmarkRoot", get_bookmarkRoot_static, set_bookmarkRoot_static},
     70     {"calculate", get_calculate_static, set_calculate_static},
     71     {"Collab", get_Collab_static, set_Collab_static},
     72     {"creationDate", get_creationDate_static, set_creationDate_static},
     73     {"creator", get_creator_static, set_creator_static},
     74     {"delay", get_delay_static, set_delay_static},
     75     {"dirty", get_dirty_static, set_dirty_static},
     76     {"documentFileName", get_documentFileName_static,
     77      set_documentFileName_static},
     78     {"external", get_external_static, set_external_static},
     79     {"filesize", get_filesize_static, set_filesize_static},
     80     {"icons", get_icons_static, set_icons_static},
     81     {"info", get_info_static, set_info_static},
     82     {"keywords", get_keywords_static, set_keywords_static},
     83     {"layout", get_layout_static, set_layout_static},
     84     {"media", get_media_static, set_media_static},
     85     {"modDate", get_modDate_static, set_modDate_static},
     86     {"mouseX", get_mouseX_static, set_mouseX_static},
     87     {"mouseY", get_mouseY_static, set_mouseY_static},
     88     {"numFields", get_numFields_static, set_numFields_static},
     89     {"numPages", get_numPages_static, set_numPages_static},
     90     {"pageNum", get_pageNum_static, set_pageNum_static},
     91     {"pageWindowRect", get_pageWindowRect_static, set_pageWindowRect_static},
     92     {"path", get_path_static, set_path_static},
     93     {"producer", get_producer_static, set_producer_static},
     94     {"subject", get_subject_static, set_subject_static},
     95     {"title", get_title_static, set_title_static},
     96     {"URL", get_URL_static, set_URL_static},
     97     {"zoom", get_zoom_static, set_zoom_static},
     98     {"zoomType", get_zoomType_static, set_zoomType_static},
     99     {0, 0, 0}};
    100 
    101 JSMethodSpec CJS_Document::MethodSpecs[] = {
    102     {"addAnnot", addAnnot_static},
    103     {"addField", addField_static},
    104     {"addLink", addLink_static},
    105     {"addIcon", addIcon_static},
    106     {"calculateNow", calculateNow_static},
    107     {"closeDoc", closeDoc_static},
    108     {"createDataObject", createDataObject_static},
    109     {"deletePages", deletePages_static},
    110     {"exportAsText", exportAsText_static},
    111     {"exportAsFDF", exportAsFDF_static},
    112     {"exportAsXFDF", exportAsXFDF_static},
    113     {"extractPages", extractPages_static},
    114     {"getAnnot", getAnnot_static},
    115     {"getAnnots", getAnnots_static},
    116     {"getAnnot3D", getAnnot3D_static},
    117     {"getAnnots3D", getAnnots3D_static},
    118     {"getField", getField_static},
    119     {"getIcon", getIcon_static},
    120     {"getLinks", getLinks_static},
    121     {"getNthFieldName", getNthFieldName_static},
    122     {"getOCGs", getOCGs_static},
    123     {"getPageBox", getPageBox_static},
    124     {"getPageNthWord", getPageNthWord_static},
    125     {"getPageNthWordQuads", getPageNthWordQuads_static},
    126     {"getPageNumWords", getPageNumWords_static},
    127     {"getPrintParams", getPrintParams_static},
    128     {"getURL", getURL_static},
    129     {"gotoNamedDest", gotoNamedDest_static},
    130     {"importAnFDF", importAnFDF_static},
    131     {"importAnXFDF", importAnXFDF_static},
    132     {"importTextData", importTextData_static},
    133     {"insertPages", insertPages_static},
    134     {"mailForm", mailForm_static},
    135     {"print", print_static},
    136     {"removeField", removeField_static},
    137     {"replacePages", replacePages_static},
    138     {"resetForm", resetForm_static},
    139     {"removeIcon", removeIcon_static},
    140     {"saveAs", saveAs_static},
    141     {"submitForm", submitForm_static},
    142     {"syncAnnotScan", syncAnnotScan_static},
    143     {"mailDoc", mailDoc_static},
    144     {0, 0}};
    145 
    146 IMPLEMENT_JS_CLASS(CJS_Document, Document)
    147 
    148 void CJS_Document::InitInstance(IJS_Runtime* pIRuntime) {
    149   CJS_Runtime* pRuntime = static_cast<CJS_Runtime*>(pIRuntime);
    150   Document* pDoc = static_cast<Document*>(GetEmbedObject());
    151   pDoc->SetFormFillEnv(pRuntime->GetFormFillEnv());
    152 }
    153 
    154 Document::Document(CJS_Object* pJSObject)
    155     : CJS_EmbedObj(pJSObject),
    156       m_pFormFillEnv(nullptr),
    157       m_cwBaseURL(L""),
    158       m_bDelay(false) {}
    159 
    160 Document::~Document() {
    161 }
    162 
    163 // the total number of fileds in document.
    164 bool Document::numFields(CJS_Runtime* pRuntime,
    165                          CJS_PropValue& vp,
    166                          CFX_WideString& sError) {
    167   if (vp.IsSetting()) {
    168     sError = JSGetStringFromID(IDS_STRING_JSREADONLY);
    169     return false;
    170   }
    171   if (!m_pFormFillEnv) {
    172     sError = JSGetStringFromID(IDS_STRING_JSBADOBJECT);
    173     return false;
    174   }
    175   CPDFSDK_InterForm* pInterForm = m_pFormFillEnv->GetInterForm();
    176   CPDF_InterForm* pPDFForm = pInterForm->GetInterForm();
    177   vp << static_cast<int>(pPDFForm->CountFields(CFX_WideString()));
    178   return true;
    179 }
    180 
    181 bool Document::dirty(CJS_Runtime* pRuntime,
    182                      CJS_PropValue& vp,
    183                      CFX_WideString& sError) {
    184   if (!m_pFormFillEnv) {
    185     sError = JSGetStringFromID(IDS_STRING_JSBADOBJECT);
    186     return false;
    187   }
    188   if (vp.IsGetting()) {
    189     vp << !!m_pFormFillEnv->GetChangeMark();
    190     return true;
    191   }
    192   bool bChanged = false;
    193   vp >> bChanged;
    194   if (bChanged)
    195     m_pFormFillEnv->SetChangeMark();
    196   else
    197     m_pFormFillEnv->ClearChangeMark();
    198 
    199   return true;
    200 }
    201 
    202 bool Document::ADBE(CJS_Runtime* pRuntime,
    203                     CJS_PropValue& vp,
    204                     CFX_WideString& sError) {
    205   if (vp.IsGetting())
    206     vp.GetJSValue()->SetNull(pRuntime);
    207 
    208   return true;
    209 }
    210 
    211 bool Document::pageNum(CJS_Runtime* pRuntime,
    212                        CJS_PropValue& vp,
    213                        CFX_WideString& sError) {
    214   if (!m_pFormFillEnv) {
    215     sError = JSGetStringFromID(IDS_STRING_JSBADOBJECT);
    216     return false;
    217   }
    218   if (vp.IsGetting()) {
    219     if (CPDFSDK_PageView* pPageView = m_pFormFillEnv->GetCurrentView())
    220       vp << pPageView->GetPageIndex();
    221     return true;
    222   }
    223   int iPageCount = m_pFormFillEnv->GetPageCount();
    224   int iPageNum = 0;
    225   vp >> iPageNum;
    226   if (iPageNum >= 0 && iPageNum < iPageCount)
    227     m_pFormFillEnv->JS_docgotoPage(iPageNum);
    228   else if (iPageNum >= iPageCount)
    229     m_pFormFillEnv->JS_docgotoPage(iPageCount - 1);
    230   else if (iPageNum < 0)
    231     m_pFormFillEnv->JS_docgotoPage(0);
    232 
    233   return true;
    234 }
    235 
    236 bool Document::addAnnot(CJS_Runtime* pRuntime,
    237                         const std::vector<CJS_Value>& params,
    238                         CJS_Value& vRet,
    239                         CFX_WideString& sError) {
    240   // Not supported.
    241   return true;
    242 }
    243 
    244 bool Document::addField(CJS_Runtime* pRuntime,
    245                         const std::vector<CJS_Value>& params,
    246                         CJS_Value& vRet,
    247                         CFX_WideString& sError) {
    248   // Not supported.
    249   return true;
    250 }
    251 
    252 bool Document::exportAsText(CJS_Runtime* pRuntime,
    253                             const std::vector<CJS_Value>& params,
    254                             CJS_Value& vRet,
    255                             CFX_WideString& sError) {
    256   // Unsafe, not supported.
    257   return true;
    258 }
    259 
    260 bool Document::exportAsFDF(CJS_Runtime* pRuntime,
    261                            const std::vector<CJS_Value>& params,
    262                            CJS_Value& vRet,
    263                            CFX_WideString& sError) {
    264   // Unsafe, not supported.
    265   return true;
    266 }
    267 
    268 bool Document::exportAsXFDF(CJS_Runtime* pRuntime,
    269                             const std::vector<CJS_Value>& params,
    270                             CJS_Value& vRet,
    271                             CFX_WideString& sError) {
    272   // Unsafe, not supported.
    273   return true;
    274 }
    275 
    276 // Maps a field object in PDF document to a JavaScript variable
    277 // comment:
    278 // note: the paremter cName, this is clue how to treat if the cName is not a
    279 // valiable filed name in this document
    280 
    281 bool Document::getField(CJS_Runtime* pRuntime,
    282                         const std::vector<CJS_Value>& params,
    283                         CJS_Value& vRet,
    284                         CFX_WideString& sError) {
    285   if (params.size() < 1) {
    286     sError = JSGetStringFromID(IDS_STRING_JSPARAMERROR);
    287     return false;
    288   }
    289   if (!m_pFormFillEnv) {
    290     sError = JSGetStringFromID(IDS_STRING_JSBADOBJECT);
    291     return false;
    292   }
    293   CFX_WideString wideName = params[0].ToCFXWideString(pRuntime);
    294   CPDFSDK_InterForm* pInterForm = m_pFormFillEnv->GetInterForm();
    295   CPDF_InterForm* pPDFForm = pInterForm->GetInterForm();
    296   if (pPDFForm->CountFields(wideName) <= 0) {
    297     vRet.SetNull(pRuntime);
    298     return true;
    299   }
    300 
    301   v8::Local<v8::Object> pFieldObj =
    302       pRuntime->NewFxDynamicObj(CJS_Field::g_nObjDefnID);
    303   if (pFieldObj.IsEmpty())
    304     return false;
    305 
    306   CJS_Field* pJSField =
    307       static_cast<CJS_Field*>(pRuntime->GetObjectPrivate(pFieldObj));
    308   Field* pField = static_cast<Field*>(pJSField->GetEmbedObject());
    309   pField->AttachField(this, wideName);
    310   vRet = CJS_Value(pRuntime, pJSField);
    311   return true;
    312 }
    313 
    314 // Gets the name of the nth field in the document
    315 bool Document::getNthFieldName(CJS_Runtime* pRuntime,
    316                                const std::vector<CJS_Value>& params,
    317                                CJS_Value& vRet,
    318                                CFX_WideString& sError) {
    319   if (params.size() != 1) {
    320     sError = JSGetStringFromID(IDS_STRING_JSPARAMERROR);
    321     return false;
    322   }
    323   if (!m_pFormFillEnv) {
    324     sError = JSGetStringFromID(IDS_STRING_JSBADOBJECT);
    325     return false;
    326   }
    327   int nIndex = params[0].ToInt(pRuntime);
    328   if (nIndex < 0) {
    329     sError = JSGetStringFromID(IDS_STRING_JSVALUEERROR);
    330     return false;
    331   }
    332   CPDFSDK_InterForm* pInterForm = m_pFormFillEnv->GetInterForm();
    333   CPDF_InterForm* pPDFForm = pInterForm->GetInterForm();
    334   CPDF_FormField* pField = pPDFForm->GetField(nIndex, CFX_WideString());
    335   if (!pField)
    336     return false;
    337 
    338   vRet = CJS_Value(pRuntime, pField->GetFullName().c_str());
    339   return true;
    340 }
    341 
    342 bool Document::importAnFDF(CJS_Runtime* pRuntime,
    343                            const std::vector<CJS_Value>& params,
    344                            CJS_Value& vRet,
    345                            CFX_WideString& sError) {
    346   // Unsafe, not supported.
    347   return true;
    348 }
    349 
    350 bool Document::importAnXFDF(CJS_Runtime* pRuntime,
    351                             const std::vector<CJS_Value>& params,
    352                             CJS_Value& vRet,
    353                             CFX_WideString& sError) {
    354   // Unsafe, not supported.
    355   return true;
    356 }
    357 
    358 bool Document::importTextData(CJS_Runtime* pRuntime,
    359                               const std::vector<CJS_Value>& params,
    360                               CJS_Value& vRet,
    361                               CFX_WideString& sError) {
    362   // Unsafe, not supported.
    363   return true;
    364 }
    365 
    366 // exports the form data and mails the resulting fdf file as an attachment to
    367 // all recipients.
    368 // comment: need reader supports
    369 bool Document::mailForm(CJS_Runtime* pRuntime,
    370                         const std::vector<CJS_Value>& params,
    371                         CJS_Value& vRet,
    372                         CFX_WideString& sError) {
    373   if (!m_pFormFillEnv) {
    374     sError = JSGetStringFromID(IDS_STRING_JSBADOBJECT);
    375     return false;
    376   }
    377   if (!m_pFormFillEnv->GetPermissions(FPDFPERM_EXTRACT_ACCESS)) {
    378     sError = JSGetStringFromID(IDS_STRING_JSNOPERMISSION);
    379     return false;
    380   }
    381   int iLength = params.size();
    382   bool bUI = iLength > 0 ? params[0].ToBool(pRuntime) : true;
    383   CFX_WideString cTo = iLength > 1 ? params[1].ToCFXWideString(pRuntime) : L"";
    384   CFX_WideString cCc = iLength > 2 ? params[2].ToCFXWideString(pRuntime) : L"";
    385   CFX_WideString cBcc = iLength > 3 ? params[3].ToCFXWideString(pRuntime) : L"";
    386   CFX_WideString cSubject =
    387       iLength > 4 ? params[4].ToCFXWideString(pRuntime) : L"";
    388   CFX_WideString cMsg = iLength > 5 ? params[5].ToCFXWideString(pRuntime) : L"";
    389   CPDFSDK_InterForm* pInterForm = m_pFormFillEnv->GetInterForm();
    390   CFX_ByteTextBuf textBuf;
    391   if (!pInterForm->ExportFormToFDFTextBuf(textBuf))
    392     return false;
    393 
    394   pRuntime->BeginBlock();
    395   CPDFSDK_FormFillEnvironment* pFormFillEnv = pRuntime->GetFormFillEnv();
    396   pFormFillEnv->JS_docmailForm(textBuf.GetBuffer(), textBuf.GetLength(), bUI,
    397                                cTo.c_str(), cSubject.c_str(), cCc.c_str(),
    398                                cBcc.c_str(), cMsg.c_str());
    399   pRuntime->EndBlock();
    400   return true;
    401 }
    402 
    403 bool Document::print(CJS_Runtime* pRuntime,
    404                      const std::vector<CJS_Value>& params,
    405                      CJS_Value& vRet,
    406                      CFX_WideString& sError) {
    407   if (!m_pFormFillEnv) {
    408     sError = JSGetStringFromID(IDS_STRING_JSBADOBJECT);
    409     return false;
    410   }
    411   bool bUI = true;
    412   int nStart = 0;
    413   int nEnd = 0;
    414   bool bSilent = false;
    415   bool bShrinkToFit = false;
    416   bool bPrintAsImage = false;
    417   bool bReverse = false;
    418   bool bAnnotations = false;
    419   int nlength = params.size();
    420   if (nlength == 9) {
    421     if (params[8].GetType() == CJS_Value::VT_object) {
    422       v8::Local<v8::Object> pObj = params[8].ToV8Object(pRuntime);
    423       if (CFXJS_Engine::GetObjDefnID(pObj) ==
    424           CJS_PrintParamsObj::g_nObjDefnID) {
    425         if (CJS_Object* pJSObj = params[8].ToCJSObject(pRuntime)) {
    426           if (PrintParamsObj* pprintparamsObj =
    427                   static_cast<PrintParamsObj*>(pJSObj->GetEmbedObject())) {
    428             bUI = pprintparamsObj->bUI;
    429             nStart = pprintparamsObj->nStart;
    430             nEnd = pprintparamsObj->nEnd;
    431             bSilent = pprintparamsObj->bSilent;
    432             bShrinkToFit = pprintparamsObj->bShrinkToFit;
    433             bPrintAsImage = pprintparamsObj->bPrintAsImage;
    434             bReverse = pprintparamsObj->bReverse;
    435             bAnnotations = pprintparamsObj->bAnnotations;
    436           }
    437         }
    438       }
    439     }
    440   } else {
    441     if (nlength >= 1)
    442       bUI = params[0].ToBool(pRuntime);
    443     if (nlength >= 2)
    444       nStart = params[1].ToInt(pRuntime);
    445     if (nlength >= 3)
    446       nEnd = params[2].ToInt(pRuntime);
    447     if (nlength >= 4)
    448       bSilent = params[3].ToBool(pRuntime);
    449     if (nlength >= 5)
    450       bShrinkToFit = params[4].ToBool(pRuntime);
    451     if (nlength >= 6)
    452       bPrintAsImage = params[5].ToBool(pRuntime);
    453     if (nlength >= 7)
    454       bReverse = params[6].ToBool(pRuntime);
    455     if (nlength >= 8)
    456       bAnnotations = params[7].ToBool(pRuntime);
    457   }
    458 
    459   if (m_pFormFillEnv) {
    460     m_pFormFillEnv->JS_docprint(bUI, nStart, nEnd, bSilent, bShrinkToFit,
    461                                 bPrintAsImage, bReverse, bAnnotations);
    462     return true;
    463   }
    464   return false;
    465 }
    466 
    467 // removes the specified field from the document.
    468 // comment:
    469 // note: if the filed name is not rational, adobe is dumb for it.
    470 
    471 bool Document::removeField(CJS_Runtime* pRuntime,
    472                            const std::vector<CJS_Value>& params,
    473                            CJS_Value& vRet,
    474                            CFX_WideString& sError) {
    475   if (params.size() != 1) {
    476     sError = JSGetStringFromID(IDS_STRING_JSPARAMERROR);
    477     return false;
    478   }
    479   if (!m_pFormFillEnv) {
    480     sError = JSGetStringFromID(IDS_STRING_JSBADOBJECT);
    481     return false;
    482   }
    483   if (!(m_pFormFillEnv->GetPermissions(FPDFPERM_MODIFY) ||
    484         m_pFormFillEnv->GetPermissions(FPDFPERM_ANNOT_FORM))) {
    485     sError = JSGetStringFromID(IDS_STRING_JSNOPERMISSION);
    486     return false;
    487   }
    488   CFX_WideString sFieldName = params[0].ToCFXWideString(pRuntime);
    489   CPDFSDK_InterForm* pInterForm = m_pFormFillEnv->GetInterForm();
    490   std::vector<CPDFSDK_Annot::ObservedPtr> widgets;
    491   pInterForm->GetWidgets(sFieldName, &widgets);
    492   if (widgets.empty())
    493     return true;
    494 
    495   for (const auto& pAnnot : widgets) {
    496     CPDFSDK_Widget* pWidget = static_cast<CPDFSDK_Widget*>(pAnnot.Get());
    497     if (!pWidget)
    498       continue;
    499 
    500     CFX_FloatRect rcAnnot = pWidget->GetRect();
    501     --rcAnnot.left;
    502     --rcAnnot.bottom;
    503     ++rcAnnot.right;
    504     ++rcAnnot.top;
    505 
    506     std::vector<CFX_FloatRect> aRefresh(1, rcAnnot);
    507     UnderlyingPageType* pPage = pWidget->GetUnderlyingPage();
    508     ASSERT(pPage);
    509 
    510     // If there is currently no pageview associated with the page being used
    511     // do not create one. We may be in the process of tearing down the document
    512     // and creating a new pageview at this point will cause bad things.
    513     CPDFSDK_PageView* pPageView = m_pFormFillEnv->GetPageView(pPage, false);
    514     if (pPageView) {
    515 #if PDF_ENABLE_XFA
    516       pPageView->DeleteAnnot(pWidget);
    517 #endif  // PDF_ENABLE_XFA
    518       pPageView->UpdateRects(aRefresh);
    519     }
    520   }
    521   m_pFormFillEnv->SetChangeMark();
    522 
    523   return true;
    524 }
    525 
    526 // reset filed values within a document.
    527 // comment:
    528 // note: if the fields names r not rational, aodbe is dumb for it.
    529 
    530 bool Document::resetForm(CJS_Runtime* pRuntime,
    531                          const std::vector<CJS_Value>& params,
    532                          CJS_Value& vRet,
    533                          CFX_WideString& sError) {
    534   if (!m_pFormFillEnv) {
    535     sError = JSGetStringFromID(IDS_STRING_JSBADOBJECT);
    536     return false;
    537   }
    538   if (!(m_pFormFillEnv->GetPermissions(FPDFPERM_MODIFY) ||
    539         m_pFormFillEnv->GetPermissions(FPDFPERM_ANNOT_FORM) ||
    540         m_pFormFillEnv->GetPermissions(FPDFPERM_FILL_FORM))) {
    541     sError = JSGetStringFromID(IDS_STRING_JSNOPERMISSION);
    542     return false;
    543   }
    544 
    545   CPDFSDK_InterForm* pInterForm = m_pFormFillEnv->GetInterForm();
    546   CPDF_InterForm* pPDFForm = pInterForm->GetInterForm();
    547   CJS_Array aName;
    548 
    549   if (params.empty()) {
    550     pPDFForm->ResetForm(true);
    551     m_pFormFillEnv->SetChangeMark();
    552     return true;
    553   }
    554 
    555   switch (params[0].GetType()) {
    556     default:
    557       aName.Attach(params[0].ToV8Array(pRuntime));
    558       break;
    559     case CJS_Value::VT_string:
    560       aName.SetElement(pRuntime, 0, params[0]);
    561       break;
    562   }
    563 
    564   std::vector<CPDF_FormField*> aFields;
    565   for (int i = 0, isz = aName.GetLength(pRuntime); i < isz; ++i) {
    566     CJS_Value valElement(pRuntime);
    567     aName.GetElement(pRuntime, i, valElement);
    568     CFX_WideString swVal = valElement.ToCFXWideString(pRuntime);
    569     for (int j = 0, jsz = pPDFForm->CountFields(swVal); j < jsz; ++j)
    570       aFields.push_back(pPDFForm->GetField(j, swVal));
    571   }
    572 
    573   if (!aFields.empty()) {
    574     pPDFForm->ResetForm(aFields, true, true);
    575     m_pFormFillEnv->SetChangeMark();
    576   }
    577 
    578   return true;
    579 }
    580 
    581 bool Document::saveAs(CJS_Runtime* pRuntime,
    582                       const std::vector<CJS_Value>& params,
    583                       CJS_Value& vRet,
    584                       CFX_WideString& sError) {
    585   // Unsafe, not supported.
    586   return true;
    587 }
    588 
    589 bool Document::syncAnnotScan(CJS_Runtime* pRuntime,
    590                              const std::vector<CJS_Value>& params,
    591                              CJS_Value& vRet,
    592                              CFX_WideString& sError) {
    593   return true;
    594 }
    595 
    596 bool Document::submitForm(CJS_Runtime* pRuntime,
    597                           const std::vector<CJS_Value>& params,
    598                           CJS_Value& vRet,
    599                           CFX_WideString& sError) {
    600   int nSize = params.size();
    601   if (nSize < 1) {
    602     sError = JSGetStringFromID(IDS_STRING_JSPARAMERROR);
    603     return false;
    604   }
    605   if (!m_pFormFillEnv) {
    606     sError = JSGetStringFromID(IDS_STRING_JSBADOBJECT);
    607     return false;
    608   }
    609 
    610   CJS_Array aFields;
    611   CFX_WideString strURL;
    612   bool bFDF = true;
    613   bool bEmpty = false;
    614   CJS_Value v = params[0];
    615   if (v.GetType() == CJS_Value::VT_string) {
    616     strURL = params[0].ToCFXWideString(pRuntime);
    617     if (nSize > 1)
    618       bFDF = params[1].ToBool(pRuntime);
    619     if (nSize > 2)
    620       bEmpty = params[2].ToBool(pRuntime);
    621     if (nSize > 3)
    622       aFields.Attach(params[3].ToV8Array(pRuntime));
    623   } else if (v.GetType() == CJS_Value::VT_object) {
    624     v8::Local<v8::Object> pObj = params[0].ToV8Object(pRuntime);
    625     v8::Local<v8::Value> pValue = pRuntime->GetObjectProperty(pObj, L"cURL");
    626     if (!pValue.IsEmpty())
    627       strURL = CJS_Value(pRuntime, pValue).ToCFXWideString(pRuntime);
    628 
    629     pValue = pRuntime->GetObjectProperty(pObj, L"bFDF");
    630     bFDF = CJS_Value(pRuntime, pValue).ToBool(pRuntime);
    631 
    632     pValue = pRuntime->GetObjectProperty(pObj, L"bEmpty");
    633     bEmpty = CJS_Value(pRuntime, pValue).ToBool(pRuntime);
    634 
    635     pValue = pRuntime->GetObjectProperty(pObj, L"aFields");
    636     aFields.Attach(CJS_Value(pRuntime, pValue).ToV8Array(pRuntime));
    637   }
    638 
    639   CPDFSDK_InterForm* pInterForm = m_pFormFillEnv->GetInterForm();
    640   CPDF_InterForm* pPDFInterForm = pInterForm->GetInterForm();
    641   if (aFields.GetLength(pRuntime) == 0 && bEmpty) {
    642     if (pPDFInterForm->CheckRequiredFields(nullptr, true)) {
    643       pRuntime->BeginBlock();
    644       pInterForm->SubmitForm(strURL, false);
    645       pRuntime->EndBlock();
    646     }
    647     return true;
    648   }
    649 
    650   std::vector<CPDF_FormField*> fieldObjects;
    651   for (int i = 0, sz = aFields.GetLength(pRuntime); i < sz; ++i) {
    652     CJS_Value valName(pRuntime);
    653     aFields.GetElement(pRuntime, i, valName);
    654 
    655     CFX_WideString sName = valName.ToCFXWideString(pRuntime);
    656     CPDF_InterForm* pPDFForm = pInterForm->GetInterForm();
    657     for (int j = 0, jsz = pPDFForm->CountFields(sName); j < jsz; ++j) {
    658       CPDF_FormField* pField = pPDFForm->GetField(j, sName);
    659       if (!bEmpty && pField->GetValue().IsEmpty())
    660         continue;
    661 
    662       fieldObjects.push_back(pField);
    663     }
    664   }
    665 
    666   if (pPDFInterForm->CheckRequiredFields(&fieldObjects, true)) {
    667     pRuntime->BeginBlock();
    668     pInterForm->SubmitFields(strURL, fieldObjects, true, !bFDF);
    669     pRuntime->EndBlock();
    670   }
    671   return true;
    672 }
    673 
    674 void Document::SetFormFillEnv(CPDFSDK_FormFillEnvironment* pFormFillEnv) {
    675   m_pFormFillEnv.Reset(pFormFillEnv);
    676 }
    677 
    678 bool Document::bookmarkRoot(CJS_Runtime* pRuntime,
    679                             CJS_PropValue& vp,
    680                             CFX_WideString& sError) {
    681   return true;
    682 }
    683 
    684 bool Document::mailDoc(CJS_Runtime* pRuntime,
    685                        const std::vector<CJS_Value>& params,
    686                        CJS_Value& vRet,
    687                        CFX_WideString& sError) {
    688   // TODO(tsepez): Check maximum number of allowed params.
    689   bool bUI = true;
    690   CFX_WideString cTo = L"";
    691   CFX_WideString cCc = L"";
    692   CFX_WideString cBcc = L"";
    693   CFX_WideString cSubject = L"";
    694   CFX_WideString cMsg = L"";
    695 
    696   if (params.size() >= 1)
    697     bUI = params[0].ToBool(pRuntime);
    698   if (params.size() >= 2)
    699     cTo = params[1].ToCFXWideString(pRuntime);
    700   if (params.size() >= 3)
    701     cCc = params[2].ToCFXWideString(pRuntime);
    702   if (params.size() >= 4)
    703     cBcc = params[3].ToCFXWideString(pRuntime);
    704   if (params.size() >= 5)
    705     cSubject = params[4].ToCFXWideString(pRuntime);
    706   if (params.size() >= 6)
    707     cMsg = params[5].ToCFXWideString(pRuntime);
    708 
    709   if (params.size() >= 1 && params[0].GetType() == CJS_Value::VT_object) {
    710     v8::Local<v8::Object> pObj = params[0].ToV8Object(pRuntime);
    711 
    712     v8::Local<v8::Value> pValue = pRuntime->GetObjectProperty(pObj, L"bUI");
    713     bUI = CJS_Value(pRuntime, pValue).ToBool(pRuntime);
    714 
    715     pValue = pRuntime->GetObjectProperty(pObj, L"cTo");
    716     cTo = CJS_Value(pRuntime, pValue).ToCFXWideString(pRuntime);
    717 
    718     pValue = pRuntime->GetObjectProperty(pObj, L"cCc");
    719     cCc = CJS_Value(pRuntime, pValue).ToCFXWideString(pRuntime);
    720 
    721     pValue = pRuntime->GetObjectProperty(pObj, L"cBcc");
    722     cBcc = CJS_Value(pRuntime, pValue).ToCFXWideString(pRuntime);
    723 
    724     pValue = pRuntime->GetObjectProperty(pObj, L"cSubject");
    725     cSubject = CJS_Value(pRuntime, pValue).ToCFXWideString(pRuntime);
    726 
    727     pValue = pRuntime->GetObjectProperty(pObj, L"cMsg");
    728     cMsg = CJS_Value(pRuntime, pValue).ToCFXWideString(pRuntime);
    729   }
    730 
    731   pRuntime->BeginBlock();
    732   CPDFSDK_FormFillEnvironment* pFormFillEnv = pRuntime->GetFormFillEnv();
    733   pFormFillEnv->JS_docmailForm(nullptr, 0, bUI, cTo.c_str(), cSubject.c_str(),
    734                                cCc.c_str(), cBcc.c_str(), cMsg.c_str());
    735   pRuntime->EndBlock();
    736   return true;
    737 }
    738 
    739 bool Document::author(CJS_Runtime* pRuntime,
    740                       CJS_PropValue& vp,
    741                       CFX_WideString& sError) {
    742   return getPropertyInternal(pRuntime, vp, "Author", sError);
    743 }
    744 
    745 bool Document::info(CJS_Runtime* pRuntime,
    746                     CJS_PropValue& vp,
    747                     CFX_WideString& sError) {
    748   if (vp.IsSetting()) {
    749     sError = JSGetStringFromID(IDS_STRING_JSREADONLY);
    750     return false;
    751   }
    752   if (!m_pFormFillEnv) {
    753     sError = JSGetStringFromID(IDS_STRING_JSBADOBJECT);
    754     return false;
    755   }
    756   CPDF_Dictionary* pDictionary = m_pFormFillEnv->GetPDFDocument()->GetInfo();
    757   if (!pDictionary)
    758     return false;
    759 
    760   CFX_WideString cwAuthor = pDictionary->GetUnicodeTextFor("Author");
    761   CFX_WideString cwTitle = pDictionary->GetUnicodeTextFor("Title");
    762   CFX_WideString cwSubject = pDictionary->GetUnicodeTextFor("Subject");
    763   CFX_WideString cwKeywords = pDictionary->GetUnicodeTextFor("Keywords");
    764   CFX_WideString cwCreator = pDictionary->GetUnicodeTextFor("Creator");
    765   CFX_WideString cwProducer = pDictionary->GetUnicodeTextFor("Producer");
    766   CFX_WideString cwCreationDate =
    767       pDictionary->GetUnicodeTextFor("CreationDate");
    768   CFX_WideString cwModDate = pDictionary->GetUnicodeTextFor("ModDate");
    769   CFX_WideString cwTrapped = pDictionary->GetUnicodeTextFor("Trapped");
    770 
    771   v8::Local<v8::Object> pObj = pRuntime->NewFxDynamicObj(-1);
    772   pRuntime->PutObjectProperty(pObj, L"Author",
    773                               pRuntime->NewString(cwAuthor.AsStringC()));
    774   pRuntime->PutObjectProperty(pObj, L"Title",
    775                               pRuntime->NewString(cwTitle.AsStringC()));
    776   pRuntime->PutObjectProperty(pObj, L"Subject",
    777                               pRuntime->NewString(cwSubject.AsStringC()));
    778   pRuntime->PutObjectProperty(pObj, L"Keywords",
    779                               pRuntime->NewString(cwKeywords.AsStringC()));
    780   pRuntime->PutObjectProperty(pObj, L"Creator",
    781                               pRuntime->NewString(cwCreator.AsStringC()));
    782   pRuntime->PutObjectProperty(pObj, L"Producer",
    783                               pRuntime->NewString(cwProducer.AsStringC()));
    784   pRuntime->PutObjectProperty(pObj, L"CreationDate",
    785                               pRuntime->NewString(cwCreationDate.AsStringC()));
    786   pRuntime->PutObjectProperty(pObj, L"ModDate",
    787                               pRuntime->NewString(cwModDate.AsStringC()));
    788   pRuntime->PutObjectProperty(pObj, L"Trapped",
    789                               pRuntime->NewString(cwTrapped.AsStringC()));
    790 
    791   // It's to be compatible to non-standard info dictionary.
    792   for (const auto& it : *pDictionary) {
    793     const CFX_ByteString& bsKey = it.first;
    794     CPDF_Object* pValueObj = it.second.get();
    795     CFX_WideString wsKey = CFX_WideString::FromUTF8(bsKey.AsStringC());
    796     if (pValueObj->IsString() || pValueObj->IsName()) {
    797       pRuntime->PutObjectProperty(
    798           pObj, wsKey,
    799           pRuntime->NewString(pValueObj->GetUnicodeText().AsStringC()));
    800     } else if (pValueObj->IsNumber()) {
    801       pRuntime->PutObjectProperty(pObj, wsKey,
    802                                   pRuntime->NewNumber(pValueObj->GetNumber()));
    803     } else if (pValueObj->IsBoolean()) {
    804       pRuntime->PutObjectProperty(
    805           pObj, wsKey, pRuntime->NewBoolean(!!pValueObj->GetInteger()));
    806     }
    807   }
    808   vp << pObj;
    809   return true;
    810 }
    811 
    812 bool Document::getPropertyInternal(CJS_Runtime* pRuntime,
    813                                    CJS_PropValue& vp,
    814                                    const CFX_ByteString& propName,
    815                                    CFX_WideString& sError) {
    816   if (!m_pFormFillEnv) {
    817     sError = JSGetStringFromID(IDS_STRING_JSBADOBJECT);
    818     return false;
    819   }
    820   CPDF_Dictionary* pDictionary = m_pFormFillEnv->GetPDFDocument()->GetInfo();
    821   if (!pDictionary)
    822     return false;
    823 
    824   if (vp.IsGetting()) {
    825     vp << pDictionary->GetUnicodeTextFor(propName);
    826   } else {
    827     if (!m_pFormFillEnv->GetPermissions(FPDFPERM_MODIFY)) {
    828       sError = JSGetStringFromID(IDS_STRING_JSNOPERMISSION);
    829       return false;
    830     }
    831     CFX_WideString csProperty;
    832     vp >> csProperty;
    833     pDictionary->SetNewFor<CPDF_String>(propName, PDF_EncodeText(csProperty),
    834                                         false);
    835     m_pFormFillEnv->SetChangeMark();
    836   }
    837   return true;
    838 }
    839 
    840 bool Document::creationDate(CJS_Runtime* pRuntime,
    841                             CJS_PropValue& vp,
    842                             CFX_WideString& sError) {
    843   return getPropertyInternal(pRuntime, vp, "CreationDate", sError);
    844 }
    845 
    846 bool Document::creator(CJS_Runtime* pRuntime,
    847                        CJS_PropValue& vp,
    848                        CFX_WideString& sError) {
    849   return getPropertyInternal(pRuntime, vp, "Creator", sError);
    850 }
    851 
    852 bool Document::delay(CJS_Runtime* pRuntime,
    853                      CJS_PropValue& vp,
    854                      CFX_WideString& sError) {
    855   if (!m_pFormFillEnv) {
    856     sError = JSGetStringFromID(IDS_STRING_JSBADOBJECT);
    857     return false;
    858   }
    859   if (vp.IsGetting()) {
    860     vp << m_bDelay;
    861     return true;
    862   }
    863   if (!m_pFormFillEnv->GetPermissions(FPDFPERM_MODIFY)) {
    864     sError = JSGetStringFromID(IDS_STRING_JSNOPERMISSION);
    865     return false;
    866   }
    867   vp >> m_bDelay;
    868   if (m_bDelay) {
    869     m_DelayData.clear();
    870     return true;
    871   }
    872   std::list<std::unique_ptr<CJS_DelayData>> DelayDataToProcess;
    873   DelayDataToProcess.swap(m_DelayData);
    874   for (const auto& pData : DelayDataToProcess)
    875     Field::DoDelay(m_pFormFillEnv.Get(), pData.get());
    876 
    877   return true;
    878 }
    879 
    880 bool Document::keywords(CJS_Runtime* pRuntime,
    881                         CJS_PropValue& vp,
    882                         CFX_WideString& sError) {
    883   return getPropertyInternal(pRuntime, vp, "Keywords", sError);
    884 }
    885 
    886 bool Document::modDate(CJS_Runtime* pRuntime,
    887                        CJS_PropValue& vp,
    888                        CFX_WideString& sError) {
    889   return getPropertyInternal(pRuntime, vp, "ModDate", sError);
    890 }
    891 
    892 bool Document::producer(CJS_Runtime* pRuntime,
    893                         CJS_PropValue& vp,
    894                         CFX_WideString& sError) {
    895   return getPropertyInternal(pRuntime, vp, "Producer", sError);
    896 }
    897 
    898 bool Document::subject(CJS_Runtime* pRuntime,
    899                        CJS_PropValue& vp,
    900                        CFX_WideString& sError) {
    901   return getPropertyInternal(pRuntime, vp, "Subject", sError);
    902 }
    903 
    904 bool Document::title(CJS_Runtime* pRuntime,
    905                      CJS_PropValue& vp,
    906                      CFX_WideString& sError) {
    907   if (!m_pFormFillEnv || !m_pFormFillEnv->GetUnderlyingDocument()) {
    908     sError = JSGetStringFromID(IDS_STRING_JSBADOBJECT);
    909     return false;
    910   }
    911   return getPropertyInternal(pRuntime, vp, "Title", sError);
    912 }
    913 
    914 bool Document::numPages(CJS_Runtime* pRuntime,
    915                         CJS_PropValue& vp,
    916                         CFX_WideString& sError) {
    917   if (vp.IsSetting()) {
    918     sError = JSGetStringFromID(IDS_STRING_JSREADONLY);
    919     return false;
    920   }
    921   if (!m_pFormFillEnv) {
    922     sError = JSGetStringFromID(IDS_STRING_JSBADOBJECT);
    923     return false;
    924   }
    925   vp << m_pFormFillEnv->GetPageCount();
    926   return true;
    927 }
    928 
    929 bool Document::external(CJS_Runtime* pRuntime,
    930                         CJS_PropValue& vp,
    931                         CFX_WideString& sError) {
    932   // In Chrome case, should always return true.
    933   if (vp.IsGetting()) {
    934     vp << true;
    935   }
    936   return true;
    937 }
    938 
    939 bool Document::filesize(CJS_Runtime* pRuntime,
    940                         CJS_PropValue& vp,
    941                         CFX_WideString& sError) {
    942   if (vp.IsSetting()) {
    943     sError = JSGetStringFromID(IDS_STRING_JSREADONLY);
    944     return false;
    945   }
    946   vp << 0;
    947   return true;
    948 }
    949 
    950 bool Document::mouseX(CJS_Runtime* pRuntime,
    951                       CJS_PropValue& vp,
    952                       CFX_WideString& sError) {
    953   return true;
    954 }
    955 
    956 bool Document::mouseY(CJS_Runtime* pRuntime,
    957                       CJS_PropValue& vp,
    958                       CFX_WideString& sError) {
    959   return true;
    960 }
    961 
    962 bool Document::URL(CJS_Runtime* pRuntime,
    963                    CJS_PropValue& vp,
    964                    CFX_WideString& sError) {
    965   if (vp.IsSetting()) {
    966     sError = JSGetStringFromID(IDS_STRING_JSREADONLY);
    967     return false;
    968   }
    969   if (!m_pFormFillEnv) {
    970     sError = JSGetStringFromID(IDS_STRING_JSBADOBJECT);
    971     return false;
    972   }
    973   vp << m_pFormFillEnv->JS_docGetFilePath();
    974   return true;
    975 }
    976 
    977 bool Document::baseURL(CJS_Runtime* pRuntime,
    978                        CJS_PropValue& vp,
    979                        CFX_WideString& sError) {
    980   if (vp.IsGetting()) {
    981     vp << m_cwBaseURL;
    982   } else {
    983     vp >> m_cwBaseURL;
    984   }
    985   return true;
    986 }
    987 
    988 bool Document::calculate(CJS_Runtime* pRuntime,
    989                          CJS_PropValue& vp,
    990                          CFX_WideString& sError) {
    991   if (!m_pFormFillEnv) {
    992     sError = JSGetStringFromID(IDS_STRING_JSBADOBJECT);
    993     return false;
    994   }
    995   CPDFSDK_InterForm* pInterForm = m_pFormFillEnv->GetInterForm();
    996   if (vp.IsGetting()) {
    997     vp << !!pInterForm->IsCalculateEnabled();
    998     return true;
    999   }
   1000   bool bCalculate;
   1001   vp >> bCalculate;
   1002   pInterForm->EnableCalculate(bCalculate);
   1003   return true;
   1004 }
   1005 
   1006 bool Document::documentFileName(CJS_Runtime* pRuntime,
   1007                                 CJS_PropValue& vp,
   1008                                 CFX_WideString& sError) {
   1009   if (vp.IsSetting()) {
   1010     sError = JSGetStringFromID(IDS_STRING_JSREADONLY);
   1011     return false;
   1012   }
   1013   if (!m_pFormFillEnv) {
   1014     sError = JSGetStringFromID(IDS_STRING_JSBADOBJECT);
   1015     return false;
   1016   }
   1017   CFX_WideString wsFilePath = m_pFormFillEnv->JS_docGetFilePath();
   1018   int32_t i = wsFilePath.GetLength() - 1;
   1019   for (; i >= 0; i--) {
   1020     if (wsFilePath.GetAt(i) == L'\\' || wsFilePath.GetAt(i) == L'/')
   1021       break;
   1022   }
   1023   if (i >= 0 && i < wsFilePath.GetLength() - 1) {
   1024     vp << (wsFilePath.GetBuffer(wsFilePath.GetLength()) + i + 1);
   1025   } else {
   1026     vp << L"";
   1027   }
   1028   return true;
   1029 }
   1030 
   1031 bool Document::path(CJS_Runtime* pRuntime,
   1032                     CJS_PropValue& vp,
   1033                     CFX_WideString& sError) {
   1034   if (vp.IsSetting()) {
   1035     sError = JSGetStringFromID(IDS_STRING_JSREADONLY);
   1036     return false;
   1037   }
   1038   if (!m_pFormFillEnv) {
   1039     sError = JSGetStringFromID(IDS_STRING_JSBADOBJECT);
   1040     return false;
   1041   }
   1042   vp << app::SysPathToPDFPath(m_pFormFillEnv->JS_docGetFilePath());
   1043   return true;
   1044 }
   1045 
   1046 bool Document::pageWindowRect(CJS_Runtime* pRuntime,
   1047                               CJS_PropValue& vp,
   1048                               CFX_WideString& sError) {
   1049   return true;
   1050 }
   1051 
   1052 bool Document::layout(CJS_Runtime* pRuntime,
   1053                       CJS_PropValue& vp,
   1054                       CFX_WideString& sError) {
   1055   return true;
   1056 }
   1057 
   1058 bool Document::addLink(CJS_Runtime* pRuntime,
   1059                        const std::vector<CJS_Value>& params,
   1060                        CJS_Value& vRet,
   1061                        CFX_WideString& sError) {
   1062   return true;
   1063 }
   1064 
   1065 bool Document::closeDoc(CJS_Runtime* pRuntime,
   1066                         const std::vector<CJS_Value>& params,
   1067                         CJS_Value& vRet,
   1068                         CFX_WideString& sError) {
   1069   return true;
   1070 }
   1071 
   1072 bool Document::getPageBox(CJS_Runtime* pRuntime,
   1073                           const std::vector<CJS_Value>& params,
   1074                           CJS_Value& vRet,
   1075                           CFX_WideString& sError) {
   1076   return true;
   1077 }
   1078 
   1079 bool Document::getAnnot(CJS_Runtime* pRuntime,
   1080                         const std::vector<CJS_Value>& params,
   1081                         CJS_Value& vRet,
   1082                         CFX_WideString& sError) {
   1083   if (params.size() != 2) {
   1084     sError = JSGetStringFromID(IDS_STRING_JSPARAMERROR);
   1085     return false;
   1086   }
   1087   if (!m_pFormFillEnv) {
   1088     sError = JSGetStringFromID(IDS_STRING_JSBADOBJECT);
   1089     return false;
   1090   }
   1091   int nPageNo = params[0].ToInt(pRuntime);
   1092   CFX_WideString swAnnotName = params[1].ToCFXWideString(pRuntime);
   1093   CPDFSDK_PageView* pPageView = m_pFormFillEnv->GetPageView(nPageNo);
   1094   if (!pPageView)
   1095     return false;
   1096 
   1097   CPDFSDK_AnnotIteration annotIteration(pPageView, false);
   1098   CPDFSDK_BAAnnot* pSDKBAAnnot = nullptr;
   1099   for (const auto& pSDKAnnotCur : annotIteration) {
   1100     CPDFSDK_BAAnnot* pBAAnnot =
   1101         static_cast<CPDFSDK_BAAnnot*>(pSDKAnnotCur.Get());
   1102     if (pBAAnnot && pBAAnnot->GetAnnotName() == swAnnotName) {
   1103       pSDKBAAnnot = pBAAnnot;
   1104       break;
   1105     }
   1106   }
   1107   if (!pSDKBAAnnot)
   1108     return false;
   1109 
   1110   v8::Local<v8::Object> pObj =
   1111       pRuntime->NewFxDynamicObj(CJS_Annot::g_nObjDefnID);
   1112   if (pObj.IsEmpty())
   1113     return false;
   1114 
   1115   CJS_Annot* pJS_Annot =
   1116       static_cast<CJS_Annot*>(pRuntime->GetObjectPrivate(pObj));
   1117   Annot* pAnnot = static_cast<Annot*>(pJS_Annot->GetEmbedObject());
   1118   pAnnot->SetSDKAnnot(pSDKBAAnnot);
   1119   vRet = CJS_Value(pRuntime, pJS_Annot);
   1120   return true;
   1121 }
   1122 
   1123 bool Document::getAnnots(CJS_Runtime* pRuntime,
   1124                          const std::vector<CJS_Value>& params,
   1125                          CJS_Value& vRet,
   1126                          CFX_WideString& sError) {
   1127   if (!m_pFormFillEnv) {
   1128     sError = JSGetStringFromID(IDS_STRING_JSBADOBJECT);
   1129     return false;
   1130   }
   1131   // TODO(tonikitoo): Add support supported parameters as per
   1132   // the PDF spec.
   1133 
   1134   int nPageNo = m_pFormFillEnv->GetPageCount();
   1135   CJS_Array annots;
   1136 
   1137   for (int i = 0; i < nPageNo; ++i) {
   1138     CPDFSDK_PageView* pPageView = m_pFormFillEnv->GetPageView(i);
   1139     if (!pPageView)
   1140       return false;
   1141 
   1142     CPDFSDK_AnnotIteration annotIteration(pPageView, false);
   1143     for (const auto& pSDKAnnotCur : annotIteration) {
   1144       if (!pSDKAnnotCur) {
   1145         sError = JSGetStringFromID(IDS_STRING_JSBADOBJECT);
   1146         return false;
   1147       }
   1148       v8::Local<v8::Object> pObj =
   1149           pRuntime->NewFxDynamicObj(CJS_Annot::g_nObjDefnID);
   1150       if (pObj.IsEmpty())
   1151         return false;
   1152 
   1153       CJS_Annot* pJS_Annot =
   1154           static_cast<CJS_Annot*>(pRuntime->GetObjectPrivate(pObj));
   1155       Annot* pAnnot = static_cast<Annot*>(pJS_Annot->GetEmbedObject());
   1156       pAnnot->SetSDKAnnot(static_cast<CPDFSDK_BAAnnot*>(pSDKAnnotCur.Get()));
   1157       annots.SetElement(pRuntime, i, CJS_Value(pRuntime, pJS_Annot));
   1158     }
   1159   }
   1160   vRet = CJS_Value(pRuntime, annots);
   1161   return true;
   1162 }
   1163 
   1164 bool Document::getAnnot3D(CJS_Runtime* pRuntime,
   1165                           const std::vector<CJS_Value>& params,
   1166                           CJS_Value& vRet,
   1167                           CFX_WideString& sError) {
   1168   vRet.SetNull(pRuntime);
   1169   return true;
   1170 }
   1171 
   1172 bool Document::getAnnots3D(CJS_Runtime* pRuntime,
   1173                            const std::vector<CJS_Value>& params,
   1174                            CJS_Value& vRet,
   1175                            CFX_WideString& sError) {
   1176   return true;
   1177 }
   1178 
   1179 bool Document::getOCGs(CJS_Runtime* pRuntime,
   1180                        const std::vector<CJS_Value>& params,
   1181                        CJS_Value& vRet,
   1182                        CFX_WideString& sError) {
   1183   return true;
   1184 }
   1185 
   1186 bool Document::getLinks(CJS_Runtime* pRuntime,
   1187                         const std::vector<CJS_Value>& params,
   1188                         CJS_Value& vRet,
   1189                         CFX_WideString& sError) {
   1190   return true;
   1191 }
   1192 
   1193 bool Document::IsEnclosedInRect(CFX_FloatRect rect, CFX_FloatRect LinkRect) {
   1194   return (rect.left <= LinkRect.left && rect.top <= LinkRect.top &&
   1195           rect.right >= LinkRect.right && rect.bottom >= LinkRect.bottom);
   1196 }
   1197 
   1198 bool Document::addIcon(CJS_Runtime* pRuntime,
   1199                        const std::vector<CJS_Value>& params,
   1200                        CJS_Value& vRet,
   1201                        CFX_WideString& sError) {
   1202   if (params.size() != 2) {
   1203     sError = JSGetStringFromID(IDS_STRING_JSPARAMERROR);
   1204     return false;
   1205   }
   1206 
   1207   CFX_WideString swIconName = params[0].ToCFXWideString(pRuntime);
   1208   if (params[1].GetType() != CJS_Value::VT_object) {
   1209     sError = JSGetStringFromID(IDS_STRING_JSTYPEERROR);
   1210     return false;
   1211   }
   1212 
   1213   v8::Local<v8::Object> pJSIcon = params[1].ToV8Object(pRuntime);
   1214   if (pRuntime->GetObjDefnID(pJSIcon) != CJS_Icon::g_nObjDefnID) {
   1215     sError = JSGetStringFromID(IDS_STRING_JSTYPEERROR);
   1216     return false;
   1217   }
   1218 
   1219   if (!params[1].ToCJSObject(pRuntime)->GetEmbedObject()) {
   1220     sError = JSGetStringFromID(IDS_STRING_JSTYPEERROR);
   1221     return false;
   1222   }
   1223 
   1224   m_IconNames.push_back(swIconName);
   1225   return true;
   1226 }
   1227 
   1228 bool Document::icons(CJS_Runtime* pRuntime,
   1229                      CJS_PropValue& vp,
   1230                      CFX_WideString& sError) {
   1231   if (vp.IsSetting()) {
   1232     sError = JSGetStringFromID(IDS_STRING_JSREADONLY);
   1233     return false;
   1234   }
   1235   if (m_IconNames.empty()) {
   1236     vp.GetJSValue()->SetNull(pRuntime);
   1237     return true;
   1238   }
   1239 
   1240   CJS_Array Icons;
   1241   int i = 0;
   1242   for (const auto& name : m_IconNames) {
   1243     v8::Local<v8::Object> pObj =
   1244         pRuntime->NewFxDynamicObj(CJS_Icon::g_nObjDefnID);
   1245     if (pObj.IsEmpty())
   1246       return false;
   1247 
   1248     CJS_Icon* pJS_Icon =
   1249         static_cast<CJS_Icon*>(pRuntime->GetObjectPrivate(pObj));
   1250     Icon* pIcon = static_cast<Icon*>(pJS_Icon->GetEmbedObject());
   1251     pIcon->SetIconName(name);
   1252     Icons.SetElement(pRuntime, i++, CJS_Value(pRuntime, pJS_Icon));
   1253   }
   1254 
   1255   vp << Icons;
   1256   return true;
   1257 }
   1258 
   1259 bool Document::getIcon(CJS_Runtime* pRuntime,
   1260                        const std::vector<CJS_Value>& params,
   1261                        CJS_Value& vRet,
   1262                        CFX_WideString& sError) {
   1263   if (params.size() != 1) {
   1264     sError = JSGetStringFromID(IDS_STRING_JSPARAMERROR);
   1265     return false;
   1266   }
   1267 
   1268   CFX_WideString swIconName = params[0].ToCFXWideString(pRuntime);
   1269   auto it = std::find(m_IconNames.begin(), m_IconNames.end(), swIconName);
   1270   if (it == m_IconNames.end())
   1271     return false;
   1272 
   1273   v8::Local<v8::Object> pObj =
   1274       pRuntime->NewFxDynamicObj(CJS_Icon::g_nObjDefnID);
   1275   if (pObj.IsEmpty())
   1276     return false;
   1277 
   1278   CJS_Icon* pJS_Icon = static_cast<CJS_Icon*>(pRuntime->GetObjectPrivate(pObj));
   1279   Icon* pIcon = static_cast<Icon*>(pJS_Icon->GetEmbedObject());
   1280   pIcon->SetIconName(*it);
   1281   vRet = CJS_Value(pRuntime, pJS_Icon);
   1282   return true;
   1283 }
   1284 
   1285 bool Document::removeIcon(CJS_Runtime* pRuntime,
   1286                           const std::vector<CJS_Value>& params,
   1287                           CJS_Value& vRet,
   1288                           CFX_WideString& sError) {
   1289   // Unsafe, no supported.
   1290   return true;
   1291 }
   1292 
   1293 bool Document::createDataObject(CJS_Runtime* pRuntime,
   1294                                 const std::vector<CJS_Value>& params,
   1295                                 CJS_Value& vRet,
   1296                                 CFX_WideString& sError) {
   1297   // Unsafe, not implemented.
   1298   return true;
   1299 }
   1300 
   1301 bool Document::media(CJS_Runtime* pRuntime,
   1302                      CJS_PropValue& vp,
   1303                      CFX_WideString& sError) {
   1304   return true;
   1305 }
   1306 
   1307 bool Document::calculateNow(CJS_Runtime* pRuntime,
   1308                             const std::vector<CJS_Value>& params,
   1309                             CJS_Value& vRet,
   1310                             CFX_WideString& sError) {
   1311   if (!m_pFormFillEnv) {
   1312     sError = JSGetStringFromID(IDS_STRING_JSBADOBJECT);
   1313     return false;
   1314   }
   1315   if (!(m_pFormFillEnv->GetPermissions(FPDFPERM_MODIFY) ||
   1316         m_pFormFillEnv->GetPermissions(FPDFPERM_ANNOT_FORM) ||
   1317         m_pFormFillEnv->GetPermissions(FPDFPERM_FILL_FORM))) {
   1318     sError = JSGetStringFromID(IDS_STRING_JSNOPERMISSION);
   1319     return false;
   1320   }
   1321   m_pFormFillEnv->GetInterForm()->OnCalculate();
   1322   return true;
   1323 }
   1324 
   1325 bool Document::Collab(CJS_Runtime* pRuntime,
   1326                       CJS_PropValue& vp,
   1327                       CFX_WideString& sError) {
   1328   return true;
   1329 }
   1330 
   1331 bool Document::getPageNthWord(CJS_Runtime* pRuntime,
   1332                               const std::vector<CJS_Value>& params,
   1333                               CJS_Value& vRet,
   1334                               CFX_WideString& sError) {
   1335   if (!m_pFormFillEnv) {
   1336     sError = JSGetStringFromID(IDS_STRING_JSBADOBJECT);
   1337     return false;
   1338   }
   1339   if (!m_pFormFillEnv->GetPermissions(FPDFPERM_EXTRACT_ACCESS)) {
   1340     sError = JSGetStringFromID(IDS_STRING_JSNOPERMISSION);
   1341     return false;
   1342   }
   1343 
   1344   // TODO(tsepez): check maximum allowable params.
   1345 
   1346   int nPageNo = params.size() > 0 ? params[0].ToInt(pRuntime) : 0;
   1347   int nWordNo = params.size() > 1 ? params[1].ToInt(pRuntime) : 0;
   1348   bool bStrip = params.size() > 2 ? params[2].ToBool(pRuntime) : true;
   1349 
   1350   CPDF_Document* pDocument = m_pFormFillEnv->GetPDFDocument();
   1351   if (!pDocument)
   1352     return false;
   1353 
   1354   if (nPageNo < 0 || nPageNo >= pDocument->GetPageCount()) {
   1355     sError = JSGetStringFromID(IDS_STRING_JSVALUEERROR);
   1356     return false;
   1357   }
   1358 
   1359   CPDF_Dictionary* pPageDict = pDocument->GetPage(nPageNo);
   1360   if (!pPageDict)
   1361     return false;
   1362 
   1363   CPDF_Page page(pDocument, pPageDict, true);
   1364   page.ParseContent();
   1365 
   1366   int nWords = 0;
   1367   CFX_WideString swRet;
   1368   for (auto& pPageObj : *page.GetPageObjectList()) {
   1369     if (pPageObj->IsText()) {
   1370       CPDF_TextObject* pTextObj = pPageObj->AsText();
   1371       int nObjWords = CountWords(pTextObj);
   1372       if (nWords + nObjWords >= nWordNo) {
   1373         swRet = GetObjWordStr(pTextObj, nWordNo - nWords);
   1374         break;
   1375       }
   1376       nWords += nObjWords;
   1377     }
   1378   }
   1379 
   1380   if (bStrip) {
   1381     swRet.TrimLeft();
   1382     swRet.TrimRight();
   1383   }
   1384 
   1385   vRet = CJS_Value(pRuntime, swRet.c_str());
   1386   return true;
   1387 }
   1388 
   1389 bool Document::getPageNthWordQuads(CJS_Runtime* pRuntime,
   1390                                    const std::vector<CJS_Value>& params,
   1391                                    CJS_Value& vRet,
   1392                                    CFX_WideString& sError) {
   1393   if (!m_pFormFillEnv) {
   1394     sError = JSGetStringFromID(IDS_STRING_JSBADOBJECT);
   1395     return false;
   1396   }
   1397   if (!m_pFormFillEnv->GetPermissions(FPDFPERM_EXTRACT_ACCESS)) {
   1398     sError = JSGetStringFromID(IDS_STRING_JSBADOBJECT);
   1399     return false;
   1400   }
   1401   return false;
   1402 }
   1403 
   1404 bool Document::getPageNumWords(CJS_Runtime* pRuntime,
   1405                                const std::vector<CJS_Value>& params,
   1406                                CJS_Value& vRet,
   1407                                CFX_WideString& sError) {
   1408   if (!m_pFormFillEnv) {
   1409     sError = JSGetStringFromID(IDS_STRING_JSBADOBJECT);
   1410     return false;
   1411   }
   1412   if (!m_pFormFillEnv->GetPermissions(FPDFPERM_EXTRACT_ACCESS)) {
   1413     sError = JSGetStringFromID(IDS_STRING_JSNOPERMISSION);
   1414     return false;
   1415   }
   1416   int nPageNo = params.size() > 0 ? params[0].ToInt(pRuntime) : 0;
   1417   CPDF_Document* pDocument = m_pFormFillEnv->GetPDFDocument();
   1418   if (nPageNo < 0 || nPageNo >= pDocument->GetPageCount()) {
   1419     sError = JSGetStringFromID(IDS_STRING_JSVALUEERROR);
   1420     return false;
   1421   }
   1422 
   1423   CPDF_Dictionary* pPageDict = pDocument->GetPage(nPageNo);
   1424   if (!pPageDict)
   1425     return false;
   1426 
   1427   CPDF_Page page(pDocument, pPageDict, true);
   1428   page.ParseContent();
   1429 
   1430   int nWords = 0;
   1431   for (auto& pPageObj : *page.GetPageObjectList()) {
   1432     if (pPageObj->IsText())
   1433       nWords += CountWords(pPageObj->AsText());
   1434   }
   1435 
   1436   vRet = CJS_Value(pRuntime, nWords);
   1437   return true;
   1438 }
   1439 
   1440 bool Document::getPrintParams(CJS_Runtime* pRuntime,
   1441                               const std::vector<CJS_Value>& params,
   1442                               CJS_Value& vRet,
   1443                               CFX_WideString& sError) {
   1444   v8::Local<v8::Object> pRetObj =
   1445       pRuntime->NewFxDynamicObj(CJS_PrintParamsObj::g_nObjDefnID);
   1446   if (pRetObj.IsEmpty())
   1447     return false;
   1448 
   1449   // Not implemented yet.
   1450 
   1451   vRet = CJS_Value(pRuntime, pRetObj);
   1452   return true;
   1453 }
   1454 
   1455 #define ISLATINWORD(u) (u != 0x20 && u <= 0x28FF)
   1456 
   1457 int Document::CountWords(CPDF_TextObject* pTextObj) {
   1458   if (!pTextObj)
   1459     return 0;
   1460 
   1461   int nWords = 0;
   1462 
   1463   CPDF_Font* pFont = pTextObj->GetFont();
   1464   if (!pFont)
   1465     return 0;
   1466 
   1467   bool bIsLatin = false;
   1468 
   1469   for (int i = 0, sz = pTextObj->CountChars(); i < sz; i++) {
   1470     uint32_t charcode = CPDF_Font::kInvalidCharCode;
   1471     FX_FLOAT kerning;
   1472 
   1473     pTextObj->GetCharInfo(i, &charcode, &kerning);
   1474     CFX_WideString swUnicode = pFont->UnicodeFromCharCode(charcode);
   1475 
   1476     uint16_t unicode = 0;
   1477     if (swUnicode.GetLength() > 0)
   1478       unicode = swUnicode[0];
   1479 
   1480     if (ISLATINWORD(unicode) && bIsLatin)
   1481       continue;
   1482 
   1483     bIsLatin = ISLATINWORD(unicode);
   1484     if (unicode != 0x20)
   1485       nWords++;
   1486   }
   1487 
   1488   return nWords;
   1489 }
   1490 
   1491 CFX_WideString Document::GetObjWordStr(CPDF_TextObject* pTextObj,
   1492                                        int nWordIndex) {
   1493   CFX_WideString swRet;
   1494 
   1495   CPDF_Font* pFont = pTextObj->GetFont();
   1496   if (!pFont)
   1497     return L"";
   1498 
   1499   int nWords = 0;
   1500   bool bIsLatin = false;
   1501 
   1502   for (int i = 0, sz = pTextObj->CountChars(); i < sz; i++) {
   1503     uint32_t charcode = CPDF_Font::kInvalidCharCode;
   1504     FX_FLOAT kerning;
   1505 
   1506     pTextObj->GetCharInfo(i, &charcode, &kerning);
   1507     CFX_WideString swUnicode = pFont->UnicodeFromCharCode(charcode);
   1508 
   1509     uint16_t unicode = 0;
   1510     if (swUnicode.GetLength() > 0)
   1511       unicode = swUnicode[0];
   1512 
   1513     if (ISLATINWORD(unicode) && bIsLatin) {
   1514     } else {
   1515       bIsLatin = ISLATINWORD(unicode);
   1516       if (unicode != 0x20)
   1517         nWords++;
   1518     }
   1519 
   1520     if (nWords - 1 == nWordIndex)
   1521       swRet += unicode;
   1522   }
   1523 
   1524   return swRet;
   1525 }
   1526 
   1527 bool Document::zoom(CJS_Runtime* pRuntime,
   1528                     CJS_PropValue& vp,
   1529                     CFX_WideString& sError) {
   1530   return true;
   1531 }
   1532 
   1533 /**
   1534 (none,  NoVary)
   1535 (fitP,  FitPage)
   1536 (fitW,  FitWidth)
   1537 (fitH,  FitHeight)
   1538 (fitV,  FitVisibleWidth)
   1539 (pref,  Preferred)
   1540 (refW,  ReflowWidth)
   1541 */
   1542 
   1543 bool Document::zoomType(CJS_Runtime* pRuntime,
   1544                         CJS_PropValue& vp,
   1545                         CFX_WideString& sError) {
   1546   return true;
   1547 }
   1548 
   1549 bool Document::deletePages(CJS_Runtime* pRuntime,
   1550                            const std::vector<CJS_Value>& params,
   1551                            CJS_Value& vRet,
   1552                            CFX_WideString& sError) {
   1553   // Unsafe, no supported.
   1554   return true;
   1555 }
   1556 
   1557 bool Document::extractPages(CJS_Runtime* pRuntime,
   1558                             const std::vector<CJS_Value>& params,
   1559                             CJS_Value& vRet,
   1560                             CFX_WideString& sError) {
   1561   // Unsafe, not supported.
   1562   return true;
   1563 }
   1564 
   1565 bool Document::insertPages(CJS_Runtime* pRuntime,
   1566                            const std::vector<CJS_Value>& params,
   1567                            CJS_Value& vRet,
   1568                            CFX_WideString& sError) {
   1569   // Unsafe, not supported.
   1570   return true;
   1571 }
   1572 
   1573 bool Document::replacePages(CJS_Runtime* pRuntime,
   1574                             const std::vector<CJS_Value>& params,
   1575                             CJS_Value& vRet,
   1576                             CFX_WideString& sError) {
   1577   // Unsafe, not supported.
   1578   return true;
   1579 }
   1580 
   1581 bool Document::getURL(CJS_Runtime* pRuntime,
   1582                       const std::vector<CJS_Value>& params,
   1583                       CJS_Value& vRet,
   1584                       CFX_WideString& sError) {
   1585   // Unsafe, not supported.
   1586   return true;
   1587 }
   1588 
   1589 bool Document::gotoNamedDest(CJS_Runtime* pRuntime,
   1590                              const std::vector<CJS_Value>& params,
   1591                              CJS_Value& vRet,
   1592                              CFX_WideString& sError) {
   1593   if (params.size() != 1) {
   1594     sError = JSGetStringFromID(IDS_STRING_JSPARAMERROR);
   1595     return false;
   1596   }
   1597   if (!m_pFormFillEnv) {
   1598     sError = JSGetStringFromID(IDS_STRING_JSBADOBJECT);
   1599     return false;
   1600   }
   1601   CFX_WideString wideName = params[0].ToCFXWideString(pRuntime);
   1602   CFX_ByteString utf8Name = wideName.UTF8Encode();
   1603   CPDF_Document* pDocument = m_pFormFillEnv->GetPDFDocument();
   1604   if (!pDocument)
   1605     return false;
   1606 
   1607   CPDF_NameTree nameTree(pDocument, "Dests");
   1608   CPDF_Array* destArray = nameTree.LookupNamedDest(pDocument, utf8Name);
   1609   if (!destArray)
   1610     return false;
   1611 
   1612   CPDF_Dest dest(destArray);
   1613   const CPDF_Array* arrayObject = ToArray(dest.GetObject());
   1614 
   1615   std::unique_ptr<float[]> scrollPositionArray;
   1616   int scrollPositionArraySize = 0;
   1617 
   1618   if (arrayObject) {
   1619     scrollPositionArray.reset(new float[arrayObject->GetCount()]);
   1620     int j = 0;
   1621     for (size_t i = 2; i < arrayObject->GetCount(); i++)
   1622       scrollPositionArray[j++] = arrayObject->GetFloatAt(i);
   1623     scrollPositionArraySize = j;
   1624   }
   1625 
   1626   pRuntime->BeginBlock();
   1627   m_pFormFillEnv->DoGoToAction(dest.GetPageIndex(pDocument), dest.GetZoomMode(),
   1628                                scrollPositionArray.get(),
   1629                                scrollPositionArraySize);
   1630   pRuntime->EndBlock();
   1631 
   1632   return true;
   1633 }
   1634 
   1635 void Document::AddDelayData(CJS_DelayData* pData) {
   1636   m_DelayData.push_back(std::unique_ptr<CJS_DelayData>(pData));
   1637 }
   1638 
   1639 void Document::DoFieldDelay(const CFX_WideString& sFieldName,
   1640                             int nControlIndex) {
   1641   std::vector<std::unique_ptr<CJS_DelayData>> DelayDataForFieldAndControlIndex;
   1642   auto iter = m_DelayData.begin();
   1643   while (iter != m_DelayData.end()) {
   1644     auto old = iter++;
   1645     if ((*old)->sFieldName == sFieldName &&
   1646         (*old)->nControlIndex == nControlIndex) {
   1647       DelayDataForFieldAndControlIndex.push_back(std::move(*old));
   1648       m_DelayData.erase(old);
   1649     }
   1650   }
   1651 
   1652   for (const auto& pData : DelayDataForFieldAndControlIndex)
   1653     Field::DoDelay(m_pFormFillEnv.Get(), pData.get());
   1654 }
   1655 
   1656 CJS_Document* Document::GetCJSDoc() const {
   1657   return static_cast<CJS_Document*>(m_pJSObject);
   1658 }
   1659