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