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