| // Copyright 2016 PDFium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com |
| |
| #include "fpdfsdk/cpdfsdk_formfillenvironment.h" |
| |
| #include <memory> |
| #include <utility> |
| #include <vector> |
| |
| #include "core/fpdfapi/page/cpdf_annotcontext.h" |
| #include "core/fpdfapi/parser/cpdf_array.h" |
| #include "core/fpdfapi/parser/cpdf_dictionary.h" |
| #include "core/fpdfdoc/cpdf_nametree.h" |
| #include "core/fxcrt/fx_memory_wrappers.h" |
| #include "core/fxcrt/stl_util.h" |
| #include "fpdfsdk/cpdfsdk_actionhandler.h" |
| #include "fpdfsdk/cpdfsdk_annothandlermgr.h" |
| #include "fpdfsdk/cpdfsdk_helpers.h" |
| #include "fpdfsdk/cpdfsdk_interactiveform.h" |
| #include "fpdfsdk/cpdfsdk_pageview.h" |
| #include "fpdfsdk/cpdfsdk_widget.h" |
| #include "fpdfsdk/formfiller/cffl_formfield.h" |
| #include "fpdfsdk/formfiller/cffl_interactiveformfiller.h" |
| #include "fpdfsdk/formfiller/cffl_perwindowdata.h" |
| #include "fxjs/ijs_runtime.h" |
| #include "third_party/base/check.h" |
| #include "third_party/base/numerics/safe_conversions.h" |
| |
| static_assert(FXCT_ARROW == |
| static_cast<int>(IPWL_SystemHandler::CursorStyle::kArrow), |
| "kArrow value mismatch"); |
| static_assert(FXCT_NESW == |
| static_cast<int>(IPWL_SystemHandler::CursorStyle::kNESW), |
| "kNEWS value mismatch"); |
| static_assert(FXCT_NWSE == |
| static_cast<int>(IPWL_SystemHandler::CursorStyle::kNWSE), |
| "kNWSE value mismatch"); |
| static_assert(FXCT_VBEAM == |
| static_cast<int>(IPWL_SystemHandler::CursorStyle::kVBeam), |
| "kVBeam value mismatch"); |
| static_assert(FXCT_HBEAM == |
| static_cast<int>(IPWL_SystemHandler::CursorStyle::kHBeam), |
| "HBeam value mismatch"); |
| static_assert(FXCT_HAND == |
| static_cast<int>(IPWL_SystemHandler::CursorStyle::kHand), |
| "kHand value mismatch"); |
| |
| FPDF_WIDESTRING AsFPDFWideString(ByteString* bsUTF16LE) { |
| // Force a private version of the string, since we're about to hand it off |
| // to the embedder. Should the embedder modify it by accident, it won't |
| // corrupt other shares of the string beyond |bsUTF16LE|. |
| return reinterpret_cast<FPDF_WIDESTRING>( |
| bsUTF16LE->GetBuffer(bsUTF16LE->GetLength()).data()); |
| } |
| |
| CPDFSDK_FormFillEnvironment::CPDFSDK_FormFillEnvironment( |
| CPDF_Document* pDoc, |
| FPDF_FORMFILLINFO* pFFinfo, |
| std::unique_ptr<CPDFSDK_AnnotHandlerMgr> pHandlerMgr) |
| : m_pInfo(pFFinfo), |
| m_pCPDFDoc(pDoc), |
| m_pAnnotHandlerMgr(std::move(pHandlerMgr)), |
| m_pInteractiveFormFiller( |
| std::make_unique<CFFL_InteractiveFormFiller>(this)) { |
| DCHECK(m_pCPDFDoc); |
| m_pAnnotHandlerMgr->SetFormFillEnv(this); |
| } |
| |
| CPDFSDK_FormFillEnvironment::~CPDFSDK_FormFillEnvironment() { |
| m_bBeingDestroyed = true; |
| ClearAllFocusedAnnots(); |
| |
| // |m_PageMap| will try to access |m_pInteractiveForm| when it cleans itself |
| // up. Make sure it is deleted before |m_pInteractiveForm|. |
| m_PageMap.clear(); |
| |
| // |m_pAnnotHandlerMgr| will try to access |m_pFormFiller| when it cleans |
| // itself up. Make sure it is deleted before |m_pFormFiller|. |
| m_pAnnotHandlerMgr.reset(); |
| |
| // Must destroy the |m_pInteractiveFormFiller| before the environment (|this|) |
| // because any created form widgets hold a pointer to the environment. |
| // Those widgets may call things like KillTimer() as they are shutdown. |
| m_pInteractiveFormFiller.reset(); |
| |
| if (m_pInfo && m_pInfo->Release) |
| m_pInfo->Release(m_pInfo); |
| } |
| |
| void CPDFSDK_FormFillEnvironment::InvalidateRect(PerWindowData* pWidgetData, |
| const CFX_FloatRect& rect) { |
| auto* pPrivateData = static_cast<CFFL_PerWindowData*>(pWidgetData); |
| CPDFSDK_Widget* widget = pPrivateData->GetWidget(); |
| if (!widget) |
| return; |
| |
| IPDF_Page* pPage = widget->GetPage(); |
| if (!pPage) |
| return; |
| |
| CFX_Matrix device2page = |
| widget->GetPageView()->GetCurrentMatrix().GetInverse(); |
| CFX_PointF left_top = device2page.Transform(CFX_PointF(rect.left, rect.top)); |
| CFX_PointF right_bottom = |
| device2page.Transform(CFX_PointF(rect.right, rect.bottom)); |
| |
| CFX_FloatRect rcPDF(left_top.x, right_bottom.y, right_bottom.x, left_top.y); |
| rcPDF.Normalize(); |
| Invalidate(pPage, rcPDF.GetOuterRect()); |
| } |
| |
| void CPDFSDK_FormFillEnvironment::OutputSelectedRect( |
| PerWindowData* pWidgetData, |
| const CFX_FloatRect& rect) { |
| if (!m_pInfo || !m_pInfo->FFI_OutputSelectedRect) |
| return; |
| |
| auto* pPrivateData = static_cast<CFFL_PerWindowData*>(pWidgetData); |
| if (!pPrivateData) |
| return; |
| |
| CFFL_FormField* pFormField = pPrivateData->GetFormField(); |
| if (!pFormField) |
| return; |
| |
| auto* pPage = FPDFPageFromIPDFPage(pFormField->GetSDKWidget()->GetPage()); |
| DCHECK(pPage); |
| |
| CFX_PointF ptA = pFormField->PWLtoFFL(CFX_PointF(rect.left, rect.bottom)); |
| CFX_PointF ptB = pFormField->PWLtoFFL(CFX_PointF(rect.right, rect.top)); |
| m_pInfo->FFI_OutputSelectedRect(m_pInfo, pPage, ptA.x, ptB.y, ptB.x, ptA.y); |
| } |
| |
| bool CPDFSDK_FormFillEnvironment::IsSelectionImplemented() const { |
| FPDF_FORMFILLINFO* pInfo = GetFormFillInfo(); |
| return pInfo && pInfo->FFI_OutputSelectedRect; |
| } |
| |
| #ifdef PDF_ENABLE_V8 |
| CPDFSDK_PageView* CPDFSDK_FormFillEnvironment::GetCurrentView() { |
| IPDF_Page* pPage = IPDFPageFromFPDFPage(GetCurrentPage()); |
| return pPage ? GetOrCreatePageView(pPage) : nullptr; |
| } |
| |
| FPDF_PAGE CPDFSDK_FormFillEnvironment::GetCurrentPage() const { |
| if (m_pInfo && m_pInfo->FFI_GetCurrentPage) { |
| return m_pInfo->FFI_GetCurrentPage( |
| m_pInfo, FPDFDocumentFromCPDFDocument(m_pCPDFDoc.Get())); |
| } |
| return nullptr; |
| } |
| |
| WideString CPDFSDK_FormFillEnvironment::GetLanguage() { |
| #ifdef PDF_ENABLE_XFA |
| if (!m_pInfo || m_pInfo->version < 2 || !m_pInfo->FFI_GetLanguage) |
| return WideString(); |
| |
| int nRequiredLen = m_pInfo->FFI_GetLanguage(m_pInfo, nullptr, 0); |
| if (nRequiredLen <= 0) |
| return WideString(); |
| |
| std::vector<uint8_t, FxAllocAllocator<uint8_t>> pBuff(nRequiredLen); |
| int nActualLen = |
| m_pInfo->FFI_GetLanguage(m_pInfo, pBuff.data(), nRequiredLen); |
| if (nActualLen <= 0 || nActualLen > nRequiredLen) |
| return WideString(); |
| |
| return WideString::FromUTF16LE(reinterpret_cast<uint16_t*>(pBuff.data()), |
| nActualLen / sizeof(uint16_t)); |
| #else // PDF_ENABLE_XFA |
| return WideString(); |
| #endif // PDF_ENABLE_XFA |
| } |
| |
| WideString CPDFSDK_FormFillEnvironment::GetPlatform() { |
| #ifdef PDF_ENABLE_XFA |
| if (!m_pInfo || m_pInfo->version < 2 || !m_pInfo->FFI_GetPlatform) |
| return WideString(); |
| |
| int nRequiredLen = m_pInfo->FFI_GetPlatform(m_pInfo, nullptr, 0); |
| if (nRequiredLen <= 0) |
| return WideString(); |
| |
| std::vector<uint8_t, FxAllocAllocator<uint8_t>> pBuff(nRequiredLen); |
| int nActualLen = |
| m_pInfo->FFI_GetPlatform(m_pInfo, pBuff.data(), nRequiredLen); |
| if (nActualLen <= 0 || nActualLen > nRequiredLen) |
| return WideString(); |
| |
| return WideString::FromUTF16LE(reinterpret_cast<uint16_t*>(pBuff.data()), |
| nActualLen / sizeof(uint16_t)); |
| #else // PDF_ENABLE_XFA |
| return WideString(); |
| #endif // PDF_ENABLE_XFA |
| } |
| |
| int CPDFSDK_FormFillEnvironment::JS_appAlert(const WideString& Msg, |
| const WideString& Title, |
| int Type, |
| int Icon) { |
| IPDF_JSPLATFORM* js_platform = GetJSPlatform(); |
| if (!js_platform || !js_platform->app_alert) |
| return -1; |
| |
| ByteString bsMsg = Msg.ToUTF16LE(); |
| ByteString bsTitle = Title.ToUTF16LE(); |
| return js_platform->app_alert(js_platform, AsFPDFWideString(&bsMsg), |
| AsFPDFWideString(&bsTitle), Type, Icon); |
| } |
| |
| int CPDFSDK_FormFillEnvironment::JS_appResponse( |
| const WideString& Question, |
| const WideString& Title, |
| const WideString& Default, |
| const WideString& Label, |
| FPDF_BOOL bPassword, |
| pdfium::span<uint8_t> response) { |
| IPDF_JSPLATFORM* js_platform = GetJSPlatform(); |
| if (!js_platform || !js_platform->app_response) |
| return -1; |
| |
| ByteString bsQuestion = Question.ToUTF16LE(); |
| ByteString bsTitle = Title.ToUTF16LE(); |
| ByteString bsDefault = Default.ToUTF16LE(); |
| ByteString bsLabel = Label.ToUTF16LE(); |
| return js_platform->app_response( |
| js_platform, AsFPDFWideString(&bsQuestion), AsFPDFWideString(&bsTitle), |
| AsFPDFWideString(&bsDefault), AsFPDFWideString(&bsLabel), bPassword, |
| response.data(), pdfium::base::checked_cast<int>(response.size())); |
| } |
| |
| void CPDFSDK_FormFillEnvironment::JS_appBeep(int nType) { |
| IPDF_JSPLATFORM* js_platform = GetJSPlatform(); |
| if (!js_platform || !js_platform->app_beep) |
| return; |
| |
| js_platform->app_beep(js_platform, nType); |
| } |
| |
| WideString CPDFSDK_FormFillEnvironment::JS_fieldBrowse() { |
| IPDF_JSPLATFORM* js_platform = GetJSPlatform(); |
| if (!js_platform || !js_platform->Field_browse) |
| return WideString(); |
| |
| const int nRequiredLen = js_platform->Field_browse(js_platform, nullptr, 0); |
| if (nRequiredLen <= 0) |
| return WideString(); |
| |
| std::vector<uint8_t, FxAllocAllocator<uint8_t>> pBuff(nRequiredLen); |
| const int nActualLen = |
| js_platform->Field_browse(js_platform, pBuff.data(), nRequiredLen); |
| if (nActualLen <= 0 || nActualLen > nRequiredLen) |
| return WideString(); |
| |
| // Don't include trailing NUL. |
| pBuff.resize(nActualLen - 1); |
| return WideString::FromDefANSI(ByteStringView(pBuff)); |
| } |
| |
| void CPDFSDK_FormFillEnvironment::JS_docmailForm(pdfium::span<uint8_t> mailData, |
| FPDF_BOOL bUI, |
| const WideString& To, |
| const WideString& Subject, |
| const WideString& CC, |
| const WideString& BCC, |
| const WideString& Msg) { |
| IPDF_JSPLATFORM* js_platform = GetJSPlatform(); |
| if (!js_platform || !js_platform->Doc_mail) |
| return; |
| |
| ByteString bsTo = To.ToUTF16LE(); |
| ByteString bsSubject = Subject.ToUTF16LE(); |
| ByteString bsCC = CC.ToUTF16LE(); |
| ByteString bsBcc = BCC.ToUTF16LE(); |
| ByteString bsMsg = Msg.ToUTF16LE(); |
| js_platform->Doc_mail(js_platform, mailData.data(), |
| pdfium::base::checked_cast<int>(mailData.size()), bUI, |
| AsFPDFWideString(&bsTo), AsFPDFWideString(&bsSubject), |
| AsFPDFWideString(&bsCC), AsFPDFWideString(&bsBcc), |
| AsFPDFWideString(&bsMsg)); |
| } |
| |
| void CPDFSDK_FormFillEnvironment::JS_docprint(FPDF_BOOL bUI, |
| int nStart, |
| int nEnd, |
| FPDF_BOOL bSilent, |
| FPDF_BOOL bShrinkToFit, |
| FPDF_BOOL bPrintAsImage, |
| FPDF_BOOL bReverse, |
| FPDF_BOOL bAnnotations) { |
| IPDF_JSPLATFORM* js_platform = GetJSPlatform(); |
| if (!js_platform || !js_platform->Doc_print) |
| return; |
| |
| js_platform->Doc_print(js_platform, bUI, nStart, nEnd, bSilent, bShrinkToFit, |
| bPrintAsImage, bReverse, bAnnotations); |
| } |
| |
| void CPDFSDK_FormFillEnvironment::JS_docgotoPage(int nPageNum) { |
| IPDF_JSPLATFORM* js_platform = GetJSPlatform(); |
| if (!js_platform || !js_platform->Doc_gotoPage) |
| return; |
| |
| js_platform->Doc_gotoPage(js_platform, nPageNum); |
| } |
| |
| WideString CPDFSDK_FormFillEnvironment::JS_docGetFilePath() { |
| return GetFilePath(); |
| } |
| #endif // PDF_ENABLE_V8 |
| |
| WideString CPDFSDK_FormFillEnvironment::GetFilePath() const { |
| IPDF_JSPLATFORM* js_platform = GetJSPlatform(); |
| if (!js_platform || !js_platform->Doc_getFilePath) |
| return WideString(); |
| |
| const int nRequiredLen = |
| js_platform->Doc_getFilePath(js_platform, nullptr, 0); |
| if (nRequiredLen <= 0) |
| return WideString(); |
| |
| std::vector<uint8_t, FxAllocAllocator<uint8_t>> pBuff(nRequiredLen); |
| const int nActualLen = |
| js_platform->Doc_getFilePath(js_platform, pBuff.data(), nRequiredLen); |
| if (nActualLen <= 0 || nActualLen > nRequiredLen) |
| return WideString(); |
| |
| // Don't include trailing NUL. |
| pBuff.resize(nActualLen - 1); |
| return WideString::FromDefANSI(ByteStringView(pBuff)); |
| } |
| |
| void CPDFSDK_FormFillEnvironment::SubmitForm(pdfium::span<uint8_t> form_data, |
| const WideString& URL) { |
| IPDF_JSPLATFORM* js_platform = GetJSPlatform(); |
| if (!js_platform || !js_platform->Doc_submitForm) |
| return; |
| |
| ByteString bsUrl = URL.ToUTF16LE(); |
| js_platform->Doc_submitForm(js_platform, form_data.data(), form_data.size(), |
| AsFPDFWideString(&bsUrl)); |
| } |
| |
| IJS_Runtime* CPDFSDK_FormFillEnvironment::GetIJSRuntime() { |
| if (!m_pIJSRuntime) |
| m_pIJSRuntime = IJS_Runtime::Create(this); |
| return m_pIJSRuntime.get(); |
| } |
| |
| CPDFSDK_AnnotHandlerMgr* CPDFSDK_FormFillEnvironment::GetAnnotHandlerMgr() { |
| return m_pAnnotHandlerMgr.get(); |
| } |
| |
| CPDFSDK_ActionHandler* CPDFSDK_FormFillEnvironment::GetActionHandler() { |
| if (!m_pActionHandler) |
| m_pActionHandler = std::make_unique<CPDFSDK_ActionHandler>(); |
| return m_pActionHandler.get(); |
| } |
| |
| void CPDFSDK_FormFillEnvironment::Invalidate(IPDF_Page* page, |
| const FX_RECT& rect) { |
| if (m_pInfo && m_pInfo->FFI_Invalidate) { |
| m_pInfo->FFI_Invalidate(m_pInfo, FPDFPageFromIPDFPage(page), rect.left, |
| rect.top, rect.right, rect.bottom); |
| } |
| } |
| |
| void CPDFSDK_FormFillEnvironment::SetCursor(CursorStyle nCursorType) { |
| if (m_pInfo && m_pInfo->FFI_SetCursor) |
| m_pInfo->FFI_SetCursor(m_pInfo, static_cast<int>(nCursorType)); |
| } |
| |
| int CPDFSDK_FormFillEnvironment::SetTimer(int uElapse, |
| TimerCallback lpTimerFunc) { |
| if (m_pInfo && m_pInfo->FFI_SetTimer) |
| return m_pInfo->FFI_SetTimer(m_pInfo, uElapse, lpTimerFunc); |
| return CFX_Timer::HandlerIface::kInvalidTimerID; |
| } |
| |
| void CPDFSDK_FormFillEnvironment::KillTimer(int nTimerID) { |
| if (m_pInfo && m_pInfo->FFI_KillTimer) |
| m_pInfo->FFI_KillTimer(m_pInfo, nTimerID); |
| } |
| |
| void CPDFSDK_FormFillEnvironment::OnChange() { |
| if (m_pInfo && m_pInfo->FFI_OnChange) |
| m_pInfo->FFI_OnChange(m_pInfo); |
| } |
| |
| void CPDFSDK_FormFillEnvironment::ExecuteNamedAction( |
| const ByteString& namedAction) { |
| if (m_pInfo && m_pInfo->FFI_ExecuteNamedAction) |
| m_pInfo->FFI_ExecuteNamedAction(m_pInfo, namedAction.c_str()); |
| } |
| |
| void CPDFSDK_FormFillEnvironment::OnSetFieldInputFocus(const WideString& text) { |
| OnSetFieldInputFocusInternal(text, true); |
| } |
| |
| void CPDFSDK_FormFillEnvironment::OnSetFieldInputFocusInternal( |
| const WideString& text, |
| bool bFocus) { |
| if (m_pInfo && m_pInfo->FFI_SetTextFieldFocus) { |
| int nCharacters = text.GetLength(); |
| ByteString bsUTFText = text.ToUTF16LE(); |
| auto* pBuffer = reinterpret_cast<const unsigned short*>(bsUTFText.c_str()); |
| m_pInfo->FFI_SetTextFieldFocus(m_pInfo, pBuffer, nCharacters, bFocus); |
| } |
| } |
| |
| void CPDFSDK_FormFillEnvironment::OnCalculate( |
| ObservedPtr<CPDFSDK_Annot>& pAnnot) { |
| CPDFSDK_Widget* pWidget = ToCPDFSDKWidget(pAnnot.Get()); |
| if (pWidget) |
| m_pInteractiveForm->OnCalculate(pWidget->GetFormField()); |
| } |
| |
| void CPDFSDK_FormFillEnvironment::OnFormat(ObservedPtr<CPDFSDK_Annot>& pAnnot) { |
| CPDFSDK_Widget* pWidget = ToCPDFSDKWidget(pAnnot.Get()); |
| DCHECK(pWidget); |
| |
| absl::optional<WideString> sValue = |
| m_pInteractiveForm->OnFormat(pWidget->GetFormField()); |
| if (!pAnnot) |
| return; |
| |
| if (sValue.has_value()) { |
| m_pInteractiveForm->ResetFieldAppearance(pWidget->GetFormField(), sValue); |
| m_pInteractiveForm->UpdateField(pWidget->GetFormField()); |
| } |
| } |
| |
| void CPDFSDK_FormFillEnvironment::DoURIAction(const ByteString& bsURI, |
| Mask<FWL_EVENTFLAG> modifiers) { |
| if (!m_pInfo) |
| return; |
| |
| if (m_pInfo->version >= 2 && m_pInfo->FFI_DoURIActionWithKeyboardModifier) { |
| m_pInfo->FFI_DoURIActionWithKeyboardModifier(m_pInfo, bsURI.c_str(), |
| modifiers.UncheckedValue()); |
| return; |
| } |
| |
| if (m_pInfo->FFI_DoURIAction) |
| m_pInfo->FFI_DoURIAction(m_pInfo, bsURI.c_str()); |
| } |
| |
| void CPDFSDK_FormFillEnvironment::DoGoToAction(int nPageIndex, |
| int zoomMode, |
| float* fPosArray, |
| int sizeOfArray) { |
| if (m_pInfo && m_pInfo->FFI_DoGoToAction) { |
| m_pInfo->FFI_DoGoToAction(m_pInfo, nPageIndex, zoomMode, fPosArray, |
| sizeOfArray); |
| } |
| } |
| |
| #ifdef PDF_ENABLE_XFA |
| int CPDFSDK_FormFillEnvironment::GetPageViewCount() const { |
| return fxcrt::CollectionSize<int>(m_PageMap); |
| } |
| |
| void CPDFSDK_FormFillEnvironment::DisplayCaret(IPDF_Page* page, |
| FPDF_BOOL bVisible, |
| double left, |
| double top, |
| double right, |
| double bottom) { |
| if (m_pInfo && m_pInfo->version >= 2 && m_pInfo->FFI_DisplayCaret) { |
| m_pInfo->FFI_DisplayCaret(m_pInfo, FPDFPageFromIPDFPage(page), bVisible, |
| left, top, right, bottom); |
| } |
| } |
| |
| int CPDFSDK_FormFillEnvironment::GetCurrentPageIndex() const { |
| if (!m_pInfo || m_pInfo->version < 2 || !m_pInfo->FFI_GetCurrentPageIndex) |
| return -1; |
| return m_pInfo->FFI_GetCurrentPageIndex( |
| m_pInfo, FPDFDocumentFromCPDFDocument(m_pCPDFDoc.Get())); |
| } |
| |
| void CPDFSDK_FormFillEnvironment::SetCurrentPage(int iCurPage) { |
| if (!m_pInfo || m_pInfo->version < 2 || !m_pInfo->FFI_SetCurrentPage) |
| return; |
| m_pInfo->FFI_SetCurrentPage( |
| m_pInfo, FPDFDocumentFromCPDFDocument(m_pCPDFDoc.Get()), iCurPage); |
| } |
| |
| void CPDFSDK_FormFillEnvironment::GotoURL(const WideString& wsURL) { |
| if (!m_pInfo || m_pInfo->version < 2 || !m_pInfo->FFI_GotoURL) |
| return; |
| |
| ByteString bsTo = wsURL.ToUTF16LE(); |
| m_pInfo->FFI_GotoURL(m_pInfo, FPDFDocumentFromCPDFDocument(m_pCPDFDoc.Get()), |
| AsFPDFWideString(&bsTo)); |
| } |
| |
| FS_RECTF CPDFSDK_FormFillEnvironment::GetPageViewRect(IPDF_Page* page) { |
| FS_RECTF rect = {0.0f, 0.0f, 0.0f, 0.0f}; |
| if (!m_pInfo || m_pInfo->version < 2 || !m_pInfo->FFI_GetPageViewRect) |
| return rect; |
| |
| double left; |
| double top; |
| double right; |
| double bottom; |
| m_pInfo->FFI_GetPageViewRect(m_pInfo, FPDFPageFromIPDFPage(page), &left, &top, |
| &right, &bottom); |
| |
| rect.left = static_cast<float>(left); |
| rect.top = static_cast<float>(top); |
| rect.bottom = static_cast<float>(bottom); |
| rect.right = static_cast<float>(right); |
| return rect; |
| } |
| |
| bool CPDFSDK_FormFillEnvironment::PopupMenu(IPDF_Page* page, |
| int menuFlag, |
| const CFX_PointF& pt) { |
| return m_pInfo && m_pInfo->version >= 2 && m_pInfo->FFI_PopupMenu && |
| m_pInfo->FFI_PopupMenu(m_pInfo, FPDFPageFromIPDFPage(page), nullptr, |
| menuFlag, pt.x, pt.y); |
| } |
| |
| void CPDFSDK_FormFillEnvironment::EmailTo(FPDF_FILEHANDLER* fileHandler, |
| FPDF_WIDESTRING pTo, |
| FPDF_WIDESTRING pSubject, |
| FPDF_WIDESTRING pCC, |
| FPDF_WIDESTRING pBcc, |
| FPDF_WIDESTRING pMsg) { |
| if (m_pInfo && m_pInfo->version >= 2 && m_pInfo->FFI_EmailTo) |
| m_pInfo->FFI_EmailTo(m_pInfo, fileHandler, pTo, pSubject, pCC, pBcc, pMsg); |
| } |
| |
| void CPDFSDK_FormFillEnvironment::UploadTo(FPDF_FILEHANDLER* fileHandler, |
| int fileFlag, |
| FPDF_WIDESTRING uploadTo) { |
| if (m_pInfo && m_pInfo->version >= 2 && m_pInfo->FFI_UploadTo) |
| m_pInfo->FFI_UploadTo(m_pInfo, fileHandler, fileFlag, uploadTo); |
| } |
| |
| FPDF_FILEHANDLER* CPDFSDK_FormFillEnvironment::OpenFile(int fileType, |
| FPDF_WIDESTRING wsURL, |
| const char* mode) { |
| if (m_pInfo && m_pInfo->version >= 2 && m_pInfo->FFI_OpenFile) |
| return m_pInfo->FFI_OpenFile(m_pInfo, fileType, wsURL, mode); |
| return nullptr; |
| } |
| |
| RetainPtr<IFX_SeekableReadStream> CPDFSDK_FormFillEnvironment::DownloadFromURL( |
| const WideString& url) { |
| if (!m_pInfo || m_pInfo->version < 2 || !m_pInfo->FFI_DownloadFromURL) |
| return nullptr; |
| |
| ByteString bstrURL = url.ToUTF16LE(); |
| FPDF_FILEHANDLER* fileHandler = |
| m_pInfo->FFI_DownloadFromURL(m_pInfo, AsFPDFWideString(&bstrURL)); |
| |
| return MakeSeekableStream(fileHandler); |
| } |
| |
| WideString CPDFSDK_FormFillEnvironment::PostRequestURL( |
| const WideString& wsURL, |
| const WideString& wsData, |
| const WideString& wsContentType, |
| const WideString& wsEncode, |
| const WideString& wsHeader) { |
| if (!m_pInfo || m_pInfo->version < 2 || !m_pInfo->FFI_PostRequestURL) |
| return WideString(); |
| |
| ByteString bsURL = wsURL.ToUTF16LE(); |
| ByteString bsData = wsData.ToUTF16LE(); |
| ByteString bsContentType = wsContentType.ToUTF16LE(); |
| ByteString bsEncode = wsEncode.ToUTF16LE(); |
| ByteString bsHeader = wsHeader.ToUTF16LE(); |
| |
| FPDF_BSTR response; |
| FPDF_BStr_Init(&response); |
| m_pInfo->FFI_PostRequestURL( |
| m_pInfo, AsFPDFWideString(&bsURL), AsFPDFWideString(&bsData), |
| AsFPDFWideString(&bsContentType), AsFPDFWideString(&bsEncode), |
| AsFPDFWideString(&bsHeader), &response); |
| |
| WideString wsRet = |
| WideString::FromUTF16LE(reinterpret_cast<FPDF_WIDESTRING>(response.str), |
| response.len / sizeof(FPDF_WIDESTRING)); |
| |
| FPDF_BStr_Clear(&response); |
| return wsRet; |
| } |
| |
| FPDF_BOOL CPDFSDK_FormFillEnvironment::PutRequestURL( |
| const WideString& wsURL, |
| const WideString& wsData, |
| const WideString& wsEncode) { |
| if (!m_pInfo || m_pInfo->version < 2 || !m_pInfo->FFI_PutRequestURL) |
| return false; |
| |
| ByteString bsURL = wsURL.ToUTF16LE(); |
| ByteString bsData = wsData.ToUTF16LE(); |
| ByteString bsEncode = wsEncode.ToUTF16LE(); |
| |
| return m_pInfo->FFI_PutRequestURL(m_pInfo, AsFPDFWideString(&bsURL), |
| AsFPDFWideString(&bsData), |
| AsFPDFWideString(&bsEncode)); |
| } |
| |
| void CPDFSDK_FormFillEnvironment::PageEvent(int iPageCount, |
| uint32_t dwEventType) const { |
| if (m_pInfo && m_pInfo->version >= 2 && m_pInfo->FFI_PageEvent) |
| m_pInfo->FFI_PageEvent(m_pInfo, iPageCount, dwEventType); |
| } |
| #endif // PDF_ENABLE_XFA |
| |
| void CPDFSDK_FormFillEnvironment::ClearAllFocusedAnnots() { |
| for (auto& it : m_PageMap) { |
| if (it.second->IsValidSDKAnnot(GetFocusAnnot())) |
| KillFocusAnnot({}); |
| } |
| } |
| |
| CPDFSDK_PageView* CPDFSDK_FormFillEnvironment::GetOrCreatePageView( |
| IPDF_Page* pUnderlyingPage) { |
| CPDFSDK_PageView* pExisting = GetPageView(pUnderlyingPage); |
| if (pExisting) |
| return pExisting; |
| |
| auto pNew = std::make_unique<CPDFSDK_PageView>(this, pUnderlyingPage); |
| CPDFSDK_PageView* pPageView = pNew.get(); |
| m_PageMap[pUnderlyingPage] = std::move(pNew); |
| |
| // Delay to load all the annotations, to avoid endless loop. |
| pPageView->LoadFXAnnots(); |
| return pPageView; |
| } |
| |
| CPDFSDK_PageView* CPDFSDK_FormFillEnvironment::GetPageView( |
| IPDF_Page* pUnderlyingPage) { |
| auto it = m_PageMap.find(pUnderlyingPage); |
| return it != m_PageMap.end() ? it->second.get() : nullptr; |
| } |
| |
| CFX_Timer::HandlerIface* CPDFSDK_FormFillEnvironment::GetTimerHandler() { |
| return this; |
| } |
| |
| IPWL_SystemHandler* CPDFSDK_FormFillEnvironment::GetSysHandler() { |
| return this; |
| } |
| |
| CPDFSDK_PageView* CPDFSDK_FormFillEnvironment::GetPageViewAtIndex(int nIndex) { |
| IPDF_Page* pTempPage = GetPage(nIndex); |
| return pTempPage ? GetPageView(pTempPage) : nullptr; |
| } |
| |
| void CPDFSDK_FormFillEnvironment::ProcJavascriptAction() { |
| auto name_tree = CPDF_NameTree::Create(m_pCPDFDoc.Get(), "JavaScript"); |
| if (!name_tree) |
| return; |
| |
| size_t count = name_tree->GetCount(); |
| for (size_t i = 0; i < count; ++i) { |
| WideString name; |
| CPDF_Action action(ToDictionary(name_tree->LookupValueAndName(i, &name))); |
| GetActionHandler()->DoAction_JavaScript(action, name, this); |
| } |
| } |
| |
| bool CPDFSDK_FormFillEnvironment::ProcOpenAction() { |
| CPDF_Dictionary* pRoot = m_pCPDFDoc->GetRoot(); |
| if (!pRoot) |
| return false; |
| |
| CPDF_Object* pOpenAction = pRoot->GetDictFor("OpenAction"); |
| if (!pOpenAction) |
| pOpenAction = pRoot->GetArrayFor("OpenAction"); |
| if (!pOpenAction) |
| return false; |
| |
| if (pOpenAction->IsArray()) |
| return true; |
| |
| CPDF_Dictionary* pDict = pOpenAction->AsDictionary(); |
| if (!pDict) |
| return false; |
| |
| CPDF_Action action(pDict); |
| GetActionHandler()->DoAction_DocOpen(action, this); |
| return true; |
| } |
| |
| void CPDFSDK_FormFillEnvironment::RemovePageView(IPDF_Page* pUnderlyingPage) { |
| auto it = m_PageMap.find(pUnderlyingPage); |
| if (it == m_PageMap.end()) |
| return; |
| |
| CPDFSDK_PageView* pPageView = it->second.get(); |
| if (pPageView->IsLocked() || pPageView->IsBeingDestroyed()) |
| return; |
| |
| // Mark the page view so we do not come into |RemovePageView| a second |
| // time while we're in the process of removing. |
| pPageView->SetBeingDestroyed(); |
| |
| // This must happen before we remove |pPageView| from the map because |
| // |KillFocusAnnot| can call into the |GetPage| method which will |
| // look for this page view in the map, if it doesn't find it a new one will |
| // be created. We then have two page views pointing to the same page and |
| // bad things happen. |
| if (pPageView->IsValidSDKAnnot(GetFocusAnnot())) |
| KillFocusAnnot({}); |
| |
| // Remove the page from the map to make sure we don't accidentally attempt |
| // to use the |pPageView| while we're cleaning it up. |
| m_PageMap.erase(it); |
| } |
| |
| IPDF_Page* CPDFSDK_FormFillEnvironment::GetPage(int nIndex) const { |
| if (!m_pInfo || !m_pInfo->FFI_GetPage) |
| return nullptr; |
| return IPDFPageFromFPDFPage(m_pInfo->FFI_GetPage( |
| m_pInfo, FPDFDocumentFromCPDFDocument(m_pCPDFDoc.Get()), nIndex)); |
| } |
| |
| CPDFSDK_InteractiveForm* CPDFSDK_FormFillEnvironment::GetInteractiveForm() { |
| if (!m_pInteractiveForm) |
| m_pInteractiveForm = std::make_unique<CPDFSDK_InteractiveForm>(this); |
| return m_pInteractiveForm.get(); |
| } |
| |
| void CPDFSDK_FormFillEnvironment::UpdateAllViews(CPDFSDK_Annot* pAnnot) { |
| for (const auto& it : m_PageMap) { |
| CPDFSDK_PageView* pPageView = it.second.get(); |
| if (pPageView) |
| pPageView->UpdateView(pAnnot); |
| } |
| } |
| |
| CPDFSDK_Annot* CPDFSDK_FormFillEnvironment::GetFocusAnnot() const { |
| return m_pFocusAnnot.Get(); |
| } |
| |
| bool CPDFSDK_FormFillEnvironment::SetFocusAnnot( |
| ObservedPtr<CPDFSDK_Annot>& pAnnot) { |
| if (m_bBeingDestroyed) |
| return false; |
| if (m_pFocusAnnot == pAnnot) |
| return true; |
| if (m_pFocusAnnot && !KillFocusAnnot({})) |
| return false; |
| if (!pAnnot) |
| return false; |
| if (!pAnnot->GetPageView()->IsValid()) |
| return false; |
| |
| CPDFSDK_AnnotHandlerMgr* pAnnotHandler = GetAnnotHandlerMgr(); |
| if (m_pFocusAnnot) |
| return false; |
| |
| #ifdef PDF_ENABLE_XFA |
| if (!pAnnotHandler->Annot_OnChangeFocus(pAnnot)) |
| return false; |
| |
| // |pAnnot| may be destroyed in |Annot_OnChangeFocus|. |
| if (!pAnnot) |
| return false; |
| #endif // PDF_ENABLE_XFA |
| |
| if (!pAnnotHandler->Annot_OnSetFocus(pAnnot, {})) |
| return false; |
| if (m_pFocusAnnot) |
| return false; |
| |
| m_pFocusAnnot.Reset(pAnnot.Get()); |
| |
| // If we are not able to inform the client about the focus change, it |
| // shouldn't be considered as failure. |
| SendOnFocusChange(pAnnot); |
| return true; |
| } |
| |
| bool CPDFSDK_FormFillEnvironment::KillFocusAnnot(Mask<FWL_EVENTFLAG> nFlag) { |
| if (!m_pFocusAnnot) |
| return false; |
| |
| CPDFSDK_AnnotHandlerMgr* pAnnotHandler = GetAnnotHandlerMgr(); |
| ObservedPtr<CPDFSDK_Annot> pFocusAnnot(m_pFocusAnnot.Get()); |
| m_pFocusAnnot.Reset(); |
| |
| if (!pAnnotHandler->Annot_OnKillFocus(pFocusAnnot, nFlag)) { |
| m_pFocusAnnot.Reset(pFocusAnnot.Get()); |
| return false; |
| } |
| |
| // Might have been destroyed by Annot_OnKillFocus(). |
| if (!pFocusAnnot) |
| return false; |
| |
| if (pFocusAnnot->GetAnnotSubtype() == CPDF_Annot::Subtype::WIDGET) { |
| CPDFSDK_Widget* pWidget = ToCPDFSDKWidget(pFocusAnnot.Get()); |
| FormFieldType fieldType = pWidget->GetFieldType(); |
| if (fieldType == FormFieldType::kTextField || |
| fieldType == FormFieldType::kComboBox) { |
| OnSetFieldInputFocusInternal(WideString(), false); |
| } |
| } |
| return !m_pFocusAnnot; |
| } |
| |
| int CPDFSDK_FormFillEnvironment::GetPageCount() const { |
| CPDF_Document::Extension* pExtension = m_pCPDFDoc->GetExtension(); |
| return pExtension ? pExtension->GetPageCount() : m_pCPDFDoc->GetPageCount(); |
| } |
| |
| bool CPDFSDK_FormFillEnvironment::HasPermissions(uint32_t flags) const { |
| return !!(m_pCPDFDoc->GetUserPermissions() & flags); |
| } |
| |
| void CPDFSDK_FormFillEnvironment::SendOnFocusChange( |
| ObservedPtr<CPDFSDK_Annot>& pAnnot) { |
| if (!m_pInfo || m_pInfo->version < 2 || !m_pInfo->FFI_OnFocusChange) |
| return; |
| |
| // TODO(crbug.com/pdfium/1482): Handle XFA case. |
| if (pAnnot->AsXFAWidget()) |
| return; |
| |
| CPDFSDK_PageView* pPageView = pAnnot->GetPageView(); |
| if (!pPageView->IsValid()) |
| return; |
| |
| IPDF_Page* page = pAnnot->GetPage(); |
| if (!page) |
| return; |
| |
| CPDF_Dictionary* annot_dict = pAnnot->GetPDFAnnot()->GetAnnotDict(); |
| auto focused_annot = std::make_unique<CPDF_AnnotContext>(annot_dict, page); |
| FPDF_ANNOTATION fpdf_annot = |
| FPDFAnnotationFromCPDFAnnotContext(focused_annot.get()); |
| |
| m_pInfo->FFI_OnFocusChange(m_pInfo, fpdf_annot, pPageView->GetPageIndex()); |
| } |