1 // Copyright 2014 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 "xfa/fxfa/cxfa_ffdoc.h"
8 
9 #include <algorithm>
10 #include <memory>
11 #include <vector>
12 
13 #include "core/fpdfapi/parser/cpdf_dictionary.h"
14 #include "core/fpdfapi/parser/cpdf_document.h"
15 #include "core/fpdfapi/parser/cpdf_stream.h"
16 #include "core/fpdfapi/parser/cpdf_stream_acc.h"
17 #include "core/fpdfdoc/cpdf_nametree.h"
18 #include "core/fxcrt/cfx_readonlymemorystream.h"
19 #include "core/fxcrt/fx_extension.h"
20 #include "core/fxcrt/xml/cfx_xmldocument.h"
21 #include "core/fxcrt/xml/cfx_xmlelement.h"
22 #include "core/fxcrt/xml/cfx_xmlnode.h"
23 #include "core/fxge/dib/cfx_dibitmap.h"
24 #include "fxjs/xfa/cjx_object.h"
25 #include "third_party/base/ptr_util.h"
26 #include "xfa/fgas/font/cfgas_pdffontmgr.h"
27 #include "xfa/fwl/cfwl_notedriver.h"
28 #include "xfa/fxfa/cxfa_ffapp.h"
29 #include "xfa/fxfa/cxfa_ffdocview.h"
30 #include "xfa/fxfa/cxfa_ffnotify.h"
31 #include "xfa/fxfa/cxfa_ffwidget.h"
32 #include "xfa/fxfa/cxfa_fontmgr.h"
33 #include "xfa/fxfa/layout/cxfa_layoutprocessor.h"
34 #include "xfa/fxfa/parser/cxfa_acrobat.h"
35 #include "xfa/fxfa/parser/cxfa_acrobat7.h"
36 #include "xfa/fxfa/parser/cxfa_dataexporter.h"
37 #include "xfa/fxfa/parser/cxfa_document.h"
38 #include "xfa/fxfa/parser/cxfa_document_parser.h"
39 #include "xfa/fxfa/parser/cxfa_dynamicrender.h"
40 #include "xfa/fxfa/parser/cxfa_node.h"
41 
42 FX_IMAGEDIB_AND_DPI::FX_IMAGEDIB_AND_DPI() = default;
43 FX_IMAGEDIB_AND_DPI::FX_IMAGEDIB_AND_DPI(const FX_IMAGEDIB_AND_DPI& that) =
44     default;
45 
FX_IMAGEDIB_AND_DPI(const RetainPtr<CFX_DIBBase> & pDib,int32_t xDpi,int32_t yDpi)46 FX_IMAGEDIB_AND_DPI::FX_IMAGEDIB_AND_DPI(const RetainPtr<CFX_DIBBase>& pDib,
47                                          int32_t xDpi,
48                                          int32_t yDpi)
49     : pDibSource(pDib), iImageXDpi(xDpi), iImageYDpi(yDpi) {}
50 
51 FX_IMAGEDIB_AND_DPI::~FX_IMAGEDIB_AND_DPI() = default;
52 
53 // static
CreateAndOpen(CXFA_FFApp * pApp,IXFA_DocEnvironment * pDocEnvironment,CPDF_Document * pPDFDoc,const RetainPtr<IFX_SeekableStream> & stream)54 std::unique_ptr<CXFA_FFDoc> CXFA_FFDoc::CreateAndOpen(
55     CXFA_FFApp* pApp,
56     IXFA_DocEnvironment* pDocEnvironment,
57     CPDF_Document* pPDFDoc,
58     const RetainPtr<IFX_SeekableStream>& stream) {
59   ASSERT(pApp);
60   ASSERT(pDocEnvironment);
61   ASSERT(pPDFDoc);
62 
63   // Use WrapUnique() to keep constructor private.
64   auto result =
65       pdfium::WrapUnique(new CXFA_FFDoc(pApp, pDocEnvironment, pPDFDoc));
66   if (!result->OpenDoc(stream))
67     return nullptr;
68 
69   return result;
70 }
71 
CXFA_FFDoc(CXFA_FFApp * pApp,IXFA_DocEnvironment * pDocEnvironment,CPDF_Document * pPDFDoc)72 CXFA_FFDoc::CXFA_FFDoc(CXFA_FFApp* pApp,
73                        IXFA_DocEnvironment* pDocEnvironment,
74                        CPDF_Document* pPDFDoc)
75     : m_pDocEnvironment(pDocEnvironment),
76       m_pApp(pApp),
77       m_pPDFDoc(pPDFDoc),
78       m_pNotify(pdfium::MakeUnique<CXFA_FFNotify>(this)),
79       m_pDocument(pdfium::MakeUnique<CXFA_Document>(
80           m_pNotify.get(),
81           pdfium::MakeUnique<CXFA_LayoutProcessor>())) {}
82 
~CXFA_FFDoc()83 CXFA_FFDoc::~CXFA_FFDoc() {
84   if (m_DocView) {
85     m_DocView->RunDocClose();
86     m_DocView.reset();
87   }
88   if (m_pDocument)
89     m_pDocument->ClearLayoutData();
90 
91   m_pDocument.reset();
92   m_pXMLDoc.reset();
93   m_pNotify.reset();
94   m_pPDFFontMgr.reset();
95   m_HashToDibDpiMap.clear();
96   m_pApp->ClearEventTargets();
97 }
98 
ParseDoc(const RetainPtr<IFX_SeekableStream> & stream)99 bool CXFA_FFDoc::ParseDoc(const RetainPtr<IFX_SeekableStream>& stream) {
100   CXFA_DocumentParser parser(m_pDocument.get());
101   bool parsed = parser.Parse(stream, XFA_PacketType::Xdp);
102 
103   // We have to set the XML document before we return so that we can clean
104   // up in the OpenDoc method. If we don't, the XMLDocument will get free'd
105   // when this method returns and UnownedPtrs get unhappy.
106   m_pXMLDoc = parser.GetXMLDoc();
107 
108   if (!parsed)
109     return false;
110 
111   m_pDocument->SetRoot(parser.GetRootNode());
112   return true;
113 }
114 
CreateDocView()115 CXFA_FFDocView* CXFA_FFDoc::CreateDocView() {
116   if (!m_DocView)
117     m_DocView = pdfium::MakeUnique<CXFA_FFDocView>(this);
118 
119   return m_DocView.get();
120 }
121 
GetDocView(CXFA_LayoutProcessor * pLayout)122 CXFA_FFDocView* CXFA_FFDoc::GetDocView(CXFA_LayoutProcessor* pLayout) {
123   return m_DocView && m_DocView->GetXFALayout() == pLayout ? m_DocView.get()
124                                                            : nullptr;
125 }
126 
GetDocView()127 CXFA_FFDocView* CXFA_FFDoc::GetDocView() {
128   return m_DocView.get();
129 }
130 
OpenDoc(const RetainPtr<IFX_SeekableStream> & stream)131 bool CXFA_FFDoc::OpenDoc(const RetainPtr<IFX_SeekableStream>& stream) {
132   if (!ParseDoc(stream))
133     return false;
134 
135   CFGAS_FontMgr* mgr = GetApp()->GetFDEFontMgr();
136   if (!mgr)
137     return false;
138 
139   // At this point we've got an XFA document and we want to always return
140   // true to signify the load succeeded.
141   m_pPDFFontMgr = pdfium::MakeUnique<CFGAS_PDFFontMgr>(GetPDFDoc(), mgr);
142 
143   m_FormType = FormType::kXFAForeground;
144   CXFA_Node* pConfig = ToNode(m_pDocument->GetXFAObject(XFA_HASHCODE_Config));
145   if (!pConfig)
146     return true;
147 
148   CXFA_Acrobat* pAcrobat =
149       pConfig->GetFirstChildByClass<CXFA_Acrobat>(XFA_Element::Acrobat);
150   if (!pAcrobat)
151     return true;
152 
153   CXFA_Acrobat7* pAcrobat7 =
154       pAcrobat->GetFirstChildByClass<CXFA_Acrobat7>(XFA_Element::Acrobat7);
155   if (!pAcrobat7)
156     return true;
157 
158   CXFA_DynamicRender* pDynamicRender =
159       pAcrobat7->GetFirstChildByClass<CXFA_DynamicRender>(
160           XFA_Element::DynamicRender);
161   if (!pDynamicRender)
162     return true;
163 
164   WideString wsType = pDynamicRender->JSObject()->GetContent(false);
165   if (wsType.EqualsASCII("required"))
166     m_FormType = FormType::kXFAFull;
167 
168   return true;
169 }
170 
GetPDFNamedImage(WideStringView wsName,int32_t & iImageXDpi,int32_t & iImageYDpi)171 RetainPtr<CFX_DIBitmap> CXFA_FFDoc::GetPDFNamedImage(WideStringView wsName,
172                                                      int32_t& iImageXDpi,
173                                                      int32_t& iImageYDpi) {
174   uint32_t dwHash = FX_HashCode_GetW(wsName, false);
175   auto it = m_HashToDibDpiMap.find(dwHash);
176   if (it != m_HashToDibDpiMap.end()) {
177     iImageXDpi = it->second.iImageXDpi;
178     iImageYDpi = it->second.iImageYDpi;
179     return it->second.pDibSource.As<CFX_DIBitmap>();
180   }
181 
182   CPDF_Dictionary* pRoot = m_pPDFDoc->GetRoot();
183   if (!pRoot)
184     return nullptr;
185 
186   CPDF_Dictionary* pNames = pRoot->GetDictFor("Names");
187   if (!pNames)
188     return nullptr;
189 
190   CPDF_Dictionary* pXFAImages = pNames->GetDictFor("XFAImages");
191   if (!pXFAImages)
192     return nullptr;
193 
194   CPDF_NameTree nametree(pXFAImages);
195   CPDF_Object* pObject = nametree.LookupValue(WideString(wsName));
196   if (!pObject) {
197     for (size_t i = 0; i < nametree.GetCount(); i++) {
198       WideString wsTemp;
199       CPDF_Object* pTempObject = nametree.LookupValueAndName(i, &wsTemp);
200       if (wsTemp == wsName) {
201         pObject = pTempObject;
202         break;
203       }
204     }
205   }
206 
207   CPDF_Stream* pStream = ToStream(pObject);
208   if (!pStream)
209     return nullptr;
210 
211   auto pAcc = pdfium::MakeRetain<CPDF_StreamAcc>(pStream);
212   pAcc->LoadAllDataFiltered();
213 
214   auto pImageFileRead =
215       pdfium::MakeRetain<CFX_ReadOnlyMemoryStream>(pAcc->GetSpan());
216 
217   RetainPtr<CFX_DIBitmap> pDibSource = XFA_LoadImageFromBuffer(
218       pImageFileRead, FXCODEC_IMAGE_UNKNOWN, iImageXDpi, iImageYDpi);
219   m_HashToDibDpiMap[dwHash] = {pDibSource, iImageXDpi, iImageYDpi};
220   return pDibSource;
221 }
222 
SavePackage(CXFA_Node * pNode,const RetainPtr<IFX_SeekableStream> & pFile)223 bool CXFA_FFDoc::SavePackage(CXFA_Node* pNode,
224                              const RetainPtr<IFX_SeekableStream>& pFile) {
225   ASSERT(pNode || GetXFADoc()->GetRoot());
226 
227   CXFA_DataExporter exporter;
228   return exporter.Export(pFile, pNode ? pNode : GetXFADoc()->GetRoot());
229 }
230