• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/check.h"
20 #include "core/fxcrt/containers/contains.h"
21 #include "core/fxcrt/data_vector.h"
22 #include "core/fxcrt/notreached.h"
23 #include "core/fxcrt/numerics/safe_conversions.h"
24 #include "core/fxcrt/stl_util.h"
25 #include "fpdfsdk/cpdfsdk_helpers.h"
26 #include "fpdfsdk/cpdfsdk_interactiveform.h"
27 #include "fpdfsdk/cpdfsdk_pageview.h"
28 #include "fpdfsdk/cpdfsdk_widget.h"
29 #include "fpdfsdk/formfiller/cffl_formfield.h"
30 #include "fpdfsdk/formfiller/cffl_interactiveformfiller.h"
31 #include "fxjs/ijs_event_context.h"
32 #include "fxjs/ijs_runtime.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(
158       pdfium::make_span(pBuff).first(static_cast<size_t>(nActualLen)));
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(
180       pdfium::make_span(pBuff).first(static_cast<size_t>(nActualLen)));
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::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::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::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   ObservedPtr<CPDFSDK_Widget> pWidget(ToCPDFSDKWidget(pAnnot.Get()));
403   if (pWidget) {
404     m_pInteractiveForm->OnCalculate(pWidget->GetFormField());
405   }
406 }
407 
OnFormat(ObservedPtr<CPDFSDK_Annot> & pAnnot)408 void CPDFSDK_FormFillEnvironment::OnFormat(ObservedPtr<CPDFSDK_Annot>& pAnnot) {
409   ObservedPtr<CPDFSDK_Widget> pWidget(ToCPDFSDKWidget(pAnnot.Get()));
410   std::optional<WideString> sValue =
411       m_pInteractiveForm->OnFormat(pWidget->GetFormField());
412   if (!pWidget) {
413     return;
414   }
415   if (sValue.has_value()) {
416     m_pInteractiveForm->ResetFieldAppearance(pWidget->GetFormField(), sValue);
417     m_pInteractiveForm->UpdateField(pWidget->GetFormField());
418   }
419 }
420 
DoURIAction(const ByteString & bsURI,Mask<FWL_EVENTFLAG> modifiers)421 void CPDFSDK_FormFillEnvironment::DoURIAction(const ByteString& bsURI,
422                                               Mask<FWL_EVENTFLAG> modifiers) {
423   if (!m_pInfo)
424     return;
425 
426   if (m_pInfo->version >= 2 && m_pInfo->FFI_DoURIActionWithKeyboardModifier) {
427     m_pInfo->FFI_DoURIActionWithKeyboardModifier(m_pInfo, bsURI.c_str(),
428                                                  modifiers.UncheckedValue());
429     return;
430   }
431 
432   if (m_pInfo->FFI_DoURIAction)
433     m_pInfo->FFI_DoURIAction(m_pInfo, bsURI.c_str());
434 }
435 
DoGoToAction(int nPageIndex,int zoomMode,pdfium::span<float> fPosArray)436 void CPDFSDK_FormFillEnvironment::DoGoToAction(int nPageIndex,
437                                                int zoomMode,
438                                                pdfium::span<float> fPosArray) {
439   if (m_pInfo && m_pInfo->FFI_DoGoToAction) {
440     m_pInfo->FFI_DoGoToAction(m_pInfo, nPageIndex, zoomMode, fPosArray.data(),
441                               fxcrt::CollectionSize<int>(fPosArray));
442   }
443 }
444 
445 #ifdef PDF_ENABLE_XFA
GetPageViewCount() const446 int CPDFSDK_FormFillEnvironment::GetPageViewCount() const {
447   return fxcrt::CollectionSize<int>(m_PageMap);
448 }
449 
DisplayCaret(IPDF_Page * page,FPDF_BOOL bVisible,double left,double top,double right,double bottom)450 void CPDFSDK_FormFillEnvironment::DisplayCaret(IPDF_Page* page,
451                                                FPDF_BOOL bVisible,
452                                                double left,
453                                                double top,
454                                                double right,
455                                                double bottom) {
456   if (m_pInfo && m_pInfo->version >= 2 && m_pInfo->FFI_DisplayCaret) {
457     m_pInfo->FFI_DisplayCaret(m_pInfo, FPDFPageFromIPDFPage(page), bVisible,
458                               left, top, right, bottom);
459   }
460 }
461 
GetCurrentPageIndex() const462 int CPDFSDK_FormFillEnvironment::GetCurrentPageIndex() const {
463   if (!m_pInfo || m_pInfo->version < 2 || !m_pInfo->FFI_GetCurrentPageIndex)
464     return -1;
465   return m_pInfo->FFI_GetCurrentPageIndex(
466       m_pInfo, FPDFDocumentFromCPDFDocument(m_pCPDFDoc));
467 }
468 
SetCurrentPage(int iCurPage)469 void CPDFSDK_FormFillEnvironment::SetCurrentPage(int iCurPage) {
470   if (!m_pInfo || m_pInfo->version < 2 || !m_pInfo->FFI_SetCurrentPage)
471     return;
472   m_pInfo->FFI_SetCurrentPage(m_pInfo, FPDFDocumentFromCPDFDocument(m_pCPDFDoc),
473                               iCurPage);
474 }
475 
GotoURL(const WideString & wsURL)476 void CPDFSDK_FormFillEnvironment::GotoURL(const WideString& wsURL) {
477   if (!m_pInfo || m_pInfo->version < 2 || !m_pInfo->FFI_GotoURL)
478     return;
479 
480   ByteString bsTo = wsURL.ToUTF16LE();
481   m_pInfo->FFI_GotoURL(m_pInfo, FPDFDocumentFromCPDFDocument(m_pCPDFDoc),
482                        AsFPDFWideString(&bsTo));
483 }
484 
GetPageViewRect(IPDF_Page * page)485 FS_RECTF CPDFSDK_FormFillEnvironment::GetPageViewRect(IPDF_Page* page) {
486   FS_RECTF rect = {0.0f, 0.0f, 0.0f, 0.0f};
487   if (!m_pInfo || m_pInfo->version < 2 || !m_pInfo->FFI_GetPageViewRect)
488     return rect;
489 
490   double left;
491   double top;
492   double right;
493   double bottom;
494   m_pInfo->FFI_GetPageViewRect(m_pInfo, FPDFPageFromIPDFPage(page), &left, &top,
495                                &right, &bottom);
496 
497   rect.left = static_cast<float>(left);
498   rect.top = static_cast<float>(top);
499   rect.bottom = static_cast<float>(bottom);
500   rect.right = static_cast<float>(right);
501   return rect;
502 }
503 
PopupMenu(IPDF_Page * page,int menuFlag,const CFX_PointF & pt)504 bool CPDFSDK_FormFillEnvironment::PopupMenu(IPDF_Page* page,
505                                             int menuFlag,
506                                             const CFX_PointF& pt) {
507   return m_pInfo && m_pInfo->version >= 2 && m_pInfo->FFI_PopupMenu &&
508          m_pInfo->FFI_PopupMenu(m_pInfo, FPDFPageFromIPDFPage(page), nullptr,
509                                 menuFlag, pt.x, pt.y);
510 }
511 
EmailTo(FPDF_FILEHANDLER * fileHandler,FPDF_WIDESTRING pTo,FPDF_WIDESTRING pSubject,FPDF_WIDESTRING pCC,FPDF_WIDESTRING pBcc,FPDF_WIDESTRING pMsg)512 void CPDFSDK_FormFillEnvironment::EmailTo(FPDF_FILEHANDLER* fileHandler,
513                                           FPDF_WIDESTRING pTo,
514                                           FPDF_WIDESTRING pSubject,
515                                           FPDF_WIDESTRING pCC,
516                                           FPDF_WIDESTRING pBcc,
517                                           FPDF_WIDESTRING pMsg) {
518   if (m_pInfo && m_pInfo->version >= 2 && m_pInfo->FFI_EmailTo)
519     m_pInfo->FFI_EmailTo(m_pInfo, fileHandler, pTo, pSubject, pCC, pBcc, pMsg);
520 }
521 
UploadTo(FPDF_FILEHANDLER * fileHandler,int fileFlag,FPDF_WIDESTRING uploadTo)522 void CPDFSDK_FormFillEnvironment::UploadTo(FPDF_FILEHANDLER* fileHandler,
523                                            int fileFlag,
524                                            FPDF_WIDESTRING uploadTo) {
525   if (m_pInfo && m_pInfo->version >= 2 && m_pInfo->FFI_UploadTo)
526     m_pInfo->FFI_UploadTo(m_pInfo, fileHandler, fileFlag, uploadTo);
527 }
528 
OpenFile(int fileType,FPDF_WIDESTRING wsURL,const char * mode)529 FPDF_FILEHANDLER* CPDFSDK_FormFillEnvironment::OpenFile(int fileType,
530                                                         FPDF_WIDESTRING wsURL,
531                                                         const char* mode) {
532   if (m_pInfo && m_pInfo->version >= 2 && m_pInfo->FFI_OpenFile)
533     return m_pInfo->FFI_OpenFile(m_pInfo, fileType, wsURL, mode);
534   return nullptr;
535 }
536 
DownloadFromURL(const WideString & url)537 RetainPtr<IFX_SeekableReadStream> CPDFSDK_FormFillEnvironment::DownloadFromURL(
538     const WideString& url) {
539   if (!m_pInfo || m_pInfo->version < 2 || !m_pInfo->FFI_DownloadFromURL) {
540     return nullptr;
541   }
542 
543   ByteString bstrURL = url.ToUTF16LE();
544   FPDF_FILEHANDLER* file_handler =
545       m_pInfo->FFI_DownloadFromURL(m_pInfo, AsFPDFWideString(&bstrURL));
546   if (!file_handler) {
547     return nullptr;
548   }
549 
550   return MakeSeekableStream(file_handler);
551 }
552 
PostRequestURL(const WideString & wsURL,const WideString & wsData,const WideString & wsContentType,const WideString & wsEncode,const WideString & wsHeader)553 WideString CPDFSDK_FormFillEnvironment::PostRequestURL(
554     const WideString& wsURL,
555     const WideString& wsData,
556     const WideString& wsContentType,
557     const WideString& wsEncode,
558     const WideString& wsHeader) {
559   if (!m_pInfo || m_pInfo->version < 2 || !m_pInfo->FFI_PostRequestURL)
560     return WideString();
561 
562   ByteString bsURL = wsURL.ToUTF16LE();
563   ByteString bsData = wsData.ToUTF16LE();
564   ByteString bsContentType = wsContentType.ToUTF16LE();
565   ByteString bsEncode = wsEncode.ToUTF16LE();
566   ByteString bsHeader = wsHeader.ToUTF16LE();
567 
568   FPDF_BSTR response;
569   FPDF_BStr_Init(&response);
570   m_pInfo->FFI_PostRequestURL(
571       m_pInfo, AsFPDFWideString(&bsURL), AsFPDFWideString(&bsData),
572       AsFPDFWideString(&bsContentType), AsFPDFWideString(&bsEncode),
573       AsFPDFWideString(&bsHeader), &response);
574 
575   // SAFETY: required from FFI callback.
576   WideString wsRet = WideString::FromUTF16LE(UNSAFE_BUFFERS(
577       pdfium::make_span(reinterpret_cast<const uint8_t*>(response.str),
578                         static_cast<size_t>(response.len))));
579 
580   FPDF_BStr_Clear(&response);
581   return wsRet;
582 }
583 
PutRequestURL(const WideString & wsURL,const WideString & wsData,const WideString & wsEncode)584 FPDF_BOOL CPDFSDK_FormFillEnvironment::PutRequestURL(
585     const WideString& wsURL,
586     const WideString& wsData,
587     const WideString& wsEncode) {
588   if (!m_pInfo || m_pInfo->version < 2 || !m_pInfo->FFI_PutRequestURL)
589     return false;
590 
591   ByteString bsURL = wsURL.ToUTF16LE();
592   ByteString bsData = wsData.ToUTF16LE();
593   ByteString bsEncode = wsEncode.ToUTF16LE();
594 
595   return m_pInfo->FFI_PutRequestURL(m_pInfo, AsFPDFWideString(&bsURL),
596                                     AsFPDFWideString(&bsData),
597                                     AsFPDFWideString(&bsEncode));
598 }
599 
PageEvent(int iPageCount,uint32_t dwEventType) const600 void CPDFSDK_FormFillEnvironment::PageEvent(int iPageCount,
601                                             uint32_t dwEventType) const {
602   if (m_pInfo && m_pInfo->version >= 2 && m_pInfo->FFI_PageEvent)
603     m_pInfo->FFI_PageEvent(m_pInfo, iPageCount, dwEventType);
604 }
605 #endif  // PDF_ENABLE_XFA
606 
ClearAllFocusedAnnots()607 void CPDFSDK_FormFillEnvironment::ClearAllFocusedAnnots() {
608   for (auto& it : m_PageMap) {
609     if (it.second->IsValidSDKAnnot(GetFocusAnnot())) {
610       ObservedPtr<CPDFSDK_PageView> pObserved(it.second.get());
611       KillFocusAnnot({});
612       if (!pObserved)
613         break;
614     }
615   }
616 }
617 
GetOrCreatePageView(IPDF_Page * pUnderlyingPage)618 CPDFSDK_PageView* CPDFSDK_FormFillEnvironment::GetOrCreatePageView(
619     IPDF_Page* pUnderlyingPage) {
620   CPDFSDK_PageView* pExisting = GetPageView(pUnderlyingPage);
621   if (pExisting)
622     return pExisting;
623 
624   auto pNew = std::make_unique<CPDFSDK_PageView>(this, pUnderlyingPage);
625   CPDFSDK_PageView* pPageView = pNew.get();
626   m_PageMap[pUnderlyingPage] = std::move(pNew);
627 
628   // Delay to load all the annotations, to avoid endless loop.
629   pPageView->LoadFXAnnots();
630   return pPageView;
631 }
632 
GetPageView(IPDF_Page * pUnderlyingPage)633 CPDFSDK_PageView* CPDFSDK_FormFillEnvironment::GetPageView(
634     IPDF_Page* pUnderlyingPage) {
635   auto it = m_PageMap.find(pUnderlyingPage);
636   return it != m_PageMap.end() ? it->second.get() : nullptr;
637 }
638 
GetTimerHandler()639 CFX_Timer::HandlerIface* CPDFSDK_FormFillEnvironment::GetTimerHandler() {
640   return this;
641 }
642 
GetPageViewAtIndex(int nIndex)643 CPDFSDK_PageView* CPDFSDK_FormFillEnvironment::GetPageViewAtIndex(int nIndex) {
644   IPDF_Page* pTempPage = GetPage(nIndex);
645   return pTempPage ? GetPageView(pTempPage) : nullptr;
646 }
647 
ProcJavascriptAction()648 void CPDFSDK_FormFillEnvironment::ProcJavascriptAction() {
649   auto name_tree = CPDF_NameTree::Create(m_pCPDFDoc, "JavaScript");
650   if (!name_tree)
651     return;
652 
653   size_t count = name_tree->GetCount();
654   for (size_t i = 0; i < count; ++i) {
655     WideString name;
656     CPDF_Action action(ToDictionary(name_tree->LookupValueAndName(i, &name)));
657     DoActionJavaScript(action, name);
658   }
659 }
660 
ProcOpenAction()661 bool CPDFSDK_FormFillEnvironment::ProcOpenAction() {
662   const CPDF_Dictionary* pRoot = m_pCPDFDoc->GetRoot();
663   if (!pRoot)
664     return false;
665 
666   RetainPtr<const CPDF_Object> pOpenAction(pRoot->GetDictFor("OpenAction"));
667   if (!pOpenAction)
668     pOpenAction = pRoot->GetArrayFor("OpenAction");
669   if (!pOpenAction)
670     return false;
671 
672   if (pOpenAction->IsArray())
673     return true;
674 
675   RetainPtr<const CPDF_Dictionary> pDict = ToDictionary(pOpenAction);
676   if (!pDict)
677     return false;
678 
679   DoActionDocOpen(CPDF_Action(std::move(pDict)));
680   return true;
681 }
682 
RemovePageView(IPDF_Page * pUnderlyingPage)683 void CPDFSDK_FormFillEnvironment::RemovePageView(IPDF_Page* pUnderlyingPage) {
684   auto it = m_PageMap.find(pUnderlyingPage);
685   if (it == m_PageMap.end())
686     return;
687 
688   CPDFSDK_PageView* pPageView = it->second.get();
689   if (pPageView->IsLocked() || pPageView->IsBeingDestroyed())
690     return;
691 
692   // Mark the page view so we do not come into |RemovePageView| a second
693   // time while we're in the process of removing.
694   pPageView->SetBeingDestroyed();
695 
696   // This must happen before we remove |pPageView| from the map because
697   // |KillFocusAnnot| can call into the |GetPage| method which will
698   // look for this page view in the map, if it doesn't find it a new one will
699   // be created. We then have two page views pointing to the same page and
700   // bad things happen.
701   if (pPageView->IsValidSDKAnnot(GetFocusAnnot()))
702     KillFocusAnnot({});
703 
704   // Remove the page from the map to make sure we don't accidentally attempt
705   // to use the |pPageView| while we're cleaning it up.
706   m_PageMap.erase(it);
707 }
708 
GetPage(int nIndex) const709 IPDF_Page* CPDFSDK_FormFillEnvironment::GetPage(int nIndex) const {
710   if (!m_pInfo || !m_pInfo->FFI_GetPage)
711     return nullptr;
712   return IPDFPageFromFPDFPage(m_pInfo->FFI_GetPage(
713       m_pInfo, FPDFDocumentFromCPDFDocument(m_pCPDFDoc), nIndex));
714 }
715 
GetInteractiveForm()716 CPDFSDK_InteractiveForm* CPDFSDK_FormFillEnvironment::GetInteractiveForm() {
717   if (!m_pInteractiveForm)
718     m_pInteractiveForm = std::make_unique<CPDFSDK_InteractiveForm>(this);
719   return m_pInteractiveForm.get();
720 }
721 
UpdateAllViews(CPDFSDK_Annot * pAnnot)722 void CPDFSDK_FormFillEnvironment::UpdateAllViews(CPDFSDK_Annot* pAnnot) {
723   for (const auto& it : m_PageMap) {
724     ObservedPtr<CPDFSDK_PageView> pObserved(it.second.get());
725     if (pObserved) {
726       pObserved->UpdateView(pAnnot);
727       if (!pObserved)
728         break;
729     }
730   }
731 }
732 
GetFocusAnnot() const733 CPDFSDK_Annot* CPDFSDK_FormFillEnvironment::GetFocusAnnot() const {
734   return m_pFocusAnnot.Get();
735 }
736 
SetFocusAnnot(ObservedPtr<CPDFSDK_Annot> & pAnnot)737 bool CPDFSDK_FormFillEnvironment::SetFocusAnnot(
738     ObservedPtr<CPDFSDK_Annot>& pAnnot) {
739   if (m_bBeingDestroyed)
740     return false;
741   if (m_pFocusAnnot == pAnnot)
742     return true;
743   if (m_pFocusAnnot && !KillFocusAnnot({}))
744     return false;
745   if (!pAnnot)
746     return false;
747   if (!pAnnot->GetPageView()->IsValid())
748     return false;
749 
750   if (m_pFocusAnnot)
751     return false;
752 
753 #ifdef PDF_ENABLE_XFA
754   CPDFXFA_Widget* pXFAWidget = pAnnot->AsXFAWidget();
755   if (pXFAWidget && pXFAWidget->OnChangedFocus())
756     return false;
757 
758   // `pAnnot` may be destroyed in `OnChangedFocus()`.
759   if (!pAnnot)
760     return false;
761 #endif  // PDF_ENABLE_XFA
762 
763   if (!CPDFSDK_Annot::OnSetFocus(pAnnot, {})) {
764     return false;
765   }
766   if (m_pFocusAnnot) {
767     return false;
768   }
769   m_pFocusAnnot = pAnnot;
770 
771   // If we are not able to inform the client about the focus change, it
772   // shouldn't be considered as failure.
773   SendOnFocusChange(pAnnot);
774   return true;
775 }
776 
KillFocusAnnot(Mask<FWL_EVENTFLAG> nFlags)777 bool CPDFSDK_FormFillEnvironment::KillFocusAnnot(Mask<FWL_EVENTFLAG> nFlags) {
778   if (!m_pFocusAnnot)
779     return false;
780 
781   ObservedPtr<CPDFSDK_Annot> pFocusAnnot(m_pFocusAnnot.Get());
782   m_pFocusAnnot.Reset();
783 
784   if (!CPDFSDK_Annot::OnKillFocus(pFocusAnnot, nFlags)) {
785     m_pFocusAnnot = pFocusAnnot;
786     return false;
787   }
788 
789   // Might have been destroyed by OnKillFocus().
790   if (!pFocusAnnot)
791     return false;
792 
793   if (pFocusAnnot->GetAnnotSubtype() == CPDF_Annot::Subtype::WIDGET) {
794     const FormFieldType field_type =
795         ToCPDFSDKWidget(pFocusAnnot.Get())->GetFieldType();
796     if (field_type == FormFieldType::kTextField ||
797         field_type == FormFieldType::kComboBox) {
798       OnSetFieldInputFocusInternal(WideString(), false);
799     }
800   }
801   return !m_pFocusAnnot;
802 }
803 
GetPageCount() const804 int CPDFSDK_FormFillEnvironment::GetPageCount() const {
805   CPDF_Document::Extension* pExtension = m_pCPDFDoc->GetExtension();
806   return pExtension ? pExtension->GetPageCount() : m_pCPDFDoc->GetPageCount();
807 }
808 
HasPermissions(uint32_t flags) const809 bool CPDFSDK_FormFillEnvironment::HasPermissions(uint32_t flags) const {
810   return !!(m_pCPDFDoc->GetUserPermissions(/*get_owner_perms=*/true) & flags);
811 }
812 
SendOnFocusChange(ObservedPtr<CPDFSDK_Annot> & pAnnot)813 void CPDFSDK_FormFillEnvironment::SendOnFocusChange(
814     ObservedPtr<CPDFSDK_Annot>& pAnnot) {
815   if (!m_pInfo || m_pInfo->version < 2 || !m_pInfo->FFI_OnFocusChange)
816     return;
817 
818   // TODO(crbug.com/pdfium/1482): Handle XFA case.
819   if (pAnnot->AsXFAWidget())
820     return;
821 
822   CPDFSDK_PageView* pPageView = pAnnot->GetPageView();
823   if (!pPageView->IsValid())
824     return;
825 
826   IPDF_Page* page = pAnnot->GetPage();
827   if (!page)
828     return;
829 
830   RetainPtr<CPDF_Dictionary> annot_dict =
831       pAnnot->GetPDFAnnot()->GetMutableAnnotDict();
832   auto focused_annot = std::make_unique<CPDF_AnnotContext>(annot_dict, page);
833   FPDF_ANNOTATION fpdf_annot =
834       FPDFAnnotationFromCPDFAnnotContext(focused_annot.get());
835 
836   m_pInfo->FFI_OnFocusChange(m_pInfo, fpdf_annot, pPageView->GetPageIndex());
837 }
838 
DoActionDocOpen(const CPDF_Action & action)839 bool CPDFSDK_FormFillEnvironment::DoActionDocOpen(const CPDF_Action& action) {
840   std::set<const CPDF_Dictionary*> visited;
841   return ExecuteDocumentOpenAction(action, &visited);
842 }
843 
DoActionJavaScript(const CPDF_Action & JsAction,WideString csJSName)844 bool CPDFSDK_FormFillEnvironment::DoActionJavaScript(
845     const CPDF_Action& JsAction,
846     WideString csJSName) {
847   if (JsAction.GetType() == CPDF_Action::Type::kJavaScript) {
848     WideString swJS = JsAction.GetJavaScript();
849     if (!swJS.IsEmpty()) {
850       RunDocumentOpenJavaScript(csJSName, swJS);
851       return true;
852     }
853   }
854 
855   return false;
856 }
857 
DoActionFieldJavaScript(const CPDF_Action & JsAction,CPDF_AAction::AActionType type,CPDF_FormField * pFormField,CFFL_FieldAction * data)858 bool CPDFSDK_FormFillEnvironment::DoActionFieldJavaScript(
859     const CPDF_Action& JsAction,
860     CPDF_AAction::AActionType type,
861     CPDF_FormField* pFormField,
862     CFFL_FieldAction* data) {
863   if (IsJSPlatformPresent() &&
864       JsAction.GetType() == CPDF_Action::Type::kJavaScript) {
865     WideString swJS = JsAction.GetJavaScript();
866     if (!swJS.IsEmpty()) {
867       RunFieldJavaScript(pFormField, type, data, swJS);
868       return true;
869     }
870   }
871   return false;
872 }
873 
DoActionLink(const CPDF_Action & action,CPDF_AAction::AActionType type,Mask<FWL_EVENTFLAG> modifiers)874 bool CPDFSDK_FormFillEnvironment::DoActionLink(const CPDF_Action& action,
875                                                CPDF_AAction::AActionType type,
876                                                Mask<FWL_EVENTFLAG> modifiers) {
877   if (!CPDF_AAction::IsUserInput(type))
878     return false;
879 
880   switch (action.GetType()) {
881     case CPDF_Action::Type::kGoTo:
882       DoActionGoTo(action);
883       return true;
884     case CPDF_Action::Type::kURI:
885       DoActionURI(action, modifiers);
886       return true;
887     default:
888       return false;
889   }
890 }
891 
DoActionDestination(const CPDF_Dest & dest)892 bool CPDFSDK_FormFillEnvironment::DoActionDestination(const CPDF_Dest& dest) {
893   CPDF_Document* document = GetPDFDocument();
894   DCHECK(document);
895 
896   std::vector<float> positions = dest.GetScrollPositionArray();
897   DoGoToAction(dest.GetDestPageIndex(document), dest.GetZoomMode(), positions);
898   return true;
899 }
900 
DoActionPage(const CPDF_Action & action,CPDF_AAction::AActionType eType)901 bool CPDFSDK_FormFillEnvironment::DoActionPage(
902     const CPDF_Action& action,
903     CPDF_AAction::AActionType eType) {
904   std::set<const CPDF_Dictionary*> visited;
905   return ExecuteDocumentPageAction(action, eType, &visited);
906 }
907 
DoActionDocument(const CPDF_Action & action,CPDF_AAction::AActionType eType)908 bool CPDFSDK_FormFillEnvironment::DoActionDocument(
909     const CPDF_Action& action,
910     CPDF_AAction::AActionType eType) {
911   std::set<const CPDF_Dictionary*> visited;
912   return ExecuteDocumentPageAction(action, eType, &visited);
913 }
914 
DoActionField(const CPDF_Action & action,CPDF_AAction::AActionType type,CPDF_FormField * pFormField,CFFL_FieldAction * data)915 bool CPDFSDK_FormFillEnvironment::DoActionField(const CPDF_Action& action,
916                                                 CPDF_AAction::AActionType type,
917                                                 CPDF_FormField* pFormField,
918                                                 CFFL_FieldAction* data) {
919   std::set<const CPDF_Dictionary*> visited;
920   return ExecuteFieldAction(action, type, pFormField, data, &visited);
921 }
922 
ExecuteDocumentOpenAction(const CPDF_Action & action,std::set<const CPDF_Dictionary * > * visited)923 bool CPDFSDK_FormFillEnvironment::ExecuteDocumentOpenAction(
924     const CPDF_Action& action,
925     std::set<const CPDF_Dictionary*>* visited) {
926   const CPDF_Dictionary* pDict = action.GetDict();
927   if (pdfium::Contains(*visited, pDict))
928     return false;
929 
930   visited->insert(pDict);
931 
932   if (action.GetType() == CPDF_Action::Type::kJavaScript) {
933     if (IsJSPlatformPresent()) {
934       WideString swJS = action.GetJavaScript();
935       if (!swJS.IsEmpty())
936         RunDocumentOpenJavaScript(WideString(), swJS);
937     }
938   } else {
939     DoActionNoJs(action, CPDF_AAction::AActionType::kDocumentOpen);
940   }
941 
942   for (size_t i = 0, sz = action.GetSubActionsCount(); i < sz; i++) {
943     CPDF_Action subaction = action.GetSubAction(i);
944     if (!ExecuteDocumentOpenAction(subaction, visited))
945       return false;
946   }
947 
948   return true;
949 }
950 
ExecuteDocumentPageAction(const CPDF_Action & action,CPDF_AAction::AActionType type,std::set<const CPDF_Dictionary * > * visited)951 bool CPDFSDK_FormFillEnvironment::ExecuteDocumentPageAction(
952     const CPDF_Action& action,
953     CPDF_AAction::AActionType type,
954     std::set<const CPDF_Dictionary*>* visited) {
955   const CPDF_Dictionary* pDict = action.GetDict();
956   if (pdfium::Contains(*visited, pDict))
957     return false;
958 
959   visited->insert(pDict);
960 
961   if (action.GetType() == CPDF_Action::Type::kJavaScript) {
962     if (IsJSPlatformPresent()) {
963       WideString swJS = action.GetJavaScript();
964       if (!swJS.IsEmpty())
965         RunDocumentPageJavaScript(type, swJS);
966     }
967   } else {
968     DoActionNoJs(action, type);
969   }
970 
971   for (size_t i = 0, sz = action.GetSubActionsCount(); i < sz; i++) {
972     CPDF_Action subaction = action.GetSubAction(i);
973     if (!ExecuteDocumentPageAction(subaction, type, visited))
974       return false;
975   }
976 
977   return true;
978 }
979 
IsValidField(const CPDF_Dictionary * pFieldDict)980 bool CPDFSDK_FormFillEnvironment::IsValidField(
981     const CPDF_Dictionary* pFieldDict) {
982   DCHECK(pFieldDict);
983 
984   CPDFSDK_InteractiveForm* pForm = GetInteractiveForm();
985   CPDF_InteractiveForm* pPDFForm = pForm->GetInteractiveForm();
986   return !!pPDFForm->GetFieldByDict(pFieldDict);
987 }
988 
ExecuteFieldAction(const CPDF_Action & action,CPDF_AAction::AActionType type,CPDF_FormField * pFormField,CFFL_FieldAction * data,std::set<const CPDF_Dictionary * > * visited)989 bool CPDFSDK_FormFillEnvironment::ExecuteFieldAction(
990     const CPDF_Action& action,
991     CPDF_AAction::AActionType type,
992     CPDF_FormField* pFormField,
993     CFFL_FieldAction* data,
994     std::set<const CPDF_Dictionary*>* visited) {
995   const CPDF_Dictionary* pDict = action.GetDict();
996   if (pdfium::Contains(*visited, pDict))
997     return false;
998 
999   visited->insert(pDict);
1000 
1001   if (action.GetType() == CPDF_Action::Type::kJavaScript) {
1002     if (IsJSPlatformPresent()) {
1003       WideString swJS = action.GetJavaScript();
1004       if (!swJS.IsEmpty()) {
1005         RunFieldJavaScript(pFormField, type, data, swJS);
1006         if (!IsValidField(pFormField->GetFieldDict()))
1007           return false;
1008       }
1009     }
1010   } else {
1011     DoActionNoJs(action, type);
1012   }
1013 
1014   for (size_t i = 0, sz = action.GetSubActionsCount(); i < sz; i++) {
1015     CPDF_Action subaction = action.GetSubAction(i);
1016     if (!ExecuteFieldAction(subaction, type, pFormField, data, visited))
1017       return false;
1018   }
1019 
1020   return true;
1021 }
1022 
DoActionNoJs(const CPDF_Action & action,CPDF_AAction::AActionType type)1023 void CPDFSDK_FormFillEnvironment::DoActionNoJs(const CPDF_Action& action,
1024                                                CPDF_AAction::AActionType type) {
1025   switch (action.GetType()) {
1026     case CPDF_Action::Type::kGoTo:
1027       DoActionGoTo(action);
1028       break;
1029     case CPDF_Action::Type::kURI:
1030       if (CPDF_AAction::IsUserInput(type))
1031         DoActionURI(action, Mask<FWL_EVENTFLAG>{});
1032       break;
1033     case CPDF_Action::Type::kHide:
1034       DoActionHide(action);
1035       break;
1036     case CPDF_Action::Type::kNamed:
1037       DoActionNamed(action);
1038       break;
1039     case CPDF_Action::Type::kSubmitForm:
1040       if (CPDF_AAction::IsUserInput(type))
1041         DoActionSubmitForm(action);
1042       break;
1043     case CPDF_Action::Type::kResetForm:
1044       DoActionResetForm(action);
1045       break;
1046     case CPDF_Action::Type::kJavaScript:
1047       NOTREACHED_NORETURN();
1048     case CPDF_Action::Type::kSetOCGState:
1049     case CPDF_Action::Type::kThread:
1050     case CPDF_Action::Type::kSound:
1051     case CPDF_Action::Type::kMovie:
1052     case CPDF_Action::Type::kRendition:
1053     case CPDF_Action::Type::kTrans:
1054     case CPDF_Action::Type::kGoTo3DView:
1055     case CPDF_Action::Type::kGoToR:
1056     case CPDF_Action::Type::kGoToE:
1057     case CPDF_Action::Type::kLaunch:
1058     case CPDF_Action::Type::kImportData:
1059       // Unimplemented
1060       break;
1061     default:
1062       break;
1063   }
1064 }
1065 
DoActionGoTo(const CPDF_Action & action)1066 void CPDFSDK_FormFillEnvironment::DoActionGoTo(const CPDF_Action& action) {
1067   DCHECK(action.GetDict());
1068 
1069   CPDF_Document* pPDFDocument = GetPDFDocument();
1070   DCHECK(pPDFDocument);
1071 
1072   CPDF_Dest MyDest = action.GetDest(pPDFDocument);
1073   DoActionDestination(MyDest);
1074 }
1075 
DoActionURI(const CPDF_Action & action,Mask<FWL_EVENTFLAG> modifiers)1076 void CPDFSDK_FormFillEnvironment::DoActionURI(const CPDF_Action& action,
1077                                               Mask<FWL_EVENTFLAG> modifiers) {
1078   DCHECK(action.GetDict());
1079   DoURIAction(action.GetURI(GetPDFDocument()), modifiers);
1080 }
1081 
DoActionNamed(const CPDF_Action & action)1082 void CPDFSDK_FormFillEnvironment::DoActionNamed(const CPDF_Action& action) {
1083   DCHECK(action.GetDict());
1084   ExecuteNamedAction(action.GetNamedAction());
1085 }
1086 
RunFieldJavaScript(CPDF_FormField * pFormField,CPDF_AAction::AActionType type,CFFL_FieldAction * data,const WideString & script)1087 void CPDFSDK_FormFillEnvironment::RunFieldJavaScript(
1088     CPDF_FormField* pFormField,
1089     CPDF_AAction::AActionType type,
1090     CFFL_FieldAction* data,
1091     const WideString& script) {
1092   DCHECK(type != CPDF_AAction::kCalculate);
1093   DCHECK(type != CPDF_AAction::kFormat);
1094 
1095   RunScript(script, [type, data, pFormField](IJS_EventContext* context) {
1096     switch (type) {
1097       case CPDF_AAction::kCursorEnter:
1098         context->OnField_MouseEnter(data->bModifier, data->bShift, pFormField);
1099         break;
1100       case CPDF_AAction::kCursorExit:
1101         context->OnField_MouseExit(data->bModifier, data->bShift, pFormField);
1102         break;
1103       case CPDF_AAction::kButtonDown:
1104         context->OnField_MouseDown(data->bModifier, data->bShift, pFormField);
1105         break;
1106       case CPDF_AAction::kButtonUp:
1107         context->OnField_MouseUp(data->bModifier, data->bShift, pFormField);
1108         break;
1109       case CPDF_AAction::kGetFocus:
1110         context->OnField_Focus(data->bModifier, data->bShift, pFormField,
1111                                &data->sValue);
1112         break;
1113       case CPDF_AAction::kLoseFocus:
1114         context->OnField_Blur(data->bModifier, data->bShift, pFormField,
1115                               &data->sValue);
1116         break;
1117       case CPDF_AAction::kKeyStroke:
1118         context->OnField_Keystroke(
1119             &data->sChange, data->sChangeEx, data->bKeyDown, data->bModifier,
1120             &data->nSelEnd, &data->nSelStart, data->bShift, pFormField,
1121             &data->sValue, data->bWillCommit, data->bFieldFull, &data->bRC);
1122         break;
1123       case CPDF_AAction::kValidate:
1124         context->OnField_Validate(&data->sChange, data->sChangeEx,
1125                                   data->bKeyDown, data->bModifier, data->bShift,
1126                                   pFormField, &data->sValue, &data->bRC);
1127         break;
1128       default:
1129         NOTREACHED_NORETURN();
1130     }
1131   });
1132 }
1133 
RunDocumentOpenJavaScript(const WideString & sScriptName,const WideString & script)1134 void CPDFSDK_FormFillEnvironment::RunDocumentOpenJavaScript(
1135     const WideString& sScriptName,
1136     const WideString& script) {
1137   RunScript(script, [sScriptName](IJS_EventContext* context) {
1138     context->OnDoc_Open(sScriptName);
1139   });
1140 }
1141 
RunDocumentPageJavaScript(CPDF_AAction::AActionType type,const WideString & script)1142 void CPDFSDK_FormFillEnvironment::RunDocumentPageJavaScript(
1143     CPDF_AAction::AActionType type,
1144     const WideString& script) {
1145   RunScript(script, [type](IJS_EventContext* context) {
1146     switch (type) {
1147       case CPDF_AAction::kOpenPage:
1148         context->OnPage_Open();
1149         break;
1150       case CPDF_AAction::kClosePage:
1151         context->OnPage_Close();
1152         break;
1153       case CPDF_AAction::kCloseDocument:
1154         context->OnDoc_WillClose();
1155         break;
1156       case CPDF_AAction::kSaveDocument:
1157         context->OnDoc_WillSave();
1158         break;
1159       case CPDF_AAction::kDocumentSaved:
1160         context->OnDoc_DidSave();
1161         break;
1162       case CPDF_AAction::kPrintDocument:
1163         context->OnDoc_WillPrint();
1164         break;
1165       case CPDF_AAction::kDocumentPrinted:
1166         context->OnDoc_DidPrint();
1167         break;
1168       case CPDF_AAction::kPageVisible:
1169         context->OnPage_InView();
1170         break;
1171       case CPDF_AAction::kPageInvisible:
1172         context->OnPage_OutView();
1173         break;
1174       default:
1175         NOTREACHED_NORETURN();
1176     }
1177   });
1178 }
1179 
DoActionHide(const CPDF_Action & action)1180 bool CPDFSDK_FormFillEnvironment::DoActionHide(const CPDF_Action& action) {
1181   CPDFSDK_InteractiveForm* pForm = GetInteractiveForm();
1182   if (pForm->DoAction_Hide(action)) {
1183     SetChangeMark();
1184     return true;
1185   }
1186   return false;
1187 }
1188 
DoActionSubmitForm(const CPDF_Action & action)1189 bool CPDFSDK_FormFillEnvironment::DoActionSubmitForm(
1190     const CPDF_Action& action) {
1191   CPDFSDK_InteractiveForm* pForm = GetInteractiveForm();
1192   return pForm->DoAction_SubmitForm(action);
1193 }
1194 
DoActionResetForm(const CPDF_Action & action)1195 void CPDFSDK_FormFillEnvironment::DoActionResetForm(const CPDF_Action& action) {
1196   CPDFSDK_InteractiveForm* pForm = GetInteractiveForm();
1197   pForm->DoAction_ResetForm(action);
1198 }
1199 
RunScript(const WideString & script,const RunScriptCallback & cb)1200 void CPDFSDK_FormFillEnvironment::RunScript(const WideString& script,
1201                                             const RunScriptCallback& cb) {
1202   IJS_Runtime::ScopedEventContext pContext(GetIJSRuntime());
1203   cb(pContext.Get());
1204   pContext->RunScript(script);
1205   // TODO(dsinclair): Return error if RunScript returns a IJS_Runtime::JS_Error.
1206 }
1207