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