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_context.h" 8 9 #include <algorithm> 10 #include <utility> 11 12 #include "core/fpdfapi/parser/cpdf_document.h" 13 #include "fpdfsdk/cpdfsdk_formfillenvironment.h" 14 #include "fpdfsdk/cpdfsdk_interform.h" 15 #include "fpdfsdk/cpdfsdk_pageview.h" 16 #include "fpdfsdk/fpdfxfa/cpdfxfa_page.h" 17 #include "fpdfsdk/fpdfxfa/cxfa_fwladaptertimermgr.h" 18 #include "fpdfsdk/fsdk_define.h" 19 #include "fxjs/cjs_runtime.h" 20 #include "fxjs/ijs_runtime.h" 21 #include "public/fpdf_formfill.h" 22 #include "third_party/base/ptr_util.h" 23 #include "third_party/base/stl_util.h" 24 #include "xfa/fgas/font/cfgas_defaultfontmanager.h" 25 #include "xfa/fxfa/cxfa_eventparam.h" 26 #include "xfa/fxfa/cxfa_ffapp.h" 27 #include "xfa/fxfa/cxfa_ffdoc.h" 28 #include "xfa/fxfa/cxfa_ffdocview.h" 29 #include "xfa/fxfa/cxfa_ffpageview.h" 30 #include "xfa/fxfa/cxfa_ffwidgethandler.h" 31 #include "xfa/fxfa/cxfa_fontmgr.h" 32 33 #ifndef _WIN32 34 extern void SetLastError(int err); 35 extern int GetLastError(); 36 #endif 37 38 CPDFXFA_Context::CPDFXFA_Context(std::unique_ptr<CPDF_Document> pPDFDoc) 39 : m_pPDFDoc(std::move(pPDFDoc)), 40 m_pXFAApp(pdfium::MakeUnique<CXFA_FFApp>(this)), 41 m_DocEnv(this) { 42 m_pXFAApp->SetDefaultFontMgr(pdfium::MakeUnique<CFGAS_DefaultFontManager>()); 43 } 44 45 CPDFXFA_Context::~CPDFXFA_Context() { 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.Reset(); 57 } 58 59 m_nLoadStatus = FXFA_LOADSTATUS_CLOSED; 60 } 61 62 void CPDFXFA_Context::CloseXFADoc() { 63 if (!m_pXFADoc) 64 return; 65 66 m_pXFADocView = nullptr; 67 m_pXFADoc->CloseDoc(); 68 m_pXFADoc.reset(); 69 } 70 71 void CPDFXFA_Context::SetFormFillEnv( 72 CPDFSDK_FormFillEnvironment* pFormFillEnv) { 73 // The layout data can have pointers back into the script context. That 74 // context will be different if the form fill environment closes, so, force 75 // the layout data to clear. 76 if (m_pXFADoc && m_pXFADoc->GetXFADoc()) 77 m_pXFADoc->GetXFADoc()->ClearLayoutData(); 78 79 m_pFormFillEnv.Reset(pFormFillEnv); 80 } 81 82 bool CPDFXFA_Context::LoadXFADoc() { 83 m_nLoadStatus = FXFA_LOADSTATUS_LOADING; 84 if (!m_pPDFDoc) 85 return false; 86 87 m_XFAPageList.clear(); 88 89 CXFA_FFApp* pApp = GetXFAApp(); 90 if (!pApp) 91 return false; 92 93 m_pXFADoc = pApp->CreateDoc(&m_DocEnv, m_pPDFDoc.get()); 94 if (!m_pXFADoc) { 95 SetLastError(FPDF_ERR_XFALOAD); 96 return false; 97 } 98 99 m_pXFADoc->StartLoad(); 100 int iStatus = m_pXFADoc->DoLoad(); 101 if (iStatus != XFA_PARSESTATUS_Done) { 102 CloseXFADoc(); 103 SetLastError(FPDF_ERR_XFALOAD); 104 return false; 105 } 106 m_pXFADoc->StopLoad(); 107 m_pXFADoc->GetXFADoc()->InitScriptContext(GetJSERuntime()); 108 109 if (m_pXFADoc->GetFormType() == FormType::kXFAFull) 110 m_FormType = FormType::kXFAFull; 111 else 112 m_FormType = FormType::kXFAForeground; 113 114 m_pXFADocView = m_pXFADoc->CreateDocView(); 115 if (m_pXFADocView->StartLayout() < 0) { 116 CloseXFADoc(); 117 SetLastError(FPDF_ERR_XFALAYOUT); 118 return false; 119 } 120 121 m_pXFADocView->DoLayout(); 122 m_pXFADocView->StopLayout(); 123 m_nLoadStatus = FXFA_LOADSTATUS_LOADED; 124 125 return true; 126 } 127 128 int CPDFXFA_Context::GetPageCount() const { 129 if (!m_pPDFDoc && !m_pXFADoc) 130 return 0; 131 132 switch (m_FormType) { 133 case FormType::kNone: 134 case FormType::kAcroForm: 135 case FormType::kXFAForeground: 136 if (m_pPDFDoc) 137 return m_pPDFDoc->GetPageCount(); 138 case FormType::kXFAFull: 139 if (m_pXFADoc) 140 return m_pXFADocView->CountPageViews(); 141 } 142 return 0; 143 } 144 145 RetainPtr<CPDFXFA_Page> CPDFXFA_Context::GetXFAPage(int page_index) { 146 if (page_index < 0) 147 return nullptr; 148 149 if (pdfium::IndexInBounds(m_XFAPageList, page_index)) { 150 if (m_XFAPageList[page_index]) 151 return m_XFAPageList[page_index]; 152 } else { 153 m_nPageCount = GetPageCount(); 154 m_XFAPageList.resize(m_nPageCount); 155 } 156 157 auto pPage = pdfium::MakeRetain<CPDFXFA_Page>(this, page_index); 158 if (!pPage->LoadPage()) 159 return nullptr; 160 161 if (pdfium::IndexInBounds(m_XFAPageList, page_index)) 162 m_XFAPageList[page_index] = pPage; 163 164 return pPage; 165 } 166 167 RetainPtr<CPDFXFA_Page> CPDFXFA_Context::GetXFAPage( 168 CXFA_FFPageView* pPage) const { 169 if (!pPage) 170 return nullptr; 171 172 if (!m_pXFADoc) 173 return nullptr; 174 175 if (m_FormType != FormType::kXFAFull) 176 return nullptr; 177 178 for (auto& pTempPage : m_XFAPageList) { 179 if (pTempPage && pTempPage->GetXFAPageView() == pPage) 180 return pTempPage; 181 } 182 return nullptr; 183 } 184 185 void CPDFXFA_Context::DeletePage(int page_index) { 186 // Delete from the document first because, if GetPage was never called for 187 // this |page_index| then |m_XFAPageList| may have size < |page_index| even 188 // if it's a valid page in the document. 189 if (m_pPDFDoc) 190 m_pPDFDoc->DeletePage(page_index); 191 192 if (pdfium::IndexInBounds(m_XFAPageList, page_index)) 193 m_XFAPageList[page_index].Reset(); 194 } 195 196 void CPDFXFA_Context::ClearChangeMark() { 197 if (m_pFormFillEnv) 198 m_pFormFillEnv->ClearChangeMark(); 199 } 200 201 v8::Isolate* CPDFXFA_Context::GetJSERuntime() const { 202 if (!m_pFormFillEnv) 203 return nullptr; 204 205 // XFA requires V8, if we have V8 then we have a CJS_Runtime and not the stub. 206 CJS_Runtime* runtime = 207 static_cast<CJS_Runtime*>(m_pFormFillEnv->GetJSRuntime()); 208 return runtime->GetIsolate(); 209 } 210 211 WideString CPDFXFA_Context::GetAppTitle() const { 212 return L"PDFium"; 213 } 214 215 WideString CPDFXFA_Context::GetAppName() { 216 return m_pFormFillEnv ? m_pFormFillEnv->FFI_GetAppName() : L""; 217 } 218 219 WideString CPDFXFA_Context::GetLanguage() { 220 return m_pFormFillEnv ? m_pFormFillEnv->GetLanguage() : L""; 221 } 222 223 WideString CPDFXFA_Context::GetPlatform() { 224 return m_pFormFillEnv ? m_pFormFillEnv->GetPlatform() : L""; 225 } 226 227 void CPDFXFA_Context::Beep(uint32_t dwType) { 228 if (m_pFormFillEnv) 229 m_pFormFillEnv->JS_appBeep(dwType); 230 } 231 232 int32_t CPDFXFA_Context::MsgBox(const WideString& wsMessage, 233 const WideString& wsTitle, 234 uint32_t dwIconType, 235 uint32_t dwButtonType) { 236 if (!m_pFormFillEnv) 237 return -1; 238 239 uint32_t iconType = 0; 240 int iButtonType = 0; 241 switch (dwIconType) { 242 case XFA_MBICON_Error: 243 iconType |= 0; 244 break; 245 case XFA_MBICON_Warning: 246 iconType |= 1; 247 break; 248 case XFA_MBICON_Question: 249 iconType |= 2; 250 break; 251 case XFA_MBICON_Status: 252 iconType |= 3; 253 break; 254 } 255 switch (dwButtonType) { 256 case XFA_MB_OK: 257 iButtonType |= 0; 258 break; 259 case XFA_MB_OKCancel: 260 iButtonType |= 1; 261 break; 262 case XFA_MB_YesNo: 263 iButtonType |= 2; 264 break; 265 case XFA_MB_YesNoCancel: 266 iButtonType |= 3; 267 break; 268 } 269 int32_t iRet = m_pFormFillEnv->JS_appAlert(wsMessage.c_str(), wsTitle.c_str(), 270 iButtonType, iconType); 271 switch (iRet) { 272 case 1: 273 return XFA_IDOK; 274 case 2: 275 return XFA_IDCancel; 276 case 3: 277 return XFA_IDNo; 278 case 4: 279 return XFA_IDYes; 280 } 281 return XFA_IDYes; 282 } 283 284 WideString CPDFXFA_Context::Response(const WideString& wsQuestion, 285 const WideString& wsTitle, 286 const WideString& wsDefaultAnswer, 287 bool bMark) { 288 if (!m_pFormFillEnv) 289 return WideString(); 290 291 int nLength = 2048; 292 std::vector<uint8_t> pBuff(nLength); 293 nLength = m_pFormFillEnv->JS_appResponse(wsQuestion.c_str(), wsTitle.c_str(), 294 wsDefaultAnswer.c_str(), nullptr, 295 bMark, pBuff.data(), nLength); 296 if (nLength <= 0) 297 return WideString(); 298 299 nLength = std::min(2046, nLength); 300 pBuff[nLength] = 0; 301 pBuff[nLength + 1] = 0; 302 return WideString::FromUTF16LE(reinterpret_cast<uint16_t*>(pBuff.data()), 303 nLength / sizeof(uint16_t)); 304 } 305 306 RetainPtr<IFX_SeekableReadStream> CPDFXFA_Context::DownloadURL( 307 const WideString& wsURL) { 308 return m_pFormFillEnv ? m_pFormFillEnv->DownloadFromURL(wsURL.c_str()) 309 : nullptr; 310 } 311 312 bool CPDFXFA_Context::PostRequestURL(const WideString& wsURL, 313 const WideString& wsData, 314 const WideString& wsContentType, 315 const WideString& wsEncode, 316 const WideString& wsHeader, 317 WideString& wsResponse) { 318 if (!m_pFormFillEnv) 319 return false; 320 321 wsResponse = m_pFormFillEnv->PostRequestURL( 322 wsURL.c_str(), wsData.c_str(), wsContentType.c_str(), wsEncode.c_str(), 323 wsHeader.c_str()); 324 return true; 325 } 326 327 bool CPDFXFA_Context::PutRequestURL(const WideString& wsURL, 328 const WideString& wsData, 329 const WideString& wsEncode) { 330 return m_pFormFillEnv && 331 m_pFormFillEnv->PutRequestURL(wsURL.c_str(), wsData.c_str(), 332 wsEncode.c_str()); 333 } 334 335 IFWL_AdapterTimerMgr* CPDFXFA_Context::GetTimerMgr() { 336 CXFA_FWLAdapterTimerMgr* pAdapter = nullptr; 337 if (m_pFormFillEnv) 338 pAdapter = new CXFA_FWLAdapterTimerMgr(m_pFormFillEnv.Get()); 339 return pAdapter; 340 } 341