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
40JSConstSpec CJS_PrintParamsObj::ConstSpecs[] = {{0, JSConstSpec::Number, 0, 0}};
41
42JSPropertySpec CJS_PrintParamsObj::PropertySpecs[] = {{0, 0, 0}};
43
44JSMethodSpec CJS_PrintParamsObj::MethodSpecs[] = {{0, 0}};
45
46IMPLEMENT_JS_CLASS(CJS_PrintParamsObj, PrintParamsObj)
47
48PrintParamsObj::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
63JSConstSpec CJS_Document::ConstSpecs[] = {{0, JSConstSpec::Number, 0, 0}};
64
65JSPropertySpec 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
101JSMethodSpec 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
146IMPLEMENT_JS_CLASS(CJS_Document, Document)
147
148void 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
154Document::Document(CJS_Object* pJSObject)
155    : CJS_EmbedObj(pJSObject),
156      m_pFormFillEnv(nullptr),
157      m_cwBaseURL(L""),
158      m_bDelay(false) {}
159
160Document::~Document() {
161}
162
163// the total number of fileds in document.
164bool 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
181bool 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
202bool 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
211bool 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
236bool 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
244bool 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
252bool 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
260bool 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
268bool 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
281bool 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
315bool 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
342bool 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
350bool 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
358bool 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
369bool 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
403bool 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
471bool 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
530bool 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
581bool 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
589bool 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
596bool 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
674void Document::SetFormFillEnv(CPDFSDK_FormFillEnvironment* pFormFillEnv) {
675  m_pFormFillEnv.Reset(pFormFillEnv);
676}
677
678bool Document::bookmarkRoot(CJS_Runtime* pRuntime,
679                            CJS_PropValue& vp,
680                            CFX_WideString& sError) {
681  return true;
682}
683
684bool 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
739bool Document::author(CJS_Runtime* pRuntime,
740                      CJS_PropValue& vp,
741                      CFX_WideString& sError) {
742  return getPropertyInternal(pRuntime, vp, "Author", sError);
743}
744
745bool 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
812bool 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
840bool Document::creationDate(CJS_Runtime* pRuntime,
841                            CJS_PropValue& vp,
842                            CFX_WideString& sError) {
843  return getPropertyInternal(pRuntime, vp, "CreationDate", sError);
844}
845
846bool Document::creator(CJS_Runtime* pRuntime,
847                       CJS_PropValue& vp,
848                       CFX_WideString& sError) {
849  return getPropertyInternal(pRuntime, vp, "Creator", sError);
850}
851
852bool 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
880bool Document::keywords(CJS_Runtime* pRuntime,
881                        CJS_PropValue& vp,
882                        CFX_WideString& sError) {
883  return getPropertyInternal(pRuntime, vp, "Keywords", sError);
884}
885
886bool Document::modDate(CJS_Runtime* pRuntime,
887                       CJS_PropValue& vp,
888                       CFX_WideString& sError) {
889  return getPropertyInternal(pRuntime, vp, "ModDate", sError);
890}
891
892bool Document::producer(CJS_Runtime* pRuntime,
893                        CJS_PropValue& vp,
894                        CFX_WideString& sError) {
895  return getPropertyInternal(pRuntime, vp, "Producer", sError);
896}
897
898bool Document::subject(CJS_Runtime* pRuntime,
899                       CJS_PropValue& vp,
900                       CFX_WideString& sError) {
901  return getPropertyInternal(pRuntime, vp, "Subject", sError);
902}
903
904bool 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
914bool 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
929bool 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
939bool 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
950bool Document::mouseX(CJS_Runtime* pRuntime,
951                      CJS_PropValue& vp,
952                      CFX_WideString& sError) {
953  return true;
954}
955
956bool Document::mouseY(CJS_Runtime* pRuntime,
957                      CJS_PropValue& vp,
958                      CFX_WideString& sError) {
959  return true;
960}
961
962bool 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
977bool 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
988bool 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
1006bool 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
1031bool 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
1046bool Document::pageWindowRect(CJS_Runtime* pRuntime,
1047                              CJS_PropValue& vp,
1048                              CFX_WideString& sError) {
1049  return true;
1050}
1051
1052bool Document::layout(CJS_Runtime* pRuntime,
1053                      CJS_PropValue& vp,
1054                      CFX_WideString& sError) {
1055  return true;
1056}
1057
1058bool 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
1065bool 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
1072bool 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
1079bool 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
1123bool 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
1164bool 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
1172bool 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
1179bool 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
1186bool 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
1193bool 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
1198bool 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
1228bool 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
1259bool 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
1285bool 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
1293bool 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
1301bool Document::media(CJS_Runtime* pRuntime,
1302                     CJS_PropValue& vp,
1303                     CFX_WideString& sError) {
1304  return true;
1305}
1306
1307bool 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
1325bool Document::Collab(CJS_Runtime* pRuntime,
1326                      CJS_PropValue& vp,
1327                      CFX_WideString& sError) {
1328  return true;
1329}
1330
1331bool 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
1389bool 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
1404bool 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
1440bool 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
1457int 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
1491CFX_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
1527bool 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
1543bool Document::zoomType(CJS_Runtime* pRuntime,
1544                        CJS_PropValue& vp,
1545                        CFX_WideString& sError) {
1546  return true;
1547}
1548
1549bool 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
1557bool 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
1565bool 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
1573bool 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
1581bool 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
1589bool 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
1635void Document::AddDelayData(CJS_DelayData* pData) {
1636  m_DelayData.push_back(std::unique_ptr<CJS_DelayData>(pData));
1637}
1638
1639void 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
1656CJS_Document* Document::GetCJSDoc() const {
1657  return static_cast<CJS_Document*>(m_pJSObject);
1658}
1659