// Copyright 2016 The PDFium Authors // 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 #include #include #include #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/data_vector.h" #include "core/fxcrt/stl_util.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 "fxjs/ijs_event_context.h" #include "fxjs/ijs_runtime.h" #include "third_party/base/check.h" #include "third_party/base/containers/contains.h" #include "third_party/base/notreached.h" #include "third_party/base/numerics/safe_conversions.h" #ifdef PDF_ENABLE_XFA #include "fpdfsdk/fpdfxfa/cpdfxfa_widget.h" #endif static_assert(FXCT_ARROW == static_cast(IPWL_FillerNotify::CursorStyle::kArrow), "kArrow value mismatch"); static_assert(FXCT_NESW == static_cast(IPWL_FillerNotify::CursorStyle::kNESW), "kNEWS value mismatch"); static_assert(FXCT_NWSE == static_cast(IPWL_FillerNotify::CursorStyle::kNWSE), "kNWSE value mismatch"); static_assert(FXCT_VBEAM == static_cast(IPWL_FillerNotify::CursorStyle::kVBeam), "kVBeam value mismatch"); static_assert(FXCT_HBEAM == static_cast(IPWL_FillerNotify::CursorStyle::kHBeam), "HBeam value mismatch"); static_assert(FXCT_HAND == static_cast(IPWL_FillerNotify::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( bsUTF16LE->GetBuffer(bsUTF16LE->GetLength()).data()); } CPDFSDK_FormFillEnvironment::CPDFSDK_FormFillEnvironment( CPDF_Document* pDoc, FPDF_FORMFILLINFO* pFFinfo) : m_pInfo(pFFinfo), m_pCPDFDoc(pDoc), m_pInteractiveFormFiller( std::make_unique(this)) { DCHECK(m_pCPDFDoc); } 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(); // 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(CPDFSDK_Widget* widget, const CFX_FloatRect& rect) { 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( CFFL_FormField* pFormField, const CFX_FloatRect& rect) { if (!m_pInfo || !m_pInfo->FFI_OutputSelectedRect) 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 = GetCurrentPage(); return pPage ? GetOrCreatePageView(pPage) : nullptr; } IPDF_Page* CPDFSDK_FormFillEnvironment::GetCurrentPage() const { if (m_pInfo && m_pInfo->FFI_GetCurrentPage) { return IPDFPageFromFPDFPage(m_pInfo->FFI_GetCurrentPage( m_pInfo, FPDFDocumentFromCPDFDocument(m_pCPDFDoc))); } 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(); DataVector 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(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(); DataVector 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(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 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(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(); DataVector 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); // Use FromDefANSI() per "local encoding" comment in fpdf_formfill.h. return WideString::FromDefANSI(ByteStringView(pBuff)); } void CPDFSDK_FormFillEnvironment::JS_docmailForm( pdfium::span 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, const_cast(mailData.data()), pdfium::base::checked_cast(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(); DataVector 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); // Use FromDefANSI() per "local encoding" comment in fpdf_formfill.h. return WideString::FromDefANSI(ByteStringView(pBuff)); } void CPDFSDK_FormFillEnvironment::SubmitForm( pdfium::span 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, const_cast(form_data.data()), fxcrt::CollectionSize(form_data), AsFPDFWideString(&bsUrl)); } IJS_Runtime* CPDFSDK_FormFillEnvironment::GetIJSRuntime() { if (!m_pIJSRuntime) m_pIJSRuntime = IJS_Runtime::Create(this); return m_pIJSRuntime.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( IPWL_FillerNotify::CursorStyle nCursorType) { if (m_pInfo && m_pInfo->FFI_SetCursor) m_pInfo->FFI_SetCursor(m_pInfo, static_cast(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) { size_t nCharacters = text.GetLength(); ByteString bsUTFText = text.ToUTF16LE(); auto* pBuffer = reinterpret_cast(bsUTFText.c_str()); m_pInfo->FFI_SetTextFieldFocus( m_pInfo, pBuffer, pdfium::base::checked_cast(nCharacters), bFocus); } } void CPDFSDK_FormFillEnvironment::OnCalculate( ObservedPtr& pAnnot) { CPDFSDK_Widget* pWidget = ToCPDFSDKWidget(pAnnot.Get()); if (pWidget) m_pInteractiveForm->OnCalculate(pWidget->GetFormField()); } void CPDFSDK_FormFillEnvironment::OnFormat(ObservedPtr& pAnnot) { CPDFSDK_Widget* pWidget = ToCPDFSDKWidget(pAnnot.Get()); DCHECK(pWidget); absl::optional 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 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, pdfium::span fPosArray) { if (m_pInfo && m_pInfo->FFI_DoGoToAction) { m_pInfo->FFI_DoGoToAction(m_pInfo, nPageIndex, zoomMode, fPosArray.data(), fxcrt::CollectionSize(fPosArray)); } } #ifdef PDF_ENABLE_XFA int CPDFSDK_FormFillEnvironment::GetPageViewCount() const { return fxcrt::CollectionSize(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)); } 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), 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), 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(left); rect.top = static_cast(top); rect.bottom = static_cast(bottom); rect.right = static_cast(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 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(response.str), response.len / sizeof(FPDF_WCHAR)); 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())) { ObservedPtr pObserved(it.second.get()); KillFocusAnnot({}); if (!pObserved) break; } } } CPDFSDK_PageView* CPDFSDK_FormFillEnvironment::GetOrCreatePageView( IPDF_Page* pUnderlyingPage) { CPDFSDK_PageView* pExisting = GetPageView(pUnderlyingPage); if (pExisting) return pExisting; auto pNew = std::make_unique(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; } 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, "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))); DoActionJavaScript(action, name); } } bool CPDFSDK_FormFillEnvironment::ProcOpenAction() { const CPDF_Dictionary* pRoot = m_pCPDFDoc->GetRoot(); if (!pRoot) return false; RetainPtr pOpenAction(pRoot->GetDictFor("OpenAction")); if (!pOpenAction) pOpenAction = pRoot->GetArrayFor("OpenAction"); if (!pOpenAction) return false; if (pOpenAction->IsArray()) return true; RetainPtr pDict = ToDictionary(pOpenAction); if (!pDict) return false; DoActionDocOpen(CPDF_Action(std::move(pDict))); 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), nIndex)); } CPDFSDK_InteractiveForm* CPDFSDK_FormFillEnvironment::GetInteractiveForm() { if (!m_pInteractiveForm) m_pInteractiveForm = std::make_unique(this); return m_pInteractiveForm.get(); } void CPDFSDK_FormFillEnvironment::UpdateAllViews(CPDFSDK_Annot* pAnnot) { for (const auto& it : m_PageMap) { ObservedPtr pObserved(it.second.get()); if (pObserved) { pObserved->UpdateView(pAnnot); if (!pObserved) break; } } } CPDFSDK_Annot* CPDFSDK_FormFillEnvironment::GetFocusAnnot() const { return m_pFocusAnnot.Get(); } bool CPDFSDK_FormFillEnvironment::SetFocusAnnot( ObservedPtr& 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; if (m_pFocusAnnot) return false; #ifdef PDF_ENABLE_XFA CPDFXFA_Widget* pXFAWidget = pAnnot->AsXFAWidget(); if (pXFAWidget && pXFAWidget->OnChangedFocus()) return false; // `pAnnot` may be destroyed in `OnChangedFocus()`. if (!pAnnot) return false; #endif // PDF_ENABLE_XFA if (!CPDFSDK_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 nFlags) { if (!m_pFocusAnnot) return false; ObservedPtr pFocusAnnot(m_pFocusAnnot.Get()); m_pFocusAnnot.Reset(); if (!CPDFSDK_Annot::OnKillFocus(pFocusAnnot, nFlags)) { m_pFocusAnnot.Reset(pFocusAnnot.Get()); return false; } // Might have been destroyed by 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& 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; RetainPtr annot_dict = pAnnot->GetPDFAnnot()->GetMutableAnnotDict(); auto focused_annot = std::make_unique(annot_dict, page); FPDF_ANNOTATION fpdf_annot = FPDFAnnotationFromCPDFAnnotContext(focused_annot.get()); m_pInfo->FFI_OnFocusChange(m_pInfo, fpdf_annot, pPageView->GetPageIndex()); } bool CPDFSDK_FormFillEnvironment::DoActionDocOpen(const CPDF_Action& action) { std::set visited; return ExecuteDocumentOpenAction(action, &visited); } bool CPDFSDK_FormFillEnvironment::DoActionJavaScript( const CPDF_Action& JsAction, WideString csJSName) { if (JsAction.GetType() == CPDF_Action::Type::kJavaScript) { WideString swJS = JsAction.GetJavaScript(); if (!swJS.IsEmpty()) { RunDocumentOpenJavaScript(csJSName, swJS); return true; } } return false; } bool CPDFSDK_FormFillEnvironment::DoActionFieldJavaScript( const CPDF_Action& JsAction, CPDF_AAction::AActionType type, CPDF_FormField* pFormField, CFFL_FieldAction* data) { if (IsJSPlatformPresent() && JsAction.GetType() == CPDF_Action::Type::kJavaScript) { WideString swJS = JsAction.GetJavaScript(); if (!swJS.IsEmpty()) { RunFieldJavaScript(pFormField, type, data, swJS); return true; } } return false; } bool CPDFSDK_FormFillEnvironment::DoActionLink(const CPDF_Action& action, CPDF_AAction::AActionType type, Mask modifiers) { if (!CPDF_AAction::IsUserInput(type)) return false; switch (action.GetType()) { case CPDF_Action::Type::kGoTo: DoActionGoTo(action); return true; case CPDF_Action::Type::kURI: DoActionURI(action, modifiers); return true; default: return false; } } bool CPDFSDK_FormFillEnvironment::DoActionDestination(const CPDF_Dest& dest) { CPDF_Document* document = GetPDFDocument(); DCHECK(document); std::vector positions = dest.GetScrollPositionArray(); DoGoToAction(dest.GetDestPageIndex(document), dest.GetZoomMode(), positions); return true; } bool CPDFSDK_FormFillEnvironment::DoActionPage( const CPDF_Action& action, CPDF_AAction::AActionType eType) { std::set visited; return ExecuteDocumentPageAction(action, eType, &visited); } bool CPDFSDK_FormFillEnvironment::DoActionDocument( const CPDF_Action& action, CPDF_AAction::AActionType eType) { std::set visited; return ExecuteDocumentPageAction(action, eType, &visited); } bool CPDFSDK_FormFillEnvironment::DoActionField(const CPDF_Action& action, CPDF_AAction::AActionType type, CPDF_FormField* pFormField, CFFL_FieldAction* data) { std::set visited; return ExecuteFieldAction(action, type, pFormField, data, &visited); } bool CPDFSDK_FormFillEnvironment::ExecuteDocumentOpenAction( const CPDF_Action& action, std::set* visited) { const CPDF_Dictionary* pDict = action.GetDict(); if (pdfium::Contains(*visited, pDict)) return false; visited->insert(pDict); if (action.GetType() == CPDF_Action::Type::kJavaScript) { if (IsJSPlatformPresent()) { WideString swJS = action.GetJavaScript(); if (!swJS.IsEmpty()) RunDocumentOpenJavaScript(WideString(), swJS); } } else { DoActionNoJs(action, CPDF_AAction::AActionType::kDocumentOpen); } for (size_t i = 0, sz = action.GetSubActionsCount(); i < sz; i++) { CPDF_Action subaction = action.GetSubAction(i); if (!ExecuteDocumentOpenAction(subaction, visited)) return false; } return true; } bool CPDFSDK_FormFillEnvironment::ExecuteDocumentPageAction( const CPDF_Action& action, CPDF_AAction::AActionType type, std::set* visited) { const CPDF_Dictionary* pDict = action.GetDict(); if (pdfium::Contains(*visited, pDict)) return false; visited->insert(pDict); if (action.GetType() == CPDF_Action::Type::kJavaScript) { if (IsJSPlatformPresent()) { WideString swJS = action.GetJavaScript(); if (!swJS.IsEmpty()) RunDocumentPageJavaScript(type, swJS); } } else { DoActionNoJs(action, type); } for (size_t i = 0, sz = action.GetSubActionsCount(); i < sz; i++) { CPDF_Action subaction = action.GetSubAction(i); if (!ExecuteDocumentPageAction(subaction, type, visited)) return false; } return true; } bool CPDFSDK_FormFillEnvironment::IsValidField( const CPDF_Dictionary* pFieldDict) { DCHECK(pFieldDict); CPDFSDK_InteractiveForm* pForm = GetInteractiveForm(); CPDF_InteractiveForm* pPDFForm = pForm->GetInteractiveForm(); return !!pPDFForm->GetFieldByDict(pFieldDict); } bool CPDFSDK_FormFillEnvironment::ExecuteFieldAction( const CPDF_Action& action, CPDF_AAction::AActionType type, CPDF_FormField* pFormField, CFFL_FieldAction* data, std::set* visited) { const CPDF_Dictionary* pDict = action.GetDict(); if (pdfium::Contains(*visited, pDict)) return false; visited->insert(pDict); if (action.GetType() == CPDF_Action::Type::kJavaScript) { if (IsJSPlatformPresent()) { WideString swJS = action.GetJavaScript(); if (!swJS.IsEmpty()) { RunFieldJavaScript(pFormField, type, data, swJS); if (!IsValidField(pFormField->GetFieldDict())) return false; } } } else { DoActionNoJs(action, type); } for (size_t i = 0, sz = action.GetSubActionsCount(); i < sz; i++) { CPDF_Action subaction = action.GetSubAction(i); if (!ExecuteFieldAction(subaction, type, pFormField, data, visited)) return false; } return true; } void CPDFSDK_FormFillEnvironment::DoActionNoJs(const CPDF_Action& action, CPDF_AAction::AActionType type) { switch (action.GetType()) { case CPDF_Action::Type::kGoTo: DoActionGoTo(action); break; case CPDF_Action::Type::kURI: if (CPDF_AAction::IsUserInput(type)) DoActionURI(action, Mask{}); break; case CPDF_Action::Type::kHide: DoActionHide(action); break; case CPDF_Action::Type::kNamed: DoActionNamed(action); break; case CPDF_Action::Type::kSubmitForm: if (CPDF_AAction::IsUserInput(type)) DoActionSubmitForm(action); break; case CPDF_Action::Type::kResetForm: DoActionResetForm(action); break; case CPDF_Action::Type::kJavaScript: NOTREACHED_NORETURN(); break; case CPDF_Action::Type::kSetOCGState: case CPDF_Action::Type::kThread: case CPDF_Action::Type::kSound: case CPDF_Action::Type::kMovie: case CPDF_Action::Type::kRendition: case CPDF_Action::Type::kTrans: case CPDF_Action::Type::kGoTo3DView: case CPDF_Action::Type::kGoToR: case CPDF_Action::Type::kGoToE: case CPDF_Action::Type::kLaunch: case CPDF_Action::Type::kImportData: // Unimplemented break; default: break; } } void CPDFSDK_FormFillEnvironment::DoActionGoTo(const CPDF_Action& action) { DCHECK(action.GetDict()); CPDF_Document* pPDFDocument = GetPDFDocument(); DCHECK(pPDFDocument); CPDF_Dest MyDest = action.GetDest(pPDFDocument); DoActionDestination(MyDest); } void CPDFSDK_FormFillEnvironment::DoActionURI(const CPDF_Action& action, Mask modifiers) { DCHECK(action.GetDict()); DoURIAction(action.GetURI(GetPDFDocument()), modifiers); } void CPDFSDK_FormFillEnvironment::DoActionNamed(const CPDF_Action& action) { DCHECK(action.GetDict()); ExecuteNamedAction(action.GetNamedAction()); } void CPDFSDK_FormFillEnvironment::RunFieldJavaScript( CPDF_FormField* pFormField, CPDF_AAction::AActionType type, CFFL_FieldAction* data, const WideString& script) { DCHECK(type != CPDF_AAction::kCalculate); DCHECK(type != CPDF_AAction::kFormat); RunScript(script, [type, data, pFormField](IJS_EventContext* context) { switch (type) { case CPDF_AAction::kCursorEnter: context->OnField_MouseEnter(data->bModifier, data->bShift, pFormField); break; case CPDF_AAction::kCursorExit: context->OnField_MouseExit(data->bModifier, data->bShift, pFormField); break; case CPDF_AAction::kButtonDown: context->OnField_MouseDown(data->bModifier, data->bShift, pFormField); break; case CPDF_AAction::kButtonUp: context->OnField_MouseUp(data->bModifier, data->bShift, pFormField); break; case CPDF_AAction::kGetFocus: context->OnField_Focus(data->bModifier, data->bShift, pFormField, &data->sValue); break; case CPDF_AAction::kLoseFocus: context->OnField_Blur(data->bModifier, data->bShift, pFormField, &data->sValue); break; case CPDF_AAction::kKeyStroke: context->OnField_Keystroke( &data->sChange, data->sChangeEx, data->bKeyDown, data->bModifier, &data->nSelEnd, &data->nSelStart, data->bShift, pFormField, &data->sValue, data->bWillCommit, data->bFieldFull, &data->bRC); break; case CPDF_AAction::kValidate: context->OnField_Validate(&data->sChange, data->sChangeEx, data->bKeyDown, data->bModifier, data->bShift, pFormField, &data->sValue, &data->bRC); break; default: NOTREACHED_NORETURN(); break; } }); } void CPDFSDK_FormFillEnvironment::RunDocumentOpenJavaScript( const WideString& sScriptName, const WideString& script) { RunScript(script, [sScriptName](IJS_EventContext* context) { context->OnDoc_Open(sScriptName); }); } void CPDFSDK_FormFillEnvironment::RunDocumentPageJavaScript( CPDF_AAction::AActionType type, const WideString& script) { RunScript(script, [type](IJS_EventContext* context) { switch (type) { case CPDF_AAction::kOpenPage: context->OnPage_Open(); break; case CPDF_AAction::kClosePage: context->OnPage_Close(); break; case CPDF_AAction::kCloseDocument: context->OnDoc_WillClose(); break; case CPDF_AAction::kSaveDocument: context->OnDoc_WillSave(); break; case CPDF_AAction::kDocumentSaved: context->OnDoc_DidSave(); break; case CPDF_AAction::kPrintDocument: context->OnDoc_WillPrint(); break; case CPDF_AAction::kDocumentPrinted: context->OnDoc_DidPrint(); break; case CPDF_AAction::kPageVisible: context->OnPage_InView(); break; case CPDF_AAction::kPageInvisible: context->OnPage_OutView(); break; default: NOTREACHED_NORETURN(); break; } }); } bool CPDFSDK_FormFillEnvironment::DoActionHide(const CPDF_Action& action) { CPDFSDK_InteractiveForm* pForm = GetInteractiveForm(); if (pForm->DoAction_Hide(action)) { SetChangeMark(); return true; } return false; } bool CPDFSDK_FormFillEnvironment::DoActionSubmitForm( const CPDF_Action& action) { CPDFSDK_InteractiveForm* pForm = GetInteractiveForm(); return pForm->DoAction_SubmitForm(action); } void CPDFSDK_FormFillEnvironment::DoActionResetForm(const CPDF_Action& action) { CPDFSDK_InteractiveForm* pForm = GetInteractiveForm(); pForm->DoAction_ResetForm(action); } void CPDFSDK_FormFillEnvironment::RunScript(const WideString& script, const RunScriptCallback& cb) { IJS_Runtime::ScopedEventContext pContext(GetIJSRuntime()); cb(pContext.Get()); pContext->RunScript(script); // TODO(dsinclair): Return error if RunScript returns a IJS_Runtime::JS_Error. }