Home | History | Annotate | Download | only in fpdfxfa
      1 // Copyright 2016 PDFium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
      6 
      7 #include "fpdfsdk/fpdfxfa/cpdfxfa_docenvironment.h"
      8 
      9 #include <memory>
     10 
     11 #include "core/fpdfapi/parser/cpdf_array.h"
     12 #include "core/fpdfapi/parser/cpdf_stream_acc.h"
     13 #include "core/fpdfapi/parser/cpdf_string.h"
     14 #include "core/fxcrt/retain_ptr.h"
     15 #include "fpdfsdk/cpdfsdk_formfillenvironment.h"
     16 #include "fpdfsdk/cpdfsdk_interform.h"
     17 #include "fpdfsdk/cpdfsdk_pageview.h"
     18 #include "fpdfsdk/fpdfxfa/cpdfxfa_context.h"
     19 #include "fpdfsdk/fpdfxfa/cpdfxfa_page.h"
     20 #include "fxjs/ijs_runtime.h"
     21 #include "xfa/fxfa/cxfa_ffdocview.h"
     22 #include "xfa/fxfa/cxfa_ffwidget.h"
     23 #include "xfa/fxfa/cxfa_ffwidgethandler.h"
     24 #include "xfa/fxfa/cxfa_widgetacciterator.h"
     25 #include "xfa/fxfa/parser/cxfa_submit.h"
     26 
     27 #define IDS_XFA_Validate_Input                                          \
     28   "At least one required field was empty. Please fill in the required " \
     29   "fields\r\n(highlighted) before continuing."
     30 
     31 // submit
     32 #define FXFA_CONFIG 0x00000001
     33 #define FXFA_TEMPLATE 0x00000010
     34 #define FXFA_LOCALESET 0x00000100
     35 #define FXFA_DATASETS 0x00001000
     36 #define FXFA_XMPMETA 0x00010000
     37 #define FXFA_XFDF 0x00100000
     38 #define FXFA_FORM 0x01000000
     39 #define FXFA_PDF 0x10000000
     40 #define FXFA_XFA_ALL 0x01111111
     41 
     42 CPDFXFA_DocEnvironment::CPDFXFA_DocEnvironment(CPDFXFA_Context* pContext)
     43     : m_pContext(pContext) {
     44   ASSERT(m_pContext);
     45 }
     46 
     47 CPDFXFA_DocEnvironment::~CPDFXFA_DocEnvironment() {}
     48 
     49 void CPDFXFA_DocEnvironment::SetChangeMark(CXFA_FFDoc* hDoc) {
     50   if (hDoc == m_pContext->GetXFADoc() && m_pContext->GetFormFillEnv())
     51     m_pContext->GetFormFillEnv()->SetChangeMark();
     52 }
     53 
     54 void CPDFXFA_DocEnvironment::InvalidateRect(CXFA_FFPageView* pPageView,
     55                                             const CFX_RectF& rt) {
     56   if (!m_pContext->GetXFADoc() || !m_pContext->GetFormFillEnv())
     57     return;
     58 
     59   if (m_pContext->GetFormType() != FormType::kXFAFull)
     60     return;
     61 
     62   RetainPtr<CPDFXFA_Page> pPage = m_pContext->GetXFAPage(pPageView);
     63   if (!pPage)
     64     return;
     65 
     66   CPDFSDK_FormFillEnvironment* pFormFillEnv = m_pContext->GetFormFillEnv();
     67   if (!pFormFillEnv)
     68     return;
     69 
     70   pFormFillEnv->Invalidate(pPage.Get(), rt.ToFloatRect().ToFxRect());
     71 }
     72 
     73 void CPDFXFA_DocEnvironment::DisplayCaret(CXFA_FFWidget* hWidget,
     74                                           bool bVisible,
     75                                           const CFX_RectF* pRtAnchor) {
     76   if (!hWidget || !pRtAnchor || !m_pContext->GetXFADoc() ||
     77       !m_pContext->GetFormFillEnv() || !m_pContext->GetXFADocView())
     78     return;
     79 
     80   if (m_pContext->GetFormType() != FormType::kXFAFull)
     81     return;
     82 
     83   CXFA_FFWidgetHandler* pWidgetHandler =
     84       m_pContext->GetXFADocView()->GetWidgetHandler();
     85   if (!pWidgetHandler)
     86     return;
     87 
     88   CXFA_FFPageView* pPageView = hWidget->GetPageView();
     89   if (!pPageView)
     90     return;
     91 
     92   RetainPtr<CPDFXFA_Page> pPage = m_pContext->GetXFAPage(pPageView);
     93   if (!pPage)
     94     return;
     95 
     96   CPDFSDK_FormFillEnvironment* pFormFillEnv = m_pContext->GetFormFillEnv();
     97   if (!pFormFillEnv)
     98     return;
     99 
    100   CFX_FloatRect rcCaret = pRtAnchor->ToFloatRect();
    101   pFormFillEnv->DisplayCaret(pPage.Get(), bVisible, rcCaret.left, rcCaret.top,
    102                              rcCaret.right, rcCaret.bottom);
    103 }
    104 
    105 bool CPDFXFA_DocEnvironment::GetPopupPos(CXFA_FFWidget* hWidget,
    106                                          float fMinPopup,
    107                                          float fMaxPopup,
    108                                          const CFX_RectF& rtAnchor,
    109                                          CFX_RectF& rtPopup) {
    110   if (!hWidget)
    111     return false;
    112 
    113   CXFA_FFPageView* pXFAPageView = hWidget->GetPageView();
    114   if (!pXFAPageView)
    115     return false;
    116 
    117   RetainPtr<CPDFXFA_Page> pPage = m_pContext->GetXFAPage(pXFAPageView);
    118   if (!pPage)
    119     return false;
    120 
    121   CPDFSDK_FormFillEnvironment* pFormFillEnv = m_pContext->GetFormFillEnv();
    122   if (!pFormFillEnv)
    123     return false;
    124 
    125   FS_RECTF pageViewRect = {0.0f, 0.0f, 0.0f, 0.0f};
    126   pFormFillEnv->GetPageViewRect(pPage.Get(), pageViewRect);
    127 
    128   int t1;
    129   int t2;
    130   CFX_FloatRect rcAnchor = rtAnchor.ToFloatRect();
    131   int nRotate = hWidget->GetNode()->GetRotate();
    132   switch (nRotate) {
    133     case 90: {
    134       t1 = (int)(pageViewRect.right - rcAnchor.right);
    135       t2 = (int)(rcAnchor.left - pageViewRect.left);
    136       if (rcAnchor.bottom < pageViewRect.bottom)
    137         rtPopup.left += rcAnchor.bottom - pageViewRect.bottom;
    138       break;
    139     }
    140     case 180: {
    141       t2 = (int)(pageViewRect.top - rcAnchor.top);
    142       t1 = (int)(rcAnchor.bottom - pageViewRect.bottom);
    143       if (rcAnchor.left < pageViewRect.left)
    144         rtPopup.left += rcAnchor.left - pageViewRect.left;
    145       break;
    146     }
    147     case 270: {
    148       t1 = (int)(rcAnchor.left - pageViewRect.left);
    149       t2 = (int)(pageViewRect.right - rcAnchor.right);
    150       if (rcAnchor.top > pageViewRect.top)
    151         rtPopup.left -= rcAnchor.top - pageViewRect.top;
    152       break;
    153     }
    154     case 0:
    155     default: {
    156       t1 = (int)(pageViewRect.top - rcAnchor.top);
    157       t2 = (int)(rcAnchor.bottom - pageViewRect.bottom);
    158       if (rcAnchor.right > pageViewRect.right)
    159         rtPopup.left -= rcAnchor.right - pageViewRect.right;
    160       break;
    161     }
    162   }
    163 
    164   int t;
    165   uint32_t dwPos;
    166   if (t1 <= 0 && t2 <= 0)
    167     return false;
    168   if (t1 <= 0) {
    169     t = t2;
    170     dwPos = 1;
    171   } else if (t2 <= 0) {
    172     t = t1;
    173     dwPos = 0;
    174   } else if (t1 > t2) {
    175     t = t1;
    176     dwPos = 0;
    177   } else {
    178     t = t2;
    179     dwPos = 1;
    180   }
    181 
    182   float fPopupHeight;
    183   if (t < fMinPopup)
    184     fPopupHeight = fMinPopup;
    185   else if (t > fMaxPopup)
    186     fPopupHeight = fMaxPopup;
    187   else
    188     fPopupHeight = static_cast<float>(t);
    189 
    190   switch (nRotate) {
    191     case 0:
    192     case 180: {
    193       if (dwPos == 0) {
    194         rtPopup.top = rtAnchor.height;
    195         rtPopup.height = fPopupHeight;
    196       } else {
    197         rtPopup.top = -fPopupHeight;
    198         rtPopup.height = fPopupHeight;
    199       }
    200       break;
    201     }
    202     case 90:
    203     case 270: {
    204       if (dwPos == 0) {
    205         rtPopup.top = rtAnchor.width;
    206         rtPopup.height = fPopupHeight;
    207       } else {
    208         rtPopup.top = -fPopupHeight;
    209         rtPopup.height = fPopupHeight;
    210       }
    211       break;
    212     }
    213     default:
    214       break;
    215   }
    216 
    217   return true;
    218 }
    219 
    220 bool CPDFXFA_DocEnvironment::PopupMenu(CXFA_FFWidget* hWidget,
    221                                        CFX_PointF ptPopup) {
    222   if (!hWidget)
    223     return false;
    224 
    225   CXFA_FFPageView* pXFAPageView = hWidget->GetPageView();
    226   if (!pXFAPageView)
    227     return false;
    228 
    229   RetainPtr<CPDFXFA_Page> pPage = m_pContext->GetXFAPage(pXFAPageView);
    230   if (!pPage)
    231     return false;
    232 
    233   CPDFSDK_FormFillEnvironment* pFormFillEnv = m_pContext->GetFormFillEnv();
    234   if (!pFormFillEnv)
    235     return false;
    236 
    237   int menuFlag = 0;
    238   if (hWidget->CanUndo())
    239     menuFlag |= FXFA_MENU_UNDO;
    240   if (hWidget->CanRedo())
    241     menuFlag |= FXFA_MENU_REDO;
    242   if (hWidget->CanPaste())
    243     menuFlag |= FXFA_MENU_PASTE;
    244   if (hWidget->CanCopy())
    245     menuFlag |= FXFA_MENU_COPY;
    246   if (hWidget->CanCut())
    247     menuFlag |= FXFA_MENU_CUT;
    248   if (hWidget->CanSelectAll())
    249     menuFlag |= FXFA_MENU_SELECTALL;
    250 
    251   return pFormFillEnv->PopupMenu(pPage.Get(), hWidget, menuFlag, ptPopup);
    252 }
    253 
    254 void CPDFXFA_DocEnvironment::PageViewEvent(CXFA_FFPageView* pPageView,
    255                                            uint32_t dwFlags) {
    256   CPDFSDK_FormFillEnvironment* pFormFillEnv = m_pContext->GetFormFillEnv();
    257   if (!pFormFillEnv)
    258     return;
    259 
    260   if (m_pContext->GetLoadStatus() == FXFA_LOADSTATUS_LOADING ||
    261       m_pContext->GetLoadStatus() == FXFA_LOADSTATUS_CLOSING ||
    262       XFA_PAGEVIEWEVENT_StopLayout != dwFlags)
    263     return;
    264 
    265   int nNewCount = m_pContext->GetPageCount();
    266   if (nNewCount == m_pContext->GetOriginalPageCount())
    267     return;
    268 
    269   CXFA_FFDocView* pXFADocView = m_pContext->GetXFADocView();
    270   if (!pXFADocView)
    271     return;
    272 
    273   for (int iPageIter = 0; iPageIter < m_pContext->GetOriginalPageCount();
    274        iPageIter++) {
    275     RetainPtr<CPDFXFA_Page> pPage = (*m_pContext->GetXFAPageList())[iPageIter];
    276     if (!pPage)
    277       continue;
    278 
    279     m_pContext->GetFormFillEnv()->RemovePageView(pPage.Get());
    280     pPage->SetXFAPageView(pXFADocView->GetPageView(iPageIter));
    281   }
    282 
    283   int flag = (nNewCount < m_pContext->GetOriginalPageCount())
    284                  ? FXFA_PAGEVIEWEVENT_POSTREMOVED
    285                  : FXFA_PAGEVIEWEVENT_POSTADDED;
    286   int count = abs(nNewCount - m_pContext->GetOriginalPageCount());
    287   m_pContext->SetOriginalPageCount(nNewCount);
    288   pFormFillEnv->PageEvent(count, flag);
    289 }
    290 
    291 void CPDFXFA_DocEnvironment::WidgetPostAdd(CXFA_FFWidget* hWidget,
    292                                            CXFA_WidgetAcc* pWidgetAcc) {
    293   if (m_pContext->GetFormType() != FormType::kXFAFull || !hWidget)
    294     return;
    295 
    296   CXFA_FFPageView* pPageView = hWidget->GetPageView();
    297   if (!pPageView)
    298     return;
    299 
    300   RetainPtr<CPDFXFA_Page> pXFAPage = m_pContext->GetXFAPage(pPageView);
    301   if (!pXFAPage)
    302     return;
    303 
    304   m_pContext->GetFormFillEnv()
    305       ->GetPageView(pXFAPage.Get(), true)
    306       ->AddAnnot(hWidget);
    307 }
    308 
    309 void CPDFXFA_DocEnvironment::WidgetPreRemove(CXFA_FFWidget* hWidget,
    310                                              CXFA_WidgetAcc* pWidgetAcc) {
    311   if (m_pContext->GetFormType() != FormType::kXFAFull || !hWidget)
    312     return;
    313 
    314   CXFA_FFPageView* pPageView = hWidget->GetPageView();
    315   if (!pPageView)
    316     return;
    317 
    318   RetainPtr<CPDFXFA_Page> pXFAPage = m_pContext->GetXFAPage(pPageView);
    319   if (!pXFAPage)
    320     return;
    321 
    322   CPDFSDK_PageView* pSdkPageView =
    323       m_pContext->GetFormFillEnv()->GetPageView(pXFAPage.Get(), true);
    324   CPDFSDK_Annot* pAnnot = pSdkPageView->GetAnnotByXFAWidget(hWidget);
    325   if (pAnnot)
    326     pSdkPageView->DeleteAnnot(pAnnot);
    327 }
    328 
    329 int32_t CPDFXFA_DocEnvironment::CountPages(CXFA_FFDoc* hDoc) {
    330   if (hDoc == m_pContext->GetXFADoc() && m_pContext->GetFormFillEnv())
    331     return m_pContext->GetPageCount();
    332   return 0;
    333 }
    334 
    335 int32_t CPDFXFA_DocEnvironment::GetCurrentPage(CXFA_FFDoc* hDoc) {
    336   if (hDoc != m_pContext->GetXFADoc() || !m_pContext->GetFormFillEnv())
    337     return -1;
    338   if (m_pContext->GetFormType() != FormType::kXFAFull)
    339     return -1;
    340 
    341   CPDFSDK_FormFillEnvironment* pFormFillEnv = m_pContext->GetFormFillEnv();
    342   if (!pFormFillEnv)
    343     return -1;
    344 
    345   return pFormFillEnv->GetCurrentPageIndex(m_pContext.Get());
    346 }
    347 
    348 void CPDFXFA_DocEnvironment::SetCurrentPage(CXFA_FFDoc* hDoc,
    349                                             int32_t iCurPage) {
    350   if (hDoc != m_pContext->GetXFADoc() || !m_pContext->GetFormFillEnv() ||
    351       m_pContext->GetFormType() != FormType::kXFAFull || iCurPage < 0 ||
    352       iCurPage >= m_pContext->GetFormFillEnv()->GetPageCount()) {
    353     return;
    354   }
    355 
    356   CPDFSDK_FormFillEnvironment* pFormFillEnv = m_pContext->GetFormFillEnv();
    357   if (!pFormFillEnv)
    358     return;
    359   pFormFillEnv->SetCurrentPage(m_pContext.Get(), iCurPage);
    360 }
    361 
    362 bool CPDFXFA_DocEnvironment::IsCalculationsEnabled(CXFA_FFDoc* hDoc) {
    363   if (hDoc != m_pContext->GetXFADoc() || !m_pContext->GetFormFillEnv())
    364     return false;
    365   if (m_pContext->GetFormFillEnv()->GetInterForm()) {
    366     return m_pContext->GetFormFillEnv()
    367         ->GetInterForm()
    368         ->IsXfaCalculateEnabled();
    369   }
    370   return false;
    371 }
    372 
    373 void CPDFXFA_DocEnvironment::SetCalculationsEnabled(CXFA_FFDoc* hDoc,
    374                                                     bool bEnabled) {
    375   if (hDoc != m_pContext->GetXFADoc() || !m_pContext->GetFormFillEnv())
    376     return;
    377   if (m_pContext->GetFormFillEnv()->GetInterForm()) {
    378     m_pContext->GetFormFillEnv()->GetInterForm()->XfaEnableCalculate(bEnabled);
    379   }
    380 }
    381 
    382 void CPDFXFA_DocEnvironment::GetTitle(CXFA_FFDoc* hDoc, WideString& wsTitle) {
    383   if (hDoc != m_pContext->GetXFADoc() || !m_pContext->GetPDFDoc())
    384     return;
    385 
    386   const CPDF_Dictionary* pInfoDict = m_pContext->GetPDFDoc()->GetInfo();
    387   if (!pInfoDict)
    388     return;
    389 
    390   ByteString csTitle = pInfoDict->GetStringFor("Title");
    391   wsTitle = wsTitle.FromLocal(csTitle.GetBuffer(csTitle.GetLength()));
    392   csTitle.ReleaseBuffer(csTitle.GetLength());
    393 }
    394 
    395 void CPDFXFA_DocEnvironment::SetTitle(CXFA_FFDoc* hDoc,
    396                                       const WideString& wsTitle) {
    397   if (hDoc != m_pContext->GetXFADoc() || !m_pContext->GetPDFDoc())
    398     return;
    399 
    400   CPDF_Dictionary* pInfoDict = m_pContext->GetPDFDoc()->GetInfo();
    401   if (pInfoDict)
    402     pInfoDict->SetNewFor<CPDF_String>("Title", wsTitle);
    403 }
    404 
    405 void CPDFXFA_DocEnvironment::ExportData(CXFA_FFDoc* hDoc,
    406                                         const WideString& wsFilePath,
    407                                         bool bXDP) {
    408   if (hDoc != m_pContext->GetXFADoc())
    409     return;
    410 
    411   if (!m_pContext->ContainsXFAForm())
    412     return;
    413 
    414   CPDFSDK_FormFillEnvironment* pFormFillEnv = m_pContext->GetFormFillEnv();
    415   if (!pFormFillEnv)
    416     return;
    417 
    418   int fileType = bXDP ? FXFA_SAVEAS_XDP : FXFA_SAVEAS_XML;
    419   ByteString bs = wsFilePath.UTF16LE_Encode();
    420   if (wsFilePath.IsEmpty()) {
    421     if (!pFormFillEnv->GetFormFillInfo() ||
    422         !pFormFillEnv->GetFormFillInfo()->m_pJsPlatform) {
    423       return;
    424     }
    425 
    426     WideString filepath = pFormFillEnv->JS_fieldBrowse();
    427     bs = filepath.UTF16LE_Encode();
    428   }
    429   int len = bs.GetLength();
    430   FPDF_FILEHANDLER* pFileHandler =
    431       pFormFillEnv->OpenFile(bXDP ? FXFA_SAVEAS_XDP : FXFA_SAVEAS_XML,
    432                              (FPDF_WIDESTRING)bs.GetBuffer(len), "wb");
    433   bs.ReleaseBuffer(len);
    434   if (!pFileHandler)
    435     return;
    436 
    437   RetainPtr<IFX_SeekableStream> fileWrite = MakeSeekableStream(pFileHandler);
    438   if (fileType == FXFA_SAVEAS_XML) {
    439     ByteString content = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n";
    440     fileWrite->WriteBlock(content.c_str(), fileWrite->GetSize(),
    441                           content.GetLength());
    442     CXFA_FFDoc* ffdoc = m_pContext->GetXFADocView()->GetDoc();
    443     ffdoc->SavePackage(
    444         ToNode(ffdoc->GetXFADoc()->GetXFAObject(XFA_HASHCODE_Data)), fileWrite,
    445         nullptr);
    446   } else if (fileType == FXFA_SAVEAS_XDP) {
    447     if (!m_pContext->GetPDFDoc())
    448       return;
    449 
    450     const CPDF_Dictionary* pRoot = m_pContext->GetPDFDoc()->GetRoot();
    451     if (!pRoot)
    452       return;
    453 
    454     CPDF_Dictionary* pAcroForm = pRoot->GetDictFor("AcroForm");
    455     if (!pAcroForm)
    456       return;
    457 
    458     CPDF_Array* pArray = ToArray(pAcroForm->GetObjectFor("XFA"));
    459     if (!pArray)
    460       return;
    461 
    462     int size = pArray->GetCount();
    463     for (int i = 1; i < size; i += 2) {
    464       CPDF_Object* pPDFObj = pArray->GetObjectAt(i);
    465       CPDF_Object* pPrePDFObj = pArray->GetObjectAt(i - 1);
    466       if (!pPrePDFObj->IsString())
    467         continue;
    468       if (!pPDFObj->IsReference())
    469         continue;
    470 
    471       CPDF_Stream* pStream = ToStream(pPDFObj->GetDirect());
    472       if (!pStream)
    473         continue;
    474       if (pPrePDFObj->GetString() == "form") {
    475         CXFA_FFDoc* ffdoc = m_pContext->GetXFADocView()->GetDoc();
    476         ffdoc->SavePackage(
    477             ToNode(ffdoc->GetXFADoc()->GetXFAObject(XFA_HASHCODE_Form)),
    478             fileWrite, nullptr);
    479         continue;
    480       }
    481       if (pPrePDFObj->GetString() == "datasets") {
    482         CXFA_FFDoc* ffdoc = m_pContext->GetXFADocView()->GetDoc();
    483         ffdoc->SavePackage(
    484             ToNode(ffdoc->GetXFADoc()->GetXFAObject(XFA_HASHCODE_Datasets)),
    485             fileWrite, nullptr);
    486         continue;
    487       }
    488       if (i == size - 1) {
    489         WideString wPath = WideString::FromUTF16LE(
    490             reinterpret_cast<const unsigned short*>(bs.c_str()),
    491             bs.GetLength() / sizeof(unsigned short));
    492         ByteString bPath = wPath.UTF8Encode();
    493         const char* szFormat =
    494             "\n<pdf href=\"%s\" xmlns=\"http://ns.adobe.com/xdp/pdf/\"/>";
    495         ByteString content = ByteString::Format(szFormat, bPath.c_str());
    496         fileWrite->WriteBlock(content.c_str(), fileWrite->GetSize(),
    497                               content.GetLength());
    498       }
    499       auto pAcc = pdfium::MakeRetain<CPDF_StreamAcc>(pStream);
    500       pAcc->LoadAllDataFiltered();
    501       fileWrite->WriteBlock(pAcc->GetData(), fileWrite->GetSize(),
    502                             pAcc->GetSize());
    503     }
    504   }
    505   fileWrite->Flush();
    506 }
    507 
    508 void CPDFXFA_DocEnvironment::GotoURL(CXFA_FFDoc* hDoc,
    509                                      const WideString& bsURL) {
    510   if (hDoc != m_pContext->GetXFADoc())
    511     return;
    512 
    513   if (m_pContext->GetFormType() != FormType::kXFAFull)
    514     return;
    515 
    516   CPDFSDK_FormFillEnvironment* pFormFillEnv = m_pContext->GetFormFillEnv();
    517   if (!pFormFillEnv)
    518     return;
    519 
    520   WideStringView str(bsURL.c_str());
    521   pFormFillEnv->GotoURL(m_pContext.Get(), str);
    522 }
    523 
    524 bool CPDFXFA_DocEnvironment::IsValidationsEnabled(CXFA_FFDoc* hDoc) {
    525   if (hDoc != m_pContext->GetXFADoc() || !m_pContext->GetFormFillEnv())
    526     return false;
    527   if (m_pContext->GetFormFillEnv()->GetInterForm()) {
    528     return m_pContext->GetFormFillEnv()
    529         ->GetInterForm()
    530         ->IsXfaValidationsEnabled();
    531   }
    532   return true;
    533 }
    534 
    535 void CPDFXFA_DocEnvironment::SetValidationsEnabled(CXFA_FFDoc* hDoc,
    536                                                    bool bEnabled) {
    537   if (hDoc != m_pContext->GetXFADoc() || !m_pContext->GetFormFillEnv())
    538     return;
    539   if (m_pContext->GetFormFillEnv()->GetInterForm()) {
    540     m_pContext->GetFormFillEnv()->GetInterForm()->XfaSetValidationsEnabled(
    541         bEnabled);
    542   }
    543 }
    544 
    545 void CPDFXFA_DocEnvironment::SetFocusWidget(CXFA_FFDoc* hDoc,
    546                                             CXFA_FFWidget* hWidget) {
    547   if (hDoc != m_pContext->GetXFADoc())
    548     return;
    549 
    550   if (!hWidget) {
    551     CPDFSDK_Annot::ObservedPtr pNull;
    552     m_pContext->GetFormFillEnv()->SetFocusAnnot(&pNull);
    553     return;
    554   }
    555 
    556   int pageViewCount = m_pContext->GetFormFillEnv()->GetPageViewCount();
    557   for (int i = 0; i < pageViewCount; i++) {
    558     CPDFSDK_PageView* pPageView = m_pContext->GetFormFillEnv()->GetPageView(i);
    559     if (!pPageView)
    560       continue;
    561 
    562     CPDFSDK_Annot::ObservedPtr pAnnot(pPageView->GetAnnotByXFAWidget(hWidget));
    563     if (pAnnot) {
    564       m_pContext->GetFormFillEnv()->SetFocusAnnot(&pAnnot);
    565       break;
    566     }
    567   }
    568 }
    569 
    570 void CPDFXFA_DocEnvironment::Print(CXFA_FFDoc* hDoc,
    571                                    int32_t nStartPage,
    572                                    int32_t nEndPage,
    573                                    uint32_t dwOptions) {
    574   if (hDoc != m_pContext->GetXFADoc())
    575     return;
    576 
    577   CPDFSDK_FormFillEnvironment* pFormFillEnv = m_pContext->GetFormFillEnv();
    578   if (!pFormFillEnv || !pFormFillEnv->GetFormFillInfo() ||
    579       !pFormFillEnv->GetFormFillInfo()->m_pJsPlatform ||
    580       !pFormFillEnv->GetFormFillInfo()->m_pJsPlatform->Doc_print) {
    581     return;
    582   }
    583 
    584   pFormFillEnv->GetFormFillInfo()->m_pJsPlatform->Doc_print(
    585       pFormFillEnv->GetFormFillInfo()->m_pJsPlatform,
    586       dwOptions & XFA_PRINTOPT_ShowDialog, nStartPage, nEndPage,
    587       dwOptions & XFA_PRINTOPT_CanCancel, dwOptions & XFA_PRINTOPT_ShrinkPage,
    588       dwOptions & XFA_PRINTOPT_AsImage, dwOptions & XFA_PRINTOPT_ReverseOrder,
    589       dwOptions & XFA_PRINTOPT_PrintAnnot);
    590 }
    591 
    592 FX_ARGB CPDFXFA_DocEnvironment::GetHighlightColor(CXFA_FFDoc* hDoc) {
    593   if (hDoc != m_pContext->GetXFADoc() || !m_pContext->GetFormFillEnv())
    594     return 0;
    595 
    596   CPDFSDK_InterForm* pInterForm = m_pContext->GetFormFillEnv()->GetInterForm();
    597   if (!pInterForm)
    598     return 0;
    599 
    600   return ArgbEncode(pInterForm->GetHighlightAlpha(),
    601                     pInterForm->GetHighlightColor(FormFieldType::kXFA));
    602 }
    603 
    604 bool CPDFXFA_DocEnvironment::NotifySubmit(bool bPrevOrPost) {
    605   if (bPrevOrPost)
    606     return OnBeforeNotifySubmit();
    607 
    608   OnAfterNotifySubmit();
    609   return true;
    610 }
    611 
    612 bool CPDFXFA_DocEnvironment::OnBeforeNotifySubmit() {
    613   if (!m_pContext->ContainsXFAForm())
    614     return true;
    615 
    616   CXFA_FFDocView* docView = m_pContext->GetXFADocView();
    617   if (!docView)
    618     return true;
    619 
    620   CXFA_FFWidgetHandler* pWidgetHandler = docView->GetWidgetHandler();
    621   if (!pWidgetHandler)
    622     return true;
    623 
    624   std::unique_ptr<CXFA_WidgetAccIterator> pWidgetAccIterator =
    625       docView->CreateWidgetAccIterator();
    626   if (pWidgetAccIterator) {
    627     CXFA_EventParam Param;
    628     Param.m_eType = XFA_EVENT_PreSubmit;
    629     while (CXFA_WidgetAcc* pWidgetAcc = pWidgetAccIterator->MoveToNext())
    630       pWidgetHandler->ProcessEvent(pWidgetAcc, &Param);
    631   }
    632 
    633   pWidgetAccIterator = docView->CreateWidgetAccIterator();
    634   if (!pWidgetAccIterator)
    635     return true;
    636 
    637   CXFA_WidgetAcc* pWidgetAcc = pWidgetAccIterator->MoveToNext();
    638   pWidgetAcc = pWidgetAccIterator->MoveToNext();
    639   while (pWidgetAcc) {
    640     int fRet = pWidgetAcc->GetNode()->ProcessValidate(docView, -1);
    641     if (fRet == XFA_EVENTERROR_Error) {
    642       CPDFSDK_FormFillEnvironment* pFormFillEnv = m_pContext->GetFormFillEnv();
    643       if (!pFormFillEnv)
    644         return false;
    645 
    646       WideString ws = WideString::FromLocal(IDS_XFA_Validate_Input);
    647       ByteString bs = ws.UTF16LE_Encode();
    648       int len = bs.GetLength();
    649       pFormFillEnv->Alert((FPDF_WIDESTRING)bs.GetBuffer(len),
    650                           (FPDF_WIDESTRING)L"", 0, 1);
    651       bs.ReleaseBuffer(len);
    652       return false;
    653     }
    654     pWidgetAcc = pWidgetAccIterator->MoveToNext();
    655   }
    656   docView->UpdateDocView();
    657 
    658   return true;
    659 }
    660 
    661 void CPDFXFA_DocEnvironment::OnAfterNotifySubmit() {
    662   if (!m_pContext->ContainsXFAForm())
    663     return;
    664 
    665   if (!m_pContext->GetXFADocView())
    666     return;
    667 
    668   CXFA_FFWidgetHandler* pWidgetHandler =
    669       m_pContext->GetXFADocView()->GetWidgetHandler();
    670   if (!pWidgetHandler)
    671     return;
    672 
    673   std::unique_ptr<CXFA_WidgetAccIterator> pWidgetAccIterator =
    674       m_pContext->GetXFADocView()->CreateWidgetAccIterator();
    675   if (!pWidgetAccIterator)
    676     return;
    677 
    678   CXFA_EventParam Param;
    679   Param.m_eType = XFA_EVENT_PostSubmit;
    680   CXFA_WidgetAcc* pWidgetAcc = pWidgetAccIterator->MoveToNext();
    681   while (pWidgetAcc) {
    682     pWidgetHandler->ProcessEvent(pWidgetAcc, &Param);
    683     pWidgetAcc = pWidgetAccIterator->MoveToNext();
    684   }
    685   m_pContext->GetXFADocView()->UpdateDocView();
    686 }
    687 
    688 bool CPDFXFA_DocEnvironment::Submit(CXFA_FFDoc* hDoc, CXFA_Submit* submit) {
    689   if (!NotifySubmit(true) || !m_pContext->GetXFADocView())
    690     return false;
    691 
    692   m_pContext->GetXFADocView()->UpdateDocView();
    693   bool ret = SubmitInternal(hDoc, submit);
    694   NotifySubmit(false);
    695   return ret;
    696 }
    697 
    698 RetainPtr<IFX_SeekableReadStream> CPDFXFA_DocEnvironment::OpenLinkedFile(
    699     CXFA_FFDoc* hDoc,
    700     const WideString& wsLink) {
    701   CPDFSDK_FormFillEnvironment* pFormFillEnv = m_pContext->GetFormFillEnv();
    702   if (!pFormFillEnv)
    703     return nullptr;
    704 
    705   ByteString bs = wsLink.UTF16LE_Encode();
    706   int len = bs.GetLength();
    707   FPDF_FILEHANDLER* pFileHandler =
    708       pFormFillEnv->OpenFile(0, (FPDF_WIDESTRING)bs.GetBuffer(len), "rb");
    709   bs.ReleaseBuffer(len);
    710   if (!pFileHandler)
    711     return nullptr;
    712 
    713   return MakeSeekableStream(pFileHandler);
    714 }
    715 
    716 bool CPDFXFA_DocEnvironment::ExportSubmitFile(FPDF_FILEHANDLER* pFileHandler,
    717                                               int fileType,
    718                                               FPDF_DWORD encodeType,
    719                                               FPDF_DWORD flag) {
    720   if (!m_pContext->GetXFADocView())
    721     return false;
    722 
    723   CPDFSDK_FormFillEnvironment* pFormFillEnv = m_pContext->GetFormFillEnv();
    724   if (!pFormFillEnv)
    725     return false;
    726 
    727   CXFA_FFDoc* ffdoc = m_pContext->GetXFADocView()->GetDoc();
    728   RetainPtr<IFX_SeekableStream> fileStream = MakeSeekableStream(pFileHandler);
    729   if (fileType == FXFA_SAVEAS_XML) {
    730     static constexpr char kContent[] =
    731         "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n";
    732     fileStream->WriteBlock(kContent, 0, strlen(kContent));
    733 
    734     ffdoc->SavePackage(
    735         ToNode(ffdoc->GetXFADoc()->GetXFAObject(XFA_HASHCODE_Data)), fileStream,
    736         nullptr);
    737     return true;
    738   }
    739 
    740   if (fileType != FXFA_SAVEAS_XDP)
    741     return true;
    742 
    743   if (!flag) {
    744     flag = FXFA_CONFIG | FXFA_TEMPLATE | FXFA_LOCALESET | FXFA_DATASETS |
    745            FXFA_XMPMETA | FXFA_XFDF | FXFA_FORM;
    746   }
    747   if (!m_pContext->GetPDFDoc()) {
    748     fileStream->Flush();
    749     return false;
    750   }
    751 
    752   const CPDF_Dictionary* pRoot = m_pContext->GetPDFDoc()->GetRoot();
    753   if (!pRoot) {
    754     fileStream->Flush();
    755     return false;
    756   }
    757 
    758   CPDF_Dictionary* pAcroForm = pRoot->GetDictFor("AcroForm");
    759   if (!pAcroForm) {
    760     fileStream->Flush();
    761     return false;
    762   }
    763 
    764   CPDF_Array* pArray = ToArray(pAcroForm->GetObjectFor("XFA"));
    765   if (!pArray) {
    766     fileStream->Flush();
    767     return false;
    768   }
    769 
    770   int size = pArray->GetCount();
    771   for (int i = 1; i < size; i += 2) {
    772     CPDF_Object* pPDFObj = pArray->GetObjectAt(i);
    773     CPDF_Object* pPrePDFObj = pArray->GetObjectAt(i - 1);
    774     if (!pPrePDFObj->IsString())
    775       continue;
    776     if (!pPDFObj->IsReference())
    777       continue;
    778 
    779     CPDF_Object* pDirectObj = pPDFObj->GetDirect();
    780     if (!pDirectObj->IsStream())
    781       continue;
    782     if (pPrePDFObj->GetString() == "config" && !(flag & FXFA_CONFIG))
    783       continue;
    784     if (pPrePDFObj->GetString() == "template" && !(flag & FXFA_TEMPLATE))
    785       continue;
    786     if (pPrePDFObj->GetString() == "localeSet" && !(flag & FXFA_LOCALESET))
    787       continue;
    788     if (pPrePDFObj->GetString() == "datasets" && !(flag & FXFA_DATASETS))
    789       continue;
    790     if (pPrePDFObj->GetString() == "xmpmeta" && !(flag & FXFA_XMPMETA))
    791       continue;
    792     if (pPrePDFObj->GetString() == "xfdf" && !(flag & FXFA_XFDF))
    793       continue;
    794     if (pPrePDFObj->GetString() == "form" && !(flag & FXFA_FORM))
    795       continue;
    796 
    797     if (pPrePDFObj->GetString() == "form") {
    798       ffdoc->SavePackage(
    799           ToNode(ffdoc->GetXFADoc()->GetXFAObject(XFA_HASHCODE_Form)),
    800           fileStream, nullptr);
    801     } else if (pPrePDFObj->GetString() == "datasets") {
    802       ffdoc->SavePackage(
    803           ToNode(ffdoc->GetXFADoc()->GetXFAObject(XFA_HASHCODE_Datasets)),
    804           fileStream, nullptr);
    805     }
    806   }
    807   return true;
    808 }
    809 
    810 void CPDFXFA_DocEnvironment::ToXFAContentFlags(WideString csSrcContent,
    811                                                FPDF_DWORD& flag) {
    812   if (csSrcContent.Contains(L" config "))
    813     flag |= FXFA_CONFIG;
    814   if (csSrcContent.Contains(L" template "))
    815     flag |= FXFA_TEMPLATE;
    816   if (csSrcContent.Contains(L" localeSet "))
    817     flag |= FXFA_LOCALESET;
    818   if (csSrcContent.Contains(L" datasets "))
    819     flag |= FXFA_DATASETS;
    820   if (csSrcContent.Contains(L" xmpmeta "))
    821     flag |= FXFA_XMPMETA;
    822   if (csSrcContent.Contains(L" xfdf "))
    823     flag |= FXFA_XFDF;
    824   if (csSrcContent.Contains(L" form "))
    825     flag |= FXFA_FORM;
    826   if (flag == 0) {
    827     flag = FXFA_CONFIG | FXFA_TEMPLATE | FXFA_LOCALESET | FXFA_DATASETS |
    828            FXFA_XMPMETA | FXFA_XFDF | FXFA_FORM;
    829   }
    830 }
    831 
    832 bool CPDFXFA_DocEnvironment::MailToInfo(WideString& csURL,
    833                                         WideString& csToAddress,
    834                                         WideString& csCCAddress,
    835                                         WideString& csBCCAddress,
    836                                         WideString& csSubject,
    837                                         WideString& csMsg) {
    838   WideString srcURL = csURL;
    839   srcURL.TrimLeft();
    840   if (srcURL.Left(7).CompareNoCase(L"mailto:") != 0)
    841     return false;
    842 
    843   auto pos = srcURL.Find(L'?');
    844   WideString tmp;
    845   if (!pos.has_value()) {
    846     pos = srcURL.Find(L'@');
    847     if (!pos.has_value())
    848       return false;
    849 
    850     tmp = srcURL.Right(csURL.GetLength() - 7);
    851   } else {
    852     tmp = srcURL.Left(pos.value());
    853     tmp = tmp.Right(tmp.GetLength() - 7);
    854   }
    855   tmp.Trim();
    856 
    857   csToAddress = tmp;
    858 
    859   srcURL = srcURL.Right(srcURL.GetLength() - (pos.value() + 1));
    860   while (!srcURL.IsEmpty()) {
    861     srcURL.Trim();
    862     pos = srcURL.Find(L'&');
    863 
    864     tmp = (!pos.has_value()) ? srcURL : srcURL.Left(pos.value());
    865     tmp.Trim();
    866     if (tmp.GetLength() >= 3 && tmp.Left(3).CompareNoCase(L"cc=") == 0) {
    867       tmp = tmp.Right(tmp.GetLength() - 3);
    868       if (!csCCAddress.IsEmpty())
    869         csCCAddress += L';';
    870       csCCAddress += tmp;
    871     } else if (tmp.GetLength() >= 4 &&
    872                tmp.Left(4).CompareNoCase(L"bcc=") == 0) {
    873       tmp = tmp.Right(tmp.GetLength() - 4);
    874       if (!csBCCAddress.IsEmpty())
    875         csBCCAddress += L';';
    876       csBCCAddress += tmp;
    877     } else if (tmp.GetLength() >= 8 &&
    878                tmp.Left(8).CompareNoCase(L"subject=") == 0) {
    879       tmp = tmp.Right(tmp.GetLength() - 8);
    880       csSubject += tmp;
    881     } else if (tmp.GetLength() >= 5 &&
    882                tmp.Left(5).CompareNoCase(L"body=") == 0) {
    883       tmp = tmp.Right(tmp.GetLength() - 5);
    884       csMsg += tmp;
    885     }
    886     srcURL = !pos.has_value()
    887                  ? L""
    888                  : srcURL.Right(csURL.GetLength() - (pos.value() + 1));
    889   }
    890   csToAddress.Replace(L",", L";");
    891   csCCAddress.Replace(L",", L";");
    892   csBCCAddress.Replace(L",", L";");
    893   return true;
    894 }
    895 
    896 bool CPDFXFA_DocEnvironment::SubmitInternal(CXFA_FFDoc* hDoc,
    897                                             CXFA_Submit* submit) {
    898   CPDFSDK_FormFillEnvironment* pFormFillEnv = m_pContext->GetFormFillEnv();
    899   if (!pFormFillEnv)
    900     return false;
    901 
    902   WideString csURL = submit->GetSubmitTarget();
    903   if (csURL.IsEmpty()) {
    904     WideString ws = WideString::FromLocal("Submit cancelled.");
    905     ByteString bs = ws.UTF16LE_Encode();
    906     int len = bs.GetLength();
    907     pFormFillEnv->Alert(reinterpret_cast<FPDF_WIDESTRING>(bs.GetBuffer(len)),
    908                         reinterpret_cast<FPDF_WIDESTRING>(L""), 0, 4);
    909     bs.ReleaseBuffer(len);
    910     return false;
    911   }
    912 
    913   FPDF_FILEHANDLER* pFileHandler = nullptr;
    914   int fileFlag = -1;
    915   switch (submit->GetSubmitFormat()) {
    916     case XFA_AttributeEnum::Xdp: {
    917       WideString csContent = submit->GetSubmitXDPContent();
    918       csContent.Trim();
    919 
    920       WideString space = WideString::FromLocal(" ");
    921       csContent = space + csContent + space;
    922       FPDF_DWORD flag = 0;
    923       if (submit->IsSubmitEmbedPDF())
    924         flag |= FXFA_PDF;
    925 
    926       ToXFAContentFlags(csContent, flag);
    927       pFileHandler = pFormFillEnv->OpenFile(FXFA_SAVEAS_XDP, nullptr, "wb");
    928       fileFlag = FXFA_SAVEAS_XDP;
    929       ExportSubmitFile(pFileHandler, FXFA_SAVEAS_XDP, 0, flag);
    930       break;
    931     }
    932     case XFA_AttributeEnum::Xml:
    933       pFileHandler = pFormFillEnv->OpenFile(FXFA_SAVEAS_XML, nullptr, "wb");
    934       fileFlag = FXFA_SAVEAS_XML;
    935       ExportSubmitFile(pFileHandler, FXFA_SAVEAS_XML, 0, FXFA_XFA_ALL);
    936       break;
    937     case XFA_AttributeEnum::Pdf:
    938       break;
    939     case XFA_AttributeEnum::Urlencoded:
    940       pFileHandler = pFormFillEnv->OpenFile(FXFA_SAVEAS_XML, nullptr, "wb");
    941       fileFlag = FXFA_SAVEAS_XML;
    942       ExportSubmitFile(pFileHandler, FXFA_SAVEAS_XML, 0, FXFA_XFA_ALL);
    943       break;
    944     default:
    945       return false;
    946   }
    947   if (!pFileHandler)
    948     return false;
    949 
    950   if (csURL.Left(7).CompareNoCase(L"mailto:") == 0) {
    951     WideString csToAddress;
    952     WideString csCCAddress;
    953     WideString csBCCAddress;
    954     WideString csSubject;
    955     WideString csMsg;
    956     if (!MailToInfo(csURL, csToAddress, csCCAddress, csBCCAddress, csSubject,
    957                     csMsg)) {
    958       return false;
    959     }
    960     ByteString bsTo = WideString(csToAddress).UTF16LE_Encode();
    961     ByteString bsCC = WideString(csCCAddress).UTF16LE_Encode();
    962     ByteString bsBcc = WideString(csBCCAddress).UTF16LE_Encode();
    963     ByteString bsSubject = WideString(csSubject).UTF16LE_Encode();
    964     ByteString bsMsg = WideString(csMsg).UTF16LE_Encode();
    965     FPDF_WIDESTRING pTo = (FPDF_WIDESTRING)bsTo.GetBuffer(bsTo.GetLength());
    966     FPDF_WIDESTRING pCC = (FPDF_WIDESTRING)bsCC.GetBuffer(bsCC.GetLength());
    967     FPDF_WIDESTRING pBcc = (FPDF_WIDESTRING)bsBcc.GetBuffer(bsBcc.GetLength());
    968     FPDF_WIDESTRING pSubject =
    969         (FPDF_WIDESTRING)bsSubject.GetBuffer(bsSubject.GetLength());
    970     FPDF_WIDESTRING pMsg = (FPDF_WIDESTRING)bsMsg.GetBuffer(bsMsg.GetLength());
    971     pFormFillEnv->EmailTo(pFileHandler, pTo, pSubject, pCC, pBcc, pMsg);
    972     bsTo.ReleaseBuffer(bsTo.GetStringLength());
    973     bsCC.ReleaseBuffer(bsCC.GetStringLength());
    974     bsBcc.ReleaseBuffer(bsBcc.GetStringLength());
    975     bsSubject.ReleaseBuffer(bsSubject.GetStringLength());
    976     bsMsg.ReleaseBuffer(bsMsg.GetStringLength());
    977   } else {
    978     // HTTP or FTP
    979     WideString ws;
    980     ByteString bs = csURL.UTF16LE_Encode();
    981     int len = bs.GetLength();
    982     pFormFillEnv->UploadTo(pFileHandler, fileFlag,
    983                            (FPDF_WIDESTRING)bs.GetBuffer(len));
    984     bs.ReleaseBuffer(len);
    985   }
    986   return true;
    987 }
    988 
    989 bool CPDFXFA_DocEnvironment::SetGlobalProperty(CXFA_FFDoc* hDoc,
    990                                                const ByteStringView& szPropName,
    991                                                CFXJSE_Value* pValue) {
    992   if (hDoc != m_pContext->GetXFADoc())
    993     return false;
    994   if (!m_pContext->GetFormFillEnv() ||
    995       !m_pContext->GetFormFillEnv()->GetJSRuntime()) {
    996     return false;
    997   }
    998   CPDFSDK_FormFillEnvironment* pFormFillEnv = m_pContext->GetFormFillEnv();
    999   IJS_EventContext* pContext = pFormFillEnv->GetJSRuntime()->NewEventContext();
   1000   bool bRet = pFormFillEnv->GetJSRuntime()->SetValueByName(szPropName, pValue);
   1001   pFormFillEnv->GetJSRuntime()->ReleaseEventContext(pContext);
   1002   return bRet;
   1003 }
   1004 
   1005 bool CPDFXFA_DocEnvironment::GetGlobalProperty(CXFA_FFDoc* hDoc,
   1006                                                const ByteStringView& szPropName,
   1007                                                CFXJSE_Value* pValue) {
   1008   if (hDoc != m_pContext->GetXFADoc())
   1009     return false;
   1010   if (!m_pContext->GetFormFillEnv() ||
   1011       !m_pContext->GetFormFillEnv()->GetJSRuntime()) {
   1012     return false;
   1013   }
   1014   CPDFSDK_FormFillEnvironment* pFormFillEnv = m_pContext->GetFormFillEnv();
   1015   IJS_EventContext* pContext = pFormFillEnv->GetJSRuntime()->NewEventContext();
   1016   bool bRet = pFormFillEnv->GetJSRuntime()->GetValueByName(szPropName, pValue);
   1017   pFormFillEnv->GetJSRuntime()->ReleaseEventContext(pContext);
   1018   return bRet;
   1019 }
   1020