• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2017 The PDFium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6 
7 #include "fxjs/cjs_document.h"
8 
9 #include <stdint.h>
10 
11 #include <utility>
12 
13 #include "constants/access_permissions.h"
14 #include "core/fpdfapi/page/cpdf_pageimagecache.h"
15 #include "core/fpdfapi/page/cpdf_pageobject.h"
16 #include "core/fpdfapi/page/cpdf_textobject.h"
17 #include "core/fpdfapi/parser/cpdf_array.h"
18 #include "core/fpdfapi/parser/cpdf_dictionary.h"
19 #include "core/fpdfapi/parser/cpdf_name.h"
20 #include "core/fpdfapi/parser/cpdf_string.h"
21 #include "core/fpdfdoc/cpdf_interactiveform.h"
22 #include "core/fpdfdoc/cpdf_nametree.h"
23 #include "fpdfsdk/cpdfsdk_annotiteration.h"
24 #include "fpdfsdk/cpdfsdk_formfillenvironment.h"
25 #include "fpdfsdk/cpdfsdk_interactiveform.h"
26 #include "fpdfsdk/cpdfsdk_pageview.h"
27 #include "fxjs/cjs_annot.h"
28 #include "fxjs/cjs_app.h"
29 #include "fxjs/cjs_delaydata.h"
30 #include "fxjs/cjs_event_context.h"
31 #include "fxjs/cjs_field.h"
32 #include "fxjs/cjs_icon.h"
33 #include "fxjs/js_resources.h"
34 #include "third_party/base/check.h"
35 #include "v8/include/v8-container.h"
36 
37 const JSPropertySpec CJS_Document::PropertySpecs[] = {
38     {"ADBE", get_ADBE_static, set_ADBE_static},
39     {"author", get_author_static, set_author_static},
40     {"baseURL", get_base_URL_static, set_base_URL_static},
41     {"bookmarkRoot", get_bookmark_root_static, set_bookmark_root_static},
42     {"calculate", get_calculate_static, set_calculate_static},
43     {"Collab", get_collab_static, set_collab_static},
44     {"creationDate", get_creation_date_static, set_creation_date_static},
45     {"creator", get_creator_static, set_creator_static},
46     {"delay", get_delay_static, set_delay_static},
47     {"dirty", get_dirty_static, set_dirty_static},
48     {"documentFileName", get_document_file_name_static,
49      set_document_file_name_static},
50     {"external", get_external_static, set_external_static},
51     {"filesize", get_filesize_static, set_filesize_static},
52     {"icons", get_icons_static, set_icons_static},
53     {"info", get_info_static, set_info_static},
54     {"keywords", get_keywords_static, set_keywords_static},
55     {"layout", get_layout_static, set_layout_static},
56     {"media", get_media_static, set_media_static},
57     {"modDate", get_mod_date_static, set_mod_date_static},
58     {"mouseX", get_mouse_x_static, set_mouse_x_static},
59     {"mouseY", get_mouse_y_static, set_mouse_y_static},
60     {"numFields", get_num_fields_static, set_num_fields_static},
61     {"numPages", get_num_pages_static, set_num_pages_static},
62     {"pageNum", get_page_num_static, set_page_num_static},
63     {"pageWindowRect", get_page_window_rect_static,
64      set_page_window_rect_static},
65     {"path", get_path_static, set_path_static},
66     {"producer", get_producer_static, set_producer_static},
67     {"subject", get_subject_static, set_subject_static},
68     {"title", get_title_static, set_title_static},
69     {"URL", get_URL_static, set_URL_static},
70     {"zoom", get_zoom_static, set_zoom_static},
71     {"zoomType", get_zoom_type_static, set_zoom_type_static}};
72 
73 const JSMethodSpec CJS_Document::MethodSpecs[] = {
74     {"addAnnot", addAnnot_static},
75     {"addField", addField_static},
76     {"addLink", addLink_static},
77     {"addIcon", addIcon_static},
78     {"calculateNow", calculateNow_static},
79     {"closeDoc", closeDoc_static},
80     {"createDataObject", createDataObject_static},
81     {"deletePages", deletePages_static},
82     {"exportAsText", exportAsText_static},
83     {"exportAsFDF", exportAsFDF_static},
84     {"exportAsXFDF", exportAsXFDF_static},
85     {"extractPages", extractPages_static},
86     {"getAnnot", getAnnot_static},
87     {"getAnnots", getAnnots_static},
88     {"getAnnot3D", getAnnot3D_static},
89     {"getAnnots3D", getAnnots3D_static},
90     {"getField", getField_static},
91     {"getIcon", getIcon_static},
92     {"getLinks", getLinks_static},
93     {"getNthFieldName", getNthFieldName_static},
94     {"getOCGs", getOCGs_static},
95     {"getPageBox", getPageBox_static},
96     {"getPageNthWord", getPageNthWord_static},
97     {"getPageNthWordQuads", getPageNthWordQuads_static},
98     {"getPageNumWords", getPageNumWords_static},
99     {"getPrintParams", getPrintParams_static},
100     {"getURL", getURL_static},
101     {"gotoNamedDest", gotoNamedDest_static},
102     {"importAnFDF", importAnFDF_static},
103     {"importAnXFDF", importAnXFDF_static},
104     {"importTextData", importTextData_static},
105     {"insertPages", insertPages_static},
106     {"mailDoc", mailDoc_static},
107     {"mailForm", mailForm_static},
108     {"print", print_static},
109     {"removeField", removeField_static},
110     {"replacePages", replacePages_static},
111     {"resetForm", resetForm_static},
112     {"removeIcon", removeIcon_static},
113     {"saveAs", saveAs_static},
114     {"submitForm", submitForm_static},
115     {"syncAnnotScan", syncAnnotScan_static}};
116 
117 uint32_t CJS_Document::ObjDefnID = 0;
118 const char CJS_Document::kName[] = "Document";
119 
120 // static
GetObjDefnID()121 uint32_t CJS_Document::GetObjDefnID() {
122   return ObjDefnID;
123 }
124 
125 // static
DefineJSObjects(CFXJS_Engine * pEngine)126 void CJS_Document::DefineJSObjects(CFXJS_Engine* pEngine) {
127   ObjDefnID = pEngine->DefineObj(CJS_Document::kName, FXJSOBJTYPE_GLOBAL,
128                                  JSConstructor<CJS_Document>, JSDestructor);
129   DefineProps(pEngine, ObjDefnID, PropertySpecs);
130   DefineMethods(pEngine, ObjDefnID, MethodSpecs);
131 }
132 
CJS_Document(v8::Local<v8::Object> pObject,CJS_Runtime * pRuntime)133 CJS_Document::CJS_Document(v8::Local<v8::Object> pObject, CJS_Runtime* pRuntime)
134     : CJS_Object(pObject, pRuntime) {
135   SetFormFillEnv(GetRuntime()->GetFormFillEnv());
136 }
137 
138 CJS_Document::~CJS_Document() = default;
139 
140 // The total number of fields in document.
get_num_fields(CJS_Runtime * pRuntime)141 CJS_Result CJS_Document::get_num_fields(CJS_Runtime* pRuntime) {
142   if (!m_pFormFillEnv)
143     return CJS_Result::Failure(JSMessage::kBadObjectError);
144 
145   CPDF_InteractiveForm* pPDFForm = GetCoreInteractiveForm();
146   return CJS_Result::Success(pRuntime->NewNumber(
147       static_cast<int>(pPDFForm->CountFields(WideString()))));
148 }
149 
set_num_fields(CJS_Runtime * pRuntime,v8::Local<v8::Value> vp)150 CJS_Result CJS_Document::set_num_fields(CJS_Runtime* pRuntime,
151                                         v8::Local<v8::Value> vp) {
152   return CJS_Result::Failure(JSMessage::kReadOnlyError);
153 }
154 
get_dirty(CJS_Runtime * pRuntime)155 CJS_Result CJS_Document::get_dirty(CJS_Runtime* pRuntime) {
156   if (!m_pFormFillEnv)
157     return CJS_Result::Failure(JSMessage::kBadObjectError);
158 
159   return CJS_Result::Success(
160       pRuntime->NewBoolean(!!m_pFormFillEnv->GetChangeMark()));
161 }
162 
set_dirty(CJS_Runtime * pRuntime,v8::Local<v8::Value> vp)163 CJS_Result CJS_Document::set_dirty(CJS_Runtime* pRuntime,
164                                    v8::Local<v8::Value> vp) {
165   if (!m_pFormFillEnv)
166     return CJS_Result::Failure(JSMessage::kBadObjectError);
167 
168   pRuntime->ToBoolean(vp) ? m_pFormFillEnv->SetChangeMark()
169                           : m_pFormFillEnv->ClearChangeMark();
170   return CJS_Result::Success();
171 }
172 
get_ADBE(CJS_Runtime * pRuntime)173 CJS_Result CJS_Document::get_ADBE(CJS_Runtime* pRuntime) {
174   return CJS_Result::Success(pRuntime->NewUndefined());
175 }
176 
set_ADBE(CJS_Runtime * pRuntime,v8::Local<v8::Value> vp)177 CJS_Result CJS_Document::set_ADBE(CJS_Runtime* pRuntime,
178                                   v8::Local<v8::Value> vp) {
179   return CJS_Result::Success();
180 }
181 
get_page_num(CJS_Runtime * pRuntime)182 CJS_Result CJS_Document::get_page_num(CJS_Runtime* pRuntime) {
183   if (!m_pFormFillEnv)
184     return CJS_Result::Failure(JSMessage::kBadObjectError);
185 
186   CPDFSDK_PageView* pPageView = m_pFormFillEnv->GetCurrentView();
187   if (!pPageView)
188     return CJS_Result::Success(pRuntime->NewUndefined());
189 
190   return CJS_Result::Success(pRuntime->NewNumber(pPageView->GetPageIndex()));
191 }
192 
set_page_num(CJS_Runtime * pRuntime,v8::Local<v8::Value> vp)193 CJS_Result CJS_Document::set_page_num(CJS_Runtime* pRuntime,
194                                       v8::Local<v8::Value> vp) {
195   if (!m_pFormFillEnv)
196     return CJS_Result::Failure(JSMessage::kBadObjectError);
197 
198   int iPageCount = m_pFormFillEnv->GetPageCount();
199   int iPageNum = pRuntime->ToInt32(vp);
200   if (iPageNum >= 0 && iPageNum < iPageCount)
201     m_pFormFillEnv->JS_docgotoPage(iPageNum);
202   else if (iPageNum >= iPageCount)
203     m_pFormFillEnv->JS_docgotoPage(iPageCount - 1);
204   else if (iPageNum < 0)
205     m_pFormFillEnv->JS_docgotoPage(0);
206 
207   return CJS_Result::Success();
208 }
209 
addAnnot(CJS_Runtime * pRuntime,const std::vector<v8::Local<v8::Value>> & params)210 CJS_Result CJS_Document::addAnnot(
211     CJS_Runtime* pRuntime,
212     const std::vector<v8::Local<v8::Value>>& params) {
213   // Not supported, but do not return an error.
214   return CJS_Result::Success();
215 }
216 
addField(CJS_Runtime * pRuntime,const std::vector<v8::Local<v8::Value>> & params)217 CJS_Result CJS_Document::addField(
218     CJS_Runtime* pRuntime,
219     const std::vector<v8::Local<v8::Value>>& params) {
220   // Not supported, but do not return an error.
221   return CJS_Result::Success();
222 }
223 
exportAsText(CJS_Runtime * pRuntime,const std::vector<v8::Local<v8::Value>> & params)224 CJS_Result CJS_Document::exportAsText(
225     CJS_Runtime* pRuntime,
226     const std::vector<v8::Local<v8::Value>>& params) {
227   // Unsafe, not supported, but do not return an error.
228   return CJS_Result::Success();
229 }
230 
exportAsFDF(CJS_Runtime * pRuntime,const std::vector<v8::Local<v8::Value>> & params)231 CJS_Result CJS_Document::exportAsFDF(
232     CJS_Runtime* pRuntime,
233     const std::vector<v8::Local<v8::Value>>& params) {
234   // Unsafe, not supported, but do not return an error.
235   return CJS_Result::Success();
236 }
237 
exportAsXFDF(CJS_Runtime * pRuntime,const std::vector<v8::Local<v8::Value>> & params)238 CJS_Result CJS_Document::exportAsXFDF(
239     CJS_Runtime* pRuntime,
240     const std::vector<v8::Local<v8::Value>>& params) {
241   // Unsafe, not supported, but do not return an error.
242   return CJS_Result::Success();
243 }
244 
getField(CJS_Runtime * pRuntime,const std::vector<v8::Local<v8::Value>> & params)245 CJS_Result CJS_Document::getField(
246     CJS_Runtime* pRuntime,
247     const std::vector<v8::Local<v8::Value>>& params) {
248   if (params.empty())
249     return CJS_Result::Failure(JSMessage::kParamError);
250 
251   if (!m_pFormFillEnv)
252     return CJS_Result::Failure(JSMessage::kBadObjectError);
253 
254   WideString wideName = pRuntime->ToWideString(params[0]);
255   CPDF_InteractiveForm* pPDFForm = GetCoreInteractiveForm();
256   if (pPDFForm->CountFields(wideName) <= 0)
257     return CJS_Result::Success(pRuntime->NewUndefined());
258 
259   v8::Local<v8::Object> pFieldObj = pRuntime->NewFXJSBoundObject(
260       CJS_Field::GetObjDefnID(), FXJSOBJTYPE_DYNAMIC);
261   if (pFieldObj.IsEmpty())
262     return CJS_Result::Failure(JSMessage::kBadObjectError);
263 
264   auto* pJSField = static_cast<CJS_Field*>(
265       CFXJS_Engine::GetObjectPrivate(pRuntime->GetIsolate(), pFieldObj));
266   if (!pJSField)
267     return CJS_Result::Failure(JSMessage::kBadObjectError);
268 
269   pJSField->AttachField(this, wideName);
270   return CJS_Result::Success(pJSField->ToV8Object());
271 }
272 
273 // Gets the name of the nth field in the document
getNthFieldName(CJS_Runtime * pRuntime,const std::vector<v8::Local<v8::Value>> & params)274 CJS_Result CJS_Document::getNthFieldName(
275     CJS_Runtime* pRuntime,
276     const std::vector<v8::Local<v8::Value>>& params) {
277   if (params.size() != 1)
278     return CJS_Result::Failure(JSMessage::kParamError);
279   if (!m_pFormFillEnv)
280     return CJS_Result::Failure(JSMessage::kBadObjectError);
281 
282   int nIndex = pRuntime->ToInt32(params[0]);
283   if (nIndex < 0)
284     return CJS_Result::Failure(JSMessage::kValueError);
285 
286   CPDF_InteractiveForm* pPDFForm = GetCoreInteractiveForm();
287   CPDF_FormField* pField = pPDFForm->GetField(nIndex, WideString());
288   if (!pField)
289     return CJS_Result::Failure(JSMessage::kBadObjectError);
290   return CJS_Result::Success(
291       pRuntime->NewString(pField->GetFullName().AsStringView()));
292 }
293 
importAnFDF(CJS_Runtime * pRuntime,const std::vector<v8::Local<v8::Value>> & params)294 CJS_Result CJS_Document::importAnFDF(
295     CJS_Runtime* pRuntime,
296     const std::vector<v8::Local<v8::Value>>& params) {
297   // Unsafe, not supported.
298   return CJS_Result::Success();
299 }
300 
importAnXFDF(CJS_Runtime * pRuntime,const std::vector<v8::Local<v8::Value>> & params)301 CJS_Result CJS_Document::importAnXFDF(
302     CJS_Runtime* pRuntime,
303     const std::vector<v8::Local<v8::Value>>& params) {
304   // Unsafe, not supported.
305   return CJS_Result::Success();
306 }
307 
importTextData(CJS_Runtime * pRuntime,const std::vector<v8::Local<v8::Value>> & params)308 CJS_Result CJS_Document::importTextData(
309     CJS_Runtime* pRuntime,
310     const std::vector<v8::Local<v8::Value>>& params) {
311   // Unsafe, not supported.
312   return CJS_Result::Success();
313 }
314 
mailDoc(CJS_Runtime * pRuntime,const std::vector<v8::Local<v8::Value>> & params)315 CJS_Result CJS_Document::mailDoc(
316     CJS_Runtime* pRuntime,
317     const std::vector<v8::Local<v8::Value>>& params) {
318   if (!m_pFormFillEnv)
319     return CJS_Result::Failure(JSMessage::kBadObjectError);
320 
321   std::vector<v8::Local<v8::Value>> newParams = ExpandKeywordParams(
322       pRuntime, params, 6, "bUI", "cTo", "cCc", "cBcc", "cSubject", "cMsg");
323 
324   bool bUI = true;
325   if (IsExpandedParamKnown(newParams[0]))
326     bUI = pRuntime->ToBoolean(newParams[0]);
327 
328   WideString cTo;
329   if (IsExpandedParamKnown(newParams[1]))
330     cTo = pRuntime->ToWideString(newParams[1]);
331 
332   WideString cCc;
333   if (IsExpandedParamKnown(newParams[2]))
334     cCc = pRuntime->ToWideString(newParams[2]);
335 
336   WideString cBcc;
337   if (IsExpandedParamKnown(newParams[3]))
338     cBcc = pRuntime->ToWideString(newParams[3]);
339 
340   WideString cSubject;
341   if (IsExpandedParamKnown(newParams[4]))
342     cSubject = pRuntime->ToWideString(newParams[4]);
343 
344   WideString cMsg;
345   if (IsExpandedParamKnown(newParams[5]))
346     cMsg = pRuntime->ToWideString(newParams[5]);
347 
348   pRuntime->BeginBlock();
349   m_pFormFillEnv->JS_docmailForm(pdfium::span<const uint8_t>(), bUI, cTo,
350                                  cSubject, cCc, cBcc, cMsg);
351   pRuntime->EndBlock();
352   return CJS_Result::Success();
353 }
354 
355 // exports the form data and mails the resulting fdf file as an attachment to
356 // all recipients.
357 // comment: need reader supports
mailForm(CJS_Runtime * pRuntime,const std::vector<v8::Local<v8::Value>> & params)358 CJS_Result CJS_Document::mailForm(
359     CJS_Runtime* pRuntime,
360     const std::vector<v8::Local<v8::Value>>& params) {
361   if (!m_pFormFillEnv)
362     return CJS_Result::Failure(JSMessage::kBadObjectError);
363 
364   using pdfium::access_permissions::kExtractForAccessibility;
365   if (!m_pFormFillEnv->HasPermissions(kExtractForAccessibility))
366     return CJS_Result::Failure(JSMessage::kPermissionError);
367 
368   CPDFSDK_InteractiveForm* pInteractiveForm = GetSDKInteractiveForm();
369   ByteString sTextBuf = pInteractiveForm->ExportFormToFDFTextBuf();
370   if (sTextBuf.IsEmpty())
371     return CJS_Result::Failure(L"Bad FDF format.");
372 
373   std::vector<v8::Local<v8::Value>> newParams = ExpandKeywordParams(
374       pRuntime, params, 6, "bUI", "cTo", "cCc", "cBcc", "cSubject", "cMsg");
375 
376   bool bUI = true;
377   if (IsExpandedParamKnown(newParams[0]))
378     bUI = pRuntime->ToBoolean(newParams[0]);
379 
380   WideString cTo;
381   if (IsExpandedParamKnown(newParams[1]))
382     cTo = pRuntime->ToWideString(newParams[1]);
383 
384   WideString cCc;
385   if (IsExpandedParamKnown(newParams[2]))
386     cCc = pRuntime->ToWideString(newParams[2]);
387 
388   WideString cBcc;
389   if (IsExpandedParamKnown(newParams[3]))
390     cBcc = pRuntime->ToWideString(newParams[3]);
391 
392   WideString cSubject;
393   if (IsExpandedParamKnown(newParams[4]))
394     cSubject = pRuntime->ToWideString(newParams[4]);
395 
396   WideString cMsg;
397   if (IsExpandedParamKnown(newParams[5]))
398     cMsg = pRuntime->ToWideString(newParams[5]);
399 
400   pRuntime->BeginBlock();
401   m_pFormFillEnv->JS_docmailForm(sTextBuf.raw_span(), bUI, cTo, cSubject, cCc,
402                                  cBcc, cMsg);
403   pRuntime->EndBlock();
404   return CJS_Result::Success();
405 }
406 
print(CJS_Runtime * pRuntime,const std::vector<v8::Local<v8::Value>> & params)407 CJS_Result CJS_Document::print(
408     CJS_Runtime* pRuntime,
409     const std::vector<v8::Local<v8::Value>>& params) {
410   std::vector<v8::Local<v8::Value>> newParams = ExpandKeywordParams(
411       pRuntime, params, 8, "bUI", "nStart", "nEnd", "bSilent", "bShrinkToFit",
412       "bPrintAsImage", "bReverse", "bAnnotations");
413 
414   bool bUI = true;
415   if (IsExpandedParamKnown(newParams[0]))
416     bUI = pRuntime->ToBoolean(newParams[0]);
417 
418   int nStart = 0;
419   if (IsExpandedParamKnown(newParams[1]))
420     nStart = pRuntime->ToInt32(newParams[1]);
421 
422   int nEnd = 0;
423   if (IsExpandedParamKnown(newParams[2]))
424     nEnd = pRuntime->ToInt32(newParams[2]);
425 
426   bool bSilent = false;
427   if (IsExpandedParamKnown(newParams[3]))
428     bSilent = pRuntime->ToBoolean(newParams[3]);
429 
430   bool bShrinkToFit = false;
431   if (IsExpandedParamKnown(newParams[4]))
432     bShrinkToFit = pRuntime->ToBoolean(newParams[4]);
433 
434   bool bPrintAsImage = false;
435   if (IsExpandedParamKnown(newParams[5]))
436     bPrintAsImage = pRuntime->ToBoolean(newParams[5]);
437 
438   bool bReverse = false;
439   if (IsExpandedParamKnown(newParams[6]))
440     bReverse = pRuntime->ToBoolean(newParams[6]);
441 
442   bool bAnnotations = false;
443   if (IsExpandedParamKnown(newParams[7]))
444     bAnnotations = pRuntime->ToBoolean(newParams[7]);
445 
446   if (!m_pFormFillEnv)
447     return CJS_Result::Failure(JSMessage::kBadObjectError);
448 
449   CJS_EventContext* pHandler = pRuntime->GetCurrentEventContext();
450   if (!pHandler->IsUserGesture())
451     return CJS_Result::Failure(JSMessage::kUserGestureRequiredError);
452 
453   m_pFormFillEnv->JS_docprint(bUI, nStart, nEnd, bSilent, bShrinkToFit,
454                               bPrintAsImage, bReverse, bAnnotations);
455   return CJS_Result::Success();
456 }
457 
458 // removes the specified field from the document.
459 // comment:
460 // note: if the filed name is not rational, adobe is dumb for it.
removeField(CJS_Runtime * pRuntime,const std::vector<v8::Local<v8::Value>> & params)461 CJS_Result CJS_Document::removeField(
462     CJS_Runtime* pRuntime,
463     const std::vector<v8::Local<v8::Value>>& params) {
464   if (params.size() != 1)
465     return CJS_Result::Failure(JSMessage::kParamError);
466   if (!m_pFormFillEnv)
467     return CJS_Result::Failure(JSMessage::kBadObjectError);
468 
469   if (!m_pFormFillEnv->HasPermissions(
470           pdfium::access_permissions::kModifyContent |
471           pdfium::access_permissions::kModifyAnnotation)) {
472     return CJS_Result::Failure(JSMessage::kPermissionError);
473   }
474 
475   WideString sFieldName = pRuntime->ToWideString(params[0]);
476   CPDFSDK_InteractiveForm* pInteractiveForm = GetSDKInteractiveForm();
477   std::vector<ObservedPtr<CPDFSDK_Widget>> widgets;
478   pInteractiveForm->GetWidgets(sFieldName, &widgets);
479   if (widgets.empty())
480     return CJS_Result::Success();
481 
482   for (const auto& pWidget : widgets) {
483     if (!pWidget)
484       continue;
485 
486     IPDF_Page* pPage = pWidget->GetPage();
487     DCHECK(pPage);
488 
489     // If there is currently no pageview associated with the page being used
490     // do not create one. We may be in the process of tearing down the document
491     // and creating a new pageview at this point will cause bad things.
492     CPDFSDK_PageView* pPageView = m_pFormFillEnv->GetPageView(pPage);
493     if (!pPageView)
494       continue;
495 
496     CFX_FloatRect rcAnnot = pWidget->GetRect();
497     rcAnnot.Inflate(1.0f, 1.0f, 1.0f, 1.0f);
498 
499     std::vector<CFX_FloatRect> aRefresh(1, rcAnnot);
500     pPageView->UpdateRects(aRefresh);
501   }
502   m_pFormFillEnv->SetChangeMark();
503   return CJS_Result::Success();
504 }
505 
506 // reset filed values within a document.
507 // comment:
508 // note: if the fields names r not rational, aodbe is dumb for it.
509 
resetForm(CJS_Runtime * pRuntime,const std::vector<v8::Local<v8::Value>> & params)510 CJS_Result CJS_Document::resetForm(
511     CJS_Runtime* pRuntime,
512     const std::vector<v8::Local<v8::Value>>& params) {
513   if (!m_pFormFillEnv)
514     return CJS_Result::Failure(JSMessage::kBadObjectError);
515 
516   if (!m_pFormFillEnv->HasPermissions(
517           pdfium::access_permissions::kModifyContent |
518           pdfium::access_permissions::kModifyAnnotation |
519           pdfium::access_permissions::kFillForm)) {
520     return CJS_Result::Failure(JSMessage::kPermissionError);
521   }
522 
523   CPDF_InteractiveForm* pPDFForm = GetCoreInteractiveForm();
524   if (params.empty()) {
525     pPDFForm->ResetForm();
526     m_pFormFillEnv->SetChangeMark();
527     return CJS_Result::Success();
528   }
529 
530   v8::Local<v8::Array> array;
531   if (params[0]->IsString()) {
532     array = pRuntime->NewArray();
533     pRuntime->PutArrayElement(array, 0, params[0]);
534   } else {
535     array = pRuntime->ToArray(params[0]);
536   }
537 
538   std::vector<CPDF_FormField*> aFields;
539   for (size_t i = 0; i < pRuntime->GetArrayLength(array); ++i) {
540     WideString swVal =
541         pRuntime->ToWideString(pRuntime->GetArrayElement(array, i));
542     const size_t jsz = pPDFForm->CountFields(swVal);
543     for (size_t j = 0; j < jsz; ++j)
544       aFields.push_back(pPDFForm->GetField(j, swVal));
545   }
546 
547   if (!aFields.empty()) {
548     pPDFForm->ResetForm(aFields, true);
549     m_pFormFillEnv->SetChangeMark();
550   }
551 
552   return CJS_Result::Success();
553 }
554 
saveAs(CJS_Runtime * pRuntime,const std::vector<v8::Local<v8::Value>> & params)555 CJS_Result CJS_Document::saveAs(
556     CJS_Runtime* pRuntime,
557     const std::vector<v8::Local<v8::Value>>& params) {
558   // Unsafe, not supported.
559   return CJS_Result::Success();
560 }
561 
syncAnnotScan(CJS_Runtime * pRuntime,const std::vector<v8::Local<v8::Value>> & params)562 CJS_Result CJS_Document::syncAnnotScan(
563     CJS_Runtime* pRuntime,
564     const std::vector<v8::Local<v8::Value>>& params) {
565   return CJS_Result::Success();
566 }
567 
submitForm(CJS_Runtime * pRuntime,const std::vector<v8::Local<v8::Value>> & params)568 CJS_Result CJS_Document::submitForm(
569     CJS_Runtime* pRuntime,
570     const std::vector<v8::Local<v8::Value>>& params) {
571   size_t nSize = params.size();
572   if (nSize < 1)
573     return CJS_Result::Failure(JSMessage::kParamError);
574   if (!m_pFormFillEnv)
575     return CJS_Result::Failure(JSMessage::kBadObjectError);
576 
577   CJS_EventContext* pHandler = pRuntime->GetCurrentEventContext();
578   if (!pHandler->IsUserGesture())
579     return CJS_Result::Failure(JSMessage::kUserGestureRequiredError);
580 
581   v8::Local<v8::Array> aFields;
582   WideString strURL;
583   bool bFDF = true;
584   bool bEmpty = false;
585   if (params[0]->IsString()) {
586     strURL = pRuntime->ToWideString(params[0]);
587     if (nSize > 1)
588       bFDF = pRuntime->ToBoolean(params[1]);
589     if (nSize > 2)
590       bEmpty = pRuntime->ToBoolean(params[2]);
591     if (nSize > 3)
592       aFields = pRuntime->ToArray(params[3]);
593   } else if (params[0]->IsObject()) {
594     v8::Local<v8::Object> pObj = pRuntime->ToObject(params[0]);
595     v8::Local<v8::Value> pValue = pRuntime->GetObjectProperty(pObj, "cURL");
596     if (!pValue.IsEmpty())
597       strURL = pRuntime->ToWideString(pValue);
598 
599     bFDF = pRuntime->ToBoolean(pRuntime->GetObjectProperty(pObj, "bFDF"));
600     bEmpty = pRuntime->ToBoolean(pRuntime->GetObjectProperty(pObj, "bEmpty"));
601     aFields = pRuntime->ToArray(pRuntime->GetObjectProperty(pObj, "aFields"));
602   }
603 
604   CPDF_InteractiveForm* pPDFForm = GetCoreInteractiveForm();
605   if (pRuntime->GetArrayLength(aFields) == 0 && bEmpty) {
606     if (pPDFForm->CheckRequiredFields(nullptr, true)) {
607       pRuntime->BeginBlock();
608       GetSDKInteractiveForm()->SubmitForm(strURL);
609       pRuntime->EndBlock();
610     }
611     return CJS_Result::Success();
612   }
613 
614   std::vector<CPDF_FormField*> fieldObjects;
615   for (size_t i = 0; i < pRuntime->GetArrayLength(aFields); ++i) {
616     WideString sName =
617         pRuntime->ToWideString(pRuntime->GetArrayElement(aFields, i));
618     const size_t jsz = pPDFForm->CountFields(sName);
619     for (size_t j = 0; j < jsz; ++j) {
620       CPDF_FormField* pField = pPDFForm->GetField(j, sName);
621       if (!bEmpty && pField->GetValue().IsEmpty())
622         continue;
623 
624       fieldObjects.push_back(pField);
625     }
626   }
627 
628   if (pPDFForm->CheckRequiredFields(&fieldObjects, true)) {
629     pRuntime->BeginBlock();
630     GetSDKInteractiveForm()->SubmitFields(strURL, fieldObjects, true, !bFDF);
631     pRuntime->EndBlock();
632   }
633   return CJS_Result::Success();
634 }
635 
SetFormFillEnv(CPDFSDK_FormFillEnvironment * pFormFillEnv)636 void CJS_Document::SetFormFillEnv(CPDFSDK_FormFillEnvironment* pFormFillEnv) {
637   m_pFormFillEnv.Reset(pFormFillEnv);
638 }
639 
get_bookmark_root(CJS_Runtime * pRuntime)640 CJS_Result CJS_Document::get_bookmark_root(CJS_Runtime* pRuntime) {
641   return CJS_Result::Success();
642 }
643 
set_bookmark_root(CJS_Runtime * pRuntime,v8::Local<v8::Value> vp)644 CJS_Result CJS_Document::set_bookmark_root(CJS_Runtime* pRuntime,
645                                            v8::Local<v8::Value> vp) {
646   return CJS_Result::Success();
647 }
648 
get_author(CJS_Runtime * pRuntime)649 CJS_Result CJS_Document::get_author(CJS_Runtime* pRuntime) {
650   return getPropertyInternal(pRuntime, "Author");
651 }
652 
set_author(CJS_Runtime * pRuntime,v8::Local<v8::Value> vp)653 CJS_Result CJS_Document::set_author(CJS_Runtime* pRuntime,
654                                     v8::Local<v8::Value> vp) {
655   // Read-only.
656   return CJS_Result::Success();
657 }
658 
get_info(CJS_Runtime * pRuntime)659 CJS_Result CJS_Document::get_info(CJS_Runtime* pRuntime) {
660   if (!m_pFormFillEnv)
661     return CJS_Result::Failure(JSMessage::kBadObjectError);
662 
663   RetainPtr<const CPDF_Dictionary> pDictionary =
664       m_pFormFillEnv->GetPDFDocument()->GetInfo();
665   if (!pDictionary)
666     return CJS_Result::Failure(JSMessage::kBadObjectError);
667 
668   WideString cwAuthor = pDictionary->GetUnicodeTextFor("Author");
669   WideString cwTitle = pDictionary->GetUnicodeTextFor("Title");
670   WideString cwSubject = pDictionary->GetUnicodeTextFor("Subject");
671   WideString cwKeywords = pDictionary->GetUnicodeTextFor("Keywords");
672   WideString cwCreator = pDictionary->GetUnicodeTextFor("Creator");
673   WideString cwProducer = pDictionary->GetUnicodeTextFor("Producer");
674   WideString cwCreationDate = pDictionary->GetUnicodeTextFor("CreationDate");
675   WideString cwModDate = pDictionary->GetUnicodeTextFor("ModDate");
676   WideString cwTrapped = pDictionary->GetUnicodeTextFor("Trapped");
677 
678   v8::Local<v8::Object> pObj = pRuntime->NewObject();
679   pRuntime->PutObjectProperty(pObj, "Author",
680                               pRuntime->NewString(cwAuthor.AsStringView()));
681   pRuntime->PutObjectProperty(pObj, "Title",
682                               pRuntime->NewString(cwTitle.AsStringView()));
683   pRuntime->PutObjectProperty(pObj, "Subject",
684                               pRuntime->NewString(cwSubject.AsStringView()));
685   pRuntime->PutObjectProperty(pObj, "Keywords",
686                               pRuntime->NewString(cwKeywords.AsStringView()));
687   pRuntime->PutObjectProperty(pObj, "Creator",
688                               pRuntime->NewString(cwCreator.AsStringView()));
689   pRuntime->PutObjectProperty(pObj, "Producer",
690                               pRuntime->NewString(cwProducer.AsStringView()));
691   pRuntime->PutObjectProperty(
692       pObj, "CreationDate", pRuntime->NewString(cwCreationDate.AsStringView()));
693   pRuntime->PutObjectProperty(pObj, "ModDate",
694                               pRuntime->NewString(cwModDate.AsStringView()));
695   pRuntime->PutObjectProperty(pObj, "Trapped",
696                               pRuntime->NewString(cwTrapped.AsStringView()));
697 
698   // PutObjectProperty() calls below may re-enter JS and change info dict.
699   CPDF_DictionaryLocker locker(ToDictionary(pDictionary->Clone()));
700   for (const auto& it : locker) {
701     const ByteString& bsKey = it.first;
702     const RetainPtr<CPDF_Object>& pValueObj = it.second;
703     if (pValueObj->IsString() || pValueObj->IsName()) {
704       pRuntime->PutObjectProperty(
705           pObj, bsKey.AsStringView(),
706           pRuntime->NewString(pValueObj->GetUnicodeText().AsStringView()));
707     } else if (pValueObj->IsNumber()) {
708       pRuntime->PutObjectProperty(pObj, bsKey.AsStringView(),
709                                   pRuntime->NewNumber(pValueObj->GetNumber()));
710     } else if (pValueObj->IsBoolean()) {
711       pRuntime->PutObjectProperty(
712           pObj, bsKey.AsStringView(),
713           pRuntime->NewBoolean(!!pValueObj->GetInteger()));
714     }
715   }
716   return CJS_Result::Success(pObj);
717 }
718 
set_info(CJS_Runtime * pRuntime,v8::Local<v8::Value> vp)719 CJS_Result CJS_Document::set_info(CJS_Runtime* pRuntime,
720                                   v8::Local<v8::Value> vp) {
721   return CJS_Result::Failure(JSMessage::kReadOnlyError);
722 }
723 
getPropertyInternal(CJS_Runtime * pRuntime,const ByteString & propName)724 CJS_Result CJS_Document::getPropertyInternal(CJS_Runtime* pRuntime,
725                                              const ByteString& propName) {
726   if (!m_pFormFillEnv)
727     return CJS_Result::Failure(JSMessage::kBadObjectError);
728 
729   RetainPtr<CPDF_Dictionary> pDictionary =
730       m_pFormFillEnv->GetPDFDocument()->GetInfo();
731   if (!pDictionary)
732     return CJS_Result::Failure(JSMessage::kBadObjectError);
733 
734   return CJS_Result::Success(pRuntime->NewString(
735       pDictionary->GetUnicodeTextFor(propName).AsStringView()));
736 }
737 
get_creation_date(CJS_Runtime * pRuntime)738 CJS_Result CJS_Document::get_creation_date(CJS_Runtime* pRuntime) {
739   return getPropertyInternal(pRuntime, "CreationDate");
740 }
741 
set_creation_date(CJS_Runtime * pRuntime,v8::Local<v8::Value> vp)742 CJS_Result CJS_Document::set_creation_date(CJS_Runtime* pRuntime,
743                                            v8::Local<v8::Value> vp) {
744   // Read-only.
745   return CJS_Result::Success();
746 }
747 
get_creator(CJS_Runtime * pRuntime)748 CJS_Result CJS_Document::get_creator(CJS_Runtime* pRuntime) {
749   return getPropertyInternal(pRuntime, "Creator");
750 }
751 
set_creator(CJS_Runtime * pRuntime,v8::Local<v8::Value> vp)752 CJS_Result CJS_Document::set_creator(CJS_Runtime* pRuntime,
753                                      v8::Local<v8::Value> vp) {
754   // Read-only.
755   return CJS_Result::Success();
756 }
757 
get_delay(CJS_Runtime * pRuntime)758 CJS_Result CJS_Document::get_delay(CJS_Runtime* pRuntime) {
759   if (!m_pFormFillEnv)
760     return CJS_Result::Failure(JSMessage::kBadObjectError);
761   return CJS_Result::Success(pRuntime->NewBoolean(m_bDelay));
762 }
763 
set_delay(CJS_Runtime * pRuntime,v8::Local<v8::Value> vp)764 CJS_Result CJS_Document::set_delay(CJS_Runtime* pRuntime,
765                                    v8::Local<v8::Value> vp) {
766   if (!m_pFormFillEnv)
767     return CJS_Result::Failure(JSMessage::kBadObjectError);
768 
769   using pdfium::access_permissions::kModifyContent;
770   if (!m_pFormFillEnv->HasPermissions(kModifyContent))
771     return CJS_Result::Failure(JSMessage::kPermissionError);
772 
773   m_bDelay = pRuntime->ToBoolean(vp);
774   if (m_bDelay) {
775     m_DelayData.clear();
776     return CJS_Result::Success();
777   }
778 
779   std::list<std::unique_ptr<CJS_DelayData>> DelayDataToProcess;
780   DelayDataToProcess.swap(m_DelayData);
781   for (const auto& pData : DelayDataToProcess)
782     CJS_Field::DoDelay(m_pFormFillEnv.Get(), pData.get());
783 
784   return CJS_Result::Success();
785 }
786 
get_keywords(CJS_Runtime * pRuntime)787 CJS_Result CJS_Document::get_keywords(CJS_Runtime* pRuntime) {
788   return getPropertyInternal(pRuntime, "Keywords");
789 }
790 
set_keywords(CJS_Runtime * pRuntime,v8::Local<v8::Value> vp)791 CJS_Result CJS_Document::set_keywords(CJS_Runtime* pRuntime,
792                                       v8::Local<v8::Value> vp) {
793   // Read-only.
794   return CJS_Result::Success();
795 }
796 
get_mod_date(CJS_Runtime * pRuntime)797 CJS_Result CJS_Document::get_mod_date(CJS_Runtime* pRuntime) {
798   return getPropertyInternal(pRuntime, "ModDate");
799 }
800 
set_mod_date(CJS_Runtime * pRuntime,v8::Local<v8::Value> vp)801 CJS_Result CJS_Document::set_mod_date(CJS_Runtime* pRuntime,
802                                       v8::Local<v8::Value> vp) {
803   // Read-only.
804   return CJS_Result::Success();
805 }
806 
get_producer(CJS_Runtime * pRuntime)807 CJS_Result CJS_Document::get_producer(CJS_Runtime* pRuntime) {
808   return getPropertyInternal(pRuntime, "Producer");
809 }
810 
set_producer(CJS_Runtime * pRuntime,v8::Local<v8::Value> vp)811 CJS_Result CJS_Document::set_producer(CJS_Runtime* pRuntime,
812                                       v8::Local<v8::Value> vp) {
813   // Read-only.
814   return CJS_Result::Success();
815 }
816 
get_subject(CJS_Runtime * pRuntime)817 CJS_Result CJS_Document::get_subject(CJS_Runtime* pRuntime) {
818   return getPropertyInternal(pRuntime, "Subject");
819 }
820 
set_subject(CJS_Runtime * pRuntime,v8::Local<v8::Value> vp)821 CJS_Result CJS_Document::set_subject(CJS_Runtime* pRuntime,
822                                      v8::Local<v8::Value> vp) {
823   // Read-only.
824   return CJS_Result::Success();
825 }
826 
get_title(CJS_Runtime * pRuntime)827 CJS_Result CJS_Document::get_title(CJS_Runtime* pRuntime) {
828   if (!m_pFormFillEnv)
829     return CJS_Result::Failure(JSMessage::kBadObjectError);
830   return getPropertyInternal(pRuntime, "Title");
831 }
832 
set_title(CJS_Runtime * pRuntime,v8::Local<v8::Value> vp)833 CJS_Result CJS_Document::set_title(CJS_Runtime* pRuntime,
834                                    v8::Local<v8::Value> vp) {
835   // Read-only.
836   return CJS_Result::Success();
837 }
838 
get_num_pages(CJS_Runtime * pRuntime)839 CJS_Result CJS_Document::get_num_pages(CJS_Runtime* pRuntime) {
840   if (!m_pFormFillEnv)
841     return CJS_Result::Failure(JSMessage::kBadObjectError);
842   return CJS_Result::Success(
843       pRuntime->NewNumber(m_pFormFillEnv->GetPageCount()));
844 }
845 
set_num_pages(CJS_Runtime * pRuntime,v8::Local<v8::Value> vp)846 CJS_Result CJS_Document::set_num_pages(CJS_Runtime* pRuntime,
847                                        v8::Local<v8::Value> vp) {
848   return CJS_Result::Failure(JSMessage::kReadOnlyError);
849 }
850 
get_external(CJS_Runtime * pRuntime)851 CJS_Result CJS_Document::get_external(CJS_Runtime* pRuntime) {
852   // In Chrome case, should always return true.
853   return CJS_Result::Success(pRuntime->NewBoolean(true));
854 }
855 
set_external(CJS_Runtime * pRuntime,v8::Local<v8::Value> vp)856 CJS_Result CJS_Document::set_external(CJS_Runtime* pRuntime,
857                                       v8::Local<v8::Value> vp) {
858   return CJS_Result::Success();
859 }
860 
get_filesize(CJS_Runtime * pRuntime)861 CJS_Result CJS_Document::get_filesize(CJS_Runtime* pRuntime) {
862   return CJS_Result::Success(pRuntime->NewNumber(0));
863 }
864 
set_filesize(CJS_Runtime * pRuntime,v8::Local<v8::Value> vp)865 CJS_Result CJS_Document::set_filesize(CJS_Runtime* pRuntime,
866                                       v8::Local<v8::Value> vp) {
867   return CJS_Result::Failure(JSMessage::kReadOnlyError);
868 }
869 
get_mouse_x(CJS_Runtime * pRuntime)870 CJS_Result CJS_Document::get_mouse_x(CJS_Runtime* pRuntime) {
871   return CJS_Result::Success();
872 }
873 
set_mouse_x(CJS_Runtime * pRuntime,v8::Local<v8::Value> vp)874 CJS_Result CJS_Document::set_mouse_x(CJS_Runtime* pRuntime,
875                                      v8::Local<v8::Value> vp) {
876   return CJS_Result::Success();
877 }
878 
get_mouse_y(CJS_Runtime * pRuntime)879 CJS_Result CJS_Document::get_mouse_y(CJS_Runtime* pRuntime) {
880   return CJS_Result::Success();
881 }
882 
set_mouse_y(CJS_Runtime * pRuntime,v8::Local<v8::Value> vp)883 CJS_Result CJS_Document::set_mouse_y(CJS_Runtime* pRuntime,
884                                      v8::Local<v8::Value> vp) {
885   return CJS_Result::Success();
886 }
887 
get_URL(CJS_Runtime * pRuntime)888 CJS_Result CJS_Document::get_URL(CJS_Runtime* pRuntime) {
889   if (!m_pFormFillEnv)
890     return CJS_Result::Failure(JSMessage::kBadObjectError);
891   return CJS_Result::Success(
892       pRuntime->NewString(m_pFormFillEnv->JS_docGetFilePath().AsStringView()));
893 }
894 
set_URL(CJS_Runtime * pRuntime,v8::Local<v8::Value> vp)895 CJS_Result CJS_Document::set_URL(CJS_Runtime* pRuntime,
896                                  v8::Local<v8::Value> vp) {
897   return CJS_Result::Failure(JSMessage::kReadOnlyError);
898 }
899 
get_base_URL(CJS_Runtime * pRuntime)900 CJS_Result CJS_Document::get_base_URL(CJS_Runtime* pRuntime) {
901   return CJS_Result::Success(pRuntime->NewString(m_cwBaseURL.AsStringView()));
902 }
903 
set_base_URL(CJS_Runtime * pRuntime,v8::Local<v8::Value> vp)904 CJS_Result CJS_Document::set_base_URL(CJS_Runtime* pRuntime,
905                                       v8::Local<v8::Value> vp) {
906   m_cwBaseURL = pRuntime->ToWideString(vp);
907   return CJS_Result::Success();
908 }
909 
get_calculate(CJS_Runtime * pRuntime)910 CJS_Result CJS_Document::get_calculate(CJS_Runtime* pRuntime) {
911   if (!m_pFormFillEnv)
912     return CJS_Result::Failure(JSMessage::kBadObjectError);
913 
914   CPDFSDK_InteractiveForm* pInteractiveForm = GetSDKInteractiveForm();
915   return CJS_Result::Success(
916       pRuntime->NewBoolean(!!pInteractiveForm->IsCalculateEnabled()));
917 }
918 
set_calculate(CJS_Runtime * pRuntime,v8::Local<v8::Value> vp)919 CJS_Result CJS_Document::set_calculate(CJS_Runtime* pRuntime,
920                                        v8::Local<v8::Value> vp) {
921   if (!m_pFormFillEnv)
922     return CJS_Result::Failure(JSMessage::kBadObjectError);
923 
924   CPDFSDK_InteractiveForm* pInteractiveForm = GetSDKInteractiveForm();
925   pInteractiveForm->EnableCalculate(pRuntime->ToBoolean(vp));
926   return CJS_Result::Success();
927 }
928 
get_document_file_name(CJS_Runtime * pRuntime)929 CJS_Result CJS_Document::get_document_file_name(CJS_Runtime* pRuntime) {
930   if (!m_pFormFillEnv)
931     return CJS_Result::Failure(JSMessage::kBadObjectError);
932 
933   WideString wsFilePath = m_pFormFillEnv->JS_docGetFilePath();
934   size_t i = wsFilePath.GetLength();
935   for (; i > 0; i--) {
936     if (wsFilePath[i - 1] == L'\\' || wsFilePath[i - 1] == L'/')
937       break;
938   }
939   if (i > 0 && i < wsFilePath.GetLength()) {
940     return CJS_Result::Success(
941         pRuntime->NewString(wsFilePath.AsStringView().Substr(i)));
942   }
943   return CJS_Result::Success(pRuntime->NewString(""));
944 }
945 
set_document_file_name(CJS_Runtime * pRuntime,v8::Local<v8::Value> vp)946 CJS_Result CJS_Document::set_document_file_name(CJS_Runtime* pRuntime,
947                                                 v8::Local<v8::Value> vp) {
948   return CJS_Result::Failure(JSMessage::kReadOnlyError);
949 }
950 
get_path(CJS_Runtime * pRuntime)951 CJS_Result CJS_Document::get_path(CJS_Runtime* pRuntime) {
952   if (!m_pFormFillEnv)
953     return CJS_Result::Failure(JSMessage::kBadObjectError);
954   return CJS_Result::Success(pRuntime->NewString(
955       CJS_App::SysPathToPDFPath(m_pFormFillEnv->JS_docGetFilePath())
956           .AsStringView()));
957 }
958 
set_path(CJS_Runtime * pRuntime,v8::Local<v8::Value> vp)959 CJS_Result CJS_Document::set_path(CJS_Runtime* pRuntime,
960                                   v8::Local<v8::Value> vp) {
961   return CJS_Result::Failure(JSMessage::kReadOnlyError);
962 }
963 
get_page_window_rect(CJS_Runtime * pRuntime)964 CJS_Result CJS_Document::get_page_window_rect(CJS_Runtime* pRuntime) {
965   return CJS_Result::Success();
966 }
967 
set_page_window_rect(CJS_Runtime * pRuntime,v8::Local<v8::Value> vp)968 CJS_Result CJS_Document::set_page_window_rect(CJS_Runtime* pRuntime,
969                                               v8::Local<v8::Value> vp) {
970   return CJS_Result::Success();
971 }
972 
get_layout(CJS_Runtime * pRuntime)973 CJS_Result CJS_Document::get_layout(CJS_Runtime* pRuntime) {
974   return CJS_Result::Success();
975 }
976 
set_layout(CJS_Runtime * pRuntime,v8::Local<v8::Value> vp)977 CJS_Result CJS_Document::set_layout(CJS_Runtime* pRuntime,
978                                     v8::Local<v8::Value> vp) {
979   return CJS_Result::Success();
980 }
981 
addLink(CJS_Runtime * pRuntime,const std::vector<v8::Local<v8::Value>> & params)982 CJS_Result CJS_Document::addLink(
983     CJS_Runtime* pRuntime,
984     const std::vector<v8::Local<v8::Value>>& params) {
985   return CJS_Result::Success();
986 }
987 
closeDoc(CJS_Runtime * pRuntime,const std::vector<v8::Local<v8::Value>> & params)988 CJS_Result CJS_Document::closeDoc(
989     CJS_Runtime* pRuntime,
990     const std::vector<v8::Local<v8::Value>>& params) {
991   return CJS_Result::Success();
992 }
993 
getPageBox(CJS_Runtime * pRuntime,const std::vector<v8::Local<v8::Value>> & params)994 CJS_Result CJS_Document::getPageBox(
995     CJS_Runtime* pRuntime,
996     const std::vector<v8::Local<v8::Value>>& params) {
997   return CJS_Result::Success();
998 }
999 
getAnnot(CJS_Runtime * pRuntime,const std::vector<v8::Local<v8::Value>> & params)1000 CJS_Result CJS_Document::getAnnot(
1001     CJS_Runtime* pRuntime,
1002     const std::vector<v8::Local<v8::Value>>& params) {
1003   if (params.size() != 2)
1004     return CJS_Result::Failure(JSMessage::kParamError);
1005   if (!m_pFormFillEnv)
1006     return CJS_Result::Failure(JSMessage::kBadObjectError);
1007 
1008   int nPageNo = pRuntime->ToInt32(params[0]);
1009   WideString swAnnotName = pRuntime->ToWideString(params[1]);
1010   CPDFSDK_PageView* pPageView = m_pFormFillEnv->GetPageViewAtIndex(nPageNo);
1011   if (!pPageView)
1012     return CJS_Result::Failure(JSMessage::kBadObjectError);
1013 
1014   CPDFSDK_AnnotIteration annot_iteration(pPageView);
1015   CPDFSDK_BAAnnot* pSDKBAAnnot = nullptr;
1016   for (const auto& pSDKAnnotCur : annot_iteration) {
1017     auto* pBAAnnot = pSDKAnnotCur->AsBAAnnot();
1018     if (pBAAnnot && pBAAnnot->GetAnnotName() == swAnnotName) {
1019       pSDKBAAnnot = pBAAnnot;
1020       break;
1021     }
1022   }
1023   if (!pSDKBAAnnot)
1024     return CJS_Result::Failure(JSMessage::kBadObjectError);
1025 
1026   v8::Local<v8::Object> pObj = pRuntime->NewFXJSBoundObject(
1027       CJS_Annot::GetObjDefnID(), FXJSOBJTYPE_DYNAMIC);
1028   if (pObj.IsEmpty())
1029     return CJS_Result::Failure(JSMessage::kBadObjectError);
1030 
1031   auto* pJS_Annot = static_cast<CJS_Annot*>(
1032       CFXJS_Engine::GetObjectPrivate(pRuntime->GetIsolate(), pObj));
1033   if (!pJS_Annot)
1034     return CJS_Result::Failure(JSMessage::kBadObjectError);
1035 
1036   pJS_Annot->SetSDKAnnot(pSDKBAAnnot);
1037   return CJS_Result::Success(pJS_Annot->ToV8Object());
1038 }
1039 
getAnnots(CJS_Runtime * pRuntime,const std::vector<v8::Local<v8::Value>> & params)1040 CJS_Result CJS_Document::getAnnots(
1041     CJS_Runtime* pRuntime,
1042     const std::vector<v8::Local<v8::Value>>& params) {
1043   if (!m_pFormFillEnv)
1044     return CJS_Result::Failure(JSMessage::kBadObjectError);
1045 
1046   // TODO(tonikitoo): Add support supported parameters as per
1047   // the PDF spec.
1048 
1049   int nPageNo = m_pFormFillEnv->GetPageCount();
1050   v8::Local<v8::Array> annots = pRuntime->NewArray();
1051   for (int i = 0; i < nPageNo; ++i) {
1052     CPDFSDK_PageView* pPageView = m_pFormFillEnv->GetPageViewAtIndex(i);
1053     if (!pPageView)
1054       return CJS_Result::Failure(JSMessage::kBadObjectError);
1055 
1056     CPDFSDK_AnnotIteration annot_iteration(pPageView);
1057     for (const auto& pSDKAnnotCur : annot_iteration) {
1058       if (!pSDKAnnotCur)
1059         return CJS_Result::Failure(JSMessage::kBadObjectError);
1060 
1061       v8::Local<v8::Object> pObj = pRuntime->NewFXJSBoundObject(
1062           CJS_Annot::GetObjDefnID(), FXJSOBJTYPE_DYNAMIC);
1063       if (pObj.IsEmpty())
1064         return CJS_Result::Failure(JSMessage::kBadObjectError);
1065 
1066       auto* pJS_Annot = static_cast<CJS_Annot*>(
1067           CFXJS_Engine::GetObjectPrivate(pRuntime->GetIsolate(), pObj));
1068       pJS_Annot->SetSDKAnnot(pSDKAnnotCur->AsBAAnnot());
1069       pRuntime->PutArrayElement(
1070           annots, i,
1071           pJS_Annot ? v8::Local<v8::Value>(pJS_Annot->ToV8Object())
1072                     : v8::Local<v8::Value>());
1073     }
1074   }
1075   return CJS_Result::Success(annots);
1076 }
1077 
getAnnot3D(CJS_Runtime * pRuntime,const std::vector<v8::Local<v8::Value>> & params)1078 CJS_Result CJS_Document::getAnnot3D(
1079     CJS_Runtime* pRuntime,
1080     const std::vector<v8::Local<v8::Value>>& params) {
1081   return CJS_Result::Success(pRuntime->NewUndefined());
1082 }
1083 
getAnnots3D(CJS_Runtime * pRuntime,const std::vector<v8::Local<v8::Value>> & params)1084 CJS_Result CJS_Document::getAnnots3D(
1085     CJS_Runtime* pRuntime,
1086     const std::vector<v8::Local<v8::Value>>& params) {
1087   return CJS_Result::Success();
1088 }
1089 
getOCGs(CJS_Runtime * pRuntime,const std::vector<v8::Local<v8::Value>> & params)1090 CJS_Result CJS_Document::getOCGs(
1091     CJS_Runtime* pRuntime,
1092     const std::vector<v8::Local<v8::Value>>& params) {
1093   return CJS_Result::Success();
1094 }
1095 
getLinks(CJS_Runtime * pRuntime,const std::vector<v8::Local<v8::Value>> & params)1096 CJS_Result CJS_Document::getLinks(
1097     CJS_Runtime* pRuntime,
1098     const std::vector<v8::Local<v8::Value>>& params) {
1099   return CJS_Result::Success();
1100 }
1101 
addIcon(CJS_Runtime * pRuntime,const std::vector<v8::Local<v8::Value>> & params)1102 CJS_Result CJS_Document::addIcon(
1103     CJS_Runtime* pRuntime,
1104     const std::vector<v8::Local<v8::Value>>& params) {
1105   if (params.size() != 2)
1106     return CJS_Result::Failure(JSMessage::kParamError);
1107 
1108   if (!params[1]->IsObject())
1109     return CJS_Result::Failure(JSMessage::kTypeError);
1110 
1111   v8::Local<v8::Object> pObj = pRuntime->ToObject(params[1]);
1112   if (!JSGetObject<CJS_Icon>(pRuntime->GetIsolate(), pObj))
1113     return CJS_Result::Failure(JSMessage::kTypeError);
1114 
1115   WideString swIconName = pRuntime->ToWideString(params[0]);
1116   m_IconNames.push_back(swIconName);
1117   return CJS_Result::Success();
1118 }
1119 
get_icons(CJS_Runtime * pRuntime)1120 CJS_Result CJS_Document::get_icons(CJS_Runtime* pRuntime) {
1121   // TODO(tsepez): Maybe make consistent with Acrobat Reader behavior which
1122   // is to throw an exception under the default security settings.
1123   if (m_IconNames.empty())
1124     return CJS_Result::Success(pRuntime->NewUndefined());
1125 
1126   v8::Local<v8::Array> Icons = pRuntime->NewArray();
1127   int i = 0;
1128   for (const auto& name : m_IconNames) {
1129     v8::Local<v8::Object> pObj = pRuntime->NewFXJSBoundObject(
1130         CJS_Icon::GetObjDefnID(), FXJSOBJTYPE_DYNAMIC);
1131     if (pObj.IsEmpty())
1132       return CJS_Result::Failure(JSMessage::kBadObjectError);
1133 
1134     auto* pJS_Icon = static_cast<CJS_Icon*>(
1135         CFXJS_Engine::GetObjectPrivate(pRuntime->GetIsolate(), pObj));
1136     pJS_Icon->SetIconName(name);
1137     pRuntime->PutArrayElement(Icons, i++,
1138                               pJS_Icon
1139                                   ? v8::Local<v8::Value>(pJS_Icon->ToV8Object())
1140                                   : v8::Local<v8::Value>());
1141   }
1142   return CJS_Result::Success(Icons);
1143 }
1144 
set_icons(CJS_Runtime * pRuntime,v8::Local<v8::Value> vp)1145 CJS_Result CJS_Document::set_icons(CJS_Runtime* pRuntime,
1146                                    v8::Local<v8::Value> vp) {
1147   return CJS_Result::Failure(JSMessage::kReadOnlyError);
1148 }
1149 
getIcon(CJS_Runtime * pRuntime,const std::vector<v8::Local<v8::Value>> & params)1150 CJS_Result CJS_Document::getIcon(
1151     CJS_Runtime* pRuntime,
1152     const std::vector<v8::Local<v8::Value>>& params) {
1153   if (params.size() != 1)
1154     return CJS_Result::Failure(JSMessage::kParamError);
1155 
1156   WideString swIconName = pRuntime->ToWideString(params[0]);
1157   auto it = std::find(m_IconNames.begin(), m_IconNames.end(), swIconName);
1158   if (it == m_IconNames.end())
1159     return CJS_Result::Failure(JSMessage::kBadObjectError);
1160 
1161   v8::Local<v8::Object> pObj = pRuntime->NewFXJSBoundObject(
1162       CJS_Icon::GetObjDefnID(), FXJSOBJTYPE_DYNAMIC);
1163   if (pObj.IsEmpty())
1164     return CJS_Result::Failure(JSMessage::kBadObjectError);
1165 
1166   auto* pJSIcon = static_cast<CJS_Icon*>(
1167       CFXJS_Engine::GetObjectPrivate(pRuntime->GetIsolate(), pObj));
1168   if (!pJSIcon)
1169     return CJS_Result::Failure(JSMessage::kBadObjectError);
1170 
1171   pJSIcon->SetIconName(*it);
1172   return CJS_Result::Success(pJSIcon->ToV8Object());
1173 }
1174 
removeIcon(CJS_Runtime * pRuntime,const std::vector<v8::Local<v8::Value>> & params)1175 CJS_Result CJS_Document::removeIcon(
1176     CJS_Runtime* pRuntime,
1177     const std::vector<v8::Local<v8::Value>>& params) {
1178   // Unsafe, no supported.
1179   return CJS_Result::Success();
1180 }
1181 
createDataObject(CJS_Runtime * pRuntime,const std::vector<v8::Local<v8::Value>> & params)1182 CJS_Result CJS_Document::createDataObject(
1183     CJS_Runtime* pRuntime,
1184     const std::vector<v8::Local<v8::Value>>& params) {
1185   // Unsafe, not implemented.
1186   return CJS_Result::Success();
1187 }
1188 
get_media(CJS_Runtime * pRuntime)1189 CJS_Result CJS_Document::get_media(CJS_Runtime* pRuntime) {
1190   return CJS_Result::Success();
1191 }
1192 
set_media(CJS_Runtime * pRuntime,v8::Local<v8::Value> vp)1193 CJS_Result CJS_Document::set_media(CJS_Runtime* pRuntime,
1194                                    v8::Local<v8::Value> vp) {
1195   return CJS_Result::Success();
1196 }
1197 
calculateNow(CJS_Runtime * pRuntime,const std::vector<v8::Local<v8::Value>> & params)1198 CJS_Result CJS_Document::calculateNow(
1199     CJS_Runtime* pRuntime,
1200     const std::vector<v8::Local<v8::Value>>& params) {
1201   if (!m_pFormFillEnv)
1202     return CJS_Result::Failure(JSMessage::kBadObjectError);
1203 
1204   if (!m_pFormFillEnv->HasPermissions(
1205           pdfium::access_permissions::kModifyContent |
1206           pdfium::access_permissions::kModifyAnnotation |
1207           pdfium::access_permissions::kFillForm)) {
1208     return CJS_Result::Failure(JSMessage::kPermissionError);
1209   }
1210 
1211   GetSDKInteractiveForm()->OnCalculate(nullptr);
1212   return CJS_Result::Success();
1213 }
1214 
get_collab(CJS_Runtime * pRuntime)1215 CJS_Result CJS_Document::get_collab(CJS_Runtime* pRuntime) {
1216   return CJS_Result::Success();
1217 }
1218 
set_collab(CJS_Runtime * pRuntime,v8::Local<v8::Value> vp)1219 CJS_Result CJS_Document::set_collab(CJS_Runtime* pRuntime,
1220                                     v8::Local<v8::Value> vp) {
1221   return CJS_Result::Success();
1222 }
1223 
getPageNthWord(CJS_Runtime * pRuntime,const std::vector<v8::Local<v8::Value>> & params)1224 CJS_Result CJS_Document::getPageNthWord(
1225     CJS_Runtime* pRuntime,
1226     const std::vector<v8::Local<v8::Value>>& params) {
1227   if (!m_pFormFillEnv)
1228     return CJS_Result::Failure(JSMessage::kBadObjectError);
1229 
1230   using pdfium::access_permissions::kExtractForAccessibility;
1231   if (!m_pFormFillEnv->HasPermissions(kExtractForAccessibility))
1232     return CJS_Result::Failure(JSMessage::kPermissionError);
1233 
1234   // TODO(tsepez): check maximum allowable params.
1235 
1236   int nPageNo = params.size() > 0 ? pRuntime->ToInt32(params[0]) : 0;
1237   int nWordNo = params.size() > 1 ? pRuntime->ToInt32(params[1]) : 0;
1238   bool bStrip = params.size() > 2 ? pRuntime->ToBoolean(params[2]) : true;
1239 
1240   CPDF_Document* pDocument = m_pFormFillEnv->GetPDFDocument();
1241   if (nPageNo < 0 || nPageNo >= pDocument->GetPageCount())
1242     return CJS_Result::Failure(JSMessage::kValueError);
1243 
1244   RetainPtr<CPDF_Dictionary> pPageDict =
1245       pDocument->GetMutablePageDictionary(nPageNo);
1246   if (!pPageDict)
1247     return CJS_Result::Failure(JSMessage::kBadObjectError);
1248 
1249   auto page = pdfium::MakeRetain<CPDF_Page>(pDocument, std::move(pPageDict));
1250   page->AddPageImageCache();
1251   page->ParseContent();
1252 
1253   int nWords = 0;
1254   WideString swRet;
1255   for (auto& pPageObj : *page) {
1256     if (pPageObj->IsText()) {
1257       CPDF_TextObject* pTextObj = pPageObj->AsText();
1258       int nObjWords = pTextObj->CountWords();
1259       if (nWords + nObjWords >= nWordNo) {
1260         swRet = pTextObj->GetWordString(nWordNo - nWords);
1261         break;
1262       }
1263       nWords += nObjWords;
1264     }
1265   }
1266 
1267   if (bStrip)
1268     swRet.Trim();
1269   return CJS_Result::Success(pRuntime->NewString(swRet.AsStringView()));
1270 }
1271 
getPageNthWordQuads(CJS_Runtime * pRuntime,const std::vector<v8::Local<v8::Value>> & params)1272 CJS_Result CJS_Document::getPageNthWordQuads(
1273     CJS_Runtime* pRuntime,
1274     const std::vector<v8::Local<v8::Value>>& params) {
1275   if (!m_pFormFillEnv)
1276     return CJS_Result::Failure(JSMessage::kBadObjectError);
1277 
1278   using pdfium::access_permissions::kExtractForAccessibility;
1279   if (!m_pFormFillEnv->HasPermissions(kExtractForAccessibility))
1280     return CJS_Result::Failure(JSMessage::kBadObjectError);
1281 
1282   return CJS_Result::Failure(JSMessage::kNotSupportedError);
1283 }
1284 
getPageNumWords(CJS_Runtime * pRuntime,const std::vector<v8::Local<v8::Value>> & params)1285 CJS_Result CJS_Document::getPageNumWords(
1286     CJS_Runtime* pRuntime,
1287     const std::vector<v8::Local<v8::Value>>& params) {
1288   if (!m_pFormFillEnv)
1289     return CJS_Result::Failure(JSMessage::kBadObjectError);
1290 
1291   using pdfium::access_permissions::kExtractForAccessibility;
1292   if (!m_pFormFillEnv->HasPermissions(kExtractForAccessibility))
1293     return CJS_Result::Failure(JSMessage::kPermissionError);
1294 
1295   int nPageNo = params.size() > 0 ? pRuntime->ToInt32(params[0]) : 0;
1296   CPDF_Document* pDocument = m_pFormFillEnv->GetPDFDocument();
1297   if (nPageNo < 0 || nPageNo >= pDocument->GetPageCount())
1298     return CJS_Result::Failure(JSMessage::kValueError);
1299 
1300   RetainPtr<CPDF_Dictionary> pPageDict =
1301       pDocument->GetMutablePageDictionary(nPageNo);
1302   if (!pPageDict)
1303     return CJS_Result::Failure(JSMessage::kBadObjectError);
1304 
1305   auto page = pdfium::MakeRetain<CPDF_Page>(pDocument, std::move(pPageDict));
1306   page->AddPageImageCache();
1307   page->ParseContent();
1308 
1309   int nWords = 0;
1310   for (auto& pPageObj : *page) {
1311     if (pPageObj->IsText())
1312       nWords += pPageObj->AsText()->CountWords();
1313   }
1314   return CJS_Result::Success(pRuntime->NewNumber(nWords));
1315 }
1316 
getPrintParams(CJS_Runtime * pRuntime,const std::vector<v8::Local<v8::Value>> & params)1317 CJS_Result CJS_Document::getPrintParams(
1318     CJS_Runtime* pRuntime,
1319     const std::vector<v8::Local<v8::Value>>& params) {
1320   return CJS_Result::Failure(JSMessage::kNotSupportedError);
1321 }
1322 
get_zoom(CJS_Runtime * pRuntime)1323 CJS_Result CJS_Document::get_zoom(CJS_Runtime* pRuntime) {
1324   return CJS_Result::Success();
1325 }
1326 
set_zoom(CJS_Runtime * pRuntime,v8::Local<v8::Value> vp)1327 CJS_Result CJS_Document::set_zoom(CJS_Runtime* pRuntime,
1328                                   v8::Local<v8::Value> vp) {
1329   return CJS_Result::Success();
1330 }
1331 
get_zoom_type(CJS_Runtime * pRuntime)1332 CJS_Result CJS_Document::get_zoom_type(CJS_Runtime* pRuntime) {
1333   return CJS_Result::Success();
1334 }
1335 
set_zoom_type(CJS_Runtime * pRuntime,v8::Local<v8::Value> vp)1336 CJS_Result CJS_Document::set_zoom_type(CJS_Runtime* pRuntime,
1337                                        v8::Local<v8::Value> vp) {
1338   return CJS_Result::Success();
1339 }
1340 
deletePages(CJS_Runtime * pRuntime,const std::vector<v8::Local<v8::Value>> & params)1341 CJS_Result CJS_Document::deletePages(
1342     CJS_Runtime* pRuntime,
1343     const std::vector<v8::Local<v8::Value>>& params) {
1344   // Unsafe, not supported.
1345   return CJS_Result::Success();
1346 }
1347 
extractPages(CJS_Runtime * pRuntime,const std::vector<v8::Local<v8::Value>> & params)1348 CJS_Result CJS_Document::extractPages(
1349     CJS_Runtime* pRuntime,
1350     const std::vector<v8::Local<v8::Value>>& params) {
1351   // Unsafe, not supported.
1352   return CJS_Result::Success();
1353 }
1354 
insertPages(CJS_Runtime * pRuntime,const std::vector<v8::Local<v8::Value>> & params)1355 CJS_Result CJS_Document::insertPages(
1356     CJS_Runtime* pRuntime,
1357     const std::vector<v8::Local<v8::Value>>& params) {
1358   // Unsafe, not supported.
1359   return CJS_Result::Success();
1360 }
1361 
replacePages(CJS_Runtime * pRuntime,const std::vector<v8::Local<v8::Value>> & params)1362 CJS_Result CJS_Document::replacePages(
1363     CJS_Runtime* pRuntime,
1364     const std::vector<v8::Local<v8::Value>>& params) {
1365   // Unsafe, not supported.
1366   return CJS_Result::Success();
1367 }
1368 
getURL(CJS_Runtime * pRuntime,const std::vector<v8::Local<v8::Value>> & params)1369 CJS_Result CJS_Document::getURL(
1370     CJS_Runtime* pRuntime,
1371     const std::vector<v8::Local<v8::Value>>& params) {
1372   // Unsafe, not supported.
1373   return CJS_Result::Success();
1374 }
1375 
gotoNamedDest(CJS_Runtime * pRuntime,const std::vector<v8::Local<v8::Value>> & params)1376 CJS_Result CJS_Document::gotoNamedDest(
1377     CJS_Runtime* pRuntime,
1378     const std::vector<v8::Local<v8::Value>>& params) {
1379   if (params.size() != 1)
1380     return CJS_Result::Failure(JSMessage::kParamError);
1381 
1382   if (!m_pFormFillEnv)
1383     return CJS_Result::Failure(JSMessage::kBadObjectError);
1384 
1385   CPDF_Document* pDocument = m_pFormFillEnv->GetPDFDocument();
1386   RetainPtr<const CPDF_Array> dest_array = CPDF_NameTree::LookupNamedDest(
1387       pDocument, pRuntime->ToByteString(params[0]));
1388   if (!dest_array)
1389     return CJS_Result::Failure(JSMessage::kBadObjectError);
1390 
1391   CPDF_Dest dest(std::move(dest_array));
1392   std::vector<float> positions = dest.GetScrollPositionArray();
1393   pRuntime->BeginBlock();
1394   m_pFormFillEnv->DoGoToAction(dest.GetDestPageIndex(pDocument),
1395                                dest.GetZoomMode(), positions);
1396   pRuntime->EndBlock();
1397   return CJS_Result::Success();
1398 }
1399 
AddDelayData(std::unique_ptr<CJS_DelayData> pData)1400 void CJS_Document::AddDelayData(std::unique_ptr<CJS_DelayData> pData) {
1401   m_DelayData.push_back(std::move(pData));
1402 }
1403 
DoFieldDelay(const WideString & sFieldName,int nControlIndex)1404 void CJS_Document::DoFieldDelay(const WideString& sFieldName,
1405                                 int nControlIndex) {
1406   std::vector<std::unique_ptr<CJS_DelayData>> delayed_data;
1407   auto iter = m_DelayData.begin();
1408   while (iter != m_DelayData.end()) {
1409     auto old = iter++;
1410     if ((*old)->sFieldName == sFieldName &&
1411         (*old)->nControlIndex == nControlIndex) {
1412       delayed_data.push_back(std::move(*old));
1413       m_DelayData.erase(old);
1414     }
1415   }
1416 
1417   for (const auto& pData : delayed_data)
1418     CJS_Field::DoDelay(m_pFormFillEnv.Get(), pData.get());
1419 }
1420 
GetCoreInteractiveForm()1421 CPDF_InteractiveForm* CJS_Document::GetCoreInteractiveForm() {
1422   return GetSDKInteractiveForm()->GetInteractiveForm();
1423 }
1424 
GetSDKInteractiveForm()1425 CPDFSDK_InteractiveForm* CJS_Document::GetSDKInteractiveForm() {
1426   return m_pFormFillEnv->GetInteractiveForm();
1427 }
1428