• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2014 PDFium Authors. All rights reserved.
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_actionhandler.h"
8 
9 #include <set>
10 #include <vector>
11 
12 #include "core/fpdfapi/parser/cpdf_array.h"
13 #include "core/fpdfdoc/cpdf_formfield.h"
14 #include "core/fpdfdoc/cpdf_interactiveform.h"
15 #include "fpdfsdk/cpdfsdk_formfillenvironment.h"
16 #include "fpdfsdk/cpdfsdk_interactiveform.h"
17 #include "fxjs/ijs_event_context.h"
18 #include "fxjs/ijs_runtime.h"
19 #include "third_party/base/logging.h"
20 #include "third_party/base/stl_util.h"
21 
DoAction_DocOpen(const CPDF_Action & action,CPDFSDK_FormFillEnvironment * pFormFillEnv)22 bool CPDFSDK_ActionHandler::DoAction_DocOpen(
23     const CPDF_Action& action,
24     CPDFSDK_FormFillEnvironment* pFormFillEnv) {
25   std::set<const CPDF_Dictionary*> visited;
26   return ExecuteDocumentOpenAction(action, pFormFillEnv, &visited);
27 }
28 
DoAction_JavaScript(const CPDF_Action & JsAction,WideString csJSName,CPDFSDK_FormFillEnvironment * pFormFillEnv)29 bool CPDFSDK_ActionHandler::DoAction_JavaScript(
30     const CPDF_Action& JsAction,
31     WideString csJSName,
32     CPDFSDK_FormFillEnvironment* pFormFillEnv) {
33   if (JsAction.GetType() == CPDF_Action::JavaScript) {
34     WideString swJS = JsAction.GetJavaScript();
35     if (!swJS.IsEmpty()) {
36       RunDocumentOpenJavaScript(pFormFillEnv, csJSName, swJS);
37       return true;
38     }
39   }
40 
41   return false;
42 }
43 
DoAction_FieldJavaScript(const CPDF_Action & JsAction,CPDF_AAction::AActionType type,CPDFSDK_FormFillEnvironment * pFormFillEnv,CPDF_FormField * pFormField,CPDFSDK_FieldAction * data)44 bool CPDFSDK_ActionHandler::DoAction_FieldJavaScript(
45     const CPDF_Action& JsAction,
46     CPDF_AAction::AActionType type,
47     CPDFSDK_FormFillEnvironment* pFormFillEnv,
48     CPDF_FormField* pFormField,
49     CPDFSDK_FieldAction* data) {
50   ASSERT(pFormFillEnv);
51   if (pFormFillEnv->IsJSPlatformPresent() &&
52       JsAction.GetType() == CPDF_Action::JavaScript) {
53     WideString swJS = JsAction.GetJavaScript();
54     if (!swJS.IsEmpty()) {
55       RunFieldJavaScript(pFormFillEnv, pFormField, type, data, swJS);
56       return true;
57     }
58   }
59   return false;
60 }
61 
DoAction_Page(const CPDF_Action & action,enum CPDF_AAction::AActionType eType,CPDFSDK_FormFillEnvironment * pFormFillEnv)62 bool CPDFSDK_ActionHandler::DoAction_Page(
63     const CPDF_Action& action,
64     enum CPDF_AAction::AActionType eType,
65     CPDFSDK_FormFillEnvironment* pFormFillEnv) {
66   std::set<const CPDF_Dictionary*> visited;
67   return ExecuteDocumentPageAction(action, eType, pFormFillEnv, &visited);
68 }
69 
DoAction_Document(const CPDF_Action & action,enum CPDF_AAction::AActionType eType,CPDFSDK_FormFillEnvironment * pFormFillEnv)70 bool CPDFSDK_ActionHandler::DoAction_Document(
71     const CPDF_Action& action,
72     enum CPDF_AAction::AActionType eType,
73     CPDFSDK_FormFillEnvironment* pFormFillEnv) {
74   std::set<const CPDF_Dictionary*> visited;
75   return ExecuteDocumentPageAction(action, eType, pFormFillEnv, &visited);
76 }
77 
DoAction_Field(const CPDF_Action & action,CPDF_AAction::AActionType type,CPDFSDK_FormFillEnvironment * pFormFillEnv,CPDF_FormField * pFormField,CPDFSDK_FieldAction * data)78 bool CPDFSDK_ActionHandler::DoAction_Field(
79     const CPDF_Action& action,
80     CPDF_AAction::AActionType type,
81     CPDFSDK_FormFillEnvironment* pFormFillEnv,
82     CPDF_FormField* pFormField,
83     CPDFSDK_FieldAction* data) {
84   std::set<const CPDF_Dictionary*> visited;
85   return ExecuteFieldAction(action, type, pFormFillEnv, pFormField, data,
86                             &visited);
87 }
88 
ExecuteDocumentOpenAction(const CPDF_Action & action,CPDFSDK_FormFillEnvironment * pFormFillEnv,std::set<const CPDF_Dictionary * > * visited)89 bool CPDFSDK_ActionHandler::ExecuteDocumentOpenAction(
90     const CPDF_Action& action,
91     CPDFSDK_FormFillEnvironment* pFormFillEnv,
92     std::set<const CPDF_Dictionary*>* visited) {
93   const CPDF_Dictionary* pDict = action.GetDict();
94   if (pdfium::ContainsKey(*visited, pDict))
95     return false;
96 
97   visited->insert(pDict);
98 
99   ASSERT(pFormFillEnv);
100   if (action.GetType() == CPDF_Action::JavaScript) {
101     if (pFormFillEnv->IsJSPlatformPresent()) {
102       WideString swJS = action.GetJavaScript();
103       if (!swJS.IsEmpty())
104         RunDocumentOpenJavaScript(pFormFillEnv, WideString(), swJS);
105     }
106   } else {
107     DoAction_NoJs(action, CPDF_AAction::AActionType::kDocumentOpen,
108                   pFormFillEnv);
109   }
110 
111   for (int32_t i = 0, sz = action.GetSubActionsCount(); i < sz; i++) {
112     CPDF_Action subaction = action.GetSubAction(i);
113     if (!ExecuteDocumentOpenAction(subaction, pFormFillEnv, visited))
114       return false;
115   }
116 
117   return true;
118 }
119 
ExecuteDocumentPageAction(const CPDF_Action & action,CPDF_AAction::AActionType type,CPDFSDK_FormFillEnvironment * pFormFillEnv,std::set<const CPDF_Dictionary * > * visited)120 bool CPDFSDK_ActionHandler::ExecuteDocumentPageAction(
121     const CPDF_Action& action,
122     CPDF_AAction::AActionType type,
123     CPDFSDK_FormFillEnvironment* pFormFillEnv,
124     std::set<const CPDF_Dictionary*>* visited) {
125   const CPDF_Dictionary* pDict = action.GetDict();
126   if (pdfium::ContainsKey(*visited, pDict))
127     return false;
128 
129   visited->insert(pDict);
130 
131   ASSERT(pFormFillEnv);
132   if (action.GetType() == CPDF_Action::JavaScript) {
133     if (pFormFillEnv->IsJSPlatformPresent()) {
134       WideString swJS = action.GetJavaScript();
135       if (!swJS.IsEmpty())
136         RunDocumentPageJavaScript(pFormFillEnv, type, swJS);
137     }
138   } else {
139     DoAction_NoJs(action, type, pFormFillEnv);
140   }
141 
142   ASSERT(pFormFillEnv);
143 
144   for (int32_t i = 0, sz = action.GetSubActionsCount(); i < sz; i++) {
145     CPDF_Action subaction = action.GetSubAction(i);
146     if (!ExecuteDocumentPageAction(subaction, type, pFormFillEnv, visited))
147       return false;
148   }
149 
150   return true;
151 }
152 
IsValidField(CPDFSDK_FormFillEnvironment * pFormFillEnv,CPDF_Dictionary * pFieldDict)153 bool CPDFSDK_ActionHandler::IsValidField(
154     CPDFSDK_FormFillEnvironment* pFormFillEnv,
155     CPDF_Dictionary* pFieldDict) {
156   ASSERT(pFieldDict);
157 
158   CPDFSDK_InteractiveForm* pForm = pFormFillEnv->GetInteractiveForm();
159   CPDF_InteractiveForm* pPDFForm = pForm->GetInteractiveForm();
160   return !!pPDFForm->GetFieldByDict(pFieldDict);
161 }
162 
ExecuteFieldAction(const CPDF_Action & action,CPDF_AAction::AActionType type,CPDFSDK_FormFillEnvironment * pFormFillEnv,CPDF_FormField * pFormField,CPDFSDK_FieldAction * data,std::set<const CPDF_Dictionary * > * visited)163 bool CPDFSDK_ActionHandler::ExecuteFieldAction(
164     const CPDF_Action& action,
165     CPDF_AAction::AActionType type,
166     CPDFSDK_FormFillEnvironment* pFormFillEnv,
167     CPDF_FormField* pFormField,
168     CPDFSDK_FieldAction* data,
169     std::set<const CPDF_Dictionary*>* visited) {
170   const CPDF_Dictionary* pDict = action.GetDict();
171   if (pdfium::ContainsKey(*visited, pDict))
172     return false;
173 
174   visited->insert(pDict);
175 
176   ASSERT(pFormFillEnv);
177   if (action.GetType() == CPDF_Action::JavaScript) {
178     if (pFormFillEnv->IsJSPlatformPresent()) {
179       WideString swJS = action.GetJavaScript();
180       if (!swJS.IsEmpty()) {
181         RunFieldJavaScript(pFormFillEnv, pFormField, type, data, swJS);
182         if (!IsValidField(pFormFillEnv, pFormField->GetFieldDict()))
183           return false;
184       }
185     }
186   } else {
187     DoAction_NoJs(action, type, pFormFillEnv);
188   }
189 
190   for (int32_t i = 0, sz = action.GetSubActionsCount(); i < sz; i++) {
191     CPDF_Action subaction = action.GetSubAction(i);
192     if (!ExecuteFieldAction(subaction, type, pFormFillEnv, pFormField, data,
193                             visited))
194       return false;
195   }
196 
197   return true;
198 }
199 
DoAction_NoJs(const CPDF_Action & action,CPDF_AAction::AActionType type,CPDFSDK_FormFillEnvironment * pFormFillEnv)200 void CPDFSDK_ActionHandler::DoAction_NoJs(
201     const CPDF_Action& action,
202     CPDF_AAction::AActionType type,
203     CPDFSDK_FormFillEnvironment* pFormFillEnv) {
204   ASSERT(pFormFillEnv);
205 
206   switch (action.GetType()) {
207     case CPDF_Action::GoTo:
208       DoAction_GoTo(pFormFillEnv, action);
209       break;
210     case CPDF_Action::URI:
211       if (CPDF_AAction::IsUserClick(type))
212         DoAction_URI(pFormFillEnv, action);
213       break;
214     case CPDF_Action::Hide:
215       DoAction_Hide(action, pFormFillEnv);
216       break;
217     case CPDF_Action::Named:
218       DoAction_Named(pFormFillEnv, action);
219       break;
220     case CPDF_Action::SubmitForm:
221       if (CPDF_AAction::IsUserClick(type))
222         DoAction_SubmitForm(action, pFormFillEnv);
223       break;
224     case CPDF_Action::ResetForm:
225       DoAction_ResetForm(action, pFormFillEnv);
226       break;
227     case CPDF_Action::JavaScript:
228       NOTREACHED();
229       break;
230     case CPDF_Action::SetOCGState:
231     case CPDF_Action::Thread:
232     case CPDF_Action::Sound:
233     case CPDF_Action::Movie:
234     case CPDF_Action::Rendition:
235     case CPDF_Action::Trans:
236     case CPDF_Action::GoTo3DView:
237     case CPDF_Action::GoToR:
238     case CPDF_Action::GoToE:
239     case CPDF_Action::Launch:
240     case CPDF_Action::ImportData:
241       // Unimplemented
242       break;
243     default:
244       break;
245   }
246 }
247 
DoAction_GoTo(CPDFSDK_FormFillEnvironment * pFormFillEnv,const CPDF_Action & action)248 void CPDFSDK_ActionHandler::DoAction_GoTo(
249     CPDFSDK_FormFillEnvironment* pFormFillEnv,
250     const CPDF_Action& action) {
251   ASSERT(action.GetDict());
252 
253   CPDF_Document* pPDFDocument = pFormFillEnv->GetPDFDocument();
254   ASSERT(pPDFDocument);
255 
256   CPDF_Dest MyDest = action.GetDest(pPDFDocument);
257   int nPageIndex = MyDest.GetDestPageIndex(pPDFDocument);
258   int nFitType = MyDest.GetZoomMode();
259   const CPDF_Array* pMyArray = MyDest.GetArray();
260   std::vector<float> posArray;
261   if (pMyArray) {
262     for (size_t i = 2; i < pMyArray->size(); i++)
263       posArray.push_back(pMyArray->GetNumberAt(i));
264   }
265   pFormFillEnv->DoGoToAction(nPageIndex, nFitType, posArray.data(),
266                              posArray.size());
267 }
268 
DoAction_URI(CPDFSDK_FormFillEnvironment * pFormFillEnv,const CPDF_Action & action)269 void CPDFSDK_ActionHandler::DoAction_URI(
270     CPDFSDK_FormFillEnvironment* pFormFillEnv,
271     const CPDF_Action& action) {
272   ASSERT(action.GetDict());
273 
274   ByteString sURI = action.GetURI(pFormFillEnv->GetPDFDocument());
275   pFormFillEnv->DoURIAction(sURI.c_str());
276 }
277 
DoAction_Named(CPDFSDK_FormFillEnvironment * pFormFillEnv,const CPDF_Action & action)278 void CPDFSDK_ActionHandler::DoAction_Named(
279     CPDFSDK_FormFillEnvironment* pFormFillEnv,
280     const CPDF_Action& action) {
281   ASSERT(action.GetDict());
282 
283   ByteString csName = action.GetNamedAction();
284   pFormFillEnv->ExecuteNamedAction(csName.c_str());
285 }
286 
RunFieldJavaScript(CPDFSDK_FormFillEnvironment * pFormFillEnv,CPDF_FormField * pFormField,CPDF_AAction::AActionType type,CPDFSDK_FieldAction * data,const WideString & script)287 void CPDFSDK_ActionHandler::RunFieldJavaScript(
288     CPDFSDK_FormFillEnvironment* pFormFillEnv,
289     CPDF_FormField* pFormField,
290     CPDF_AAction::AActionType type,
291     CPDFSDK_FieldAction* data,
292     const WideString& script) {
293   ASSERT(type != CPDF_AAction::kCalculate);
294   ASSERT(type != CPDF_AAction::kFormat);
295 
296   RunScript(pFormFillEnv, script,
297             [type, data, pFormField](IJS_EventContext* context) {
298               switch (type) {
299                 case CPDF_AAction::kCursorEnter:
300                   context->OnField_MouseEnter(data->bModifier, data->bShift,
301                                               pFormField);
302                   break;
303                 case CPDF_AAction::kCursorExit:
304                   context->OnField_MouseExit(data->bModifier, data->bShift,
305                                              pFormField);
306                   break;
307                 case CPDF_AAction::kButtonDown:
308                   context->OnField_MouseDown(data->bModifier, data->bShift,
309                                              pFormField);
310                   break;
311                 case CPDF_AAction::kButtonUp:
312                   context->OnField_MouseUp(data->bModifier, data->bShift,
313                                            pFormField);
314                   break;
315                 case CPDF_AAction::kGetFocus:
316                   context->OnField_Focus(data->bModifier, data->bShift,
317                                          pFormField, &data->sValue);
318                   break;
319                 case CPDF_AAction::kLoseFocus:
320                   context->OnField_Blur(data->bModifier, data->bShift,
321                                         pFormField, &data->sValue);
322                   break;
323                 case CPDF_AAction::kKeyStroke:
324                   context->OnField_Keystroke(
325                       &data->sChange, data->sChangeEx, data->bKeyDown,
326                       data->bModifier, &data->nSelEnd, &data->nSelStart,
327                       data->bShift, pFormField, &data->sValue,
328                       data->bWillCommit, data->bFieldFull, &data->bRC);
329                   break;
330                 case CPDF_AAction::kValidate:
331                   context->OnField_Validate(&data->sChange, data->sChangeEx,
332                                             data->bKeyDown, data->bModifier,
333                                             data->bShift, pFormField,
334                                             &data->sValue, &data->bRC);
335                   break;
336                 default:
337                   NOTREACHED();
338                   break;
339               }
340             });
341 }
342 
RunDocumentOpenJavaScript(CPDFSDK_FormFillEnvironment * pFormFillEnv,const WideString & sScriptName,const WideString & script)343 void CPDFSDK_ActionHandler::RunDocumentOpenJavaScript(
344     CPDFSDK_FormFillEnvironment* pFormFillEnv,
345     const WideString& sScriptName,
346     const WideString& script) {
347   RunScript(pFormFillEnv, script,
348             [pFormFillEnv, sScriptName](IJS_EventContext* context) {
349               context->OnDoc_Open(pFormFillEnv, sScriptName);
350             });
351 }
352 
RunDocumentPageJavaScript(CPDFSDK_FormFillEnvironment * pFormFillEnv,CPDF_AAction::AActionType type,const WideString & script)353 void CPDFSDK_ActionHandler::RunDocumentPageJavaScript(
354     CPDFSDK_FormFillEnvironment* pFormFillEnv,
355     CPDF_AAction::AActionType type,
356     const WideString& script) {
357   RunScript(pFormFillEnv, script,
358             [type, pFormFillEnv](IJS_EventContext* context) {
359               switch (type) {
360                 case CPDF_AAction::kOpenPage:
361                   context->OnPage_Open(pFormFillEnv);
362                   break;
363                 case CPDF_AAction::kClosePage:
364                   context->OnPage_Close(pFormFillEnv);
365                   break;
366                 case CPDF_AAction::kCloseDocument:
367                   context->OnDoc_WillClose(pFormFillEnv);
368                   break;
369                 case CPDF_AAction::kSaveDocument:
370                   context->OnDoc_WillSave(pFormFillEnv);
371                   break;
372                 case CPDF_AAction::kDocumentSaved:
373                   context->OnDoc_DidSave(pFormFillEnv);
374                   break;
375                 case CPDF_AAction::kPrintDocument:
376                   context->OnDoc_WillPrint(pFormFillEnv);
377                   break;
378                 case CPDF_AAction::kDocumentPrinted:
379                   context->OnDoc_DidPrint(pFormFillEnv);
380                   break;
381                 case CPDF_AAction::kPageVisible:
382                   context->OnPage_InView(pFormFillEnv);
383                   break;
384                 case CPDF_AAction::kPageInvisible:
385                   context->OnPage_OutView(pFormFillEnv);
386                   break;
387                 default:
388                   NOTREACHED();
389                   break;
390               }
391             });
392 }
393 
DoAction_Hide(const CPDF_Action & action,CPDFSDK_FormFillEnvironment * pFormFillEnv)394 bool CPDFSDK_ActionHandler::DoAction_Hide(
395     const CPDF_Action& action,
396     CPDFSDK_FormFillEnvironment* pFormFillEnv) {
397   CPDFSDK_InteractiveForm* pForm = pFormFillEnv->GetInteractiveForm();
398   if (pForm->DoAction_Hide(action)) {
399     pFormFillEnv->SetChangeMark();
400     return true;
401   }
402   return false;
403 }
404 
DoAction_SubmitForm(const CPDF_Action & action,CPDFSDK_FormFillEnvironment * pFormFillEnv)405 bool CPDFSDK_ActionHandler::DoAction_SubmitForm(
406     const CPDF_Action& action,
407     CPDFSDK_FormFillEnvironment* pFormFillEnv) {
408   CPDFSDK_InteractiveForm* pForm = pFormFillEnv->GetInteractiveForm();
409   return pForm->DoAction_SubmitForm(action);
410 }
411 
DoAction_ResetForm(const CPDF_Action & action,CPDFSDK_FormFillEnvironment * pFormFillEnv)412 void CPDFSDK_ActionHandler::DoAction_ResetForm(
413     const CPDF_Action& action,
414     CPDFSDK_FormFillEnvironment* pFormFillEnv) {
415   CPDFSDK_InteractiveForm* pForm = pFormFillEnv->GetInteractiveForm();
416   pForm->DoAction_ResetForm(action);
417 }
418 
RunScript(CPDFSDK_FormFillEnvironment * pFormFillEnv,const WideString & script,const RunScriptCallback & cb)419 void CPDFSDK_ActionHandler::RunScript(CPDFSDK_FormFillEnvironment* pFormFillEnv,
420                                       const WideString& script,
421                                       const RunScriptCallback& cb) {
422   IJS_Runtime::ScopedEventContext pContext(pFormFillEnv->GetIJSRuntime());
423   cb(pContext.Get());
424   pContext->RunScript(script);
425   // TODO(dsinclair): Return error if RunScript returns a IJS_Runtime::JS_Error.
426 }
427