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