1 // Copyright 2016 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 "fpdfsdk/cpdfsdk_formfillenvironment.h"
8
9 #include <stdint.h>
10
11 #include <memory>
12 #include <utility>
13 #include <vector>
14
15 #include "core/fpdfapi/page/cpdf_annotcontext.h"
16 #include "core/fpdfapi/parser/cpdf_array.h"
17 #include "core/fpdfapi/parser/cpdf_dictionary.h"
18 #include "core/fpdfdoc/cpdf_nametree.h"
19 #include "core/fxcrt/data_vector.h"
20 #include "core/fxcrt/stl_util.h"
21 #include "fpdfsdk/cpdfsdk_helpers.h"
22 #include "fpdfsdk/cpdfsdk_interactiveform.h"
23 #include "fpdfsdk/cpdfsdk_pageview.h"
24 #include "fpdfsdk/cpdfsdk_widget.h"
25 #include "fpdfsdk/formfiller/cffl_formfield.h"
26 #include "fpdfsdk/formfiller/cffl_interactiveformfiller.h"
27 #include "fxjs/ijs_event_context.h"
28 #include "fxjs/ijs_runtime.h"
29 #include "third_party/base/check.h"
30 #include "third_party/base/containers/contains.h"
31 #include "third_party/base/notreached.h"
32 #include "third_party/base/numerics/safe_conversions.h"
33
34 #ifdef PDF_ENABLE_XFA
35 #include "fpdfsdk/fpdfxfa/cpdfxfa_widget.h"
36 #endif
37
38 static_assert(FXCT_ARROW ==
39 static_cast<int>(IPWL_FillerNotify::CursorStyle::kArrow),
40 "kArrow value mismatch");
41 static_assert(FXCT_NESW ==
42 static_cast<int>(IPWL_FillerNotify::CursorStyle::kNESW),
43 "kNEWS value mismatch");
44 static_assert(FXCT_NWSE ==
45 static_cast<int>(IPWL_FillerNotify::CursorStyle::kNWSE),
46 "kNWSE value mismatch");
47 static_assert(FXCT_VBEAM ==
48 static_cast<int>(IPWL_FillerNotify::CursorStyle::kVBeam),
49 "kVBeam value mismatch");
50 static_assert(FXCT_HBEAM ==
51 static_cast<int>(IPWL_FillerNotify::CursorStyle::kHBeam),
52 "HBeam value mismatch");
53 static_assert(FXCT_HAND ==
54 static_cast<int>(IPWL_FillerNotify::CursorStyle::kHand),
55 "kHand value mismatch");
56
AsFPDFWideString(ByteString * bsUTF16LE)57 FPDF_WIDESTRING AsFPDFWideString(ByteString* bsUTF16LE) {
58 // Force a private version of the string, since we're about to hand it off
59 // to the embedder. Should the embedder modify it by accident, it won't
60 // corrupt other shares of the string beyond |bsUTF16LE|.
61 return reinterpret_cast<FPDF_WIDESTRING>(
62 bsUTF16LE->GetBuffer(bsUTF16LE->GetLength()).data());
63 }
64
CPDFSDK_FormFillEnvironment(CPDF_Document * pDoc,FPDF_FORMFILLINFO * pFFinfo)65 CPDFSDK_FormFillEnvironment::CPDFSDK_FormFillEnvironment(
66 CPDF_Document* pDoc,
67 FPDF_FORMFILLINFO* pFFinfo)
68 : m_pInfo(pFFinfo),
69 m_pCPDFDoc(pDoc),
70 m_pInteractiveFormFiller(
71 std::make_unique<CFFL_InteractiveFormFiller>(this)) {
72 DCHECK(m_pCPDFDoc);
73 }
74
~CPDFSDK_FormFillEnvironment()75 CPDFSDK_FormFillEnvironment::~CPDFSDK_FormFillEnvironment() {
76 m_bBeingDestroyed = true;
77 ClearAllFocusedAnnots();
78
79 // |m_PageMap| will try to access |m_pInteractiveForm| when it cleans itself
80 // up. Make sure it is deleted before |m_pInteractiveForm|.
81 m_PageMap.clear();
82
83 // Must destroy the |m_pInteractiveFormFiller| before the environment (|this|)
84 // because any created form widgets hold a pointer to the environment.
85 // Those widgets may call things like KillTimer() as they are shutdown.
86 m_pInteractiveFormFiller.reset();
87
88 if (m_pInfo && m_pInfo->Release)
89 m_pInfo->Release(m_pInfo);
90 }
91
InvalidateRect(CPDFSDK_Widget * widget,const CFX_FloatRect & rect)92 void CPDFSDK_FormFillEnvironment::InvalidateRect(CPDFSDK_Widget* widget,
93 const CFX_FloatRect& rect) {
94 IPDF_Page* pPage = widget->GetPage();
95 if (!pPage)
96 return;
97
98 CFX_Matrix device2page =
99 widget->GetPageView()->GetCurrentMatrix().GetInverse();
100 CFX_PointF left_top = device2page.Transform(CFX_PointF(rect.left, rect.top));
101 CFX_PointF right_bottom =
102 device2page.Transform(CFX_PointF(rect.right, rect.bottom));
103
104 CFX_FloatRect rcPDF(left_top.x, right_bottom.y, right_bottom.x, left_top.y);
105 rcPDF.Normalize();
106 Invalidate(pPage, rcPDF.GetOuterRect());
107 }
108
OutputSelectedRect(CFFL_FormField * pFormField,const CFX_FloatRect & rect)109 void CPDFSDK_FormFillEnvironment::OutputSelectedRect(
110 CFFL_FormField* pFormField,
111 const CFX_FloatRect& rect) {
112 if (!m_pInfo || !m_pInfo->FFI_OutputSelectedRect)
113 return;
114
115 auto* pPage = FPDFPageFromIPDFPage(pFormField->GetSDKWidget()->GetPage());
116 DCHECK(pPage);
117
118 CFX_PointF ptA = pFormField->PWLtoFFL(CFX_PointF(rect.left, rect.bottom));
119 CFX_PointF ptB = pFormField->PWLtoFFL(CFX_PointF(rect.right, rect.top));
120 m_pInfo->FFI_OutputSelectedRect(m_pInfo, pPage, ptA.x, ptB.y, ptB.x, ptA.y);
121 }
122
IsSelectionImplemented() const123 bool CPDFSDK_FormFillEnvironment::IsSelectionImplemented() const {
124 FPDF_FORMFILLINFO* pInfo = GetFormFillInfo();
125 return pInfo && pInfo->FFI_OutputSelectedRect;
126 }
127
128 #ifdef PDF_ENABLE_V8
GetCurrentView()129 CPDFSDK_PageView* CPDFSDK_FormFillEnvironment::GetCurrentView() {
130 IPDF_Page* pPage = GetCurrentPage();
131 return pPage ? GetOrCreatePageView(pPage) : nullptr;
132 }
133
GetCurrentPage() const134 IPDF_Page* CPDFSDK_FormFillEnvironment::GetCurrentPage() const {
135 if (m_pInfo && m_pInfo->FFI_GetCurrentPage) {
136 return IPDFPageFromFPDFPage(m_pInfo->FFI_GetCurrentPage(
137 m_pInfo, FPDFDocumentFromCPDFDocument(m_pCPDFDoc)));
138 }
139 return nullptr;
140 }
141
GetLanguage()142 WideString CPDFSDK_FormFillEnvironment::GetLanguage() {
143 #ifdef PDF_ENABLE_XFA
144 if (!m_pInfo || m_pInfo->version < 2 || !m_pInfo->FFI_GetLanguage)
145 return WideString();
146
147 int nRequiredLen = m_pInfo->FFI_GetLanguage(m_pInfo, nullptr, 0);
148 if (nRequiredLen <= 0)
149 return WideString();
150
151 DataVector<uint8_t> pBuff(nRequiredLen);
152 int nActualLen =
153 m_pInfo->FFI_GetLanguage(m_pInfo, pBuff.data(), nRequiredLen);
154 if (nActualLen <= 0 || nActualLen > nRequiredLen)
155 return WideString();
156
157 return WideString::FromUTF16LE(reinterpret_cast<uint16_t*>(pBuff.data()),
158 nActualLen / sizeof(uint16_t));
159 #else // PDF_ENABLE_XFA
160 return WideString();
161 #endif // PDF_ENABLE_XFA
162 }
163
GetPlatform()164 WideString CPDFSDK_FormFillEnvironment::GetPlatform() {
165 #ifdef PDF_ENABLE_XFA
166 if (!m_pInfo || m_pInfo->version < 2 || !m_pInfo->FFI_GetPlatform)
167 return WideString();
168
169 int nRequiredLen = m_pInfo->FFI_GetPlatform(m_pInfo, nullptr, 0);
170 if (nRequiredLen <= 0)
171 return WideString();
172
173 DataVector<uint8_t> pBuff(nRequiredLen);
174 int nActualLen =
175 m_pInfo->FFI_GetPlatform(m_pInfo, pBuff.data(), nRequiredLen);
176 if (nActualLen <= 0 || nActualLen > nRequiredLen)
177 return WideString();
178
179 return WideString::FromUTF16LE(reinterpret_cast<uint16_t*>(pBuff.data()),
180 nActualLen / sizeof(uint16_t));
181 #else // PDF_ENABLE_XFA
182 return WideString();
183 #endif // PDF_ENABLE_XFA
184 }
185
JS_appAlert(const WideString & Msg,const WideString & Title,int Type,int Icon)186 int CPDFSDK_FormFillEnvironment::JS_appAlert(const WideString& Msg,
187 const WideString& Title,
188 int Type,
189 int Icon) {
190 IPDF_JSPLATFORM* js_platform = GetJSPlatform();
191 if (!js_platform || !js_platform->app_alert)
192 return -1;
193
194 ByteString bsMsg = Msg.ToUTF16LE();
195 ByteString bsTitle = Title.ToUTF16LE();
196 return js_platform->app_alert(js_platform, AsFPDFWideString(&bsMsg),
197 AsFPDFWideString(&bsTitle), Type, Icon);
198 }
199
JS_appResponse(const WideString & Question,const WideString & Title,const WideString & Default,const WideString & Label,FPDF_BOOL bPassword,pdfium::span<uint8_t> response)200 int CPDFSDK_FormFillEnvironment::JS_appResponse(
201 const WideString& Question,
202 const WideString& Title,
203 const WideString& Default,
204 const WideString& Label,
205 FPDF_BOOL bPassword,
206 pdfium::span<uint8_t> response) {
207 IPDF_JSPLATFORM* js_platform = GetJSPlatform();
208 if (!js_platform || !js_platform->app_response)
209 return -1;
210
211 ByteString bsQuestion = Question.ToUTF16LE();
212 ByteString bsTitle = Title.ToUTF16LE();
213 ByteString bsDefault = Default.ToUTF16LE();
214 ByteString bsLabel = Label.ToUTF16LE();
215 return js_platform->app_response(
216 js_platform, AsFPDFWideString(&bsQuestion), AsFPDFWideString(&bsTitle),
217 AsFPDFWideString(&bsDefault), AsFPDFWideString(&bsLabel), bPassword,
218 response.data(), pdfium::base::checked_cast<int>(response.size()));
219 }
220
JS_appBeep(int nType)221 void CPDFSDK_FormFillEnvironment::JS_appBeep(int nType) {
222 IPDF_JSPLATFORM* js_platform = GetJSPlatform();
223 if (!js_platform || !js_platform->app_beep)
224 return;
225
226 js_platform->app_beep(js_platform, nType);
227 }
228
JS_fieldBrowse()229 WideString CPDFSDK_FormFillEnvironment::JS_fieldBrowse() {
230 IPDF_JSPLATFORM* js_platform = GetJSPlatform();
231 if (!js_platform || !js_platform->Field_browse)
232 return WideString();
233
234 const int nRequiredLen = js_platform->Field_browse(js_platform, nullptr, 0);
235 if (nRequiredLen <= 0)
236 return WideString();
237
238 DataVector<uint8_t> pBuff(nRequiredLen);
239 const int nActualLen =
240 js_platform->Field_browse(js_platform, pBuff.data(), nRequiredLen);
241 if (nActualLen <= 0 || nActualLen > nRequiredLen)
242 return WideString();
243
244 // Don't include trailing NUL.
245 pBuff.resize(nActualLen - 1);
246
247 // Use FromDefANSI() per "local encoding" comment in fpdf_formfill.h.
248 return WideString::FromDefANSI(ByteStringView(pBuff));
249 }
250
JS_docmailForm(pdfium::span<const uint8_t> mailData,FPDF_BOOL bUI,const WideString & To,const WideString & Subject,const WideString & CC,const WideString & BCC,const WideString & Msg)251 void CPDFSDK_FormFillEnvironment::JS_docmailForm(
252 pdfium::span<const uint8_t> mailData,
253 FPDF_BOOL bUI,
254 const WideString& To,
255 const WideString& Subject,
256 const WideString& CC,
257 const WideString& BCC,
258 const WideString& Msg) {
259 IPDF_JSPLATFORM* js_platform = GetJSPlatform();
260 if (!js_platform || !js_platform->Doc_mail)
261 return;
262
263 ByteString bsTo = To.ToUTF16LE();
264 ByteString bsSubject = Subject.ToUTF16LE();
265 ByteString bsCC = CC.ToUTF16LE();
266 ByteString bsBcc = BCC.ToUTF16LE();
267 ByteString bsMsg = Msg.ToUTF16LE();
268 js_platform->Doc_mail(js_platform, const_cast<uint8_t*>(mailData.data()),
269 pdfium::base::checked_cast<int>(mailData.size()), bUI,
270 AsFPDFWideString(&bsTo), AsFPDFWideString(&bsSubject),
271 AsFPDFWideString(&bsCC), AsFPDFWideString(&bsBcc),
272 AsFPDFWideString(&bsMsg));
273 }
274
JS_docprint(FPDF_BOOL bUI,int nStart,int nEnd,FPDF_BOOL bSilent,FPDF_BOOL bShrinkToFit,FPDF_BOOL bPrintAsImage,FPDF_BOOL bReverse,FPDF_BOOL bAnnotations)275 void CPDFSDK_FormFillEnvironment::JS_docprint(FPDF_BOOL bUI,
276 int nStart,
277 int nEnd,
278 FPDF_BOOL bSilent,
279 FPDF_BOOL bShrinkToFit,
280 FPDF_BOOL bPrintAsImage,
281 FPDF_BOOL bReverse,
282 FPDF_BOOL bAnnotations) {
283 IPDF_JSPLATFORM* js_platform = GetJSPlatform();
284 if (!js_platform || !js_platform->Doc_print)
285 return;
286
287 js_platform->Doc_print(js_platform, bUI, nStart, nEnd, bSilent, bShrinkToFit,
288 bPrintAsImage, bReverse, bAnnotations);
289 }
290
JS_docgotoPage(int nPageNum)291 void CPDFSDK_FormFillEnvironment::JS_docgotoPage(int nPageNum) {
292 IPDF_JSPLATFORM* js_platform = GetJSPlatform();
293 if (!js_platform || !js_platform->Doc_gotoPage)
294 return;
295
296 js_platform->Doc_gotoPage(js_platform, nPageNum);
297 }
298
JS_docGetFilePath()299 WideString CPDFSDK_FormFillEnvironment::JS_docGetFilePath() {
300 return GetFilePath();
301 }
302 #endif // PDF_ENABLE_V8
303
GetFilePath() const304 WideString CPDFSDK_FormFillEnvironment::GetFilePath() const {
305 IPDF_JSPLATFORM* js_platform = GetJSPlatform();
306 if (!js_platform || !js_platform->Doc_getFilePath)
307 return WideString();
308
309 const int nRequiredLen =
310 js_platform->Doc_getFilePath(js_platform, nullptr, 0);
311 if (nRequiredLen <= 0)
312 return WideString();
313
314 DataVector<uint8_t> pBuff(nRequiredLen);
315 const int nActualLen =
316 js_platform->Doc_getFilePath(js_platform, pBuff.data(), nRequiredLen);
317 if (nActualLen <= 0 || nActualLen > nRequiredLen)
318 return WideString();
319
320 // Don't include trailing NUL.
321 pBuff.resize(nActualLen - 1);
322
323 // Use FromDefANSI() per "local encoding" comment in fpdf_formfill.h.
324 return WideString::FromDefANSI(ByteStringView(pBuff));
325 }
326
SubmitForm(pdfium::span<const uint8_t> form_data,const WideString & URL)327 void CPDFSDK_FormFillEnvironment::SubmitForm(
328 pdfium::span<const uint8_t> form_data,
329 const WideString& URL) {
330 IPDF_JSPLATFORM* js_platform = GetJSPlatform();
331 if (!js_platform || !js_platform->Doc_submitForm)
332 return;
333
334 ByteString bsUrl = URL.ToUTF16LE();
335 js_platform->Doc_submitForm(
336 js_platform, const_cast<uint8_t*>(form_data.data()),
337 fxcrt::CollectionSize<int>(form_data), AsFPDFWideString(&bsUrl));
338 }
339
GetIJSRuntime()340 IJS_Runtime* CPDFSDK_FormFillEnvironment::GetIJSRuntime() {
341 if (!m_pIJSRuntime)
342 m_pIJSRuntime = IJS_Runtime::Create(this);
343 return m_pIJSRuntime.get();
344 }
345
Invalidate(IPDF_Page * page,const FX_RECT & rect)346 void CPDFSDK_FormFillEnvironment::Invalidate(IPDF_Page* page,
347 const FX_RECT& rect) {
348 if (m_pInfo && m_pInfo->FFI_Invalidate) {
349 m_pInfo->FFI_Invalidate(m_pInfo, FPDFPageFromIPDFPage(page), rect.left,
350 rect.top, rect.right, rect.bottom);
351 }
352 }
353
SetCursor(IPWL_FillerNotify::CursorStyle nCursorType)354 void CPDFSDK_FormFillEnvironment::SetCursor(
355 IPWL_FillerNotify::CursorStyle nCursorType) {
356 if (m_pInfo && m_pInfo->FFI_SetCursor)
357 m_pInfo->FFI_SetCursor(m_pInfo, static_cast<int>(nCursorType));
358 }
359
SetTimer(int uElapse,TimerCallback lpTimerFunc)360 int CPDFSDK_FormFillEnvironment::SetTimer(int uElapse,
361 TimerCallback lpTimerFunc) {
362 if (m_pInfo && m_pInfo->FFI_SetTimer)
363 return m_pInfo->FFI_SetTimer(m_pInfo, uElapse, lpTimerFunc);
364 return CFX_Timer::HandlerIface::kInvalidTimerID;
365 }
366
KillTimer(int nTimerID)367 void CPDFSDK_FormFillEnvironment::KillTimer(int nTimerID) {
368 if (m_pInfo && m_pInfo->FFI_KillTimer)
369 m_pInfo->FFI_KillTimer(m_pInfo, nTimerID);
370 }
371
OnChange()372 void CPDFSDK_FormFillEnvironment::OnChange() {
373 if (m_pInfo && m_pInfo->FFI_OnChange)
374 m_pInfo->FFI_OnChange(m_pInfo);
375 }
376
ExecuteNamedAction(const ByteString & namedAction)377 void CPDFSDK_FormFillEnvironment::ExecuteNamedAction(
378 const ByteString& namedAction) {
379 if (m_pInfo && m_pInfo->FFI_ExecuteNamedAction)
380 m_pInfo->FFI_ExecuteNamedAction(m_pInfo, namedAction.c_str());
381 }
382
OnSetFieldInputFocus(const WideString & text)383 void CPDFSDK_FormFillEnvironment::OnSetFieldInputFocus(const WideString& text) {
384 OnSetFieldInputFocusInternal(text, true);
385 }
386
OnSetFieldInputFocusInternal(const WideString & text,bool bFocus)387 void CPDFSDK_FormFillEnvironment::OnSetFieldInputFocusInternal(
388 const WideString& text,
389 bool bFocus) {
390 if (m_pInfo && m_pInfo->FFI_SetTextFieldFocus) {
391 size_t nCharacters = text.GetLength();
392 ByteString bsUTFText = text.ToUTF16LE();
393 auto* pBuffer = reinterpret_cast<const unsigned short*>(bsUTFText.c_str());
394 m_pInfo->FFI_SetTextFieldFocus(
395 m_pInfo, pBuffer, pdfium::base::checked_cast<FPDF_DWORD>(nCharacters),
396 bFocus);
397 }
398 }
399
OnCalculate(ObservedPtr<CPDFSDK_Annot> & pAnnot)400 void CPDFSDK_FormFillEnvironment::OnCalculate(
401 ObservedPtr<CPDFSDK_Annot>& pAnnot) {
402 CPDFSDK_Widget* pWidget = ToCPDFSDKWidget(pAnnot.Get());
403 if (pWidget)
404 m_pInteractiveForm->OnCalculate(pWidget->GetFormField());
405 }
406
OnFormat(ObservedPtr<CPDFSDK_Annot> & pAnnot)407 void CPDFSDK_FormFillEnvironment::OnFormat(ObservedPtr<CPDFSDK_Annot>& pAnnot) {
408 CPDFSDK_Widget* pWidget = ToCPDFSDKWidget(pAnnot.Get());
409 DCHECK(pWidget);
410
411 absl::optional<WideString> sValue =
412 m_pInteractiveForm->OnFormat(pWidget->GetFormField());
413 if (!pAnnot)
414 return;
415
416 if (sValue.has_value()) {
417 m_pInteractiveForm->ResetFieldAppearance(pWidget->GetFormField(), sValue);
418 m_pInteractiveForm->UpdateField(pWidget->GetFormField());
419 }
420 }
421
DoURIAction(const ByteString & bsURI,Mask<FWL_EVENTFLAG> modifiers)422 void CPDFSDK_FormFillEnvironment::DoURIAction(const ByteString& bsURI,
423 Mask<FWL_EVENTFLAG> modifiers) {
424 if (!m_pInfo)
425 return;
426
427 if (m_pInfo->version >= 2 && m_pInfo->FFI_DoURIActionWithKeyboardModifier) {
428 m_pInfo->FFI_DoURIActionWithKeyboardModifier(m_pInfo, bsURI.c_str(),
429 modifiers.UncheckedValue());
430 return;
431 }
432
433 if (m_pInfo->FFI_DoURIAction)
434 m_pInfo->FFI_DoURIAction(m_pInfo, bsURI.c_str());
435 }
436
DoGoToAction(int nPageIndex,int zoomMode,pdfium::span<float> fPosArray)437 void CPDFSDK_FormFillEnvironment::DoGoToAction(int nPageIndex,
438 int zoomMode,
439 pdfium::span<float> fPosArray) {
440 if (m_pInfo && m_pInfo->FFI_DoGoToAction) {
441 m_pInfo->FFI_DoGoToAction(m_pInfo, nPageIndex, zoomMode, fPosArray.data(),
442 fxcrt::CollectionSize<int>(fPosArray));
443 }
444 }
445
446 #ifdef PDF_ENABLE_XFA
GetPageViewCount() const447 int CPDFSDK_FormFillEnvironment::GetPageViewCount() const {
448 return fxcrt::CollectionSize<int>(m_PageMap);
449 }
450
DisplayCaret(IPDF_Page * page,FPDF_BOOL bVisible,double left,double top,double right,double bottom)451 void CPDFSDK_FormFillEnvironment::DisplayCaret(IPDF_Page* page,
452 FPDF_BOOL bVisible,
453 double left,
454 double top,
455 double right,
456 double bottom) {
457 if (m_pInfo && m_pInfo->version >= 2 && m_pInfo->FFI_DisplayCaret) {
458 m_pInfo->FFI_DisplayCaret(m_pInfo, FPDFPageFromIPDFPage(page), bVisible,
459 left, top, right, bottom);
460 }
461 }
462
GetCurrentPageIndex() const463 int CPDFSDK_FormFillEnvironment::GetCurrentPageIndex() const {
464 if (!m_pInfo || m_pInfo->version < 2 || !m_pInfo->FFI_GetCurrentPageIndex)
465 return -1;
466 return m_pInfo->FFI_GetCurrentPageIndex(
467 m_pInfo, FPDFDocumentFromCPDFDocument(m_pCPDFDoc));
468 }
469
SetCurrentPage(int iCurPage)470 void CPDFSDK_FormFillEnvironment::SetCurrentPage(int iCurPage) {
471 if (!m_pInfo || m_pInfo->version < 2 || !m_pInfo->FFI_SetCurrentPage)
472 return;
473 m_pInfo->FFI_SetCurrentPage(m_pInfo, FPDFDocumentFromCPDFDocument(m_pCPDFDoc),
474 iCurPage);
475 }
476
GotoURL(const WideString & wsURL)477 void CPDFSDK_FormFillEnvironment::GotoURL(const WideString& wsURL) {
478 if (!m_pInfo || m_pInfo->version < 2 || !m_pInfo->FFI_GotoURL)
479 return;
480
481 ByteString bsTo = wsURL.ToUTF16LE();
482 m_pInfo->FFI_GotoURL(m_pInfo, FPDFDocumentFromCPDFDocument(m_pCPDFDoc),
483 AsFPDFWideString(&bsTo));
484 }
485
GetPageViewRect(IPDF_Page * page)486 FS_RECTF CPDFSDK_FormFillEnvironment::GetPageViewRect(IPDF_Page* page) {
487 FS_RECTF rect = {0.0f, 0.0f, 0.0f, 0.0f};
488 if (!m_pInfo || m_pInfo->version < 2 || !m_pInfo->FFI_GetPageViewRect)
489 return rect;
490
491 double left;
492 double top;
493 double right;
494 double bottom;
495 m_pInfo->FFI_GetPageViewRect(m_pInfo, FPDFPageFromIPDFPage(page), &left, &top,
496 &right, &bottom);
497
498 rect.left = static_cast<float>(left);
499 rect.top = static_cast<float>(top);
500 rect.bottom = static_cast<float>(bottom);
501 rect.right = static_cast<float>(right);
502 return rect;
503 }
504
PopupMenu(IPDF_Page * page,int menuFlag,const CFX_PointF & pt)505 bool CPDFSDK_FormFillEnvironment::PopupMenu(IPDF_Page* page,
506 int menuFlag,
507 const CFX_PointF& pt) {
508 return m_pInfo && m_pInfo->version >= 2 && m_pInfo->FFI_PopupMenu &&
509 m_pInfo->FFI_PopupMenu(m_pInfo, FPDFPageFromIPDFPage(page), nullptr,
510 menuFlag, pt.x, pt.y);
511 }
512
EmailTo(FPDF_FILEHANDLER * fileHandler,FPDF_WIDESTRING pTo,FPDF_WIDESTRING pSubject,FPDF_WIDESTRING pCC,FPDF_WIDESTRING pBcc,FPDF_WIDESTRING pMsg)513 void CPDFSDK_FormFillEnvironment::EmailTo(FPDF_FILEHANDLER* fileHandler,
514 FPDF_WIDESTRING pTo,
515 FPDF_WIDESTRING pSubject,
516 FPDF_WIDESTRING pCC,
517 FPDF_WIDESTRING pBcc,
518 FPDF_WIDESTRING pMsg) {
519 if (m_pInfo && m_pInfo->version >= 2 && m_pInfo->FFI_EmailTo)
520 m_pInfo->FFI_EmailTo(m_pInfo, fileHandler, pTo, pSubject, pCC, pBcc, pMsg);
521 }
522
UploadTo(FPDF_FILEHANDLER * fileHandler,int fileFlag,FPDF_WIDESTRING uploadTo)523 void CPDFSDK_FormFillEnvironment::UploadTo(FPDF_FILEHANDLER* fileHandler,
524 int fileFlag,
525 FPDF_WIDESTRING uploadTo) {
526 if (m_pInfo && m_pInfo->version >= 2 && m_pInfo->FFI_UploadTo)
527 m_pInfo->FFI_UploadTo(m_pInfo, fileHandler, fileFlag, uploadTo);
528 }
529
OpenFile(int fileType,FPDF_WIDESTRING wsURL,const char * mode)530 FPDF_FILEHANDLER* CPDFSDK_FormFillEnvironment::OpenFile(int fileType,
531 FPDF_WIDESTRING wsURL,
532 const char* mode) {
533 if (m_pInfo && m_pInfo->version >= 2 && m_pInfo->FFI_OpenFile)
534 return m_pInfo->FFI_OpenFile(m_pInfo, fileType, wsURL, mode);
535 return nullptr;
536 }
537
DownloadFromURL(const WideString & url)538 RetainPtr<IFX_SeekableReadStream> CPDFSDK_FormFillEnvironment::DownloadFromURL(
539 const WideString& url) {
540 if (!m_pInfo || m_pInfo->version < 2 || !m_pInfo->FFI_DownloadFromURL)
541 return nullptr;
542
543 ByteString bstrURL = url.ToUTF16LE();
544 FPDF_FILEHANDLER* fileHandler =
545 m_pInfo->FFI_DownloadFromURL(m_pInfo, AsFPDFWideString(&bstrURL));
546
547 return MakeSeekableStream(fileHandler);
548 }
549
PostRequestURL(const WideString & wsURL,const WideString & wsData,const WideString & wsContentType,const WideString & wsEncode,const WideString & wsHeader)550 WideString CPDFSDK_FormFillEnvironment::PostRequestURL(
551 const WideString& wsURL,
552 const WideString& wsData,
553 const WideString& wsContentType,
554 const WideString& wsEncode,
555 const WideString& wsHeader) {
556 if (!m_pInfo || m_pInfo->version < 2 || !m_pInfo->FFI_PostRequestURL)
557 return WideString();
558
559 ByteString bsURL = wsURL.ToUTF16LE();
560 ByteString bsData = wsData.ToUTF16LE();
561 ByteString bsContentType = wsContentType.ToUTF16LE();
562 ByteString bsEncode = wsEncode.ToUTF16LE();
563 ByteString bsHeader = wsHeader.ToUTF16LE();
564
565 FPDF_BSTR response;
566 FPDF_BStr_Init(&response);
567 m_pInfo->FFI_PostRequestURL(
568 m_pInfo, AsFPDFWideString(&bsURL), AsFPDFWideString(&bsData),
569 AsFPDFWideString(&bsContentType), AsFPDFWideString(&bsEncode),
570 AsFPDFWideString(&bsHeader), &response);
571
572 WideString wsRet =
573 WideString::FromUTF16LE(reinterpret_cast<FPDF_WIDESTRING>(response.str),
574 response.len / sizeof(FPDF_WCHAR));
575
576 FPDF_BStr_Clear(&response);
577 return wsRet;
578 }
579
PutRequestURL(const WideString & wsURL,const WideString & wsData,const WideString & wsEncode)580 FPDF_BOOL CPDFSDK_FormFillEnvironment::PutRequestURL(
581 const WideString& wsURL,
582 const WideString& wsData,
583 const WideString& wsEncode) {
584 if (!m_pInfo || m_pInfo->version < 2 || !m_pInfo->FFI_PutRequestURL)
585 return false;
586
587 ByteString bsURL = wsURL.ToUTF16LE();
588 ByteString bsData = wsData.ToUTF16LE();
589 ByteString bsEncode = wsEncode.ToUTF16LE();
590
591 return m_pInfo->FFI_PutRequestURL(m_pInfo, AsFPDFWideString(&bsURL),
592 AsFPDFWideString(&bsData),
593 AsFPDFWideString(&bsEncode));
594 }
595
PageEvent(int iPageCount,uint32_t dwEventType) const596 void CPDFSDK_FormFillEnvironment::PageEvent(int iPageCount,
597 uint32_t dwEventType) const {
598 if (m_pInfo && m_pInfo->version >= 2 && m_pInfo->FFI_PageEvent)
599 m_pInfo->FFI_PageEvent(m_pInfo, iPageCount, dwEventType);
600 }
601 #endif // PDF_ENABLE_XFA
602
ClearAllFocusedAnnots()603 void CPDFSDK_FormFillEnvironment::ClearAllFocusedAnnots() {
604 for (auto& it : m_PageMap) {
605 if (it.second->IsValidSDKAnnot(GetFocusAnnot())) {
606 ObservedPtr<CPDFSDK_PageView> pObserved(it.second.get());
607 KillFocusAnnot({});
608 if (!pObserved)
609 break;
610 }
611 }
612 }
613
GetOrCreatePageView(IPDF_Page * pUnderlyingPage)614 CPDFSDK_PageView* CPDFSDK_FormFillEnvironment::GetOrCreatePageView(
615 IPDF_Page* pUnderlyingPage) {
616 CPDFSDK_PageView* pExisting = GetPageView(pUnderlyingPage);
617 if (pExisting)
618 return pExisting;
619
620 auto pNew = std::make_unique<CPDFSDK_PageView>(this, pUnderlyingPage);
621 CPDFSDK_PageView* pPageView = pNew.get();
622 m_PageMap[pUnderlyingPage] = std::move(pNew);
623
624 // Delay to load all the annotations, to avoid endless loop.
625 pPageView->LoadFXAnnots();
626 return pPageView;
627 }
628
GetPageView(IPDF_Page * pUnderlyingPage)629 CPDFSDK_PageView* CPDFSDK_FormFillEnvironment::GetPageView(
630 IPDF_Page* pUnderlyingPage) {
631 auto it = m_PageMap.find(pUnderlyingPage);
632 return it != m_PageMap.end() ? it->second.get() : nullptr;
633 }
634
GetTimerHandler()635 CFX_Timer::HandlerIface* CPDFSDK_FormFillEnvironment::GetTimerHandler() {
636 return this;
637 }
638
GetPageViewAtIndex(int nIndex)639 CPDFSDK_PageView* CPDFSDK_FormFillEnvironment::GetPageViewAtIndex(int nIndex) {
640 IPDF_Page* pTempPage = GetPage(nIndex);
641 return pTempPage ? GetPageView(pTempPage) : nullptr;
642 }
643
ProcJavascriptAction()644 void CPDFSDK_FormFillEnvironment::ProcJavascriptAction() {
645 auto name_tree = CPDF_NameTree::Create(m_pCPDFDoc, "JavaScript");
646 if (!name_tree)
647 return;
648
649 size_t count = name_tree->GetCount();
650 for (size_t i = 0; i < count; ++i) {
651 WideString name;
652 CPDF_Action action(ToDictionary(name_tree->LookupValueAndName(i, &name)));
653 DoActionJavaScript(action, name);
654 }
655 }
656
ProcOpenAction()657 bool CPDFSDK_FormFillEnvironment::ProcOpenAction() {
658 const CPDF_Dictionary* pRoot = m_pCPDFDoc->GetRoot();
659 if (!pRoot)
660 return false;
661
662 RetainPtr<const CPDF_Object> pOpenAction(pRoot->GetDictFor("OpenAction"));
663 if (!pOpenAction)
664 pOpenAction = pRoot->GetArrayFor("OpenAction");
665 if (!pOpenAction)
666 return false;
667
668 if (pOpenAction->IsArray())
669 return true;
670
671 RetainPtr<const CPDF_Dictionary> pDict = ToDictionary(pOpenAction);
672 if (!pDict)
673 return false;
674
675 DoActionDocOpen(CPDF_Action(std::move(pDict)));
676 return true;
677 }
678
RemovePageView(IPDF_Page * pUnderlyingPage)679 void CPDFSDK_FormFillEnvironment::RemovePageView(IPDF_Page* pUnderlyingPage) {
680 auto it = m_PageMap.find(pUnderlyingPage);
681 if (it == m_PageMap.end())
682 return;
683
684 CPDFSDK_PageView* pPageView = it->second.get();
685 if (pPageView->IsLocked() || pPageView->IsBeingDestroyed())
686 return;
687
688 // Mark the page view so we do not come into |RemovePageView| a second
689 // time while we're in the process of removing.
690 pPageView->SetBeingDestroyed();
691
692 // This must happen before we remove |pPageView| from the map because
693 // |KillFocusAnnot| can call into the |GetPage| method which will
694 // look for this page view in the map, if it doesn't find it a new one will
695 // be created. We then have two page views pointing to the same page and
696 // bad things happen.
697 if (pPageView->IsValidSDKAnnot(GetFocusAnnot()))
698 KillFocusAnnot({});
699
700 // Remove the page from the map to make sure we don't accidentally attempt
701 // to use the |pPageView| while we're cleaning it up.
702 m_PageMap.erase(it);
703 }
704
GetPage(int nIndex) const705 IPDF_Page* CPDFSDK_FormFillEnvironment::GetPage(int nIndex) const {
706 if (!m_pInfo || !m_pInfo->FFI_GetPage)
707 return nullptr;
708 return IPDFPageFromFPDFPage(m_pInfo->FFI_GetPage(
709 m_pInfo, FPDFDocumentFromCPDFDocument(m_pCPDFDoc), nIndex));
710 }
711
GetInteractiveForm()712 CPDFSDK_InteractiveForm* CPDFSDK_FormFillEnvironment::GetInteractiveForm() {
713 if (!m_pInteractiveForm)
714 m_pInteractiveForm = std::make_unique<CPDFSDK_InteractiveForm>(this);
715 return m_pInteractiveForm.get();
716 }
717
UpdateAllViews(CPDFSDK_Annot * pAnnot)718 void CPDFSDK_FormFillEnvironment::UpdateAllViews(CPDFSDK_Annot* pAnnot) {
719 for (const auto& it : m_PageMap) {
720 ObservedPtr<CPDFSDK_PageView> pObserved(it.second.get());
721 if (pObserved) {
722 pObserved->UpdateView(pAnnot);
723 if (!pObserved)
724 break;
725 }
726 }
727 }
728
GetFocusAnnot() const729 CPDFSDK_Annot* CPDFSDK_FormFillEnvironment::GetFocusAnnot() const {
730 return m_pFocusAnnot.Get();
731 }
732
SetFocusAnnot(ObservedPtr<CPDFSDK_Annot> & pAnnot)733 bool CPDFSDK_FormFillEnvironment::SetFocusAnnot(
734 ObservedPtr<CPDFSDK_Annot>& pAnnot) {
735 if (m_bBeingDestroyed)
736 return false;
737 if (m_pFocusAnnot == pAnnot)
738 return true;
739 if (m_pFocusAnnot && !KillFocusAnnot({}))
740 return false;
741 if (!pAnnot)
742 return false;
743 if (!pAnnot->GetPageView()->IsValid())
744 return false;
745
746 if (m_pFocusAnnot)
747 return false;
748
749 #ifdef PDF_ENABLE_XFA
750 CPDFXFA_Widget* pXFAWidget = pAnnot->AsXFAWidget();
751 if (pXFAWidget && pXFAWidget->OnChangedFocus())
752 return false;
753
754 // `pAnnot` may be destroyed in `OnChangedFocus()`.
755 if (!pAnnot)
756 return false;
757 #endif // PDF_ENABLE_XFA
758
759 if (!CPDFSDK_Annot::OnSetFocus(pAnnot, {}))
760 return false;
761 if (m_pFocusAnnot)
762 return false;
763
764 m_pFocusAnnot.Reset(pAnnot.Get());
765
766 // If we are not able to inform the client about the focus change, it
767 // shouldn't be considered as failure.
768 SendOnFocusChange(pAnnot);
769 return true;
770 }
771
KillFocusAnnot(Mask<FWL_EVENTFLAG> nFlags)772 bool CPDFSDK_FormFillEnvironment::KillFocusAnnot(Mask<FWL_EVENTFLAG> nFlags) {
773 if (!m_pFocusAnnot)
774 return false;
775
776 ObservedPtr<CPDFSDK_Annot> pFocusAnnot(m_pFocusAnnot.Get());
777 m_pFocusAnnot.Reset();
778
779 if (!CPDFSDK_Annot::OnKillFocus(pFocusAnnot, nFlags)) {
780 m_pFocusAnnot.Reset(pFocusAnnot.Get());
781 return false;
782 }
783
784 // Might have been destroyed by OnKillFocus().
785 if (!pFocusAnnot)
786 return false;
787
788 if (pFocusAnnot->GetAnnotSubtype() == CPDF_Annot::Subtype::WIDGET) {
789 CPDFSDK_Widget* pWidget = ToCPDFSDKWidget(pFocusAnnot.Get());
790 FormFieldType fieldType = pWidget->GetFieldType();
791 if (fieldType == FormFieldType::kTextField ||
792 fieldType == FormFieldType::kComboBox) {
793 OnSetFieldInputFocusInternal(WideString(), false);
794 }
795 }
796 return !m_pFocusAnnot;
797 }
798
GetPageCount() const799 int CPDFSDK_FormFillEnvironment::GetPageCount() const {
800 CPDF_Document::Extension* pExtension = m_pCPDFDoc->GetExtension();
801 return pExtension ? pExtension->GetPageCount() : m_pCPDFDoc->GetPageCount();
802 }
803
HasPermissions(uint32_t flags) const804 bool CPDFSDK_FormFillEnvironment::HasPermissions(uint32_t flags) const {
805 return !!(m_pCPDFDoc->GetUserPermissions() & flags);
806 }
807
SendOnFocusChange(ObservedPtr<CPDFSDK_Annot> & pAnnot)808 void CPDFSDK_FormFillEnvironment::SendOnFocusChange(
809 ObservedPtr<CPDFSDK_Annot>& pAnnot) {
810 if (!m_pInfo || m_pInfo->version < 2 || !m_pInfo->FFI_OnFocusChange)
811 return;
812
813 // TODO(crbug.com/pdfium/1482): Handle XFA case.
814 if (pAnnot->AsXFAWidget())
815 return;
816
817 CPDFSDK_PageView* pPageView = pAnnot->GetPageView();
818 if (!pPageView->IsValid())
819 return;
820
821 IPDF_Page* page = pAnnot->GetPage();
822 if (!page)
823 return;
824
825 RetainPtr<CPDF_Dictionary> annot_dict =
826 pAnnot->GetPDFAnnot()->GetMutableAnnotDict();
827 auto focused_annot = std::make_unique<CPDF_AnnotContext>(annot_dict, page);
828 FPDF_ANNOTATION fpdf_annot =
829 FPDFAnnotationFromCPDFAnnotContext(focused_annot.get());
830
831 m_pInfo->FFI_OnFocusChange(m_pInfo, fpdf_annot, pPageView->GetPageIndex());
832 }
833
DoActionDocOpen(const CPDF_Action & action)834 bool CPDFSDK_FormFillEnvironment::DoActionDocOpen(const CPDF_Action& action) {
835 std::set<const CPDF_Dictionary*> visited;
836 return ExecuteDocumentOpenAction(action, &visited);
837 }
838
DoActionJavaScript(const CPDF_Action & JsAction,WideString csJSName)839 bool CPDFSDK_FormFillEnvironment::DoActionJavaScript(
840 const CPDF_Action& JsAction,
841 WideString csJSName) {
842 if (JsAction.GetType() == CPDF_Action::Type::kJavaScript) {
843 WideString swJS = JsAction.GetJavaScript();
844 if (!swJS.IsEmpty()) {
845 RunDocumentOpenJavaScript(csJSName, swJS);
846 return true;
847 }
848 }
849
850 return false;
851 }
852
DoActionFieldJavaScript(const CPDF_Action & JsAction,CPDF_AAction::AActionType type,CPDF_FormField * pFormField,CFFL_FieldAction * data)853 bool CPDFSDK_FormFillEnvironment::DoActionFieldJavaScript(
854 const CPDF_Action& JsAction,
855 CPDF_AAction::AActionType type,
856 CPDF_FormField* pFormField,
857 CFFL_FieldAction* data) {
858 if (IsJSPlatformPresent() &&
859 JsAction.GetType() == CPDF_Action::Type::kJavaScript) {
860 WideString swJS = JsAction.GetJavaScript();
861 if (!swJS.IsEmpty()) {
862 RunFieldJavaScript(pFormField, type, data, swJS);
863 return true;
864 }
865 }
866 return false;
867 }
868
DoActionLink(const CPDF_Action & action,CPDF_AAction::AActionType type,Mask<FWL_EVENTFLAG> modifiers)869 bool CPDFSDK_FormFillEnvironment::DoActionLink(const CPDF_Action& action,
870 CPDF_AAction::AActionType type,
871 Mask<FWL_EVENTFLAG> modifiers) {
872 if (!CPDF_AAction::IsUserInput(type))
873 return false;
874
875 switch (action.GetType()) {
876 case CPDF_Action::Type::kGoTo:
877 DoActionGoTo(action);
878 return true;
879 case CPDF_Action::Type::kURI:
880 DoActionURI(action, modifiers);
881 return true;
882 default:
883 return false;
884 }
885 }
886
DoActionDestination(const CPDF_Dest & dest)887 bool CPDFSDK_FormFillEnvironment::DoActionDestination(const CPDF_Dest& dest) {
888 CPDF_Document* document = GetPDFDocument();
889 DCHECK(document);
890
891 std::vector<float> positions = dest.GetScrollPositionArray();
892 DoGoToAction(dest.GetDestPageIndex(document), dest.GetZoomMode(), positions);
893 return true;
894 }
895
DoActionPage(const CPDF_Action & action,CPDF_AAction::AActionType eType)896 bool CPDFSDK_FormFillEnvironment::DoActionPage(
897 const CPDF_Action& action,
898 CPDF_AAction::AActionType eType) {
899 std::set<const CPDF_Dictionary*> visited;
900 return ExecuteDocumentPageAction(action, eType, &visited);
901 }
902
DoActionDocument(const CPDF_Action & action,CPDF_AAction::AActionType eType)903 bool CPDFSDK_FormFillEnvironment::DoActionDocument(
904 const CPDF_Action& action,
905 CPDF_AAction::AActionType eType) {
906 std::set<const CPDF_Dictionary*> visited;
907 return ExecuteDocumentPageAction(action, eType, &visited);
908 }
909
DoActionField(const CPDF_Action & action,CPDF_AAction::AActionType type,CPDF_FormField * pFormField,CFFL_FieldAction * data)910 bool CPDFSDK_FormFillEnvironment::DoActionField(const CPDF_Action& action,
911 CPDF_AAction::AActionType type,
912 CPDF_FormField* pFormField,
913 CFFL_FieldAction* data) {
914 std::set<const CPDF_Dictionary*> visited;
915 return ExecuteFieldAction(action, type, pFormField, data, &visited);
916 }
917
ExecuteDocumentOpenAction(const CPDF_Action & action,std::set<const CPDF_Dictionary * > * visited)918 bool CPDFSDK_FormFillEnvironment::ExecuteDocumentOpenAction(
919 const CPDF_Action& action,
920 std::set<const CPDF_Dictionary*>* visited) {
921 const CPDF_Dictionary* pDict = action.GetDict();
922 if (pdfium::Contains(*visited, pDict))
923 return false;
924
925 visited->insert(pDict);
926
927 if (action.GetType() == CPDF_Action::Type::kJavaScript) {
928 if (IsJSPlatformPresent()) {
929 WideString swJS = action.GetJavaScript();
930 if (!swJS.IsEmpty())
931 RunDocumentOpenJavaScript(WideString(), swJS);
932 }
933 } else {
934 DoActionNoJs(action, CPDF_AAction::AActionType::kDocumentOpen);
935 }
936
937 for (size_t i = 0, sz = action.GetSubActionsCount(); i < sz; i++) {
938 CPDF_Action subaction = action.GetSubAction(i);
939 if (!ExecuteDocumentOpenAction(subaction, visited))
940 return false;
941 }
942
943 return true;
944 }
945
ExecuteDocumentPageAction(const CPDF_Action & action,CPDF_AAction::AActionType type,std::set<const CPDF_Dictionary * > * visited)946 bool CPDFSDK_FormFillEnvironment::ExecuteDocumentPageAction(
947 const CPDF_Action& action,
948 CPDF_AAction::AActionType type,
949 std::set<const CPDF_Dictionary*>* visited) {
950 const CPDF_Dictionary* pDict = action.GetDict();
951 if (pdfium::Contains(*visited, pDict))
952 return false;
953
954 visited->insert(pDict);
955
956 if (action.GetType() == CPDF_Action::Type::kJavaScript) {
957 if (IsJSPlatformPresent()) {
958 WideString swJS = action.GetJavaScript();
959 if (!swJS.IsEmpty())
960 RunDocumentPageJavaScript(type, swJS);
961 }
962 } else {
963 DoActionNoJs(action, type);
964 }
965
966 for (size_t i = 0, sz = action.GetSubActionsCount(); i < sz; i++) {
967 CPDF_Action subaction = action.GetSubAction(i);
968 if (!ExecuteDocumentPageAction(subaction, type, visited))
969 return false;
970 }
971
972 return true;
973 }
974
IsValidField(const CPDF_Dictionary * pFieldDict)975 bool CPDFSDK_FormFillEnvironment::IsValidField(
976 const CPDF_Dictionary* pFieldDict) {
977 DCHECK(pFieldDict);
978
979 CPDFSDK_InteractiveForm* pForm = GetInteractiveForm();
980 CPDF_InteractiveForm* pPDFForm = pForm->GetInteractiveForm();
981 return !!pPDFForm->GetFieldByDict(pFieldDict);
982 }
983
ExecuteFieldAction(const CPDF_Action & action,CPDF_AAction::AActionType type,CPDF_FormField * pFormField,CFFL_FieldAction * data,std::set<const CPDF_Dictionary * > * visited)984 bool CPDFSDK_FormFillEnvironment::ExecuteFieldAction(
985 const CPDF_Action& action,
986 CPDF_AAction::AActionType type,
987 CPDF_FormField* pFormField,
988 CFFL_FieldAction* data,
989 std::set<const CPDF_Dictionary*>* visited) {
990 const CPDF_Dictionary* pDict = action.GetDict();
991 if (pdfium::Contains(*visited, pDict))
992 return false;
993
994 visited->insert(pDict);
995
996 if (action.GetType() == CPDF_Action::Type::kJavaScript) {
997 if (IsJSPlatformPresent()) {
998 WideString swJS = action.GetJavaScript();
999 if (!swJS.IsEmpty()) {
1000 RunFieldJavaScript(pFormField, type, data, swJS);
1001 if (!IsValidField(pFormField->GetFieldDict()))
1002 return false;
1003 }
1004 }
1005 } else {
1006 DoActionNoJs(action, type);
1007 }
1008
1009 for (size_t i = 0, sz = action.GetSubActionsCount(); i < sz; i++) {
1010 CPDF_Action subaction = action.GetSubAction(i);
1011 if (!ExecuteFieldAction(subaction, type, pFormField, data, visited))
1012 return false;
1013 }
1014
1015 return true;
1016 }
1017
DoActionNoJs(const CPDF_Action & action,CPDF_AAction::AActionType type)1018 void CPDFSDK_FormFillEnvironment::DoActionNoJs(const CPDF_Action& action,
1019 CPDF_AAction::AActionType type) {
1020 switch (action.GetType()) {
1021 case CPDF_Action::Type::kGoTo:
1022 DoActionGoTo(action);
1023 break;
1024 case CPDF_Action::Type::kURI:
1025 if (CPDF_AAction::IsUserInput(type))
1026 DoActionURI(action, Mask<FWL_EVENTFLAG>{});
1027 break;
1028 case CPDF_Action::Type::kHide:
1029 DoActionHide(action);
1030 break;
1031 case CPDF_Action::Type::kNamed:
1032 DoActionNamed(action);
1033 break;
1034 case CPDF_Action::Type::kSubmitForm:
1035 if (CPDF_AAction::IsUserInput(type))
1036 DoActionSubmitForm(action);
1037 break;
1038 case CPDF_Action::Type::kResetForm:
1039 DoActionResetForm(action);
1040 break;
1041 case CPDF_Action::Type::kJavaScript:
1042 NOTREACHED_NORETURN();
1043 break;
1044 case CPDF_Action::Type::kSetOCGState:
1045 case CPDF_Action::Type::kThread:
1046 case CPDF_Action::Type::kSound:
1047 case CPDF_Action::Type::kMovie:
1048 case CPDF_Action::Type::kRendition:
1049 case CPDF_Action::Type::kTrans:
1050 case CPDF_Action::Type::kGoTo3DView:
1051 case CPDF_Action::Type::kGoToR:
1052 case CPDF_Action::Type::kGoToE:
1053 case CPDF_Action::Type::kLaunch:
1054 case CPDF_Action::Type::kImportData:
1055 // Unimplemented
1056 break;
1057 default:
1058 break;
1059 }
1060 }
1061
DoActionGoTo(const CPDF_Action & action)1062 void CPDFSDK_FormFillEnvironment::DoActionGoTo(const CPDF_Action& action) {
1063 DCHECK(action.GetDict());
1064
1065 CPDF_Document* pPDFDocument = GetPDFDocument();
1066 DCHECK(pPDFDocument);
1067
1068 CPDF_Dest MyDest = action.GetDest(pPDFDocument);
1069 DoActionDestination(MyDest);
1070 }
1071
DoActionURI(const CPDF_Action & action,Mask<FWL_EVENTFLAG> modifiers)1072 void CPDFSDK_FormFillEnvironment::DoActionURI(const CPDF_Action& action,
1073 Mask<FWL_EVENTFLAG> modifiers) {
1074 DCHECK(action.GetDict());
1075 DoURIAction(action.GetURI(GetPDFDocument()), modifiers);
1076 }
1077
DoActionNamed(const CPDF_Action & action)1078 void CPDFSDK_FormFillEnvironment::DoActionNamed(const CPDF_Action& action) {
1079 DCHECK(action.GetDict());
1080 ExecuteNamedAction(action.GetNamedAction());
1081 }
1082
RunFieldJavaScript(CPDF_FormField * pFormField,CPDF_AAction::AActionType type,CFFL_FieldAction * data,const WideString & script)1083 void CPDFSDK_FormFillEnvironment::RunFieldJavaScript(
1084 CPDF_FormField* pFormField,
1085 CPDF_AAction::AActionType type,
1086 CFFL_FieldAction* data,
1087 const WideString& script) {
1088 DCHECK(type != CPDF_AAction::kCalculate);
1089 DCHECK(type != CPDF_AAction::kFormat);
1090
1091 RunScript(script, [type, data, pFormField](IJS_EventContext* context) {
1092 switch (type) {
1093 case CPDF_AAction::kCursorEnter:
1094 context->OnField_MouseEnter(data->bModifier, data->bShift, pFormField);
1095 break;
1096 case CPDF_AAction::kCursorExit:
1097 context->OnField_MouseExit(data->bModifier, data->bShift, pFormField);
1098 break;
1099 case CPDF_AAction::kButtonDown:
1100 context->OnField_MouseDown(data->bModifier, data->bShift, pFormField);
1101 break;
1102 case CPDF_AAction::kButtonUp:
1103 context->OnField_MouseUp(data->bModifier, data->bShift, pFormField);
1104 break;
1105 case CPDF_AAction::kGetFocus:
1106 context->OnField_Focus(data->bModifier, data->bShift, pFormField,
1107 &data->sValue);
1108 break;
1109 case CPDF_AAction::kLoseFocus:
1110 context->OnField_Blur(data->bModifier, data->bShift, pFormField,
1111 &data->sValue);
1112 break;
1113 case CPDF_AAction::kKeyStroke:
1114 context->OnField_Keystroke(
1115 &data->sChange, data->sChangeEx, data->bKeyDown, data->bModifier,
1116 &data->nSelEnd, &data->nSelStart, data->bShift, pFormField,
1117 &data->sValue, data->bWillCommit, data->bFieldFull, &data->bRC);
1118 break;
1119 case CPDF_AAction::kValidate:
1120 context->OnField_Validate(&data->sChange, data->sChangeEx,
1121 data->bKeyDown, data->bModifier, data->bShift,
1122 pFormField, &data->sValue, &data->bRC);
1123 break;
1124 default:
1125 NOTREACHED_NORETURN();
1126 break;
1127 }
1128 });
1129 }
1130
RunDocumentOpenJavaScript(const WideString & sScriptName,const WideString & script)1131 void CPDFSDK_FormFillEnvironment::RunDocumentOpenJavaScript(
1132 const WideString& sScriptName,
1133 const WideString& script) {
1134 RunScript(script, [sScriptName](IJS_EventContext* context) {
1135 context->OnDoc_Open(sScriptName);
1136 });
1137 }
1138
RunDocumentPageJavaScript(CPDF_AAction::AActionType type,const WideString & script)1139 void CPDFSDK_FormFillEnvironment::RunDocumentPageJavaScript(
1140 CPDF_AAction::AActionType type,
1141 const WideString& script) {
1142 RunScript(script, [type](IJS_EventContext* context) {
1143 switch (type) {
1144 case CPDF_AAction::kOpenPage:
1145 context->OnPage_Open();
1146 break;
1147 case CPDF_AAction::kClosePage:
1148 context->OnPage_Close();
1149 break;
1150 case CPDF_AAction::kCloseDocument:
1151 context->OnDoc_WillClose();
1152 break;
1153 case CPDF_AAction::kSaveDocument:
1154 context->OnDoc_WillSave();
1155 break;
1156 case CPDF_AAction::kDocumentSaved:
1157 context->OnDoc_DidSave();
1158 break;
1159 case CPDF_AAction::kPrintDocument:
1160 context->OnDoc_WillPrint();
1161 break;
1162 case CPDF_AAction::kDocumentPrinted:
1163 context->OnDoc_DidPrint();
1164 break;
1165 case CPDF_AAction::kPageVisible:
1166 context->OnPage_InView();
1167 break;
1168 case CPDF_AAction::kPageInvisible:
1169 context->OnPage_OutView();
1170 break;
1171 default:
1172 NOTREACHED_NORETURN();
1173 break;
1174 }
1175 });
1176 }
1177
DoActionHide(const CPDF_Action & action)1178 bool CPDFSDK_FormFillEnvironment::DoActionHide(const CPDF_Action& action) {
1179 CPDFSDK_InteractiveForm* pForm = GetInteractiveForm();
1180 if (pForm->DoAction_Hide(action)) {
1181 SetChangeMark();
1182 return true;
1183 }
1184 return false;
1185 }
1186
DoActionSubmitForm(const CPDF_Action & action)1187 bool CPDFSDK_FormFillEnvironment::DoActionSubmitForm(
1188 const CPDF_Action& action) {
1189 CPDFSDK_InteractiveForm* pForm = GetInteractiveForm();
1190 return pForm->DoAction_SubmitForm(action);
1191 }
1192
DoActionResetForm(const CPDF_Action & action)1193 void CPDFSDK_FormFillEnvironment::DoActionResetForm(const CPDF_Action& action) {
1194 CPDFSDK_InteractiveForm* pForm = GetInteractiveForm();
1195 pForm->DoAction_ResetForm(action);
1196 }
1197
RunScript(const WideString & script,const RunScriptCallback & cb)1198 void CPDFSDK_FormFillEnvironment::RunScript(const WideString& script,
1199 const RunScriptCallback& cb) {
1200 IJS_Runtime::ScopedEventContext pContext(GetIJSRuntime());
1201 cb(pContext.Get());
1202 pContext->RunScript(script);
1203 // TODO(dsinclair): Return error if RunScript returns a IJS_Runtime::JS_Error.
1204 }
1205