| OLD | NEW |
| (Empty) |
| 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/fpdfxfa/cpdfxfa_document.h" | |
| 8 | |
| 9 #include "core/fpdfapi/parser/cpdf_document.h" | |
| 10 #include "fpdfsdk/cpdfsdk_formfillenvironment.h" | |
| 11 #include "fpdfsdk/cpdfsdk_interform.h" | |
| 12 #include "fpdfsdk/cpdfsdk_pageview.h" | |
| 13 #include "fpdfsdk/fpdfxfa/cpdfxfa_page.h" | |
| 14 #include "fpdfsdk/fpdfxfa/cxfa_fwladaptertimermgr.h" | |
| 15 #include "fpdfsdk/fsdk_define.h" | |
| 16 #include "fpdfsdk/javascript/cjs_runtime.h" | |
| 17 #include "fpdfsdk/javascript/ijs_runtime.h" | |
| 18 #include "public/fpdf_formfill.h" | |
| 19 #include "third_party/base/ptr_util.h" | |
| 20 #include "xfa/fxfa/cxfa_eventparam.h" | |
| 21 #include "xfa/fxfa/xfa_ffapp.h" | |
| 22 #include "xfa/fxfa/xfa_ffdoc.h" | |
| 23 #include "xfa/fxfa/xfa_ffdocview.h" | |
| 24 #include "xfa/fxfa/xfa_ffpageview.h" | |
| 25 #include "xfa/fxfa/xfa_ffwidgethandler.h" | |
| 26 #include "xfa/fxfa/xfa_fontmgr.h" | |
| 27 | |
| 28 #ifndef _WIN32 | |
| 29 extern void SetLastError(int err); | |
| 30 extern int GetLastError(); | |
| 31 #endif | |
| 32 | |
| 33 CPDFXFA_Document::CPDFXFA_Document(std::unique_ptr<CPDF_Document> pPDFDoc) | |
| 34 : m_iDocType(DOCTYPE_PDF), | |
| 35 m_pPDFDoc(std::move(pPDFDoc)), | |
| 36 m_pFormFillEnv(nullptr), | |
| 37 m_pXFADocView(nullptr), | |
| 38 m_nLoadStatus(FXFA_LOADSTATUS_PRELOAD), | |
| 39 m_nPageCount(0), | |
| 40 m_DocEnv(this) { | |
| 41 m_pXFAApp = pdfium::MakeUnique<CXFA_FFApp>(this); | |
| 42 m_pXFAApp->SetDefaultFontMgr(pdfium::MakeUnique<CXFA_DefFontMgr>()); | |
| 43 } | |
| 44 | |
| 45 CPDFXFA_Document::~CPDFXFA_Document() { | |
| 46 m_nLoadStatus = FXFA_LOADSTATUS_CLOSING; | |
| 47 | |
| 48 // Must happen before we remove the form fill environment. | |
| 49 CloseXFADoc(); | |
| 50 | |
| 51 if (m_pFormFillEnv) { | |
| 52 m_pFormFillEnv->ClearAllFocusedAnnots(); | |
| 53 // Once we're deleted the FormFillEnvironment will point at a bad underlying | |
| 54 // doc so we need to reset it ... | |
| 55 m_pFormFillEnv->ResetXFADocument(); | |
| 56 m_pFormFillEnv = nullptr; | |
| 57 } | |
| 58 | |
| 59 m_nLoadStatus = FXFA_LOADSTATUS_CLOSED; | |
| 60 } | |
| 61 | |
| 62 void CPDFXFA_Document::CloseXFADoc() { | |
| 63 if (!m_pXFADoc) | |
| 64 return; | |
| 65 m_pXFADoc->CloseDoc(); | |
| 66 m_pXFADoc.reset(); | |
| 67 m_pXFADocView = nullptr; | |
| 68 } | |
| 69 | |
| 70 void CPDFXFA_Document::SetFormFillEnv( | |
| 71 CPDFSDK_FormFillEnvironment* pFormFillEnv) { | |
| 72 // The layout data can have pointers back into the script context. That | |
| 73 // context will be different if the form fill environment closes, so, force | |
| 74 // the layout data to clear. | |
| 75 if (m_pXFADoc && m_pXFADoc->GetXFADoc()) | |
| 76 m_pXFADoc->GetXFADoc()->ClearLayoutData(); | |
| 77 | |
| 78 m_pFormFillEnv = pFormFillEnv; | |
| 79 } | |
| 80 | |
| 81 FX_BOOL CPDFXFA_Document::LoadXFADoc() { | |
| 82 m_nLoadStatus = FXFA_LOADSTATUS_LOADING; | |
| 83 | |
| 84 if (!m_pPDFDoc) | |
| 85 return FALSE; | |
| 86 | |
| 87 m_XFAPageList.RemoveAll(); | |
| 88 | |
| 89 CXFA_FFApp* pApp = GetXFAApp(); | |
| 90 if (!pApp) | |
| 91 return FALSE; | |
| 92 | |
| 93 m_pXFADoc.reset(pApp->CreateDoc(&m_DocEnv, m_pPDFDoc.get())); | |
| 94 if (!m_pXFADoc) { | |
| 95 SetLastError(FPDF_ERR_XFALOAD); | |
| 96 return FALSE; | |
| 97 } | |
| 98 | |
| 99 CXFA_FFDocHandler* pDocHandler = pApp->GetDocHandler(); | |
| 100 if (!pDocHandler) { | |
| 101 SetLastError(FPDF_ERR_XFALOAD); | |
| 102 return FALSE; | |
| 103 } | |
| 104 | |
| 105 m_pXFADoc->StartLoad(); | |
| 106 int iStatus = m_pXFADoc->DoLoad(nullptr); | |
| 107 if (iStatus != XFA_PARSESTATUS_Done) { | |
| 108 CloseXFADoc(); | |
| 109 SetLastError(FPDF_ERR_XFALOAD); | |
| 110 return FALSE; | |
| 111 } | |
| 112 m_pXFADoc->StopLoad(); | |
| 113 m_pXFADoc->GetXFADoc()->InitScriptContext(GetJSERuntime()); | |
| 114 | |
| 115 if (m_pXFADoc->GetDocType() == XFA_DOCTYPE_Dynamic) | |
| 116 m_iDocType = DOCTYPE_DYNAMIC_XFA; | |
| 117 else | |
| 118 m_iDocType = DOCTYPE_STATIC_XFA; | |
| 119 | |
| 120 m_pXFADocView = m_pXFADoc->CreateDocView(XFA_DOCVIEW_View); | |
| 121 if (m_pXFADocView->StartLayout() < 0) { | |
| 122 CloseXFADoc(); | |
| 123 SetLastError(FPDF_ERR_XFALAYOUT); | |
| 124 return FALSE; | |
| 125 } | |
| 126 | |
| 127 m_pXFADocView->DoLayout(nullptr); | |
| 128 m_pXFADocView->StopLayout(); | |
| 129 m_nLoadStatus = FXFA_LOADSTATUS_LOADED; | |
| 130 | |
| 131 return TRUE; | |
| 132 } | |
| 133 | |
| 134 int CPDFXFA_Document::GetPageCount() const { | |
| 135 if (!m_pPDFDoc && !m_pXFADoc) | |
| 136 return 0; | |
| 137 | |
| 138 switch (m_iDocType) { | |
| 139 case DOCTYPE_PDF: | |
| 140 case DOCTYPE_STATIC_XFA: | |
| 141 if (m_pPDFDoc) | |
| 142 return m_pPDFDoc->GetPageCount(); | |
| 143 case DOCTYPE_DYNAMIC_XFA: | |
| 144 if (m_pXFADoc) | |
| 145 return m_pXFADocView->CountPageViews(); | |
| 146 default: | |
| 147 return 0; | |
| 148 } | |
| 149 } | |
| 150 | |
| 151 CPDFXFA_Page* CPDFXFA_Document::GetXFAPage(int page_index) { | |
| 152 if (page_index < 0) | |
| 153 return nullptr; | |
| 154 | |
| 155 CPDFXFA_Page* pPage = nullptr; | |
| 156 int nCount = m_XFAPageList.GetSize(); | |
| 157 if (nCount > 0 && page_index < nCount) { | |
| 158 pPage = m_XFAPageList.GetAt(page_index); | |
| 159 if (pPage) | |
| 160 pPage->Retain(); | |
| 161 } else { | |
| 162 m_nPageCount = GetPageCount(); | |
| 163 m_XFAPageList.SetSize(m_nPageCount); | |
| 164 } | |
| 165 if (pPage) | |
| 166 return pPage; | |
| 167 | |
| 168 pPage = new CPDFXFA_Page(this, page_index); | |
| 169 if (!pPage->LoadPage()) { | |
| 170 pPage->Release(); | |
| 171 return nullptr; | |
| 172 } | |
| 173 m_XFAPageList.SetAt(page_index, pPage); | |
| 174 return pPage; | |
| 175 } | |
| 176 | |
| 177 CPDFXFA_Page* CPDFXFA_Document::GetXFAPage(CXFA_FFPageView* pPage) const { | |
| 178 if (!pPage) | |
| 179 return nullptr; | |
| 180 | |
| 181 if (!m_pXFADoc) | |
| 182 return nullptr; | |
| 183 | |
| 184 if (m_iDocType != DOCTYPE_DYNAMIC_XFA) | |
| 185 return nullptr; | |
| 186 | |
| 187 int nSize = m_XFAPageList.GetSize(); | |
| 188 for (int i = 0; i < nSize; i++) { | |
| 189 CPDFXFA_Page* pTempPage = m_XFAPageList.GetAt(i); | |
| 190 if (!pTempPage) | |
| 191 continue; | |
| 192 if (pTempPage->GetXFAPageView() && pTempPage->GetXFAPageView() == pPage) | |
| 193 return pTempPage; | |
| 194 } | |
| 195 | |
| 196 return nullptr; | |
| 197 } | |
| 198 | |
| 199 void CPDFXFA_Document::DeletePage(int page_index) { | |
| 200 // Delete from the document first because, if GetPage was never called for | |
| 201 // this |page_index| then |m_XFAPageList| may have size < |page_index| even | |
| 202 // if it's a valid page in the document. | |
| 203 if (m_pPDFDoc) | |
| 204 m_pPDFDoc->DeletePage(page_index); | |
| 205 | |
| 206 if (page_index < 0 || page_index >= m_XFAPageList.GetSize()) | |
| 207 return; | |
| 208 | |
| 209 if (CPDFXFA_Page* pPage = m_XFAPageList.GetAt(page_index)) | |
| 210 pPage->Release(); | |
| 211 } | |
| 212 | |
| 213 void CPDFXFA_Document::RemovePage(CPDFXFA_Page* page) { | |
| 214 m_XFAPageList.SetAt(page->GetPageIndex(), nullptr); | |
| 215 } | |
| 216 | |
| 217 void CPDFXFA_Document::ClearChangeMark() { | |
| 218 if (m_pFormFillEnv) | |
| 219 m_pFormFillEnv->ClearChangeMark(); | |
| 220 } | |
| 221 | |
| 222 v8::Isolate* CPDFXFA_Document::GetJSERuntime() const { | |
| 223 if (!m_pFormFillEnv) | |
| 224 return nullptr; | |
| 225 | |
| 226 // XFA requires V8, if we have V8 then we have a CJS_Runtime and not the stub. | |
| 227 CJS_Runtime* runtime = | |
| 228 static_cast<CJS_Runtime*>(m_pFormFillEnv->GetJSRuntime()); | |
| 229 return runtime->GetIsolate(); | |
| 230 } | |
| 231 | |
| 232 void CPDFXFA_Document::GetAppName(CFX_WideString& wsName) { | |
| 233 if (m_pFormFillEnv) | |
| 234 wsName = m_pFormFillEnv->FFI_GetAppName(); | |
| 235 } | |
| 236 | |
| 237 void CPDFXFA_Document::GetLanguage(CFX_WideString& wsLanguage) { | |
| 238 if (m_pFormFillEnv) | |
| 239 wsLanguage = m_pFormFillEnv->GetLanguage(); | |
| 240 } | |
| 241 | |
| 242 void CPDFXFA_Document::GetPlatform(CFX_WideString& wsPlatform) { | |
| 243 if (m_pFormFillEnv) | |
| 244 wsPlatform = m_pFormFillEnv->GetPlatform(); | |
| 245 } | |
| 246 | |
| 247 void CPDFXFA_Document::Beep(uint32_t dwType) { | |
| 248 if (m_pFormFillEnv) | |
| 249 m_pFormFillEnv->JS_appBeep(dwType); | |
| 250 } | |
| 251 | |
| 252 int32_t CPDFXFA_Document::MsgBox(const CFX_WideString& wsMessage, | |
| 253 const CFX_WideString& wsTitle, | |
| 254 uint32_t dwIconType, | |
| 255 uint32_t dwButtonType) { | |
| 256 if (!m_pFormFillEnv) | |
| 257 return -1; | |
| 258 | |
| 259 uint32_t iconType = 0; | |
| 260 int iButtonType = 0; | |
| 261 switch (dwIconType) { | |
| 262 case XFA_MBICON_Error: | |
| 263 iconType |= 0; | |
| 264 break; | |
| 265 case XFA_MBICON_Warning: | |
| 266 iconType |= 1; | |
| 267 break; | |
| 268 case XFA_MBICON_Question: | |
| 269 iconType |= 2; | |
| 270 break; | |
| 271 case XFA_MBICON_Status: | |
| 272 iconType |= 3; | |
| 273 break; | |
| 274 } | |
| 275 switch (dwButtonType) { | |
| 276 case XFA_MB_OK: | |
| 277 iButtonType |= 0; | |
| 278 break; | |
| 279 case XFA_MB_OKCancel: | |
| 280 iButtonType |= 1; | |
| 281 break; | |
| 282 case XFA_MB_YesNo: | |
| 283 iButtonType |= 2; | |
| 284 break; | |
| 285 case XFA_MB_YesNoCancel: | |
| 286 iButtonType |= 3; | |
| 287 break; | |
| 288 } | |
| 289 int32_t iRet = m_pFormFillEnv->JS_appAlert(wsMessage.c_str(), wsTitle.c_str(), | |
| 290 iButtonType, iconType); | |
| 291 switch (iRet) { | |
| 292 case 1: | |
| 293 return XFA_IDOK; | |
| 294 case 2: | |
| 295 return XFA_IDCancel; | |
| 296 case 3: | |
| 297 return XFA_IDNo; | |
| 298 case 4: | |
| 299 return XFA_IDYes; | |
| 300 } | |
| 301 return XFA_IDYes; | |
| 302 } | |
| 303 | |
| 304 CFX_WideString CPDFXFA_Document::Response(const CFX_WideString& wsQuestion, | |
| 305 const CFX_WideString& wsTitle, | |
| 306 const CFX_WideString& wsDefaultAnswer, | |
| 307 FX_BOOL bMark) { | |
| 308 CFX_WideString wsAnswer; | |
| 309 if (!m_pFormFillEnv) | |
| 310 return wsAnswer; | |
| 311 | |
| 312 int nLength = 2048; | |
| 313 char* pBuff = new char[nLength]; | |
| 314 nLength = m_pFormFillEnv->JS_appResponse(wsQuestion.c_str(), wsTitle.c_str(), | |
| 315 wsDefaultAnswer.c_str(), nullptr, | |
| 316 bMark, pBuff, nLength); | |
| 317 if (nLength > 0) { | |
| 318 nLength = nLength > 2046 ? 2046 : nLength; | |
| 319 pBuff[nLength] = 0; | |
| 320 pBuff[nLength + 1] = 0; | |
| 321 wsAnswer = CFX_WideString::FromUTF16LE( | |
| 322 reinterpret_cast<const unsigned short*>(pBuff), | |
| 323 nLength / sizeof(unsigned short)); | |
| 324 } | |
| 325 delete[] pBuff; | |
| 326 return wsAnswer; | |
| 327 } | |
| 328 | |
| 329 IFX_SeekableReadStream* CPDFXFA_Document::DownloadURL( | |
| 330 const CFX_WideString& wsURL) { | |
| 331 return m_pFormFillEnv ? m_pFormFillEnv->DownloadFromURL(wsURL.c_str()) | |
| 332 : nullptr; | |
| 333 } | |
| 334 | |
| 335 FX_BOOL CPDFXFA_Document::PostRequestURL(const CFX_WideString& wsURL, | |
| 336 const CFX_WideString& wsData, | |
| 337 const CFX_WideString& wsContentType, | |
| 338 const CFX_WideString& wsEncode, | |
| 339 const CFX_WideString& wsHeader, | |
| 340 CFX_WideString& wsResponse) { | |
| 341 if (!m_pFormFillEnv) | |
| 342 return FALSE; | |
| 343 | |
| 344 wsResponse = m_pFormFillEnv->PostRequestURL( | |
| 345 wsURL.c_str(), wsData.c_str(), wsContentType.c_str(), wsEncode.c_str(), | |
| 346 wsHeader.c_str()); | |
| 347 return TRUE; | |
| 348 } | |
| 349 | |
| 350 FX_BOOL CPDFXFA_Document::PutRequestURL(const CFX_WideString& wsURL, | |
| 351 const CFX_WideString& wsData, | |
| 352 const CFX_WideString& wsEncode) { | |
| 353 return m_pFormFillEnv && | |
| 354 m_pFormFillEnv->PutRequestURL(wsURL.c_str(), wsData.c_str(), | |
| 355 wsEncode.c_str()); | |
| 356 } | |
| 357 | |
| 358 void CPDFXFA_Document::LoadString(int32_t iStringID, CFX_WideString& wsString) { | |
| 359 switch (iStringID) { | |
| 360 case XFA_IDS_ValidateFailed: | |
| 361 wsString = L"%s validation failed"; | |
| 362 return; | |
| 363 case XFA_IDS_CalcOverride: | |
| 364 wsString = L"Calculate Override"; | |
| 365 return; | |
| 366 case XFA_IDS_ModifyField: | |
| 367 wsString = L"Are you sure you want to modify this field?"; | |
| 368 return; | |
| 369 case XFA_IDS_NotModifyField: | |
| 370 wsString = L"You are not allowed to modify this field."; | |
| 371 return; | |
| 372 case XFA_IDS_AppName: | |
| 373 wsString = L"pdfium"; | |
| 374 return; | |
| 375 case XFA_IDS_Unable_TO_SET: | |
| 376 wsString = L"Unable to set "; | |
| 377 return; | |
| 378 case XFA_IDS_INVAlID_PROP_SET: | |
| 379 wsString = L"Invalid property set operation."; | |
| 380 return; | |
| 381 case XFA_IDS_NOT_DEFAUL_VALUE: | |
| 382 wsString = L" doesn't have a default property."; | |
| 383 return; | |
| 384 case XFA_IDS_UNABLE_SET_LANGUAGE: | |
| 385 wsString = L"Unable to set language value."; | |
| 386 return; | |
| 387 case XFA_IDS_UNABLE_SET_NUMPAGES: | |
| 388 wsString = L"Unable to set numPages value."; | |
| 389 return; | |
| 390 case XFA_IDS_UNABLE_SET_PLATFORM: | |
| 391 wsString = L"Unable to set platform value."; | |
| 392 return; | |
| 393 case XFA_IDS_UNABLE_SET_VARIATION: | |
| 394 wsString = L"Unable to set variation value."; | |
| 395 return; | |
| 396 case XFA_IDS_UNABLE_SET_VERSION: | |
| 397 wsString = L"Unable to set version value."; | |
| 398 return; | |
| 399 case XFA_IDS_UNABLE_SET_READY: | |
| 400 wsString = L"Unable to set ready value."; | |
| 401 return; | |
| 402 case XFA_IDS_COMPILER_ERROR: | |
| 403 wsString = L"Compiler error."; | |
| 404 return; | |
| 405 case XFA_IDS_DIVIDE_ZERO: | |
| 406 wsString = L"Divide by zero."; | |
| 407 return; | |
| 408 case XFA_IDS_ACCESS_PROPERTY_IN_NOT_OBJECT: | |
| 409 wsString = | |
| 410 L"An attempt was made to reference property '%s' of a non-object in " | |
| 411 L"SOM expression %s."; | |
| 412 return; | |
| 413 case XFA_IDS_INDEX_OUT_OF_BOUNDS: | |
| 414 wsString = L"Index value is out of bounds."; | |
| 415 return; | |
| 416 case XFA_IDS_INCORRECT_NUMBER_OF_METHOD: | |
| 417 wsString = L"Incorrect number of parameters calling method '%s'."; | |
| 418 return; | |
| 419 case XFA_IDS_ARGUMENT_MISMATCH: | |
| 420 wsString = L"Argument mismatch in property or function argument."; | |
| 421 return; | |
| 422 case XFA_IDS_NOT_HAVE_PROPERTY: | |
| 423 wsString = L"'%s' doesn't have property '%s'."; | |
| 424 return; | |
| 425 case XFA_IDS_VIOLATE_BOUNDARY: | |
| 426 wsString = | |
| 427 L"The element [%s] has violated its allowable number of occurrences."; | |
| 428 return; | |
| 429 case XFA_IDS_SERVER_DENY: | |
| 430 wsString = L"Server does not permit."; | |
| 431 return; | |
| 432 case XFA_IDS_ValidateLimit: | |
| 433 wsString = | |
| 434 L"Message limit exceeded. Remaining %d validation errors not " | |
| 435 L"reported."; | |
| 436 return; | |
| 437 case XFA_IDS_ValidateNullWarning: | |
| 438 wsString = | |
| 439 L"%s cannot be blank. To ignore validations for %s, click Ignore."; | |
| 440 return; | |
| 441 case XFA_IDS_ValidateNullError: | |
| 442 wsString = L"%s cannot be blank."; | |
| 443 return; | |
| 444 case XFA_IDS_ValidateWarning: | |
| 445 wsString = | |
| 446 L"The value you entered for %s is invalid. To ignore validations for " | |
| 447 L"%s, click Ignore."; | |
| 448 return; | |
| 449 case XFA_IDS_ValidateError: | |
| 450 wsString = L"The value you entered for %s is invalid."; | |
| 451 return; | |
| 452 } | |
| 453 } | |
| 454 | |
| 455 IFWL_AdapterTimerMgr* CPDFXFA_Document::GetTimerMgr() { | |
| 456 CXFA_FWLAdapterTimerMgr* pAdapter = nullptr; | |
| 457 if (m_pFormFillEnv) | |
| 458 pAdapter = new CXFA_FWLAdapterTimerMgr(m_pFormFillEnv); | |
| 459 return pAdapter; | |
| 460 } | |
| OLD | NEW |