| // 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/fpdfxfa/cpdfxfa_docenvironment.h" | |
| #include <memory> | |
| #include "core/fpdfapi/parser/cpdf_array.h" | |
| #include "core/fpdfapi/parser/cpdf_stream_acc.h" | |
| #include "core/fpdfapi/parser/cpdf_string.h" | |
| #include "core/fxcrt/cfx_retain_ptr.h" | |
| #include "fpdfsdk/cpdfsdk_formfillenvironment.h" | |
| #include "fpdfsdk/cpdfsdk_interform.h" | |
| #include "fpdfsdk/cpdfsdk_pageview.h" | |
| #include "fpdfsdk/fpdfxfa/cpdfxfa_context.h" | |
| #include "fpdfsdk/fpdfxfa/cpdfxfa_page.h" | |
| #include "fpdfsdk/javascript/ijs_runtime.h" | |
| #include "xfa/fxfa/cxfa_ffdocview.h" | |
| #include "xfa/fxfa/cxfa_ffwidget.h" | |
| #include "xfa/fxfa/cxfa_ffwidgethandler.h" | |
| #include "xfa/fxfa/cxfa_widgetacciterator.h" | |
| #define IDS_XFA_Validate_Input \ | |
| "At least one required field was empty. Please fill in the required " \ | |
| "fields\r\n(highlighted) before continuing." | |
| // submit | |
| #define FXFA_CONFIG 0x00000001 | |
| #define FXFA_TEMPLATE 0x00000010 | |
| #define FXFA_LOCALESET 0x00000100 | |
| #define FXFA_DATASETS 0x00001000 | |
| #define FXFA_XMPMETA 0x00010000 | |
| #define FXFA_XFDF 0x00100000 | |
| #define FXFA_FORM 0x01000000 | |
| #define FXFA_PDF 0x10000000 | |
| #define FXFA_XFA_ALL 0x01111111 | |
| CPDFXFA_DocEnvironment::CPDFXFA_DocEnvironment(CPDFXFA_Context* pContext) | |
| : m_pContext(pContext) { | |
| ASSERT(m_pContext); | |
| } | |
| CPDFXFA_DocEnvironment::~CPDFXFA_DocEnvironment() {} | |
| void CPDFXFA_DocEnvironment::SetChangeMark(CXFA_FFDoc* hDoc) { | |
| if (hDoc == m_pContext->GetXFADoc() && m_pContext->GetFormFillEnv()) | |
| m_pContext->GetFormFillEnv()->SetChangeMark(); | |
| } | |
| void CPDFXFA_DocEnvironment::InvalidateRect(CXFA_FFPageView* pPageView, | |
| const CFX_RectF& rt) { | |
| if (!m_pContext->GetXFADoc() || !m_pContext->GetFormFillEnv()) | |
| return; | |
| if (m_pContext->GetDocType() != XFA_DocType::Dynamic) | |
| return; | |
| CFX_RetainPtr<CPDFXFA_Page> pPage = m_pContext->GetXFAPage(pPageView); | |
| if (!pPage) | |
| return; | |
| CPDFSDK_FormFillEnvironment* pFormFillEnv = m_pContext->GetFormFillEnv(); | |
| if (!pFormFillEnv) | |
| return; | |
| pFormFillEnv->Invalidate(pPage.Get(), | |
| CFX_FloatRect::FromCFXRectF(rt).ToFxRect()); | |
| } | |
| void CPDFXFA_DocEnvironment::DisplayCaret(CXFA_FFWidget* hWidget, | |
| bool bVisible, | |
| const CFX_RectF* pRtAnchor) { | |
| if (!hWidget || !pRtAnchor || !m_pContext->GetXFADoc() || | |
| !m_pContext->GetFormFillEnv() || !m_pContext->GetXFADocView()) | |
| return; | |
| if (m_pContext->GetDocType() != XFA_DocType::Dynamic) | |
| return; | |
| CXFA_FFWidgetHandler* pWidgetHandler = | |
| m_pContext->GetXFADocView()->GetWidgetHandler(); | |
| if (!pWidgetHandler) | |
| return; | |
| CXFA_FFPageView* pPageView = hWidget->GetPageView(); | |
| if (!pPageView) | |
| return; | |
| CFX_RetainPtr<CPDFXFA_Page> pPage = m_pContext->GetXFAPage(pPageView); | |
| if (!pPage) | |
| return; | |
| CPDFSDK_FormFillEnvironment* pFormFillEnv = m_pContext->GetFormFillEnv(); | |
| if (!pFormFillEnv) | |
| return; | |
| CFX_FloatRect rcCaret = CFX_FloatRect::FromCFXRectF(*pRtAnchor); | |
| pFormFillEnv->DisplayCaret(pPage.Get(), bVisible, rcCaret.left, rcCaret.top, | |
| rcCaret.right, rcCaret.bottom); | |
| } | |
| bool CPDFXFA_DocEnvironment::GetPopupPos(CXFA_FFWidget* hWidget, | |
| float fMinPopup, | |
| float fMaxPopup, | |
| const CFX_RectF& rtAnchor, | |
| CFX_RectF& rtPopup) { | |
| if (!hWidget) | |
| return false; | |
| CXFA_FFPageView* pXFAPageView = hWidget->GetPageView(); | |
| if (!pXFAPageView) | |
| return false; | |
| CFX_RetainPtr<CPDFXFA_Page> pPage = m_pContext->GetXFAPage(pXFAPageView); | |
| if (!pPage) | |
| return false; | |
| CPDFSDK_FormFillEnvironment* pFormFillEnv = m_pContext->GetFormFillEnv(); | |
| if (!pFormFillEnv) | |
| return false; | |
| FS_RECTF pageViewRect = {0.0f, 0.0f, 0.0f, 0.0f}; | |
| pFormFillEnv->GetPageViewRect(pPage.Get(), pageViewRect); | |
| int t1; | |
| int t2; | |
| CFX_FloatRect rcAnchor = CFX_FloatRect::FromCFXRectF(rtAnchor); | |
| int nRotate = hWidget->GetDataAcc()->GetRotate(); | |
| switch (nRotate) { | |
| case 90: { | |
| t1 = (int)(pageViewRect.right - rcAnchor.right); | |
| t2 = (int)(rcAnchor.left - pageViewRect.left); | |
| if (rcAnchor.bottom < pageViewRect.bottom) | |
| rtPopup.left += rcAnchor.bottom - pageViewRect.bottom; | |
| break; | |
| } | |
| case 180: { | |
| t2 = (int)(pageViewRect.top - rcAnchor.top); | |
| t1 = (int)(rcAnchor.bottom - pageViewRect.bottom); | |
| if (rcAnchor.left < pageViewRect.left) | |
| rtPopup.left += rcAnchor.left - pageViewRect.left; | |
| break; | |
| } | |
| case 270: { | |
| t1 = (int)(rcAnchor.left - pageViewRect.left); | |
| t2 = (int)(pageViewRect.right - rcAnchor.right); | |
| if (rcAnchor.top > pageViewRect.top) | |
| rtPopup.left -= rcAnchor.top - pageViewRect.top; | |
| break; | |
| } | |
| case 0: | |
| default: { | |
| t1 = (int)(pageViewRect.top - rcAnchor.top); | |
| t2 = (int)(rcAnchor.bottom - pageViewRect.bottom); | |
| if (rcAnchor.right > pageViewRect.right) | |
| rtPopup.left -= rcAnchor.right - pageViewRect.right; | |
| break; | |
| } | |
| } | |
| int t; | |
| uint32_t dwPos; | |
| if (t1 <= 0 && t2 <= 0) | |
| return false; | |
| if (t1 <= 0) { | |
| t = t2; | |
| dwPos = 1; | |
| } else if (t2 <= 0) { | |
| t = t1; | |
| dwPos = 0; | |
| } else if (t1 > t2) { | |
| t = t1; | |
| dwPos = 0; | |
| } else { | |
| t = t2; | |
| dwPos = 1; | |
| } | |
| float fPopupHeight; | |
| if (t < fMinPopup) | |
| fPopupHeight = fMinPopup; | |
| else if (t > fMaxPopup) | |
| fPopupHeight = fMaxPopup; | |
| else | |
| fPopupHeight = static_cast<float>(t); | |
| switch (nRotate) { | |
| case 0: | |
| case 180: { | |
| if (dwPos == 0) { | |
| rtPopup.top = rtAnchor.height; | |
| rtPopup.height = fPopupHeight; | |
| } else { | |
| rtPopup.top = -fPopupHeight; | |
| rtPopup.height = fPopupHeight; | |
| } | |
| break; | |
| } | |
| case 90: | |
| case 270: { | |
| if (dwPos == 0) { | |
| rtPopup.top = rtAnchor.width; | |
| rtPopup.height = fPopupHeight; | |
| } else { | |
| rtPopup.top = -fPopupHeight; | |
| rtPopup.height = fPopupHeight; | |
| } | |
| break; | |
| } | |
| default: | |
| break; | |
| } | |
| return true; | |
| } | |
| bool CPDFXFA_DocEnvironment::PopupMenu(CXFA_FFWidget* hWidget, | |
| CFX_PointF ptPopup) { | |
| if (!hWidget) | |
| return false; | |
| CXFA_FFPageView* pXFAPageView = hWidget->GetPageView(); | |
| if (!pXFAPageView) | |
| return false; | |
| CFX_RetainPtr<CPDFXFA_Page> pPage = m_pContext->GetXFAPage(pXFAPageView); | |
| if (!pPage) | |
| return false; | |
| CPDFSDK_FormFillEnvironment* pFormFillEnv = m_pContext->GetFormFillEnv(); | |
| if (!pFormFillEnv) | |
| return false; | |
| int menuFlag = 0; | |
| if (hWidget->CanUndo()) | |
| menuFlag |= FXFA_MENU_UNDO; | |
| if (hWidget->CanRedo()) | |
| menuFlag |= FXFA_MENU_REDO; | |
| if (hWidget->CanPaste()) | |
| menuFlag |= FXFA_MENU_PASTE; | |
| if (hWidget->CanCopy()) | |
| menuFlag |= FXFA_MENU_COPY; | |
| if (hWidget->CanCut()) | |
| menuFlag |= FXFA_MENU_CUT; | |
| if (hWidget->CanSelectAll()) | |
| menuFlag |= FXFA_MENU_SELECTALL; | |
| return pFormFillEnv->PopupMenu(pPage.Get(), hWidget, menuFlag, ptPopup); | |
| } | |
| void CPDFXFA_DocEnvironment::PageViewEvent(CXFA_FFPageView* pPageView, | |
| uint32_t dwFlags) { | |
| CPDFSDK_FormFillEnvironment* pFormFillEnv = m_pContext->GetFormFillEnv(); | |
| if (!pFormFillEnv) | |
| return; | |
| if (m_pContext->GetLoadStatus() == FXFA_LOADSTATUS_LOADING || | |
| m_pContext->GetLoadStatus() == FXFA_LOADSTATUS_CLOSING || | |
| XFA_PAGEVIEWEVENT_StopLayout != dwFlags) | |
| return; | |
| int nNewCount = m_pContext->GetPageCount(); | |
| if (nNewCount == m_pContext->GetOriginalPageCount()) | |
| return; | |
| CXFA_FFDocView* pXFADocView = m_pContext->GetXFADocView(); | |
| if (!pXFADocView) | |
| return; | |
| for (int iPageIter = 0; iPageIter < m_pContext->GetOriginalPageCount(); | |
| iPageIter++) { | |
| CFX_RetainPtr<CPDFXFA_Page> pPage = | |
| (*m_pContext->GetXFAPageList())[iPageIter]; | |
| if (!pPage) | |
| continue; | |
| m_pContext->GetFormFillEnv()->RemovePageView(pPage.Get()); | |
| pPage->SetXFAPageView(pXFADocView->GetPageView(iPageIter)); | |
| } | |
| int flag = (nNewCount < m_pContext->GetOriginalPageCount()) | |
| ? FXFA_PAGEVIEWEVENT_POSTREMOVED | |
| : FXFA_PAGEVIEWEVENT_POSTADDED; | |
| int count = abs(nNewCount - m_pContext->GetOriginalPageCount()); | |
| m_pContext->SetOriginalPageCount(nNewCount); | |
| pFormFillEnv->PageEvent(count, flag); | |
| } | |
| void CPDFXFA_DocEnvironment::WidgetPostAdd(CXFA_FFWidget* hWidget, | |
| CXFA_WidgetAcc* pWidgetData) { | |
| if (m_pContext->GetDocType() != XFA_DocType::Dynamic || !hWidget) | |
| return; | |
| CXFA_FFPageView* pPageView = hWidget->GetPageView(); | |
| if (!pPageView) | |
| return; | |
| CFX_RetainPtr<CPDFXFA_Page> pXFAPage = m_pContext->GetXFAPage(pPageView); | |
| if (!pXFAPage) | |
| return; | |
| m_pContext->GetFormFillEnv() | |
| ->GetPageView(pXFAPage.Get(), true) | |
| ->AddAnnot(hWidget); | |
| } | |
| void CPDFXFA_DocEnvironment::WidgetPreRemove(CXFA_FFWidget* hWidget, | |
| CXFA_WidgetAcc* pWidgetData) { | |
| if (m_pContext->GetDocType() != XFA_DocType::Dynamic || !hWidget) | |
| return; | |
| CXFA_FFPageView* pPageView = hWidget->GetPageView(); | |
| if (!pPageView) | |
| return; | |
| CFX_RetainPtr<CPDFXFA_Page> pXFAPage = m_pContext->GetXFAPage(pPageView); | |
| if (!pXFAPage) | |
| return; | |
| CPDFSDK_PageView* pSdkPageView = | |
| m_pContext->GetFormFillEnv()->GetPageView(pXFAPage.Get(), true); | |
| CPDFSDK_Annot* pAnnot = pSdkPageView->GetAnnotByXFAWidget(hWidget); | |
| if (pAnnot) | |
| pSdkPageView->DeleteAnnot(pAnnot); | |
| } | |
| int32_t CPDFXFA_DocEnvironment::CountPages(CXFA_FFDoc* hDoc) { | |
| if (hDoc == m_pContext->GetXFADoc() && m_pContext->GetFormFillEnv()) | |
| return m_pContext->GetPageCount(); | |
| return 0; | |
| } | |
| int32_t CPDFXFA_DocEnvironment::GetCurrentPage(CXFA_FFDoc* hDoc) { | |
| if (hDoc != m_pContext->GetXFADoc() || !m_pContext->GetFormFillEnv()) | |
| return -1; | |
| if (m_pContext->GetDocType() != XFA_DocType::Dynamic) | |
| return -1; | |
| CPDFSDK_FormFillEnvironment* pFormFillEnv = m_pContext->GetFormFillEnv(); | |
| if (!pFormFillEnv) | |
| return -1; | |
| return pFormFillEnv->GetCurrentPageIndex(m_pContext.Get()); | |
| } | |
| void CPDFXFA_DocEnvironment::SetCurrentPage(CXFA_FFDoc* hDoc, | |
| int32_t iCurPage) { | |
| if (hDoc != m_pContext->GetXFADoc() || !m_pContext->GetFormFillEnv() || | |
| m_pContext->GetDocType() != XFA_DocType::Dynamic || iCurPage < 0 || | |
| iCurPage >= m_pContext->GetFormFillEnv()->GetPageCount()) { | |
| return; | |
| } | |
| CPDFSDK_FormFillEnvironment* pFormFillEnv = m_pContext->GetFormFillEnv(); | |
| if (!pFormFillEnv) | |
| return; | |
| pFormFillEnv->SetCurrentPage(m_pContext.Get(), iCurPage); | |
| } | |
| bool CPDFXFA_DocEnvironment::IsCalculationsEnabled(CXFA_FFDoc* hDoc) { | |
| if (hDoc != m_pContext->GetXFADoc() || !m_pContext->GetFormFillEnv()) | |
| return false; | |
| if (m_pContext->GetFormFillEnv()->GetInterForm()) { | |
| return m_pContext->GetFormFillEnv() | |
| ->GetInterForm() | |
| ->IsXfaCalculateEnabled(); | |
| } | |
| return false; | |
| } | |
| void CPDFXFA_DocEnvironment::SetCalculationsEnabled(CXFA_FFDoc* hDoc, | |
| bool bEnabled) { | |
| if (hDoc != m_pContext->GetXFADoc() || !m_pContext->GetFormFillEnv()) | |
| return; | |
| if (m_pContext->GetFormFillEnv()->GetInterForm()) { | |
| m_pContext->GetFormFillEnv()->GetInterForm()->XfaEnableCalculate(bEnabled); | |
| } | |
| } | |
| void CPDFXFA_DocEnvironment::GetTitle(CXFA_FFDoc* hDoc, | |
| CFX_WideString& wsTitle) { | |
| if (hDoc != m_pContext->GetXFADoc() || !m_pContext->GetPDFDoc()) | |
| return; | |
| CPDF_Dictionary* pInfoDict = m_pContext->GetPDFDoc()->GetInfo(); | |
| if (!pInfoDict) | |
| return; | |
| CFX_ByteString csTitle = pInfoDict->GetStringFor("Title"); | |
| wsTitle = wsTitle.FromLocal(csTitle.GetBuffer(csTitle.GetLength())); | |
| csTitle.ReleaseBuffer(csTitle.GetLength()); | |
| } | |
| void CPDFXFA_DocEnvironment::SetTitle(CXFA_FFDoc* hDoc, | |
| const CFX_WideString& wsTitle) { | |
| if (hDoc != m_pContext->GetXFADoc() || !m_pContext->GetPDFDoc()) | |
| return; | |
| if (CPDF_Dictionary* pInfoDict = m_pContext->GetPDFDoc()->GetInfo()) | |
| pInfoDict->SetNewFor<CPDF_String>("Title", wsTitle); | |
| } | |
| void CPDFXFA_DocEnvironment::ExportData(CXFA_FFDoc* hDoc, | |
| const CFX_WideString& wsFilePath, | |
| bool bXDP) { | |
| if (hDoc != m_pContext->GetXFADoc()) | |
| return; | |
| if (m_pContext->GetDocType() != XFA_DocType::Dynamic && | |
| m_pContext->GetDocType() != XFA_DocType::Static) { | |
| return; | |
| } | |
| CPDFSDK_FormFillEnvironment* pFormFillEnv = m_pContext->GetFormFillEnv(); | |
| if (!pFormFillEnv) | |
| return; | |
| int fileType = bXDP ? FXFA_SAVEAS_XDP : FXFA_SAVEAS_XML; | |
| CFX_ByteString bs = wsFilePath.UTF16LE_Encode(); | |
| if (wsFilePath.IsEmpty()) { | |
| if (!pFormFillEnv->GetFormFillInfo() || | |
| !pFormFillEnv->GetFormFillInfo()->m_pJsPlatform) { | |
| return; | |
| } | |
| CFX_WideString filepath = pFormFillEnv->JS_fieldBrowse(); | |
| bs = filepath.UTF16LE_Encode(); | |
| } | |
| int len = bs.GetLength(); | |
| FPDF_FILEHANDLER* pFileHandler = | |
| pFormFillEnv->OpenFile(bXDP ? FXFA_SAVEAS_XDP : FXFA_SAVEAS_XML, | |
| (FPDF_WIDESTRING)bs.GetBuffer(len), "wb"); | |
| bs.ReleaseBuffer(len); | |
| if (!pFileHandler) | |
| return; | |
| CFX_RetainPtr<IFX_SeekableStream> fileWrite = | |
| MakeSeekableStream(pFileHandler); | |
| CFX_ByteString content; | |
| if (fileType == FXFA_SAVEAS_XML) { | |
| content = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n"; | |
| fileWrite->WriteBlock(content.c_str(), fileWrite->GetSize(), | |
| content.GetLength()); | |
| m_pContext->GetXFADocView()->GetDoc()->SavePackage(XFA_HASHCODE_Data, | |
| fileWrite, nullptr); | |
| } else if (fileType == FXFA_SAVEAS_XDP) { | |
| if (!m_pContext->GetPDFDoc()) | |
| return; | |
| CPDF_Dictionary* pRoot = m_pContext->GetPDFDoc()->GetRoot(); | |
| if (!pRoot) | |
| return; | |
| CPDF_Dictionary* pAcroForm = pRoot->GetDictFor("AcroForm"); | |
| if (!pAcroForm) | |
| return; | |
| CPDF_Array* pArray = ToArray(pAcroForm->GetObjectFor("XFA")); | |
| if (!pArray) | |
| return; | |
| int size = pArray->GetCount(); | |
| for (int i = 1; i < size; i += 2) { | |
| CPDF_Object* pPDFObj = pArray->GetObjectAt(i); | |
| CPDF_Object* pPrePDFObj = pArray->GetObjectAt(i - 1); | |
| if (!pPrePDFObj->IsString()) | |
| continue; | |
| if (!pPDFObj->IsReference()) | |
| continue; | |
| CPDF_Stream* pStream = ToStream(pPDFObj->GetDirect()); | |
| if (!pStream) | |
| continue; | |
| if (pPrePDFObj->GetString() == "form") { | |
| m_pContext->GetXFADocView()->GetDoc()->SavePackage(XFA_HASHCODE_Form, | |
| fileWrite, nullptr); | |
| continue; | |
| } | |
| if (pPrePDFObj->GetString() == "datasets") { | |
| m_pContext->GetXFADocView()->GetDoc()->SavePackage( | |
| XFA_HASHCODE_Datasets, fileWrite, nullptr); | |
| continue; | |
| } | |
| if (i == size - 1) { | |
| CFX_WideString wPath = CFX_WideString::FromUTF16LE( | |
| reinterpret_cast<const unsigned short*>(bs.c_str()), | |
| bs.GetLength() / sizeof(unsigned short)); | |
| CFX_ByteString bPath = wPath.UTF8Encode(); | |
| const char* szFormat = | |
| "\n<pdf href=\"%s\" xmlns=\"http://ns.adobe.com/xdp/pdf/\"/>"; | |
| content.Format(szFormat, bPath.c_str()); | |
| fileWrite->WriteBlock(content.c_str(), fileWrite->GetSize(), | |
| content.GetLength()); | |
| } | |
| auto pAcc = pdfium::MakeRetain<CPDF_StreamAcc>(pStream); | |
| pAcc->LoadAllData(); | |
| fileWrite->WriteBlock(pAcc->GetData(), fileWrite->GetSize(), | |
| pAcc->GetSize()); | |
| } | |
| } | |
| fileWrite->Flush(); | |
| } | |
| void CPDFXFA_DocEnvironment::GotoURL(CXFA_FFDoc* hDoc, | |
| const CFX_WideString& bsURL) { | |
| if (hDoc != m_pContext->GetXFADoc()) | |
| return; | |
| if (m_pContext->GetDocType() != XFA_DocType::Dynamic) | |
| return; | |
| CPDFSDK_FormFillEnvironment* pFormFillEnv = m_pContext->GetFormFillEnv(); | |
| if (!pFormFillEnv) | |
| return; | |
| CFX_WideStringC str(bsURL.c_str()); | |
| pFormFillEnv->GotoURL(m_pContext.Get(), str); | |
| } | |
| bool CPDFXFA_DocEnvironment::IsValidationsEnabled(CXFA_FFDoc* hDoc) { | |
| if (hDoc != m_pContext->GetXFADoc() || !m_pContext->GetFormFillEnv()) | |
| return false; | |
| if (m_pContext->GetFormFillEnv()->GetInterForm()) { | |
| return m_pContext->GetFormFillEnv() | |
| ->GetInterForm() | |
| ->IsXfaValidationsEnabled(); | |
| } | |
| return true; | |
| } | |
| void CPDFXFA_DocEnvironment::SetValidationsEnabled(CXFA_FFDoc* hDoc, | |
| bool bEnabled) { | |
| if (hDoc != m_pContext->GetXFADoc() || !m_pContext->GetFormFillEnv()) | |
| return; | |
| if (m_pContext->GetFormFillEnv()->GetInterForm()) { | |
| m_pContext->GetFormFillEnv()->GetInterForm()->XfaSetValidationsEnabled( | |
| bEnabled); | |
| } | |
| } | |
| void CPDFXFA_DocEnvironment::SetFocusWidget(CXFA_FFDoc* hDoc, | |
| CXFA_FFWidget* hWidget) { | |
| if (hDoc != m_pContext->GetXFADoc()) | |
| return; | |
| if (!hWidget) { | |
| CPDFSDK_Annot::ObservedPtr pNull; | |
| m_pContext->GetFormFillEnv()->SetFocusAnnot(&pNull); | |
| return; | |
| } | |
| int pageViewCount = m_pContext->GetFormFillEnv()->GetPageViewCount(); | |
| for (int i = 0; i < pageViewCount; i++) { | |
| CPDFSDK_PageView* pPageView = m_pContext->GetFormFillEnv()->GetPageView(i); | |
| if (!pPageView) | |
| continue; | |
| CPDFSDK_Annot::ObservedPtr pAnnot(pPageView->GetAnnotByXFAWidget(hWidget)); | |
| if (pAnnot) { | |
| m_pContext->GetFormFillEnv()->SetFocusAnnot(&pAnnot); | |
| break; | |
| } | |
| } | |
| } | |
| void CPDFXFA_DocEnvironment::Print(CXFA_FFDoc* hDoc, | |
| int32_t nStartPage, | |
| int32_t nEndPage, | |
| uint32_t dwOptions) { | |
| if (hDoc != m_pContext->GetXFADoc()) | |
| return; | |
| CPDFSDK_FormFillEnvironment* pFormFillEnv = m_pContext->GetFormFillEnv(); | |
| if (!pFormFillEnv || !pFormFillEnv->GetFormFillInfo() || | |
| !pFormFillEnv->GetFormFillInfo()->m_pJsPlatform || | |
| !pFormFillEnv->GetFormFillInfo()->m_pJsPlatform->Doc_print) { | |
| return; | |
| } | |
| pFormFillEnv->GetFormFillInfo()->m_pJsPlatform->Doc_print( | |
| pFormFillEnv->GetFormFillInfo()->m_pJsPlatform, | |
| dwOptions & XFA_PRINTOPT_ShowDialog, nStartPage, nEndPage, | |
| dwOptions & XFA_PRINTOPT_CanCancel, dwOptions & XFA_PRINTOPT_ShrinkPage, | |
| dwOptions & XFA_PRINTOPT_AsImage, dwOptions & XFA_PRINTOPT_ReverseOrder, | |
| dwOptions & XFA_PRINTOPT_PrintAnnot); | |
| } | |
| FX_ARGB CPDFXFA_DocEnvironment::GetHighlightColor(CXFA_FFDoc* hDoc) { | |
| if (hDoc != m_pContext->GetXFADoc() || !m_pContext->GetFormFillEnv()) | |
| return 0; | |
| CPDFSDK_InterForm* pInterForm = m_pContext->GetFormFillEnv()->GetInterForm(); | |
| if (!pInterForm) | |
| return 0; | |
| return ArgbEncode(pInterForm->GetHighlightAlpha(), | |
| pInterForm->GetHighlightColor(FPDF_FORMFIELD_XFA)); | |
| } | |
| bool CPDFXFA_DocEnvironment::NotifySubmit(bool bPrevOrPost) { | |
| if (bPrevOrPost) | |
| return OnBeforeNotifySubmit(); | |
| OnAfterNotifySubmit(); | |
| return true; | |
| } | |
| bool CPDFXFA_DocEnvironment::OnBeforeNotifySubmit() { | |
| if (m_pContext->GetDocType() != XFA_DocType::Dynamic && | |
| m_pContext->GetDocType() != XFA_DocType::Static) { | |
| return true; | |
| } | |
| if (!m_pContext->GetXFADocView()) | |
| return true; | |
| CXFA_FFWidgetHandler* pWidgetHandler = | |
| m_pContext->GetXFADocView()->GetWidgetHandler(); | |
| if (!pWidgetHandler) | |
| return true; | |
| std::unique_ptr<CXFA_WidgetAccIterator> pWidgetAccIterator = | |
| m_pContext->GetXFADocView()->CreateWidgetAccIterator(); | |
| if (pWidgetAccIterator) { | |
| CXFA_EventParam Param; | |
| Param.m_eType = XFA_EVENT_PreSubmit; | |
| while (CXFA_WidgetAcc* pWidgetAcc = pWidgetAccIterator->MoveToNext()) | |
| pWidgetHandler->ProcessEvent(pWidgetAcc, &Param); | |
| } | |
| pWidgetAccIterator = m_pContext->GetXFADocView()->CreateWidgetAccIterator(); | |
| if (!pWidgetAccIterator) | |
| return true; | |
| CXFA_WidgetAcc* pWidgetAcc = pWidgetAccIterator->MoveToNext(); | |
| pWidgetAcc = pWidgetAccIterator->MoveToNext(); | |
| while (pWidgetAcc) { | |
| int fRet = pWidgetAcc->ProcessValidate(-1); | |
| if (fRet == XFA_EVENTERROR_Error) { | |
| CPDFSDK_FormFillEnvironment* pFormFillEnv = m_pContext->GetFormFillEnv(); | |
| if (!pFormFillEnv) | |
| return false; | |
| CFX_WideString ws; | |
| ws.FromLocal(IDS_XFA_Validate_Input); | |
| CFX_ByteString bs = ws.UTF16LE_Encode(); | |
| int len = bs.GetLength(); | |
| pFormFillEnv->Alert((FPDF_WIDESTRING)bs.GetBuffer(len), | |
| (FPDF_WIDESTRING)L"", 0, 1); | |
| bs.ReleaseBuffer(len); | |
| return false; | |
| } | |
| pWidgetAcc = pWidgetAccIterator->MoveToNext(); | |
| } | |
| m_pContext->GetXFADocView()->UpdateDocView(); | |
| return true; | |
| } | |
| void CPDFXFA_DocEnvironment::OnAfterNotifySubmit() { | |
| if (m_pContext->GetDocType() != XFA_DocType::Dynamic && | |
| m_pContext->GetDocType() != XFA_DocType::Static) | |
| return; | |
| if (!m_pContext->GetXFADocView()) | |
| return; | |
| CXFA_FFWidgetHandler* pWidgetHandler = | |
| m_pContext->GetXFADocView()->GetWidgetHandler(); | |
| if (!pWidgetHandler) | |
| return; | |
| std::unique_ptr<CXFA_WidgetAccIterator> pWidgetAccIterator = | |
| m_pContext->GetXFADocView()->CreateWidgetAccIterator(); | |
| if (!pWidgetAccIterator) | |
| return; | |
| CXFA_EventParam Param; | |
| Param.m_eType = XFA_EVENT_PostSubmit; | |
| CXFA_WidgetAcc* pWidgetAcc = pWidgetAccIterator->MoveToNext(); | |
| while (pWidgetAcc) { | |
| pWidgetHandler->ProcessEvent(pWidgetAcc, &Param); | |
| pWidgetAcc = pWidgetAccIterator->MoveToNext(); | |
| } | |
| m_pContext->GetXFADocView()->UpdateDocView(); | |
| } | |
| bool CPDFXFA_DocEnvironment::SubmitData(CXFA_FFDoc* hDoc, CXFA_Submit submit) { | |
| if (!NotifySubmit(true) || !m_pContext->GetXFADocView()) | |
| return false; | |
| m_pContext->GetXFADocView()->UpdateDocView(); | |
| bool ret = SubmitDataInternal(hDoc, submit); | |
| NotifySubmit(false); | |
| return ret; | |
| } | |
| CFX_RetainPtr<IFX_SeekableReadStream> CPDFXFA_DocEnvironment::OpenLinkedFile( | |
| CXFA_FFDoc* hDoc, | |
| const CFX_WideString& wsLink) { | |
| CPDFSDK_FormFillEnvironment* pFormFillEnv = m_pContext->GetFormFillEnv(); | |
| if (!pFormFillEnv) | |
| return nullptr; | |
| CFX_ByteString bs = wsLink.UTF16LE_Encode(); | |
| int len = bs.GetLength(); | |
| FPDF_FILEHANDLER* pFileHandler = | |
| pFormFillEnv->OpenFile(0, (FPDF_WIDESTRING)bs.GetBuffer(len), "rb"); | |
| bs.ReleaseBuffer(len); | |
| if (!pFileHandler) | |
| return nullptr; | |
| return MakeSeekableStream(pFileHandler); | |
| } | |
| bool CPDFXFA_DocEnvironment::ExportSubmitFile(FPDF_FILEHANDLER* pFileHandler, | |
| int fileType, | |
| FPDF_DWORD encodeType, | |
| FPDF_DWORD flag) { | |
| if (!m_pContext->GetXFADocView()) | |
| return false; | |
| CFX_ByteString content; | |
| CPDFSDK_FormFillEnvironment* pFormFillEnv = m_pContext->GetFormFillEnv(); | |
| if (!pFormFillEnv) | |
| return false; | |
| CFX_RetainPtr<IFX_SeekableStream> fileStream = | |
| MakeSeekableStream(pFileHandler); | |
| if (fileType == FXFA_SAVEAS_XML) { | |
| const char kContent[] = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n"; | |
| fileStream->WriteBlock(kContent, 0, strlen(kContent)); | |
| m_pContext->GetXFADoc()->SavePackage(XFA_HASHCODE_Data, fileStream, | |
| nullptr); | |
| return true; | |
| } | |
| if (fileType != FXFA_SAVEAS_XDP) | |
| return true; | |
| if (!flag) { | |
| flag = FXFA_CONFIG | FXFA_TEMPLATE | FXFA_LOCALESET | FXFA_DATASETS | | |
| FXFA_XMPMETA | FXFA_XFDF | FXFA_FORM; | |
| } | |
| if (!m_pContext->GetPDFDoc()) { | |
| fileStream->Flush(); | |
| return false; | |
| } | |
| CPDF_Dictionary* pRoot = m_pContext->GetPDFDoc()->GetRoot(); | |
| if (!pRoot) { | |
| fileStream->Flush(); | |
| return false; | |
| } | |
| CPDF_Dictionary* pAcroForm = pRoot->GetDictFor("AcroForm"); | |
| if (!pAcroForm) { | |
| fileStream->Flush(); | |
| return false; | |
| } | |
| CPDF_Array* pArray = ToArray(pAcroForm->GetObjectFor("XFA")); | |
| if (!pArray) { | |
| fileStream->Flush(); | |
| return false; | |
| } | |
| int size = pArray->GetCount(); | |
| for (int i = 1; i < size; i += 2) { | |
| CPDF_Object* pPDFObj = pArray->GetObjectAt(i); | |
| CPDF_Object* pPrePDFObj = pArray->GetObjectAt(i - 1); | |
| if (!pPrePDFObj->IsString()) | |
| continue; | |
| if (!pPDFObj->IsReference()) | |
| continue; | |
| CPDF_Object* pDirectObj = pPDFObj->GetDirect(); | |
| if (!pDirectObj->IsStream()) | |
| continue; | |
| if (pPrePDFObj->GetString() == "config" && !(flag & FXFA_CONFIG)) | |
| continue; | |
| if (pPrePDFObj->GetString() == "template" && !(flag & FXFA_TEMPLATE)) | |
| continue; | |
| if (pPrePDFObj->GetString() == "localeSet" && !(flag & FXFA_LOCALESET)) | |
| continue; | |
| if (pPrePDFObj->GetString() == "datasets" && !(flag & FXFA_DATASETS)) | |
| continue; | |
| if (pPrePDFObj->GetString() == "xmpmeta" && !(flag & FXFA_XMPMETA)) | |
| continue; | |
| if (pPrePDFObj->GetString() == "xfdf" && !(flag & FXFA_XFDF)) | |
| continue; | |
| if (pPrePDFObj->GetString() == "form" && !(flag & FXFA_FORM)) | |
| continue; | |
| if (pPrePDFObj->GetString() == "form") { | |
| m_pContext->GetXFADoc()->SavePackage(XFA_HASHCODE_Form, fileStream, | |
| nullptr); | |
| } else if (pPrePDFObj->GetString() == "datasets") { | |
| m_pContext->GetXFADoc()->SavePackage(XFA_HASHCODE_Datasets, fileStream, | |
| nullptr); | |
| } else { | |
| // PDF,creator. | |
| } | |
| } | |
| return true; | |
| } | |
| void CPDFXFA_DocEnvironment::ToXFAContentFlags(CFX_WideString csSrcContent, | |
| FPDF_DWORD& flag) { | |
| if (csSrcContent.Find(L" config ", 0) != -1) | |
| flag |= FXFA_CONFIG; | |
| if (csSrcContent.Find(L" template ", 0) != -1) | |
| flag |= FXFA_TEMPLATE; | |
| if (csSrcContent.Find(L" localeSet ", 0) != -1) | |
| flag |= FXFA_LOCALESET; | |
| if (csSrcContent.Find(L" datasets ", 0) != -1) | |
| flag |= FXFA_DATASETS; | |
| if (csSrcContent.Find(L" xmpmeta ", 0) != -1) | |
| flag |= FXFA_XMPMETA; | |
| if (csSrcContent.Find(L" xfdf ", 0) != -1) | |
| flag |= FXFA_XFDF; | |
| if (csSrcContent.Find(L" form ", 0) != -1) | |
| flag |= FXFA_FORM; | |
| if (flag == 0) { | |
| flag = FXFA_CONFIG | FXFA_TEMPLATE | FXFA_LOCALESET | FXFA_DATASETS | | |
| FXFA_XMPMETA | FXFA_XFDF | FXFA_FORM; | |
| } | |
| } | |
| bool CPDFXFA_DocEnvironment::MailToInfo(CFX_WideString& csURL, | |
| CFX_WideString& csToAddress, | |
| CFX_WideString& csCCAddress, | |
| CFX_WideString& csBCCAddress, | |
| CFX_WideString& csSubject, | |
| CFX_WideString& csMsg) { | |
| CFX_WideString srcURL = csURL; | |
| srcURL.TrimLeft(); | |
| if (srcURL.Left(7).CompareNoCase(L"mailto:") != 0) | |
| return false; | |
| int pos = srcURL.Find(L'?', 0); | |
| CFX_WideString tmp; | |
| if (pos == -1) { | |
| pos = srcURL.Find(L'@', 0); | |
| if (pos == -1) | |
| return false; | |
| tmp = srcURL.Right(csURL.GetLength() - 7); | |
| } else { | |
| tmp = srcURL.Left(pos); | |
| tmp = tmp.Right(tmp.GetLength() - 7); | |
| } | |
| tmp.TrimLeft(); | |
| tmp.TrimRight(); | |
| csToAddress = tmp; | |
| srcURL = srcURL.Right(srcURL.GetLength() - (pos + 1)); | |
| while (!srcURL.IsEmpty()) { | |
| srcURL.TrimLeft(); | |
| srcURL.TrimRight(); | |
| pos = srcURL.Find(L'&', 0); | |
| tmp = (pos == -1) ? srcURL : srcURL.Left(pos); | |
| tmp.TrimLeft(); | |
| tmp.TrimRight(); | |
| if (tmp.GetLength() >= 3 && tmp.Left(3).CompareNoCase(L"cc=") == 0) { | |
| tmp = tmp.Right(tmp.GetLength() - 3); | |
| if (!csCCAddress.IsEmpty()) | |
| csCCAddress += L';'; | |
| csCCAddress += tmp; | |
| } else if (tmp.GetLength() >= 4 && | |
| tmp.Left(4).CompareNoCase(L"bcc=") == 0) { | |
| tmp = tmp.Right(tmp.GetLength() - 4); | |
| if (!csBCCAddress.IsEmpty()) | |
| csBCCAddress += L';'; | |
| csBCCAddress += tmp; | |
| } else if (tmp.GetLength() >= 8 && | |
| tmp.Left(8).CompareNoCase(L"subject=") == 0) { | |
| tmp = tmp.Right(tmp.GetLength() - 8); | |
| csSubject += tmp; | |
| } else if (tmp.GetLength() >= 5 && | |
| tmp.Left(5).CompareNoCase(L"body=") == 0) { | |
| tmp = tmp.Right(tmp.GetLength() - 5); | |
| csMsg += tmp; | |
| } | |
| srcURL = (pos == -1) ? L"" : srcURL.Right(csURL.GetLength() - (pos + 1)); | |
| } | |
| csToAddress.Replace(L",", L";"); | |
| csCCAddress.Replace(L",", L";"); | |
| csBCCAddress.Replace(L",", L";"); | |
| return true; | |
| } | |
| bool CPDFXFA_DocEnvironment::SubmitDataInternal(CXFA_FFDoc* hDoc, | |
| CXFA_Submit submit) { | |
| CPDFSDK_FormFillEnvironment* pFormFillEnv = m_pContext->GetFormFillEnv(); | |
| if (!pFormFillEnv) | |
| return false; | |
| CFX_WideStringC csURLC; | |
| submit.GetSubmitTarget(csURLC); | |
| CFX_WideString csURL(csURLC); | |
| if (csURL.IsEmpty()) { | |
| CFX_WideString ws; | |
| ws.FromLocal("Submit cancelled."); | |
| CFX_ByteString bs = ws.UTF16LE_Encode(); | |
| int len = bs.GetLength(); | |
| pFormFillEnv->Alert((FPDF_WIDESTRING)bs.GetBuffer(len), | |
| (FPDF_WIDESTRING)L"", 0, 4); | |
| bs.ReleaseBuffer(len); | |
| return false; | |
| } | |
| FPDF_FILEHANDLER* pFileHandler = nullptr; | |
| int fileFlag = -1; | |
| switch (submit.GetSubmitFormat()) { | |
| case XFA_ATTRIBUTEENUM_Xdp: { | |
| CFX_WideStringC csContentC; | |
| submit.GetSubmitXDPContent(csContentC); | |
| CFX_WideString csContent; | |
| csContent = csContentC; | |
| csContent.TrimLeft(); | |
| csContent.TrimRight(); | |
| CFX_WideString space; | |
| space.FromLocal(" "); | |
| csContent = space + csContent + space; | |
| FPDF_DWORD flag = 0; | |
| if (submit.IsSubmitEmbedPDF()) | |
| flag |= FXFA_PDF; | |
| ToXFAContentFlags(csContent, flag); | |
| pFileHandler = pFormFillEnv->OpenFile(FXFA_SAVEAS_XDP, nullptr, "wb"); | |
| fileFlag = FXFA_SAVEAS_XDP; | |
| ExportSubmitFile(pFileHandler, FXFA_SAVEAS_XDP, 0, flag); | |
| break; | |
| } | |
| case XFA_ATTRIBUTEENUM_Xml: | |
| pFileHandler = pFormFillEnv->OpenFile(FXFA_SAVEAS_XML, nullptr, "wb"); | |
| fileFlag = FXFA_SAVEAS_XML; | |
| ExportSubmitFile(pFileHandler, FXFA_SAVEAS_XML, 0, FXFA_XFA_ALL); | |
| break; | |
| case XFA_ATTRIBUTEENUM_Pdf: | |
| break; | |
| case XFA_ATTRIBUTEENUM_Urlencoded: | |
| pFileHandler = pFormFillEnv->OpenFile(FXFA_SAVEAS_XML, nullptr, "wb"); | |
| fileFlag = FXFA_SAVEAS_XML; | |
| ExportSubmitFile(pFileHandler, FXFA_SAVEAS_XML, 0, FXFA_XFA_ALL); | |
| break; | |
| default: | |
| return false; | |
| } | |
| if (!pFileHandler) | |
| return false; | |
| if (csURL.Left(7).CompareNoCase(L"mailto:") == 0) { | |
| CFX_WideString csToAddress; | |
| CFX_WideString csCCAddress; | |
| CFX_WideString csBCCAddress; | |
| CFX_WideString csSubject; | |
| CFX_WideString csMsg; | |
| if (!MailToInfo(csURL, csToAddress, csCCAddress, csBCCAddress, csSubject, | |
| csMsg)) { | |
| return false; | |
| } | |
| CFX_ByteString bsTo = CFX_WideString(csToAddress).UTF16LE_Encode(); | |
| CFX_ByteString bsCC = CFX_WideString(csCCAddress).UTF16LE_Encode(); | |
| CFX_ByteString bsBcc = CFX_WideString(csBCCAddress).UTF16LE_Encode(); | |
| CFX_ByteString bsSubject = CFX_WideString(csSubject).UTF16LE_Encode(); | |
| CFX_ByteString bsMsg = CFX_WideString(csMsg).UTF16LE_Encode(); | |
| FPDF_WIDESTRING pTo = (FPDF_WIDESTRING)bsTo.GetBuffer(bsTo.GetLength()); | |
| FPDF_WIDESTRING pCC = (FPDF_WIDESTRING)bsCC.GetBuffer(bsCC.GetLength()); | |
| FPDF_WIDESTRING pBcc = (FPDF_WIDESTRING)bsBcc.GetBuffer(bsBcc.GetLength()); | |
| FPDF_WIDESTRING pSubject = | |
| (FPDF_WIDESTRING)bsSubject.GetBuffer(bsSubject.GetLength()); | |
| FPDF_WIDESTRING pMsg = (FPDF_WIDESTRING)bsMsg.GetBuffer(bsMsg.GetLength()); | |
| pFormFillEnv->EmailTo(pFileHandler, pTo, pSubject, pCC, pBcc, pMsg); | |
| bsTo.ReleaseBuffer(); | |
| bsCC.ReleaseBuffer(); | |
| bsBcc.ReleaseBuffer(); | |
| bsSubject.ReleaseBuffer(); | |
| bsMsg.ReleaseBuffer(); | |
| } else { | |
| // HTTP or FTP | |
| CFX_WideString ws; | |
| CFX_ByteString bs = csURL.UTF16LE_Encode(); | |
| int len = bs.GetLength(); | |
| pFormFillEnv->UploadTo(pFileHandler, fileFlag, | |
| (FPDF_WIDESTRING)bs.GetBuffer(len)); | |
| bs.ReleaseBuffer(len); | |
| } | |
| return true; | |
| } | |
| bool CPDFXFA_DocEnvironment::SetGlobalProperty( | |
| CXFA_FFDoc* hDoc, | |
| const CFX_ByteStringC& szPropName, | |
| CFXJSE_Value* pValue) { | |
| if (hDoc != m_pContext->GetXFADoc()) | |
| return false; | |
| if (!m_pContext->GetFormFillEnv() || | |
| !m_pContext->GetFormFillEnv()->GetJSRuntime()) { | |
| return false; | |
| } | |
| CPDFSDK_FormFillEnvironment* pFormFillEnv = m_pContext->GetFormFillEnv(); | |
| IJS_EventContext* pContext = pFormFillEnv->GetJSRuntime()->NewEventContext(); | |
| bool bRet = pFormFillEnv->GetJSRuntime()->SetValueByName(szPropName, pValue); | |
| pFormFillEnv->GetJSRuntime()->ReleaseEventContext(pContext); | |
| return bRet; | |
| } | |
| bool CPDFXFA_DocEnvironment::GetGlobalProperty( | |
| CXFA_FFDoc* hDoc, | |
| const CFX_ByteStringC& szPropName, | |
| CFXJSE_Value* pValue) { | |
| if (hDoc != m_pContext->GetXFADoc()) | |
| return false; | |
| if (!m_pContext->GetFormFillEnv() || | |
| !m_pContext->GetFormFillEnv()->GetJSRuntime()) { | |
| return false; | |
| } | |
| CPDFSDK_FormFillEnvironment* pFormFillEnv = m_pContext->GetFormFillEnv(); | |
| IJS_EventContext* pContext = pFormFillEnv->GetJSRuntime()->NewEventContext(); | |
| bool bRet = pFormFillEnv->GetJSRuntime()->GetValueByName(szPropName, pValue); | |
| pFormFillEnv->GetJSRuntime()->ReleaseEventContext(pContext); | |
| return bRet; | |
| } |