| // Copyright 2014 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 "xfa/fxfa/cxfa_ffdoc.h" |
| |
| #include <algorithm> |
| #include <memory> |
| #include <utility> |
| |
| #include "core/fpdfapi/parser/cpdf_dictionary.h" |
| #include "core/fpdfapi/parser/cpdf_document.h" |
| #include "core/fpdfapi/parser/cpdf_stream.h" |
| #include "core/fpdfapi/parser/cpdf_stream_acc.h" |
| #include "core/fpdfdoc/cpdf_nametree.h" |
| #include "core/fxcrt/cfx_read_only_span_stream.h" |
| #include "core/fxcrt/fx_extension.h" |
| #include "core/fxcrt/xml/cfx_xmldocument.h" |
| #include "core/fxcrt/xml/cfx_xmlelement.h" |
| #include "core/fxcrt/xml/cfx_xmlnode.h" |
| #include "core/fxcrt/xml/cfx_xmlparser.h" |
| #include "core/fxge/dib/cfx_dibitmap.h" |
| #include "fxjs/xfa/cjx_object.h" |
| #include "third_party/base/check.h" |
| #include "v8/include/cppgc/allocation.h" |
| #include "v8/include/cppgc/heap.h" |
| #include "xfa/fgas/font/cfgas_gefont.h" |
| #include "xfa/fgas/font/cfgas_pdffontmgr.h" |
| #include "xfa/fwl/cfwl_notedriver.h" |
| #include "xfa/fxfa/cxfa_ffapp.h" |
| #include "xfa/fxfa/cxfa_ffdocview.h" |
| #include "xfa/fxfa/cxfa_ffnotify.h" |
| #include "xfa/fxfa/cxfa_ffwidget.h" |
| #include "xfa/fxfa/cxfa_fontmgr.h" |
| #include "xfa/fxfa/layout/cxfa_layoutprocessor.h" |
| #include "xfa/fxfa/parser/cxfa_acrobat.h" |
| #include "xfa/fxfa/parser/cxfa_acrobat7.h" |
| #include "xfa/fxfa/parser/cxfa_dataexporter.h" |
| #include "xfa/fxfa/parser/cxfa_document.h" |
| #include "xfa/fxfa/parser/cxfa_document_builder.h" |
| #include "xfa/fxfa/parser/cxfa_dynamicrender.h" |
| #include "xfa/fxfa/parser/cxfa_node.h" |
| |
| FX_IMAGEDIB_AND_DPI::FX_IMAGEDIB_AND_DPI() = default; |
| FX_IMAGEDIB_AND_DPI::FX_IMAGEDIB_AND_DPI(const FX_IMAGEDIB_AND_DPI& that) = |
| default; |
| |
| FX_IMAGEDIB_AND_DPI::FX_IMAGEDIB_AND_DPI(const RetainPtr<CFX_DIBBase>& pDib, |
| int32_t xDpi, |
| int32_t yDpi) |
| : pDibSource(pDib), iImageXDpi(xDpi), iImageYDpi(yDpi) {} |
| |
| FX_IMAGEDIB_AND_DPI::~FX_IMAGEDIB_AND_DPI() = default; |
| |
| CXFA_FFDoc::CXFA_FFDoc(CXFA_FFApp* pApp, |
| CallbackIface* pDocEnvironment, |
| CPDF_Document* pPDFDoc, |
| cppgc::Heap* pHeap) |
| : m_pDocEnvironment(pDocEnvironment), |
| m_pPDFDoc(pPDFDoc), |
| m_pHeap(pHeap), |
| m_pApp(pApp), |
| m_pNotify(cppgc::MakeGarbageCollected<CXFA_FFNotify>( |
| pHeap->GetAllocationHandle(), |
| this)), |
| m_pDocument(cppgc::MakeGarbageCollected<CXFA_Document>( |
| pHeap->GetAllocationHandle(), |
| m_pNotify, |
| pHeap, |
| cppgc::MakeGarbageCollected<CXFA_LayoutProcessor>( |
| pHeap->GetAllocationHandle(), |
| pHeap))) {} |
| |
| CXFA_FFDoc::~CXFA_FFDoc() = default; |
| |
| void CXFA_FFDoc::PreFinalize() { |
| if (m_DocView) |
| m_DocView->RunDocClose(); |
| |
| if (m_pDocument) |
| m_pDocument->ClearLayoutData(); |
| } |
| |
| void CXFA_FFDoc::Trace(cppgc::Visitor* visitor) const { |
| visitor->Trace(m_pApp); |
| visitor->Trace(m_pNotify); |
| visitor->Trace(m_pDocument); |
| visitor->Trace(m_DocView); |
| } |
| |
| bool CXFA_FFDoc::BuildDoc(CFX_XMLDocument* pXML) { |
| DCHECK(pXML); |
| |
| CXFA_DocumentBuilder builder(m_pDocument); |
| if (!builder.BuildDocument(pXML, XFA_PacketType::Xdp)) |
| return false; |
| |
| m_pDocument->SetRoot(builder.GetRootNode()); |
| return true; |
| } |
| |
| CXFA_FFDocView* CXFA_FFDoc::CreateDocView() { |
| if (!m_DocView) { |
| m_DocView = cppgc::MakeGarbageCollected<CXFA_FFDocView>( |
| m_pHeap->GetAllocationHandle(), this); |
| } |
| return m_DocView; |
| } |
| |
| void CXFA_FFDoc::SetChangeMark() { |
| m_pDocEnvironment->SetChangeMark(this); |
| } |
| |
| void CXFA_FFDoc::InvalidateRect(CXFA_FFPageView* pPageView, |
| const CFX_RectF& rt) { |
| m_pDocEnvironment->InvalidateRect(pPageView, rt); |
| } |
| |
| void CXFA_FFDoc::DisplayCaret(CXFA_FFWidget* hWidget, |
| bool bVisible, |
| const CFX_RectF* pRtAnchor) { |
| return m_pDocEnvironment->DisplayCaret(hWidget, bVisible, pRtAnchor); |
| } |
| |
| bool CXFA_FFDoc::GetPopupPos(CXFA_FFWidget* hWidget, |
| float fMinPopup, |
| float fMaxPopup, |
| const CFX_RectF& rtAnchor, |
| CFX_RectF* pPopupRect) const { |
| return m_pDocEnvironment->GetPopupPos(hWidget, fMinPopup, fMaxPopup, rtAnchor, |
| pPopupRect); |
| } |
| |
| bool CXFA_FFDoc::PopupMenu(CXFA_FFWidget* hWidget, const CFX_PointF& ptPopup) { |
| return m_pDocEnvironment->PopupMenu(hWidget, ptPopup); |
| } |
| |
| void CXFA_FFDoc::OnPageViewEvent(CXFA_FFPageView* pPageView, |
| PageViewEvent eEvent) { |
| m_pDocEnvironment->OnPageViewEvent(pPageView, eEvent); |
| } |
| |
| void CXFA_FFDoc::WidgetPostAdd(CXFA_FFWidget* hWidget) { |
| m_pDocEnvironment->WidgetPostAdd(hWidget); |
| } |
| |
| void CXFA_FFDoc::WidgetPreRemove(CXFA_FFWidget* hWidget) { |
| m_pDocEnvironment->WidgetPreRemove(hWidget); |
| } |
| |
| int32_t CXFA_FFDoc::CountPages() const { |
| return m_pDocEnvironment->CountPages(this); |
| } |
| |
| int32_t CXFA_FFDoc::GetCurrentPage() const { |
| return m_pDocEnvironment->GetCurrentPage(this); |
| } |
| |
| void CXFA_FFDoc::SetCurrentPage(int32_t iCurPage) { |
| m_pDocEnvironment->SetCurrentPage(this, iCurPage); |
| } |
| |
| bool CXFA_FFDoc::IsCalculationsEnabled() const { |
| return m_pDocEnvironment->IsCalculationsEnabled(this); |
| } |
| |
| void CXFA_FFDoc::SetCalculationsEnabled(bool bEnabled) { |
| return m_pDocEnvironment->SetCalculationsEnabled(this, bEnabled); |
| } |
| |
| WideString CXFA_FFDoc::GetTitle() const { |
| return m_pDocEnvironment->GetTitle(this); |
| } |
| |
| void CXFA_FFDoc::SetTitle(const WideString& wsTitle) { |
| m_pDocEnvironment->SetTitle(this, wsTitle); |
| } |
| |
| void CXFA_FFDoc::ExportData(const WideString& wsFilePath, bool bXDP) { |
| m_pDocEnvironment->ExportData(this, wsFilePath, bXDP); |
| } |
| |
| void CXFA_FFDoc::GotoURL(const WideString& bsURL) { |
| m_pDocEnvironment->GotoURL(this, bsURL); |
| } |
| |
| bool CXFA_FFDoc::IsValidationsEnabled() const { |
| return m_pDocEnvironment->IsValidationsEnabled(this); |
| } |
| |
| void CXFA_FFDoc::SetValidationsEnabled(bool bEnabled) { |
| m_pDocEnvironment->SetValidationsEnabled(this, bEnabled); |
| } |
| |
| void CXFA_FFDoc::SetFocusWidget(CXFA_FFWidget* hWidget) { |
| m_pDocEnvironment->SetFocusWidget(this, hWidget); |
| } |
| |
| void CXFA_FFDoc::Print(int32_t nStartPage, |
| int32_t nEndPage, |
| Mask<XFA_PrintOpt> dwOptions) { |
| m_pDocEnvironment->Print(this, nStartPage, nEndPage, dwOptions); |
| } |
| |
| FX_ARGB CXFA_FFDoc::GetHighlightColor() const { |
| return m_pDocEnvironment->GetHighlightColor(this); |
| } |
| |
| IJS_Runtime* CXFA_FFDoc::GetIJSRuntime() const { |
| return m_pDocEnvironment->GetIJSRuntime(this); |
| } |
| |
| CFX_XMLDocument* CXFA_FFDoc::GetXMLDocument() const { |
| return m_pDocEnvironment->GetXMLDoc(); |
| } |
| |
| RetainPtr<IFX_SeekableReadStream> CXFA_FFDoc::OpenLinkedFile( |
| const WideString& wsLink) { |
| return m_pDocEnvironment->OpenLinkedFile(this, wsLink); |
| } |
| |
| CXFA_FFDocView* CXFA_FFDoc::GetDocView(CXFA_LayoutProcessor* pLayout) { |
| return m_DocView && m_DocView->GetLayoutProcessor() == pLayout ? m_DocView |
| : nullptr; |
| } |
| |
| CXFA_FFDocView* CXFA_FFDoc::GetDocView() { |
| return m_DocView; |
| } |
| |
| bool CXFA_FFDoc::OpenDoc(CFX_XMLDocument* pXML) { |
| if (!BuildDoc(pXML)) |
| return false; |
| |
| // At this point we've got an XFA document and we want to always return |
| // true to signify the load succeeded. |
| m_pPDFFontMgr = std::make_unique<CFGAS_PDFFontMgr>(GetPDFDoc()); |
| m_FormType = FormType::kXFAForeground; |
| CXFA_Node* pConfig = ToNode(m_pDocument->GetXFAObject(XFA_HASHCODE_Config)); |
| if (!pConfig) |
| return true; |
| |
| CXFA_Acrobat* pAcrobat = |
| pConfig->GetFirstChildByClass<CXFA_Acrobat>(XFA_Element::Acrobat); |
| if (!pAcrobat) |
| return true; |
| |
| CXFA_Acrobat7* pAcrobat7 = |
| pAcrobat->GetFirstChildByClass<CXFA_Acrobat7>(XFA_Element::Acrobat7); |
| if (!pAcrobat7) |
| return true; |
| |
| CXFA_DynamicRender* pDynamicRender = |
| pAcrobat7->GetFirstChildByClass<CXFA_DynamicRender>( |
| XFA_Element::DynamicRender); |
| if (!pDynamicRender) |
| return true; |
| |
| WideString wsType = pDynamicRender->JSObject()->GetContent(false); |
| if (wsType.EqualsASCII("required")) |
| m_FormType = FormType::kXFAFull; |
| |
| return true; |
| } |
| |
| RetainPtr<CFGAS_GEFont> CXFA_FFDoc::GetPDFFont(const WideString& family, |
| uint32_t styles, |
| bool strict) { |
| if (!m_pPDFFontMgr) |
| return nullptr; |
| |
| return m_pPDFFontMgr->GetFont(family, styles, strict); |
| } |
| |
| RetainPtr<CFX_DIBitmap> CXFA_FFDoc::GetPDFNamedImage(WideStringView wsName, |
| int32_t& iImageXDpi, |
| int32_t& iImageYDpi) { |
| uint32_t dwHash = FX_HashCode_GetW(wsName); |
| auto it = m_HashToDibDpiMap.find(dwHash); |
| if (it != m_HashToDibDpiMap.end()) { |
| iImageXDpi = it->second.iImageXDpi; |
| iImageYDpi = it->second.iImageYDpi; |
| return it->second.pDibSource.As<CFX_DIBitmap>(); |
| } |
| |
| auto name_tree = CPDF_NameTree::Create(m_pPDFDoc, "XFAImages"); |
| size_t count = name_tree ? name_tree->GetCount() : 0; |
| if (count == 0) |
| return nullptr; |
| |
| RetainPtr<const CPDF_Object> pObject = |
| name_tree->LookupValue(WideString(wsName)); |
| if (!pObject) { |
| for (size_t i = 0; i < count; ++i) { |
| WideString wsTemp; |
| RetainPtr<CPDF_Object> pTempObject = |
| name_tree->LookupValueAndName(i, &wsTemp); |
| if (wsTemp == wsName) { |
| pObject = std::move(pTempObject); |
| break; |
| } |
| } |
| } |
| |
| RetainPtr<const CPDF_Stream> pStream = ToStream(pObject); |
| if (!pStream) |
| return nullptr; |
| |
| auto pAcc = pdfium::MakeRetain<CPDF_StreamAcc>(std::move(pStream)); |
| pAcc->LoadAllDataFiltered(); |
| |
| auto pImageFileRead = |
| pdfium::MakeRetain<CFX_ReadOnlySpanStream>(pAcc->GetSpan()); |
| RetainPtr<CFX_DIBitmap> pDibSource = XFA_LoadImageFromBuffer( |
| std::move(pImageFileRead), FXCODEC_IMAGE_UNKNOWN, iImageXDpi, iImageYDpi); |
| m_HashToDibDpiMap[dwHash] = {pDibSource, iImageXDpi, iImageYDpi}; |
| return pDibSource; |
| } |
| |
| bool CXFA_FFDoc::SavePackage(CXFA_Node* pNode, |
| const RetainPtr<IFX_SeekableStream>& pFile) { |
| DCHECK(pNode || GetXFADoc()->GetRoot()); |
| |
| CXFA_DataExporter exporter; |
| return exporter.Export(pFile, pNode ? pNode : GetXFADoc()->GetRoot()); |
| } |