xref: /aosp_15_r20/external/pdfium/fpdfsdk/fpdf_ppo.cpp (revision 3ac0a46f773bac49fa9476ec2b1cf3f8da5ec3a4)
1*3ac0a46fSAndroid Build Coastguard Worker // Copyright 2014 The PDFium Authors
2*3ac0a46fSAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*3ac0a46fSAndroid Build Coastguard Worker // found in the LICENSE file.
4*3ac0a46fSAndroid Build Coastguard Worker 
5*3ac0a46fSAndroid Build Coastguard Worker // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6*3ac0a46fSAndroid Build Coastguard Worker 
7*3ac0a46fSAndroid Build Coastguard Worker #include "public/fpdf_ppo.h"
8*3ac0a46fSAndroid Build Coastguard Worker 
9*3ac0a46fSAndroid Build Coastguard Worker #include <algorithm>
10*3ac0a46fSAndroid Build Coastguard Worker #include <map>
11*3ac0a46fSAndroid Build Coastguard Worker #include <memory>
12*3ac0a46fSAndroid Build Coastguard Worker #include <numeric>
13*3ac0a46fSAndroid Build Coastguard Worker #include <sstream>
14*3ac0a46fSAndroid Build Coastguard Worker #include <utility>
15*3ac0a46fSAndroid Build Coastguard Worker #include <vector>
16*3ac0a46fSAndroid Build Coastguard Worker 
17*3ac0a46fSAndroid Build Coastguard Worker #include "constants/page_object.h"
18*3ac0a46fSAndroid Build Coastguard Worker #include "core/fpdfapi/page/cpdf_form.h"
19*3ac0a46fSAndroid Build Coastguard Worker #include "core/fpdfapi/page/cpdf_formobject.h"
20*3ac0a46fSAndroid Build Coastguard Worker #include "core/fpdfapi/page/cpdf_page.h"
21*3ac0a46fSAndroid Build Coastguard Worker #include "core/fpdfapi/page/cpdf_pageimagecache.h"
22*3ac0a46fSAndroid Build Coastguard Worker #include "core/fpdfapi/page/cpdf_pageobject.h"
23*3ac0a46fSAndroid Build Coastguard Worker #include "core/fpdfapi/parser/cpdf_array.h"
24*3ac0a46fSAndroid Build Coastguard Worker #include "core/fpdfapi/parser/cpdf_dictionary.h"
25*3ac0a46fSAndroid Build Coastguard Worker #include "core/fpdfapi/parser/cpdf_document.h"
26*3ac0a46fSAndroid Build Coastguard Worker #include "core/fpdfapi/parser/cpdf_name.h"
27*3ac0a46fSAndroid Build Coastguard Worker #include "core/fpdfapi/parser/cpdf_number.h"
28*3ac0a46fSAndroid Build Coastguard Worker #include "core/fpdfapi/parser/cpdf_object.h"
29*3ac0a46fSAndroid Build Coastguard Worker #include "core/fpdfapi/parser/cpdf_reference.h"
30*3ac0a46fSAndroid Build Coastguard Worker #include "core/fpdfapi/parser/cpdf_stream.h"
31*3ac0a46fSAndroid Build Coastguard Worker #include "core/fpdfapi/parser/cpdf_stream_acc.h"
32*3ac0a46fSAndroid Build Coastguard Worker #include "core/fpdfapi/parser/cpdf_string.h"
33*3ac0a46fSAndroid Build Coastguard Worker #include "core/fpdfapi/parser/fpdf_parser_utility.h"
34*3ac0a46fSAndroid Build Coastguard Worker #include "core/fxcrt/fx_safe_types.h"
35*3ac0a46fSAndroid Build Coastguard Worker #include "core/fxcrt/fx_string_wrappers.h"
36*3ac0a46fSAndroid Build Coastguard Worker #include "core/fxcrt/retain_ptr.h"
37*3ac0a46fSAndroid Build Coastguard Worker #include "core/fxcrt/unowned_ptr.h"
38*3ac0a46fSAndroid Build Coastguard Worker #include "fpdfsdk/cpdfsdk_helpers.h"
39*3ac0a46fSAndroid Build Coastguard Worker #include "public/cpp/fpdf_scopers.h"
40*3ac0a46fSAndroid Build Coastguard Worker #include "third_party/base/check.h"
41*3ac0a46fSAndroid Build Coastguard Worker #include "third_party/base/containers/span.h"
42*3ac0a46fSAndroid Build Coastguard Worker 
43*3ac0a46fSAndroid Build Coastguard Worker struct XObjectContext {
44*3ac0a46fSAndroid Build Coastguard Worker   UnownedPtr<CPDF_Document> dest_doc;
45*3ac0a46fSAndroid Build Coastguard Worker   RetainPtr<CPDF_Stream> xobject;
46*3ac0a46fSAndroid Build Coastguard Worker };
47*3ac0a46fSAndroid Build Coastguard Worker 
48*3ac0a46fSAndroid Build Coastguard Worker namespace {
49*3ac0a46fSAndroid Build Coastguard Worker 
50*3ac0a46fSAndroid Build Coastguard Worker // Struct that stores sub page origin and scale information.  When importing
51*3ac0a46fSAndroid Build Coastguard Worker // more than one pages onto the same page, most likely the pages will need to be
52*3ac0a46fSAndroid Build Coastguard Worker // scaled down, and scale is in range of (0, 1) exclusive.
53*3ac0a46fSAndroid Build Coastguard Worker struct NupPageSettings {
54*3ac0a46fSAndroid Build Coastguard Worker   CFX_PointF subPageStartPoint;
55*3ac0a46fSAndroid Build Coastguard Worker   float scale = 0.0f;
56*3ac0a46fSAndroid Build Coastguard Worker };
57*3ac0a46fSAndroid Build Coastguard Worker 
58*3ac0a46fSAndroid Build Coastguard Worker // Calculates the N-up parameters.  When importing multiple pages into one page.
59*3ac0a46fSAndroid Build Coastguard Worker // The space of output page is evenly divided along the X axis and Y axis based
60*3ac0a46fSAndroid Build Coastguard Worker // on the input |nPagesOnXAxis| and |nPagesOnYAxis|.
61*3ac0a46fSAndroid Build Coastguard Worker class NupState {
62*3ac0a46fSAndroid Build Coastguard Worker  public:
63*3ac0a46fSAndroid Build Coastguard Worker   NupState(const CFX_SizeF& pagesize,
64*3ac0a46fSAndroid Build Coastguard Worker            size_t nPagesOnXAxis,
65*3ac0a46fSAndroid Build Coastguard Worker            size_t nPagesOnYAxis);
66*3ac0a46fSAndroid Build Coastguard Worker 
67*3ac0a46fSAndroid Build Coastguard Worker   // Calculate sub page origin and scale with the source page of |pagesize| and
68*3ac0a46fSAndroid Build Coastguard Worker   // new page of |m_subPageSize|.
69*3ac0a46fSAndroid Build Coastguard Worker   NupPageSettings CalculateNewPagePosition(const CFX_SizeF& pagesize);
70*3ac0a46fSAndroid Build Coastguard Worker 
71*3ac0a46fSAndroid Build Coastguard Worker  private:
72*3ac0a46fSAndroid Build Coastguard Worker   // Helper function to get the |iSubX|, |iSubY| pair based on |m_subPageIndex|.
73*3ac0a46fSAndroid Build Coastguard Worker   // The space of output page is evenly divided into slots along x and y axis.
74*3ac0a46fSAndroid Build Coastguard Worker   // |iSubX| and |iSubY| are 0-based indices that indicate which allocation
75*3ac0a46fSAndroid Build Coastguard Worker   // slot to use.
76*3ac0a46fSAndroid Build Coastguard Worker   std::pair<size_t, size_t> ConvertPageOrder() const;
77*3ac0a46fSAndroid Build Coastguard Worker 
78*3ac0a46fSAndroid Build Coastguard Worker   // Given the |iSubX| and |iSubY| subpage position within a page, and a source
79*3ac0a46fSAndroid Build Coastguard Worker   // page with dimensions of |pagesize|, calculate the sub page's origin and
80*3ac0a46fSAndroid Build Coastguard Worker   // scale.
81*3ac0a46fSAndroid Build Coastguard Worker   NupPageSettings CalculatePageEdit(size_t iSubX,
82*3ac0a46fSAndroid Build Coastguard Worker                                     size_t iSubY,
83*3ac0a46fSAndroid Build Coastguard Worker                                     const CFX_SizeF& pagesize) const;
84*3ac0a46fSAndroid Build Coastguard Worker 
85*3ac0a46fSAndroid Build Coastguard Worker   const CFX_SizeF m_destPageSize;
86*3ac0a46fSAndroid Build Coastguard Worker   const size_t m_nPagesOnXAxis;
87*3ac0a46fSAndroid Build Coastguard Worker   const size_t m_nPagesOnYAxis;
88*3ac0a46fSAndroid Build Coastguard Worker   const size_t m_nPagesPerSheet;
89*3ac0a46fSAndroid Build Coastguard Worker   CFX_SizeF m_subPageSize;
90*3ac0a46fSAndroid Build Coastguard Worker 
91*3ac0a46fSAndroid Build Coastguard Worker   // A 0-based index, in range of [0, m_nPagesPerSheet - 1).
92*3ac0a46fSAndroid Build Coastguard Worker   size_t m_subPageIndex = 0;
93*3ac0a46fSAndroid Build Coastguard Worker };
94*3ac0a46fSAndroid Build Coastguard Worker 
NupState(const CFX_SizeF & pagesize,size_t nPagesOnXAxis,size_t nPagesOnYAxis)95*3ac0a46fSAndroid Build Coastguard Worker NupState::NupState(const CFX_SizeF& pagesize,
96*3ac0a46fSAndroid Build Coastguard Worker                    size_t nPagesOnXAxis,
97*3ac0a46fSAndroid Build Coastguard Worker                    size_t nPagesOnYAxis)
98*3ac0a46fSAndroid Build Coastguard Worker     : m_destPageSize(pagesize),
99*3ac0a46fSAndroid Build Coastguard Worker       m_nPagesOnXAxis(nPagesOnXAxis),
100*3ac0a46fSAndroid Build Coastguard Worker       m_nPagesOnYAxis(nPagesOnYAxis),
101*3ac0a46fSAndroid Build Coastguard Worker       m_nPagesPerSheet(nPagesOnXAxis * nPagesOnYAxis) {
102*3ac0a46fSAndroid Build Coastguard Worker   DCHECK(m_nPagesOnXAxis > 0);
103*3ac0a46fSAndroid Build Coastguard Worker   DCHECK(m_nPagesOnYAxis > 0);
104*3ac0a46fSAndroid Build Coastguard Worker   DCHECK(m_destPageSize.width > 0);
105*3ac0a46fSAndroid Build Coastguard Worker   DCHECK(m_destPageSize.height > 0);
106*3ac0a46fSAndroid Build Coastguard Worker 
107*3ac0a46fSAndroid Build Coastguard Worker   m_subPageSize.width = m_destPageSize.width / m_nPagesOnXAxis;
108*3ac0a46fSAndroid Build Coastguard Worker   m_subPageSize.height = m_destPageSize.height / m_nPagesOnYAxis;
109*3ac0a46fSAndroid Build Coastguard Worker }
110*3ac0a46fSAndroid Build Coastguard Worker 
ConvertPageOrder() const111*3ac0a46fSAndroid Build Coastguard Worker std::pair<size_t, size_t> NupState::ConvertPageOrder() const {
112*3ac0a46fSAndroid Build Coastguard Worker   size_t iSubX = m_subPageIndex % m_nPagesOnXAxis;
113*3ac0a46fSAndroid Build Coastguard Worker   size_t iSubY = m_subPageIndex / m_nPagesOnXAxis;
114*3ac0a46fSAndroid Build Coastguard Worker 
115*3ac0a46fSAndroid Build Coastguard Worker   // Y Axis, pages start from the top of the output page.
116*3ac0a46fSAndroid Build Coastguard Worker   iSubY = m_nPagesOnYAxis - iSubY - 1;
117*3ac0a46fSAndroid Build Coastguard Worker 
118*3ac0a46fSAndroid Build Coastguard Worker   return {iSubX, iSubY};
119*3ac0a46fSAndroid Build Coastguard Worker }
120*3ac0a46fSAndroid Build Coastguard Worker 
CalculatePageEdit(size_t iSubX,size_t iSubY,const CFX_SizeF & pagesize) const121*3ac0a46fSAndroid Build Coastguard Worker NupPageSettings NupState::CalculatePageEdit(size_t iSubX,
122*3ac0a46fSAndroid Build Coastguard Worker                                             size_t iSubY,
123*3ac0a46fSAndroid Build Coastguard Worker                                             const CFX_SizeF& pagesize) const {
124*3ac0a46fSAndroid Build Coastguard Worker   NupPageSettings settings;
125*3ac0a46fSAndroid Build Coastguard Worker   settings.subPageStartPoint.x = iSubX * m_subPageSize.width;
126*3ac0a46fSAndroid Build Coastguard Worker   settings.subPageStartPoint.y = iSubY * m_subPageSize.height;
127*3ac0a46fSAndroid Build Coastguard Worker 
128*3ac0a46fSAndroid Build Coastguard Worker   const float xScale = m_subPageSize.width / pagesize.width;
129*3ac0a46fSAndroid Build Coastguard Worker   const float yScale = m_subPageSize.height / pagesize.height;
130*3ac0a46fSAndroid Build Coastguard Worker   settings.scale = std::min(xScale, yScale);
131*3ac0a46fSAndroid Build Coastguard Worker 
132*3ac0a46fSAndroid Build Coastguard Worker   float subWidth = pagesize.width * settings.scale;
133*3ac0a46fSAndroid Build Coastguard Worker   float subHeight = pagesize.height * settings.scale;
134*3ac0a46fSAndroid Build Coastguard Worker   if (xScale > yScale)
135*3ac0a46fSAndroid Build Coastguard Worker     settings.subPageStartPoint.x += (m_subPageSize.width - subWidth) / 2;
136*3ac0a46fSAndroid Build Coastguard Worker   else
137*3ac0a46fSAndroid Build Coastguard Worker     settings.subPageStartPoint.y += (m_subPageSize.height - subHeight) / 2;
138*3ac0a46fSAndroid Build Coastguard Worker   return settings;
139*3ac0a46fSAndroid Build Coastguard Worker }
140*3ac0a46fSAndroid Build Coastguard Worker 
CalculateNewPagePosition(const CFX_SizeF & pagesize)141*3ac0a46fSAndroid Build Coastguard Worker NupPageSettings NupState::CalculateNewPagePosition(const CFX_SizeF& pagesize) {
142*3ac0a46fSAndroid Build Coastguard Worker   if (m_subPageIndex >= m_nPagesPerSheet)
143*3ac0a46fSAndroid Build Coastguard Worker     m_subPageIndex = 0;
144*3ac0a46fSAndroid Build Coastguard Worker 
145*3ac0a46fSAndroid Build Coastguard Worker   size_t iSubX;
146*3ac0a46fSAndroid Build Coastguard Worker   size_t iSubY;
147*3ac0a46fSAndroid Build Coastguard Worker   std::tie(iSubX, iSubY) = ConvertPageOrder();
148*3ac0a46fSAndroid Build Coastguard Worker   ++m_subPageIndex;
149*3ac0a46fSAndroid Build Coastguard Worker   return CalculatePageEdit(iSubX, iSubY, pagesize);
150*3ac0a46fSAndroid Build Coastguard Worker }
151*3ac0a46fSAndroid Build Coastguard Worker 
PageDictGetInheritableTag(RetainPtr<const CPDF_Dictionary> pDict,const ByteString & bsSrcTag)152*3ac0a46fSAndroid Build Coastguard Worker RetainPtr<const CPDF_Object> PageDictGetInheritableTag(
153*3ac0a46fSAndroid Build Coastguard Worker     RetainPtr<const CPDF_Dictionary> pDict,
154*3ac0a46fSAndroid Build Coastguard Worker     const ByteString& bsSrcTag) {
155*3ac0a46fSAndroid Build Coastguard Worker   if (!pDict || bsSrcTag.IsEmpty())
156*3ac0a46fSAndroid Build Coastguard Worker     return nullptr;
157*3ac0a46fSAndroid Build Coastguard Worker   if (!pDict->KeyExist(pdfium::page_object::kParent) ||
158*3ac0a46fSAndroid Build Coastguard Worker       !pDict->KeyExist(pdfium::page_object::kType)) {
159*3ac0a46fSAndroid Build Coastguard Worker     return nullptr;
160*3ac0a46fSAndroid Build Coastguard Worker   }
161*3ac0a46fSAndroid Build Coastguard Worker 
162*3ac0a46fSAndroid Build Coastguard Worker   RetainPtr<const CPDF_Name> pName =
163*3ac0a46fSAndroid Build Coastguard Worker       ToName(pDict->GetObjectFor(pdfium::page_object::kType)->GetDirect());
164*3ac0a46fSAndroid Build Coastguard Worker   if (!pName || pName->GetString() != "Page")
165*3ac0a46fSAndroid Build Coastguard Worker     return nullptr;
166*3ac0a46fSAndroid Build Coastguard Worker 
167*3ac0a46fSAndroid Build Coastguard Worker   RetainPtr<const CPDF_Dictionary> pp = ToDictionary(
168*3ac0a46fSAndroid Build Coastguard Worker       pDict->GetObjectFor(pdfium::page_object::kParent)->GetDirect());
169*3ac0a46fSAndroid Build Coastguard Worker   if (!pp)
170*3ac0a46fSAndroid Build Coastguard Worker     return nullptr;
171*3ac0a46fSAndroid Build Coastguard Worker 
172*3ac0a46fSAndroid Build Coastguard Worker   if (pDict->KeyExist(bsSrcTag))
173*3ac0a46fSAndroid Build Coastguard Worker     return pDict->GetObjectFor(bsSrcTag);
174*3ac0a46fSAndroid Build Coastguard Worker 
175*3ac0a46fSAndroid Build Coastguard Worker   while (pp) {
176*3ac0a46fSAndroid Build Coastguard Worker     if (pp->KeyExist(bsSrcTag))
177*3ac0a46fSAndroid Build Coastguard Worker       return pp->GetObjectFor(bsSrcTag);
178*3ac0a46fSAndroid Build Coastguard Worker     if (!pp->KeyExist(pdfium::page_object::kParent))
179*3ac0a46fSAndroid Build Coastguard Worker       break;
180*3ac0a46fSAndroid Build Coastguard Worker     pp = ToDictionary(
181*3ac0a46fSAndroid Build Coastguard Worker         pp->GetObjectFor(pdfium::page_object::kParent)->GetDirect());
182*3ac0a46fSAndroid Build Coastguard Worker   }
183*3ac0a46fSAndroid Build Coastguard Worker   return nullptr;
184*3ac0a46fSAndroid Build Coastguard Worker }
185*3ac0a46fSAndroid Build Coastguard Worker 
CopyInheritable(RetainPtr<CPDF_Dictionary> pDestPageDict,RetainPtr<const CPDF_Dictionary> pSrcPageDict,const ByteString & key)186*3ac0a46fSAndroid Build Coastguard Worker bool CopyInheritable(RetainPtr<CPDF_Dictionary> pDestPageDict,
187*3ac0a46fSAndroid Build Coastguard Worker                      RetainPtr<const CPDF_Dictionary> pSrcPageDict,
188*3ac0a46fSAndroid Build Coastguard Worker                      const ByteString& key) {
189*3ac0a46fSAndroid Build Coastguard Worker   if (pDestPageDict->KeyExist(key))
190*3ac0a46fSAndroid Build Coastguard Worker     return true;
191*3ac0a46fSAndroid Build Coastguard Worker 
192*3ac0a46fSAndroid Build Coastguard Worker   RetainPtr<const CPDF_Object> pInheritable =
193*3ac0a46fSAndroid Build Coastguard Worker       PageDictGetInheritableTag(std::move(pSrcPageDict), key);
194*3ac0a46fSAndroid Build Coastguard Worker   if (!pInheritable)
195*3ac0a46fSAndroid Build Coastguard Worker     return false;
196*3ac0a46fSAndroid Build Coastguard Worker 
197*3ac0a46fSAndroid Build Coastguard Worker   pDestPageDict->SetFor(key, pInheritable->Clone());
198*3ac0a46fSAndroid Build Coastguard Worker   return true;
199*3ac0a46fSAndroid Build Coastguard Worker }
200*3ac0a46fSAndroid Build Coastguard Worker 
GetPageIndices(const CPDF_Document & doc,const ByteString & bsPageRange)201*3ac0a46fSAndroid Build Coastguard Worker std::vector<uint32_t> GetPageIndices(const CPDF_Document& doc,
202*3ac0a46fSAndroid Build Coastguard Worker                                      const ByteString& bsPageRange) {
203*3ac0a46fSAndroid Build Coastguard Worker   uint32_t nCount = doc.GetPageCount();
204*3ac0a46fSAndroid Build Coastguard Worker   if (!bsPageRange.IsEmpty())
205*3ac0a46fSAndroid Build Coastguard Worker     return ParsePageRangeString(bsPageRange, nCount);
206*3ac0a46fSAndroid Build Coastguard Worker 
207*3ac0a46fSAndroid Build Coastguard Worker   std::vector<uint32_t> page_indices(nCount);
208*3ac0a46fSAndroid Build Coastguard Worker   std::iota(page_indices.begin(), page_indices.end(), 0);
209*3ac0a46fSAndroid Build Coastguard Worker   return page_indices;
210*3ac0a46fSAndroid Build Coastguard Worker }
211*3ac0a46fSAndroid Build Coastguard Worker 
212*3ac0a46fSAndroid Build Coastguard Worker class CPDF_PageOrganizer {
213*3ac0a46fSAndroid Build Coastguard Worker  protected:
214*3ac0a46fSAndroid Build Coastguard Worker   CPDF_PageOrganizer(CPDF_Document* pDestDoc, CPDF_Document* pSrcDoc);
215*3ac0a46fSAndroid Build Coastguard Worker   ~CPDF_PageOrganizer();
216*3ac0a46fSAndroid Build Coastguard Worker 
217*3ac0a46fSAndroid Build Coastguard Worker   // Must be called after construction before doing anything else.
218*3ac0a46fSAndroid Build Coastguard Worker   bool Init();
219*3ac0a46fSAndroid Build Coastguard Worker 
220*3ac0a46fSAndroid Build Coastguard Worker   bool UpdateReference(RetainPtr<CPDF_Object> pObj);
221*3ac0a46fSAndroid Build Coastguard Worker 
dest()222*3ac0a46fSAndroid Build Coastguard Worker   CPDF_Document* dest() { return m_pDestDoc; }
dest() const223*3ac0a46fSAndroid Build Coastguard Worker   const CPDF_Document* dest() const { return m_pDestDoc; }
224*3ac0a46fSAndroid Build Coastguard Worker 
src()225*3ac0a46fSAndroid Build Coastguard Worker   CPDF_Document* src() { return m_pSrcDoc; }
src() const226*3ac0a46fSAndroid Build Coastguard Worker   const CPDF_Document* src() const { return m_pSrcDoc; }
227*3ac0a46fSAndroid Build Coastguard Worker 
AddObjectMapping(uint32_t dwOldPageObj,uint32_t dwNewPageObj)228*3ac0a46fSAndroid Build Coastguard Worker   void AddObjectMapping(uint32_t dwOldPageObj, uint32_t dwNewPageObj) {
229*3ac0a46fSAndroid Build Coastguard Worker     m_ObjectNumberMap[dwOldPageObj] = dwNewPageObj;
230*3ac0a46fSAndroid Build Coastguard Worker   }
231*3ac0a46fSAndroid Build Coastguard Worker 
ClearObjectNumberMap()232*3ac0a46fSAndroid Build Coastguard Worker   void ClearObjectNumberMap() { m_ObjectNumberMap.clear(); }
233*3ac0a46fSAndroid Build Coastguard Worker 
234*3ac0a46fSAndroid Build Coastguard Worker  private:
235*3ac0a46fSAndroid Build Coastguard Worker   uint32_t GetNewObjId(CPDF_Reference* pRef);
236*3ac0a46fSAndroid Build Coastguard Worker 
237*3ac0a46fSAndroid Build Coastguard Worker   UnownedPtr<CPDF_Document> const m_pDestDoc;
238*3ac0a46fSAndroid Build Coastguard Worker   UnownedPtr<CPDF_Document> const m_pSrcDoc;
239*3ac0a46fSAndroid Build Coastguard Worker 
240*3ac0a46fSAndroid Build Coastguard Worker   // Mapping of source object number to destination object number.
241*3ac0a46fSAndroid Build Coastguard Worker   std::map<uint32_t, uint32_t> m_ObjectNumberMap;
242*3ac0a46fSAndroid Build Coastguard Worker };
243*3ac0a46fSAndroid Build Coastguard Worker 
CPDF_PageOrganizer(CPDF_Document * pDestDoc,CPDF_Document * pSrcDoc)244*3ac0a46fSAndroid Build Coastguard Worker CPDF_PageOrganizer::CPDF_PageOrganizer(CPDF_Document* pDestDoc,
245*3ac0a46fSAndroid Build Coastguard Worker                                        CPDF_Document* pSrcDoc)
246*3ac0a46fSAndroid Build Coastguard Worker     : m_pDestDoc(pDestDoc), m_pSrcDoc(pSrcDoc) {}
247*3ac0a46fSAndroid Build Coastguard Worker 
248*3ac0a46fSAndroid Build Coastguard Worker CPDF_PageOrganizer::~CPDF_PageOrganizer() = default;
249*3ac0a46fSAndroid Build Coastguard Worker 
Init()250*3ac0a46fSAndroid Build Coastguard Worker bool CPDF_PageOrganizer::Init() {
251*3ac0a46fSAndroid Build Coastguard Worker   DCHECK(m_pDestDoc);
252*3ac0a46fSAndroid Build Coastguard Worker   DCHECK(m_pSrcDoc);
253*3ac0a46fSAndroid Build Coastguard Worker 
254*3ac0a46fSAndroid Build Coastguard Worker   RetainPtr<CPDF_Dictionary> pNewRoot = dest()->GetMutableRoot();
255*3ac0a46fSAndroid Build Coastguard Worker   if (!pNewRoot)
256*3ac0a46fSAndroid Build Coastguard Worker     return false;
257*3ac0a46fSAndroid Build Coastguard Worker 
258*3ac0a46fSAndroid Build Coastguard Worker   RetainPtr<CPDF_Dictionary> pDocInfoDict = dest()->GetInfo();
259*3ac0a46fSAndroid Build Coastguard Worker   if (!pDocInfoDict)
260*3ac0a46fSAndroid Build Coastguard Worker     return false;
261*3ac0a46fSAndroid Build Coastguard Worker 
262*3ac0a46fSAndroid Build Coastguard Worker   pDocInfoDict->SetNewFor<CPDF_String>("Producer", "PDFium", false);
263*3ac0a46fSAndroid Build Coastguard Worker 
264*3ac0a46fSAndroid Build Coastguard Worker   ByteString cbRootType = pNewRoot->GetByteStringFor("Type", ByteString());
265*3ac0a46fSAndroid Build Coastguard Worker   if (cbRootType.IsEmpty())
266*3ac0a46fSAndroid Build Coastguard Worker     pNewRoot->SetNewFor<CPDF_Name>("Type", "Catalog");
267*3ac0a46fSAndroid Build Coastguard Worker 
268*3ac0a46fSAndroid Build Coastguard Worker   RetainPtr<CPDF_Object> pElement = pNewRoot->GetMutableObjectFor("Pages");
269*3ac0a46fSAndroid Build Coastguard Worker   RetainPtr<CPDF_Dictionary> pNewPages =
270*3ac0a46fSAndroid Build Coastguard Worker       pElement ? ToDictionary(pElement->GetMutableDirect()) : nullptr;
271*3ac0a46fSAndroid Build Coastguard Worker   if (!pNewPages) {
272*3ac0a46fSAndroid Build Coastguard Worker     pNewPages = dest()->NewIndirect<CPDF_Dictionary>();
273*3ac0a46fSAndroid Build Coastguard Worker     pNewRoot->SetNewFor<CPDF_Reference>("Pages", dest(),
274*3ac0a46fSAndroid Build Coastguard Worker                                         pNewPages->GetObjNum());
275*3ac0a46fSAndroid Build Coastguard Worker   }
276*3ac0a46fSAndroid Build Coastguard Worker   ByteString cbPageType = pNewPages->GetByteStringFor("Type", ByteString());
277*3ac0a46fSAndroid Build Coastguard Worker   if (cbPageType.IsEmpty())
278*3ac0a46fSAndroid Build Coastguard Worker     pNewPages->SetNewFor<CPDF_Name>("Type", "Pages");
279*3ac0a46fSAndroid Build Coastguard Worker 
280*3ac0a46fSAndroid Build Coastguard Worker   if (!pNewPages->GetArrayFor("Kids")) {
281*3ac0a46fSAndroid Build Coastguard Worker     auto pNewArray = dest()->NewIndirect<CPDF_Array>();
282*3ac0a46fSAndroid Build Coastguard Worker     pNewPages->SetNewFor<CPDF_Number>("Count", 0);
283*3ac0a46fSAndroid Build Coastguard Worker     pNewPages->SetNewFor<CPDF_Reference>("Kids", dest(),
284*3ac0a46fSAndroid Build Coastguard Worker                                          pNewArray->GetObjNum());
285*3ac0a46fSAndroid Build Coastguard Worker   }
286*3ac0a46fSAndroid Build Coastguard Worker   return true;
287*3ac0a46fSAndroid Build Coastguard Worker }
288*3ac0a46fSAndroid Build Coastguard Worker 
UpdateReference(RetainPtr<CPDF_Object> pObj)289*3ac0a46fSAndroid Build Coastguard Worker bool CPDF_PageOrganizer::UpdateReference(RetainPtr<CPDF_Object> pObj) {
290*3ac0a46fSAndroid Build Coastguard Worker   switch (pObj->GetType()) {
291*3ac0a46fSAndroid Build Coastguard Worker     case CPDF_Object::kReference: {
292*3ac0a46fSAndroid Build Coastguard Worker       CPDF_Reference* pReference = pObj->AsMutableReference();
293*3ac0a46fSAndroid Build Coastguard Worker       uint32_t newobjnum = GetNewObjId(pReference);
294*3ac0a46fSAndroid Build Coastguard Worker       if (newobjnum == 0)
295*3ac0a46fSAndroid Build Coastguard Worker         return false;
296*3ac0a46fSAndroid Build Coastguard Worker       pReference->SetRef(dest(), newobjnum);
297*3ac0a46fSAndroid Build Coastguard Worker       return true;
298*3ac0a46fSAndroid Build Coastguard Worker     }
299*3ac0a46fSAndroid Build Coastguard Worker     case CPDF_Object::kDictionary: {
300*3ac0a46fSAndroid Build Coastguard Worker       CPDF_Dictionary* pDict = pObj->AsMutableDictionary();
301*3ac0a46fSAndroid Build Coastguard Worker       std::vector<ByteString> bad_keys;
302*3ac0a46fSAndroid Build Coastguard Worker       {
303*3ac0a46fSAndroid Build Coastguard Worker         CPDF_DictionaryLocker locker(pDict);
304*3ac0a46fSAndroid Build Coastguard Worker         for (const auto& it : locker) {
305*3ac0a46fSAndroid Build Coastguard Worker           const ByteString& key = it.first;
306*3ac0a46fSAndroid Build Coastguard Worker           if (key == "Parent" || key == "Prev" || key == "First")
307*3ac0a46fSAndroid Build Coastguard Worker             continue;
308*3ac0a46fSAndroid Build Coastguard Worker           RetainPtr<CPDF_Object> pNextObj = it.second;
309*3ac0a46fSAndroid Build Coastguard Worker           if (!UpdateReference(pNextObj))
310*3ac0a46fSAndroid Build Coastguard Worker             bad_keys.push_back(key);
311*3ac0a46fSAndroid Build Coastguard Worker         }
312*3ac0a46fSAndroid Build Coastguard Worker       }
313*3ac0a46fSAndroid Build Coastguard Worker       for (const auto& key : bad_keys)
314*3ac0a46fSAndroid Build Coastguard Worker         pDict->RemoveFor(key.AsStringView());
315*3ac0a46fSAndroid Build Coastguard Worker       return true;
316*3ac0a46fSAndroid Build Coastguard Worker     }
317*3ac0a46fSAndroid Build Coastguard Worker     case CPDF_Object::kArray: {
318*3ac0a46fSAndroid Build Coastguard Worker       CPDF_Array* pArray = pObj->AsMutableArray();
319*3ac0a46fSAndroid Build Coastguard Worker       for (size_t i = 0; i < pArray->size(); ++i) {
320*3ac0a46fSAndroid Build Coastguard Worker         if (!UpdateReference(pArray->GetMutableObjectAt(i)))
321*3ac0a46fSAndroid Build Coastguard Worker           return false;
322*3ac0a46fSAndroid Build Coastguard Worker       }
323*3ac0a46fSAndroid Build Coastguard Worker       return true;
324*3ac0a46fSAndroid Build Coastguard Worker     }
325*3ac0a46fSAndroid Build Coastguard Worker     case CPDF_Object::kStream: {
326*3ac0a46fSAndroid Build Coastguard Worker       CPDF_Stream* pStream = pObj->AsMutableStream();
327*3ac0a46fSAndroid Build Coastguard Worker       RetainPtr<CPDF_Dictionary> pDict = pStream->GetMutableDict();
328*3ac0a46fSAndroid Build Coastguard Worker       return pDict && UpdateReference(std::move(pDict));
329*3ac0a46fSAndroid Build Coastguard Worker     }
330*3ac0a46fSAndroid Build Coastguard Worker     default:
331*3ac0a46fSAndroid Build Coastguard Worker       return true;
332*3ac0a46fSAndroid Build Coastguard Worker   }
333*3ac0a46fSAndroid Build Coastguard Worker }
334*3ac0a46fSAndroid Build Coastguard Worker 
GetNewObjId(CPDF_Reference * pRef)335*3ac0a46fSAndroid Build Coastguard Worker uint32_t CPDF_PageOrganizer::GetNewObjId(CPDF_Reference* pRef) {
336*3ac0a46fSAndroid Build Coastguard Worker   if (!pRef)
337*3ac0a46fSAndroid Build Coastguard Worker     return 0;
338*3ac0a46fSAndroid Build Coastguard Worker 
339*3ac0a46fSAndroid Build Coastguard Worker   uint32_t dwObjnum = pRef->GetRefObjNum();
340*3ac0a46fSAndroid Build Coastguard Worker   uint32_t dwNewObjNum = 0;
341*3ac0a46fSAndroid Build Coastguard Worker   const auto it = m_ObjectNumberMap.find(dwObjnum);
342*3ac0a46fSAndroid Build Coastguard Worker   if (it != m_ObjectNumberMap.end())
343*3ac0a46fSAndroid Build Coastguard Worker     dwNewObjNum = it->second;
344*3ac0a46fSAndroid Build Coastguard Worker   if (dwNewObjNum)
345*3ac0a46fSAndroid Build Coastguard Worker     return dwNewObjNum;
346*3ac0a46fSAndroid Build Coastguard Worker 
347*3ac0a46fSAndroid Build Coastguard Worker   RetainPtr<const CPDF_Object> pDirect = pRef->GetDirect();
348*3ac0a46fSAndroid Build Coastguard Worker   if (!pDirect)
349*3ac0a46fSAndroid Build Coastguard Worker     return 0;
350*3ac0a46fSAndroid Build Coastguard Worker 
351*3ac0a46fSAndroid Build Coastguard Worker   RetainPtr<CPDF_Object> pClone = pDirect->Clone();
352*3ac0a46fSAndroid Build Coastguard Worker   const CPDF_Dictionary* pDictClone = pClone->AsDictionary();
353*3ac0a46fSAndroid Build Coastguard Worker   if (pDictClone && pDictClone->KeyExist("Type")) {
354*3ac0a46fSAndroid Build Coastguard Worker     ByteString strType = pDictClone->GetByteStringFor("Type");
355*3ac0a46fSAndroid Build Coastguard Worker     if (strType.EqualNoCase("Pages"))
356*3ac0a46fSAndroid Build Coastguard Worker       return 4;
357*3ac0a46fSAndroid Build Coastguard Worker     if (strType.EqualNoCase("Page"))
358*3ac0a46fSAndroid Build Coastguard Worker       return 0;
359*3ac0a46fSAndroid Build Coastguard Worker   }
360*3ac0a46fSAndroid Build Coastguard Worker 
361*3ac0a46fSAndroid Build Coastguard Worker   dwNewObjNum = dest()->AddIndirectObject(pClone);
362*3ac0a46fSAndroid Build Coastguard Worker   AddObjectMapping(dwObjnum, dwNewObjNum);
363*3ac0a46fSAndroid Build Coastguard Worker   if (!UpdateReference(std::move(pClone)))
364*3ac0a46fSAndroid Build Coastguard Worker     return 0;
365*3ac0a46fSAndroid Build Coastguard Worker 
366*3ac0a46fSAndroid Build Coastguard Worker   return dwNewObjNum;
367*3ac0a46fSAndroid Build Coastguard Worker }
368*3ac0a46fSAndroid Build Coastguard Worker 
369*3ac0a46fSAndroid Build Coastguard Worker // Copies pages from a source document into a destination document.
370*3ac0a46fSAndroid Build Coastguard Worker // This class is intended to be used once via ExportPage() and then destroyed.
371*3ac0a46fSAndroid Build Coastguard Worker class CPDF_PageExporter final : public CPDF_PageOrganizer {
372*3ac0a46fSAndroid Build Coastguard Worker  public:
373*3ac0a46fSAndroid Build Coastguard Worker   CPDF_PageExporter(CPDF_Document* pDestDoc, CPDF_Document* pSrcDoc);
374*3ac0a46fSAndroid Build Coastguard Worker   ~CPDF_PageExporter();
375*3ac0a46fSAndroid Build Coastguard Worker 
376*3ac0a46fSAndroid Build Coastguard Worker   // For the pages from the source document with |pageIndices| as their page
377*3ac0a46fSAndroid Build Coastguard Worker   // indices, insert them into the destination document at page |nIndex|.
378*3ac0a46fSAndroid Build Coastguard Worker   // |pageIndices| and |nIndex| are 0-based.
379*3ac0a46fSAndroid Build Coastguard Worker   bool ExportPage(pdfium::span<const uint32_t> pageIndices, int nIndex);
380*3ac0a46fSAndroid Build Coastguard Worker };
381*3ac0a46fSAndroid Build Coastguard Worker 
CPDF_PageExporter(CPDF_Document * pDestDoc,CPDF_Document * pSrcDoc)382*3ac0a46fSAndroid Build Coastguard Worker CPDF_PageExporter::CPDF_PageExporter(CPDF_Document* pDestDoc,
383*3ac0a46fSAndroid Build Coastguard Worker                                      CPDF_Document* pSrcDoc)
384*3ac0a46fSAndroid Build Coastguard Worker     : CPDF_PageOrganizer(pDestDoc, pSrcDoc) {}
385*3ac0a46fSAndroid Build Coastguard Worker 
386*3ac0a46fSAndroid Build Coastguard Worker CPDF_PageExporter::~CPDF_PageExporter() = default;
387*3ac0a46fSAndroid Build Coastguard Worker 
ExportPage(pdfium::span<const uint32_t> pageIndices,int nIndex)388*3ac0a46fSAndroid Build Coastguard Worker bool CPDF_PageExporter::ExportPage(pdfium::span<const uint32_t> pageIndices,
389*3ac0a46fSAndroid Build Coastguard Worker                                    int nIndex) {
390*3ac0a46fSAndroid Build Coastguard Worker   if (!Init())
391*3ac0a46fSAndroid Build Coastguard Worker     return false;
392*3ac0a46fSAndroid Build Coastguard Worker 
393*3ac0a46fSAndroid Build Coastguard Worker   int curpage = nIndex;
394*3ac0a46fSAndroid Build Coastguard Worker   for (uint32_t pageIndex : pageIndices) {
395*3ac0a46fSAndroid Build Coastguard Worker     RetainPtr<CPDF_Dictionary> pDestPageDict = dest()->CreateNewPage(curpage);
396*3ac0a46fSAndroid Build Coastguard Worker     RetainPtr<const CPDF_Dictionary> pSrcPageDict =
397*3ac0a46fSAndroid Build Coastguard Worker         src()->GetPageDictionary(pageIndex);
398*3ac0a46fSAndroid Build Coastguard Worker     if (!pSrcPageDict || !pDestPageDict)
399*3ac0a46fSAndroid Build Coastguard Worker       return false;
400*3ac0a46fSAndroid Build Coastguard Worker 
401*3ac0a46fSAndroid Build Coastguard Worker     // Clone the page dictionary
402*3ac0a46fSAndroid Build Coastguard Worker     CPDF_DictionaryLocker locker(pSrcPageDict);
403*3ac0a46fSAndroid Build Coastguard Worker     for (const auto& it : locker) {
404*3ac0a46fSAndroid Build Coastguard Worker       const ByteString& cbSrcKeyStr = it.first;
405*3ac0a46fSAndroid Build Coastguard Worker       const RetainPtr<CPDF_Object>& pObj = it.second;
406*3ac0a46fSAndroid Build Coastguard Worker       if (cbSrcKeyStr == pdfium::page_object::kType ||
407*3ac0a46fSAndroid Build Coastguard Worker           cbSrcKeyStr == pdfium::page_object::kParent) {
408*3ac0a46fSAndroid Build Coastguard Worker         continue;
409*3ac0a46fSAndroid Build Coastguard Worker       }
410*3ac0a46fSAndroid Build Coastguard Worker       pDestPageDict->SetFor(cbSrcKeyStr, pObj->Clone());
411*3ac0a46fSAndroid Build Coastguard Worker     }
412*3ac0a46fSAndroid Build Coastguard Worker 
413*3ac0a46fSAndroid Build Coastguard Worker     // inheritable item
414*3ac0a46fSAndroid Build Coastguard Worker     // Even though some entries are required by the PDF spec, there exist
415*3ac0a46fSAndroid Build Coastguard Worker     // PDFs that omit them. Set some defaults in this case.
416*3ac0a46fSAndroid Build Coastguard Worker     // 1 MediaBox - required
417*3ac0a46fSAndroid Build Coastguard Worker     if (!CopyInheritable(pDestPageDict, pSrcPageDict,
418*3ac0a46fSAndroid Build Coastguard Worker                          pdfium::page_object::kMediaBox)) {
419*3ac0a46fSAndroid Build Coastguard Worker       // Search for "CropBox" in the source page dictionary.
420*3ac0a46fSAndroid Build Coastguard Worker       // If it does not exist, use the default letter size.
421*3ac0a46fSAndroid Build Coastguard Worker       RetainPtr<const CPDF_Object> pInheritable = PageDictGetInheritableTag(
422*3ac0a46fSAndroid Build Coastguard Worker           pSrcPageDict, pdfium::page_object::kCropBox);
423*3ac0a46fSAndroid Build Coastguard Worker       if (pInheritable) {
424*3ac0a46fSAndroid Build Coastguard Worker         pDestPageDict->SetFor(pdfium::page_object::kMediaBox,
425*3ac0a46fSAndroid Build Coastguard Worker                               pInheritable->Clone());
426*3ac0a46fSAndroid Build Coastguard Worker       } else {
427*3ac0a46fSAndroid Build Coastguard Worker         // Make the default size letter size (8.5"x11")
428*3ac0a46fSAndroid Build Coastguard Worker         static const CFX_FloatRect kDefaultLetterRect(0, 0, 612, 792);
429*3ac0a46fSAndroid Build Coastguard Worker         pDestPageDict->SetRectFor(pdfium::page_object::kMediaBox,
430*3ac0a46fSAndroid Build Coastguard Worker                                   kDefaultLetterRect);
431*3ac0a46fSAndroid Build Coastguard Worker       }
432*3ac0a46fSAndroid Build Coastguard Worker     }
433*3ac0a46fSAndroid Build Coastguard Worker 
434*3ac0a46fSAndroid Build Coastguard Worker     // 2 Resources - required
435*3ac0a46fSAndroid Build Coastguard Worker     if (!CopyInheritable(pDestPageDict, pSrcPageDict,
436*3ac0a46fSAndroid Build Coastguard Worker                          pdfium::page_object::kResources)) {
437*3ac0a46fSAndroid Build Coastguard Worker       // Use a default empty resources if it does not exist.
438*3ac0a46fSAndroid Build Coastguard Worker       pDestPageDict->SetNewFor<CPDF_Dictionary>(
439*3ac0a46fSAndroid Build Coastguard Worker           pdfium::page_object::kResources);
440*3ac0a46fSAndroid Build Coastguard Worker     }
441*3ac0a46fSAndroid Build Coastguard Worker 
442*3ac0a46fSAndroid Build Coastguard Worker     // 3 CropBox - optional
443*3ac0a46fSAndroid Build Coastguard Worker     CopyInheritable(pDestPageDict, pSrcPageDict, pdfium::page_object::kCropBox);
444*3ac0a46fSAndroid Build Coastguard Worker     // 4 Rotate - optional
445*3ac0a46fSAndroid Build Coastguard Worker     CopyInheritable(pDestPageDict, pSrcPageDict, pdfium::page_object::kRotate);
446*3ac0a46fSAndroid Build Coastguard Worker 
447*3ac0a46fSAndroid Build Coastguard Worker     // Update the reference
448*3ac0a46fSAndroid Build Coastguard Worker     uint32_t dwOldPageObj = pSrcPageDict->GetObjNum();
449*3ac0a46fSAndroid Build Coastguard Worker     uint32_t dwNewPageObj = pDestPageDict->GetObjNum();
450*3ac0a46fSAndroid Build Coastguard Worker     AddObjectMapping(dwOldPageObj, dwNewPageObj);
451*3ac0a46fSAndroid Build Coastguard Worker     UpdateReference(pDestPageDict);
452*3ac0a46fSAndroid Build Coastguard Worker     ++curpage;
453*3ac0a46fSAndroid Build Coastguard Worker   }
454*3ac0a46fSAndroid Build Coastguard Worker 
455*3ac0a46fSAndroid Build Coastguard Worker   return true;
456*3ac0a46fSAndroid Build Coastguard Worker }
457*3ac0a46fSAndroid Build Coastguard Worker 
458*3ac0a46fSAndroid Build Coastguard Worker // Copies pages from a source document into a destination document. Creates 1
459*3ac0a46fSAndroid Build Coastguard Worker // page in the destination document for every N source pages. This class is
460*3ac0a46fSAndroid Build Coastguard Worker // intended to be used once via ExportNPagesToOne() and then destroyed.
461*3ac0a46fSAndroid Build Coastguard Worker class CPDF_NPageToOneExporter final : public CPDF_PageOrganizer {
462*3ac0a46fSAndroid Build Coastguard Worker  public:
463*3ac0a46fSAndroid Build Coastguard Worker   CPDF_NPageToOneExporter(CPDF_Document* pDestDoc, CPDF_Document* pSrcDoc);
464*3ac0a46fSAndroid Build Coastguard Worker   ~CPDF_NPageToOneExporter();
465*3ac0a46fSAndroid Build Coastguard Worker 
466*3ac0a46fSAndroid Build Coastguard Worker   // For the pages from the source document with |pageIndices| as their page
467*3ac0a46fSAndroid Build Coastguard Worker   // indices, insert them into the destination document, starting at page index
468*3ac0a46fSAndroid Build Coastguard Worker   // 0.
469*3ac0a46fSAndroid Build Coastguard Worker   // |pageIndices| is 0-based.
470*3ac0a46fSAndroid Build Coastguard Worker   // |destPageSize| is the destination document page dimensions, measured in
471*3ac0a46fSAndroid Build Coastguard Worker   // PDF "user space" units.
472*3ac0a46fSAndroid Build Coastguard Worker   // |nPagesOnXAxis| and |nPagesOnXAxis| together defines how many source
473*3ac0a46fSAndroid Build Coastguard Worker   // pages fit on one destination page.
474*3ac0a46fSAndroid Build Coastguard Worker   bool ExportNPagesToOne(pdfium::span<const uint32_t> pageIndices,
475*3ac0a46fSAndroid Build Coastguard Worker                          const CFX_SizeF& destPageSize,
476*3ac0a46fSAndroid Build Coastguard Worker                          size_t nPagesOnXAxis,
477*3ac0a46fSAndroid Build Coastguard Worker                          size_t nPagesOnYAxis);
478*3ac0a46fSAndroid Build Coastguard Worker 
479*3ac0a46fSAndroid Build Coastguard Worker   std::unique_ptr<XObjectContext> CreateXObjectContextFromPage(
480*3ac0a46fSAndroid Build Coastguard Worker       int src_page_index);
481*3ac0a46fSAndroid Build Coastguard Worker 
482*3ac0a46fSAndroid Build Coastguard Worker  private:
483*3ac0a46fSAndroid Build Coastguard Worker   // Map page object number to XObject object name.
484*3ac0a46fSAndroid Build Coastguard Worker   using PageXObjectMap = std::map<uint32_t, ByteString>;
485*3ac0a46fSAndroid Build Coastguard Worker 
486*3ac0a46fSAndroid Build Coastguard Worker   // Creates an XObject from |pSrcPage|, or find an existing XObject that
487*3ac0a46fSAndroid Build Coastguard Worker   // represents |pSrcPage|. The transformation matrix is specified in
488*3ac0a46fSAndroid Build Coastguard Worker   // |settings|.
489*3ac0a46fSAndroid Build Coastguard Worker   // Returns the XObject reference surrounded by the transformation matrix.
490*3ac0a46fSAndroid Build Coastguard Worker   ByteString AddSubPage(const RetainPtr<CPDF_Page>& pSrcPage,
491*3ac0a46fSAndroid Build Coastguard Worker                         const NupPageSettings& settings);
492*3ac0a46fSAndroid Build Coastguard Worker 
493*3ac0a46fSAndroid Build Coastguard Worker   // Creates an XObject from |pSrcPage|. Updates mapping as needed.
494*3ac0a46fSAndroid Build Coastguard Worker   // Returns the name of the newly created XObject.
495*3ac0a46fSAndroid Build Coastguard Worker   ByteString MakeXObjectFromPage(RetainPtr<CPDF_Page> pSrcPage);
496*3ac0a46fSAndroid Build Coastguard Worker   RetainPtr<CPDF_Stream> MakeXObjectFromPageRaw(RetainPtr<CPDF_Page> pSrcPage);
497*3ac0a46fSAndroid Build Coastguard Worker 
498*3ac0a46fSAndroid Build Coastguard Worker   // Adds |bsContent| as the Contents key in |pDestPageDict|.
499*3ac0a46fSAndroid Build Coastguard Worker   // Adds the objects in |m_XObjectNameToNumberMap| to the XObject dictionary in
500*3ac0a46fSAndroid Build Coastguard Worker   // |pDestPageDict|'s Resources dictionary.
501*3ac0a46fSAndroid Build Coastguard Worker   void FinishPage(RetainPtr<CPDF_Dictionary> pDestPageDict,
502*3ac0a46fSAndroid Build Coastguard Worker                   const ByteString& bsContent);
503*3ac0a46fSAndroid Build Coastguard Worker 
504*3ac0a46fSAndroid Build Coastguard Worker   // Counter for giving new XObjects unique names.
505*3ac0a46fSAndroid Build Coastguard Worker   uint32_t m_nObjectNumber = 0;
506*3ac0a46fSAndroid Build Coastguard Worker 
507*3ac0a46fSAndroid Build Coastguard Worker   // Keeps track of created XObjects in the current page.
508*3ac0a46fSAndroid Build Coastguard Worker   // Map XObject's object name to it's object number.
509*3ac0a46fSAndroid Build Coastguard Worker   std::map<ByteString, uint32_t> m_XObjectNameToNumberMap;
510*3ac0a46fSAndroid Build Coastguard Worker 
511*3ac0a46fSAndroid Build Coastguard Worker   // Mapping of source page object number and XObject name of the entire doc.
512*3ac0a46fSAndroid Build Coastguard Worker   // If there are multiple source pages that reference the same object number,
513*3ac0a46fSAndroid Build Coastguard Worker   // they can also share the same created XObject.
514*3ac0a46fSAndroid Build Coastguard Worker   PageXObjectMap m_SrcPageXObjectMap;
515*3ac0a46fSAndroid Build Coastguard Worker };
516*3ac0a46fSAndroid Build Coastguard Worker 
CPDF_NPageToOneExporter(CPDF_Document * pDestDoc,CPDF_Document * pSrcDoc)517*3ac0a46fSAndroid Build Coastguard Worker CPDF_NPageToOneExporter::CPDF_NPageToOneExporter(CPDF_Document* pDestDoc,
518*3ac0a46fSAndroid Build Coastguard Worker                                                  CPDF_Document* pSrcDoc)
519*3ac0a46fSAndroid Build Coastguard Worker     : CPDF_PageOrganizer(pDestDoc, pSrcDoc) {}
520*3ac0a46fSAndroid Build Coastguard Worker 
521*3ac0a46fSAndroid Build Coastguard Worker CPDF_NPageToOneExporter::~CPDF_NPageToOneExporter() = default;
522*3ac0a46fSAndroid Build Coastguard Worker 
ExportNPagesToOne(pdfium::span<const uint32_t> pageIndices,const CFX_SizeF & destPageSize,size_t nPagesOnXAxis,size_t nPagesOnYAxis)523*3ac0a46fSAndroid Build Coastguard Worker bool CPDF_NPageToOneExporter::ExportNPagesToOne(
524*3ac0a46fSAndroid Build Coastguard Worker     pdfium::span<const uint32_t> pageIndices,
525*3ac0a46fSAndroid Build Coastguard Worker     const CFX_SizeF& destPageSize,
526*3ac0a46fSAndroid Build Coastguard Worker     size_t nPagesOnXAxis,
527*3ac0a46fSAndroid Build Coastguard Worker     size_t nPagesOnYAxis) {
528*3ac0a46fSAndroid Build Coastguard Worker   if (!Init())
529*3ac0a46fSAndroid Build Coastguard Worker     return false;
530*3ac0a46fSAndroid Build Coastguard Worker 
531*3ac0a46fSAndroid Build Coastguard Worker   FX_SAFE_SIZE_T nSafePagesPerSheet = nPagesOnXAxis;
532*3ac0a46fSAndroid Build Coastguard Worker   nSafePagesPerSheet *= nPagesOnYAxis;
533*3ac0a46fSAndroid Build Coastguard Worker   if (!nSafePagesPerSheet.IsValid())
534*3ac0a46fSAndroid Build Coastguard Worker     return false;
535*3ac0a46fSAndroid Build Coastguard Worker 
536*3ac0a46fSAndroid Build Coastguard Worker   ClearObjectNumberMap();
537*3ac0a46fSAndroid Build Coastguard Worker   m_SrcPageXObjectMap.clear();
538*3ac0a46fSAndroid Build Coastguard Worker   size_t nPagesPerSheet = nSafePagesPerSheet.ValueOrDie();
539*3ac0a46fSAndroid Build Coastguard Worker   NupState nupState(destPageSize, nPagesOnXAxis, nPagesOnYAxis);
540*3ac0a46fSAndroid Build Coastguard Worker 
541*3ac0a46fSAndroid Build Coastguard Worker   FX_SAFE_INT32 curpage = 0;
542*3ac0a46fSAndroid Build Coastguard Worker   const CFX_FloatRect destPageRect(0, 0, destPageSize.width,
543*3ac0a46fSAndroid Build Coastguard Worker                                    destPageSize.height);
544*3ac0a46fSAndroid Build Coastguard Worker   for (size_t iOuterPage = 0; iOuterPage < pageIndices.size();
545*3ac0a46fSAndroid Build Coastguard Worker        iOuterPage += nPagesPerSheet) {
546*3ac0a46fSAndroid Build Coastguard Worker     m_XObjectNameToNumberMap.clear();
547*3ac0a46fSAndroid Build Coastguard Worker 
548*3ac0a46fSAndroid Build Coastguard Worker     RetainPtr<CPDF_Dictionary> pDestPageDict =
549*3ac0a46fSAndroid Build Coastguard Worker         dest()->CreateNewPage(curpage.ValueOrDie());
550*3ac0a46fSAndroid Build Coastguard Worker     if (!pDestPageDict)
551*3ac0a46fSAndroid Build Coastguard Worker       return false;
552*3ac0a46fSAndroid Build Coastguard Worker 
553*3ac0a46fSAndroid Build Coastguard Worker     pDestPageDict->SetRectFor(pdfium::page_object::kMediaBox, destPageRect);
554*3ac0a46fSAndroid Build Coastguard Worker     ByteString bsContent;
555*3ac0a46fSAndroid Build Coastguard Worker     size_t iInnerPageMax =
556*3ac0a46fSAndroid Build Coastguard Worker         std::min(iOuterPage + nPagesPerSheet, pageIndices.size());
557*3ac0a46fSAndroid Build Coastguard Worker     for (size_t i = iOuterPage; i < iInnerPageMax; ++i) {
558*3ac0a46fSAndroid Build Coastguard Worker       RetainPtr<CPDF_Dictionary> pSrcPageDict =
559*3ac0a46fSAndroid Build Coastguard Worker           src()->GetMutablePageDictionary(pageIndices[i]);
560*3ac0a46fSAndroid Build Coastguard Worker       if (!pSrcPageDict)
561*3ac0a46fSAndroid Build Coastguard Worker         return false;
562*3ac0a46fSAndroid Build Coastguard Worker 
563*3ac0a46fSAndroid Build Coastguard Worker       auto pSrcPage = pdfium::MakeRetain<CPDF_Page>(src(), pSrcPageDict);
564*3ac0a46fSAndroid Build Coastguard Worker       pSrcPage->AddPageImageCache();
565*3ac0a46fSAndroid Build Coastguard Worker       NupPageSettings settings =
566*3ac0a46fSAndroid Build Coastguard Worker           nupState.CalculateNewPagePosition(pSrcPage->GetPageSize());
567*3ac0a46fSAndroid Build Coastguard Worker       bsContent += AddSubPage(pSrcPage, settings);
568*3ac0a46fSAndroid Build Coastguard Worker     }
569*3ac0a46fSAndroid Build Coastguard Worker 
570*3ac0a46fSAndroid Build Coastguard Worker     FinishPage(pDestPageDict, bsContent);
571*3ac0a46fSAndroid Build Coastguard Worker     ++curpage;
572*3ac0a46fSAndroid Build Coastguard Worker   }
573*3ac0a46fSAndroid Build Coastguard Worker 
574*3ac0a46fSAndroid Build Coastguard Worker   return true;
575*3ac0a46fSAndroid Build Coastguard Worker }
576*3ac0a46fSAndroid Build Coastguard Worker 
AddSubPage(const RetainPtr<CPDF_Page> & pSrcPage,const NupPageSettings & settings)577*3ac0a46fSAndroid Build Coastguard Worker ByteString CPDF_NPageToOneExporter::AddSubPage(
578*3ac0a46fSAndroid Build Coastguard Worker     const RetainPtr<CPDF_Page>& pSrcPage,
579*3ac0a46fSAndroid Build Coastguard Worker     const NupPageSettings& settings) {
580*3ac0a46fSAndroid Build Coastguard Worker   uint32_t dwSrcPageObjnum = pSrcPage->GetDict()->GetObjNum();
581*3ac0a46fSAndroid Build Coastguard Worker   const auto it = m_SrcPageXObjectMap.find(dwSrcPageObjnum);
582*3ac0a46fSAndroid Build Coastguard Worker   ByteString bsXObjectName = it != m_SrcPageXObjectMap.end()
583*3ac0a46fSAndroid Build Coastguard Worker                                  ? it->second
584*3ac0a46fSAndroid Build Coastguard Worker                                  : MakeXObjectFromPage(pSrcPage);
585*3ac0a46fSAndroid Build Coastguard Worker 
586*3ac0a46fSAndroid Build Coastguard Worker   CFX_Matrix matrix;
587*3ac0a46fSAndroid Build Coastguard Worker   matrix.Scale(settings.scale, settings.scale);
588*3ac0a46fSAndroid Build Coastguard Worker   matrix.Translate(settings.subPageStartPoint.x, settings.subPageStartPoint.y);
589*3ac0a46fSAndroid Build Coastguard Worker 
590*3ac0a46fSAndroid Build Coastguard Worker   fxcrt::ostringstream contentStream;
591*3ac0a46fSAndroid Build Coastguard Worker   contentStream << "q\n"
592*3ac0a46fSAndroid Build Coastguard Worker                 << matrix.a << " " << matrix.b << " " << matrix.c << " "
593*3ac0a46fSAndroid Build Coastguard Worker                 << matrix.d << " " << matrix.e << " " << matrix.f << " cm\n"
594*3ac0a46fSAndroid Build Coastguard Worker                 << "/" << bsXObjectName << " Do Q\n";
595*3ac0a46fSAndroid Build Coastguard Worker   return ByteString(contentStream);
596*3ac0a46fSAndroid Build Coastguard Worker }
597*3ac0a46fSAndroid Build Coastguard Worker 
MakeXObjectFromPageRaw(RetainPtr<CPDF_Page> pSrcPage)598*3ac0a46fSAndroid Build Coastguard Worker RetainPtr<CPDF_Stream> CPDF_NPageToOneExporter::MakeXObjectFromPageRaw(
599*3ac0a46fSAndroid Build Coastguard Worker     RetainPtr<CPDF_Page> pSrcPage) {
600*3ac0a46fSAndroid Build Coastguard Worker   RetainPtr<const CPDF_Dictionary> pSrcPageDict = pSrcPage->GetDict();
601*3ac0a46fSAndroid Build Coastguard Worker   RetainPtr<const CPDF_Object> pSrcContentObj =
602*3ac0a46fSAndroid Build Coastguard Worker       pSrcPageDict->GetDirectObjectFor(pdfium::page_object::kContents);
603*3ac0a46fSAndroid Build Coastguard Worker 
604*3ac0a46fSAndroid Build Coastguard Worker   auto pNewXObject =
605*3ac0a46fSAndroid Build Coastguard Worker       dest()->NewIndirect<CPDF_Stream>(dest()->New<CPDF_Dictionary>());
606*3ac0a46fSAndroid Build Coastguard Worker   RetainPtr<CPDF_Dictionary> pNewXObjectDict = pNewXObject->GetMutableDict();
607*3ac0a46fSAndroid Build Coastguard Worker   static const char kResourceString[] = "Resources";
608*3ac0a46fSAndroid Build Coastguard Worker   if (!CopyInheritable(pNewXObjectDict, pSrcPageDict, kResourceString)) {
609*3ac0a46fSAndroid Build Coastguard Worker     // Use a default empty resources if it does not exist.
610*3ac0a46fSAndroid Build Coastguard Worker     pNewXObjectDict->SetNewFor<CPDF_Dictionary>(kResourceString);
611*3ac0a46fSAndroid Build Coastguard Worker   }
612*3ac0a46fSAndroid Build Coastguard Worker   uint32_t dwSrcPageObj = pSrcPageDict->GetObjNum();
613*3ac0a46fSAndroid Build Coastguard Worker   uint32_t dwNewXobjectObj = pNewXObjectDict->GetObjNum();
614*3ac0a46fSAndroid Build Coastguard Worker   AddObjectMapping(dwSrcPageObj, dwNewXobjectObj);
615*3ac0a46fSAndroid Build Coastguard Worker   UpdateReference(pNewXObjectDict);
616*3ac0a46fSAndroid Build Coastguard Worker   pNewXObjectDict->SetNewFor<CPDF_Name>("Type", "XObject");
617*3ac0a46fSAndroid Build Coastguard Worker   pNewXObjectDict->SetNewFor<CPDF_Name>("Subtype", "Form");
618*3ac0a46fSAndroid Build Coastguard Worker   pNewXObjectDict->SetNewFor<CPDF_Number>("FormType", 1);
619*3ac0a46fSAndroid Build Coastguard Worker   pNewXObjectDict->SetRectFor("BBox", pSrcPage->GetBBox());
620*3ac0a46fSAndroid Build Coastguard Worker   pNewXObjectDict->SetMatrixFor("Matrix", pSrcPage->GetPageMatrix());
621*3ac0a46fSAndroid Build Coastguard Worker 
622*3ac0a46fSAndroid Build Coastguard Worker   if (pSrcContentObj) {
623*3ac0a46fSAndroid Build Coastguard Worker     ByteString bsSrcContentStream;
624*3ac0a46fSAndroid Build Coastguard Worker     const CPDF_Array* pSrcContentArray = pSrcContentObj->AsArray();
625*3ac0a46fSAndroid Build Coastguard Worker     if (pSrcContentArray) {
626*3ac0a46fSAndroid Build Coastguard Worker       for (size_t i = 0; i < pSrcContentArray->size(); ++i) {
627*3ac0a46fSAndroid Build Coastguard Worker         RetainPtr<const CPDF_Stream> pStream = pSrcContentArray->GetStreamAt(i);
628*3ac0a46fSAndroid Build Coastguard Worker         auto pAcc = pdfium::MakeRetain<CPDF_StreamAcc>(std::move(pStream));
629*3ac0a46fSAndroid Build Coastguard Worker         pAcc->LoadAllDataFiltered();
630*3ac0a46fSAndroid Build Coastguard Worker         bsSrcContentStream += ByteString(pAcc->GetSpan());
631*3ac0a46fSAndroid Build Coastguard Worker         bsSrcContentStream += "\n";
632*3ac0a46fSAndroid Build Coastguard Worker       }
633*3ac0a46fSAndroid Build Coastguard Worker     } else {
634*3ac0a46fSAndroid Build Coastguard Worker       RetainPtr<const CPDF_Stream> pStream(pSrcContentObj->AsStream());
635*3ac0a46fSAndroid Build Coastguard Worker       auto pAcc = pdfium::MakeRetain<CPDF_StreamAcc>(std::move(pStream));
636*3ac0a46fSAndroid Build Coastguard Worker       pAcc->LoadAllDataFiltered();
637*3ac0a46fSAndroid Build Coastguard Worker       bsSrcContentStream = ByteString(pAcc->GetSpan());
638*3ac0a46fSAndroid Build Coastguard Worker     }
639*3ac0a46fSAndroid Build Coastguard Worker     pNewXObject->SetDataAndRemoveFilter(bsSrcContentStream.raw_span());
640*3ac0a46fSAndroid Build Coastguard Worker   }
641*3ac0a46fSAndroid Build Coastguard Worker   return pNewXObject;
642*3ac0a46fSAndroid Build Coastguard Worker }
643*3ac0a46fSAndroid Build Coastguard Worker 
MakeXObjectFromPage(RetainPtr<CPDF_Page> pSrcPage)644*3ac0a46fSAndroid Build Coastguard Worker ByteString CPDF_NPageToOneExporter::MakeXObjectFromPage(
645*3ac0a46fSAndroid Build Coastguard Worker     RetainPtr<CPDF_Page> pSrcPage) {
646*3ac0a46fSAndroid Build Coastguard Worker   RetainPtr<CPDF_Stream> pNewXObject = MakeXObjectFromPageRaw(pSrcPage);
647*3ac0a46fSAndroid Build Coastguard Worker 
648*3ac0a46fSAndroid Build Coastguard Worker   // TODO(xlou): A better name schema to avoid possible object name collision.
649*3ac0a46fSAndroid Build Coastguard Worker   ByteString bsXObjectName = ByteString::Format("X%d", ++m_nObjectNumber);
650*3ac0a46fSAndroid Build Coastguard Worker   m_XObjectNameToNumberMap[bsXObjectName] = pNewXObject->GetObjNum();
651*3ac0a46fSAndroid Build Coastguard Worker   m_SrcPageXObjectMap[pSrcPage->GetDict()->GetObjNum()] = bsXObjectName;
652*3ac0a46fSAndroid Build Coastguard Worker   return bsXObjectName;
653*3ac0a46fSAndroid Build Coastguard Worker }
654*3ac0a46fSAndroid Build Coastguard Worker 
655*3ac0a46fSAndroid Build Coastguard Worker std::unique_ptr<XObjectContext>
CreateXObjectContextFromPage(int src_page_index)656*3ac0a46fSAndroid Build Coastguard Worker CPDF_NPageToOneExporter::CreateXObjectContextFromPage(int src_page_index) {
657*3ac0a46fSAndroid Build Coastguard Worker   RetainPtr<CPDF_Dictionary> src_page_dict =
658*3ac0a46fSAndroid Build Coastguard Worker       src()->GetMutablePageDictionary(src_page_index);
659*3ac0a46fSAndroid Build Coastguard Worker   if (!src_page_dict)
660*3ac0a46fSAndroid Build Coastguard Worker     return nullptr;
661*3ac0a46fSAndroid Build Coastguard Worker 
662*3ac0a46fSAndroid Build Coastguard Worker   auto src_page = pdfium::MakeRetain<CPDF_Page>(src(), src_page_dict);
663*3ac0a46fSAndroid Build Coastguard Worker   auto xobject = std::make_unique<XObjectContext>();
664*3ac0a46fSAndroid Build Coastguard Worker   xobject->dest_doc = dest();
665*3ac0a46fSAndroid Build Coastguard Worker   xobject->xobject.Reset(MakeXObjectFromPageRaw(src_page));
666*3ac0a46fSAndroid Build Coastguard Worker   return xobject;
667*3ac0a46fSAndroid Build Coastguard Worker }
668*3ac0a46fSAndroid Build Coastguard Worker 
FinishPage(RetainPtr<CPDF_Dictionary> pDestPageDict,const ByteString & bsContent)669*3ac0a46fSAndroid Build Coastguard Worker void CPDF_NPageToOneExporter::FinishPage(
670*3ac0a46fSAndroid Build Coastguard Worker     RetainPtr<CPDF_Dictionary> pDestPageDict,
671*3ac0a46fSAndroid Build Coastguard Worker     const ByteString& bsContent) {
672*3ac0a46fSAndroid Build Coastguard Worker   RetainPtr<CPDF_Dictionary> pRes =
673*3ac0a46fSAndroid Build Coastguard Worker       pDestPageDict->GetOrCreateDictFor(pdfium::page_object::kResources);
674*3ac0a46fSAndroid Build Coastguard Worker   RetainPtr<CPDF_Dictionary> pPageXObject = pRes->GetOrCreateDictFor("XObject");
675*3ac0a46fSAndroid Build Coastguard Worker   for (auto& it : m_XObjectNameToNumberMap)
676*3ac0a46fSAndroid Build Coastguard Worker     pPageXObject->SetNewFor<CPDF_Reference>(it.first, dest(), it.second);
677*3ac0a46fSAndroid Build Coastguard Worker 
678*3ac0a46fSAndroid Build Coastguard Worker   auto pStream =
679*3ac0a46fSAndroid Build Coastguard Worker       dest()->NewIndirect<CPDF_Stream>(dest()->New<CPDF_Dictionary>());
680*3ac0a46fSAndroid Build Coastguard Worker   pStream->SetData(bsContent.raw_span());
681*3ac0a46fSAndroid Build Coastguard Worker   pDestPageDict->SetNewFor<CPDF_Reference>(pdfium::page_object::kContents,
682*3ac0a46fSAndroid Build Coastguard Worker                                            dest(), pStream->GetObjNum());
683*3ac0a46fSAndroid Build Coastguard Worker }
684*3ac0a46fSAndroid Build Coastguard Worker 
685*3ac0a46fSAndroid Build Coastguard Worker // Make sure arrays only contain objects of basic types.
IsValidViewerPreferencesArray(const CPDF_Array * array)686*3ac0a46fSAndroid Build Coastguard Worker bool IsValidViewerPreferencesArray(const CPDF_Array* array) {
687*3ac0a46fSAndroid Build Coastguard Worker   CPDF_ArrayLocker locker(array);
688*3ac0a46fSAndroid Build Coastguard Worker   for (const auto& obj : locker) {
689*3ac0a46fSAndroid Build Coastguard Worker     if (obj->IsArray() || obj->IsDictionary() || obj->IsReference() ||
690*3ac0a46fSAndroid Build Coastguard Worker         obj->IsStream()) {
691*3ac0a46fSAndroid Build Coastguard Worker       return false;
692*3ac0a46fSAndroid Build Coastguard Worker     }
693*3ac0a46fSAndroid Build Coastguard Worker   }
694*3ac0a46fSAndroid Build Coastguard Worker   return true;
695*3ac0a46fSAndroid Build Coastguard Worker }
696*3ac0a46fSAndroid Build Coastguard Worker 
IsValidViewerPreferencesObject(const CPDF_Object * obj)697*3ac0a46fSAndroid Build Coastguard Worker bool IsValidViewerPreferencesObject(const CPDF_Object* obj) {
698*3ac0a46fSAndroid Build Coastguard Worker   // Per spec, there are no valid entries of these types.
699*3ac0a46fSAndroid Build Coastguard Worker   if (obj->IsDictionary() || obj->IsNull() || obj->IsReference() ||
700*3ac0a46fSAndroid Build Coastguard Worker       obj->IsStream()) {
701*3ac0a46fSAndroid Build Coastguard Worker     return false;
702*3ac0a46fSAndroid Build Coastguard Worker   }
703*3ac0a46fSAndroid Build Coastguard Worker 
704*3ac0a46fSAndroid Build Coastguard Worker   const CPDF_Array* array = obj->AsArray();
705*3ac0a46fSAndroid Build Coastguard Worker   if (!array) {
706*3ac0a46fSAndroid Build Coastguard Worker     return true;
707*3ac0a46fSAndroid Build Coastguard Worker   }
708*3ac0a46fSAndroid Build Coastguard Worker 
709*3ac0a46fSAndroid Build Coastguard Worker   return IsValidViewerPreferencesArray(array);
710*3ac0a46fSAndroid Build Coastguard Worker }
711*3ac0a46fSAndroid Build Coastguard Worker 
712*3ac0a46fSAndroid Build Coastguard Worker }  // namespace
713*3ac0a46fSAndroid Build Coastguard Worker 
714*3ac0a46fSAndroid Build Coastguard Worker FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
FPDF_ImportPagesByIndex(FPDF_DOCUMENT dest_doc,FPDF_DOCUMENT src_doc,const int * page_indices,unsigned long length,int index)715*3ac0a46fSAndroid Build Coastguard Worker FPDF_ImportPagesByIndex(FPDF_DOCUMENT dest_doc,
716*3ac0a46fSAndroid Build Coastguard Worker                         FPDF_DOCUMENT src_doc,
717*3ac0a46fSAndroid Build Coastguard Worker                         const int* page_indices,
718*3ac0a46fSAndroid Build Coastguard Worker                         unsigned long length,
719*3ac0a46fSAndroid Build Coastguard Worker                         int index) {
720*3ac0a46fSAndroid Build Coastguard Worker   CPDF_Document* pDestDoc = CPDFDocumentFromFPDFDocument(dest_doc);
721*3ac0a46fSAndroid Build Coastguard Worker   if (!dest_doc)
722*3ac0a46fSAndroid Build Coastguard Worker     return false;
723*3ac0a46fSAndroid Build Coastguard Worker 
724*3ac0a46fSAndroid Build Coastguard Worker   CPDF_Document* pSrcDoc = CPDFDocumentFromFPDFDocument(src_doc);
725*3ac0a46fSAndroid Build Coastguard Worker   if (!pSrcDoc)
726*3ac0a46fSAndroid Build Coastguard Worker     return false;
727*3ac0a46fSAndroid Build Coastguard Worker 
728*3ac0a46fSAndroid Build Coastguard Worker   CPDF_PageExporter exporter(pDestDoc, pSrcDoc);
729*3ac0a46fSAndroid Build Coastguard Worker 
730*3ac0a46fSAndroid Build Coastguard Worker   if (!page_indices) {
731*3ac0a46fSAndroid Build Coastguard Worker     std::vector<uint32_t> page_indices_vec(pSrcDoc->GetPageCount());
732*3ac0a46fSAndroid Build Coastguard Worker     std::iota(page_indices_vec.begin(), page_indices_vec.end(), 0);
733*3ac0a46fSAndroid Build Coastguard Worker     return exporter.ExportPage(page_indices_vec, index);
734*3ac0a46fSAndroid Build Coastguard Worker   }
735*3ac0a46fSAndroid Build Coastguard Worker 
736*3ac0a46fSAndroid Build Coastguard Worker   if (length == 0)
737*3ac0a46fSAndroid Build Coastguard Worker     return false;
738*3ac0a46fSAndroid Build Coastguard Worker 
739*3ac0a46fSAndroid Build Coastguard Worker   return exporter.ExportPage(
740*3ac0a46fSAndroid Build Coastguard Worker       pdfium::make_span(reinterpret_cast<const uint32_t*>(page_indices),
741*3ac0a46fSAndroid Build Coastguard Worker                         length),
742*3ac0a46fSAndroid Build Coastguard Worker       index);
743*3ac0a46fSAndroid Build Coastguard Worker }
744*3ac0a46fSAndroid Build Coastguard Worker 
FPDF_ImportPages(FPDF_DOCUMENT dest_doc,FPDF_DOCUMENT src_doc,FPDF_BYTESTRING pagerange,int index)745*3ac0a46fSAndroid Build Coastguard Worker FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_ImportPages(FPDF_DOCUMENT dest_doc,
746*3ac0a46fSAndroid Build Coastguard Worker                                                      FPDF_DOCUMENT src_doc,
747*3ac0a46fSAndroid Build Coastguard Worker                                                      FPDF_BYTESTRING pagerange,
748*3ac0a46fSAndroid Build Coastguard Worker                                                      int index) {
749*3ac0a46fSAndroid Build Coastguard Worker   CPDF_Document* pDestDoc = CPDFDocumentFromFPDFDocument(dest_doc);
750*3ac0a46fSAndroid Build Coastguard Worker   if (!dest_doc)
751*3ac0a46fSAndroid Build Coastguard Worker     return false;
752*3ac0a46fSAndroid Build Coastguard Worker 
753*3ac0a46fSAndroid Build Coastguard Worker   CPDF_Document* pSrcDoc = CPDFDocumentFromFPDFDocument(src_doc);
754*3ac0a46fSAndroid Build Coastguard Worker   if (!pSrcDoc)
755*3ac0a46fSAndroid Build Coastguard Worker     return false;
756*3ac0a46fSAndroid Build Coastguard Worker 
757*3ac0a46fSAndroid Build Coastguard Worker   std::vector<uint32_t> page_indices = GetPageIndices(*pSrcDoc, pagerange);
758*3ac0a46fSAndroid Build Coastguard Worker   if (page_indices.empty())
759*3ac0a46fSAndroid Build Coastguard Worker     return false;
760*3ac0a46fSAndroid Build Coastguard Worker 
761*3ac0a46fSAndroid Build Coastguard Worker   CPDF_PageExporter exporter(pDestDoc, pSrcDoc);
762*3ac0a46fSAndroid Build Coastguard Worker   return exporter.ExportPage(page_indices, index);
763*3ac0a46fSAndroid Build Coastguard Worker }
764*3ac0a46fSAndroid Build Coastguard Worker 
765*3ac0a46fSAndroid Build Coastguard Worker FPDF_EXPORT FPDF_DOCUMENT FPDF_CALLCONV
FPDF_ImportNPagesToOne(FPDF_DOCUMENT src_doc,float output_width,float output_height,size_t num_pages_on_x_axis,size_t num_pages_on_y_axis)766*3ac0a46fSAndroid Build Coastguard Worker FPDF_ImportNPagesToOne(FPDF_DOCUMENT src_doc,
767*3ac0a46fSAndroid Build Coastguard Worker                        float output_width,
768*3ac0a46fSAndroid Build Coastguard Worker                        float output_height,
769*3ac0a46fSAndroid Build Coastguard Worker                        size_t num_pages_on_x_axis,
770*3ac0a46fSAndroid Build Coastguard Worker                        size_t num_pages_on_y_axis) {
771*3ac0a46fSAndroid Build Coastguard Worker   CPDF_Document* pSrcDoc = CPDFDocumentFromFPDFDocument(src_doc);
772*3ac0a46fSAndroid Build Coastguard Worker   if (!pSrcDoc)
773*3ac0a46fSAndroid Build Coastguard Worker     return nullptr;
774*3ac0a46fSAndroid Build Coastguard Worker 
775*3ac0a46fSAndroid Build Coastguard Worker   if (output_width <= 0 || output_height <= 0 || num_pages_on_x_axis <= 0 ||
776*3ac0a46fSAndroid Build Coastguard Worker       num_pages_on_y_axis <= 0) {
777*3ac0a46fSAndroid Build Coastguard Worker     return nullptr;
778*3ac0a46fSAndroid Build Coastguard Worker   }
779*3ac0a46fSAndroid Build Coastguard Worker 
780*3ac0a46fSAndroid Build Coastguard Worker   ScopedFPDFDocument output_doc(FPDF_CreateNewDocument());
781*3ac0a46fSAndroid Build Coastguard Worker   if (!output_doc)
782*3ac0a46fSAndroid Build Coastguard Worker     return nullptr;
783*3ac0a46fSAndroid Build Coastguard Worker 
784*3ac0a46fSAndroid Build Coastguard Worker   CPDF_Document* pDestDoc = CPDFDocumentFromFPDFDocument(output_doc.get());
785*3ac0a46fSAndroid Build Coastguard Worker   DCHECK(pDestDoc);
786*3ac0a46fSAndroid Build Coastguard Worker 
787*3ac0a46fSAndroid Build Coastguard Worker   std::vector<uint32_t> page_indices = GetPageIndices(*pSrcDoc, ByteString());
788*3ac0a46fSAndroid Build Coastguard Worker   if (page_indices.empty())
789*3ac0a46fSAndroid Build Coastguard Worker     return nullptr;
790*3ac0a46fSAndroid Build Coastguard Worker 
791*3ac0a46fSAndroid Build Coastguard Worker   if (num_pages_on_x_axis == 1 && num_pages_on_y_axis == 1) {
792*3ac0a46fSAndroid Build Coastguard Worker     CPDF_PageExporter exporter(pDestDoc, pSrcDoc);
793*3ac0a46fSAndroid Build Coastguard Worker     if (!exporter.ExportPage(page_indices, 0))
794*3ac0a46fSAndroid Build Coastguard Worker       return nullptr;
795*3ac0a46fSAndroid Build Coastguard Worker     return output_doc.release();
796*3ac0a46fSAndroid Build Coastguard Worker   }
797*3ac0a46fSAndroid Build Coastguard Worker 
798*3ac0a46fSAndroid Build Coastguard Worker   CPDF_NPageToOneExporter exporter(pDestDoc, pSrcDoc);
799*3ac0a46fSAndroid Build Coastguard Worker   if (!exporter.ExportNPagesToOne(page_indices,
800*3ac0a46fSAndroid Build Coastguard Worker                                   CFX_SizeF(output_width, output_height),
801*3ac0a46fSAndroid Build Coastguard Worker                                   num_pages_on_x_axis, num_pages_on_y_axis)) {
802*3ac0a46fSAndroid Build Coastguard Worker     return nullptr;
803*3ac0a46fSAndroid Build Coastguard Worker   }
804*3ac0a46fSAndroid Build Coastguard Worker   return output_doc.release();
805*3ac0a46fSAndroid Build Coastguard Worker }
806*3ac0a46fSAndroid Build Coastguard Worker 
807*3ac0a46fSAndroid Build Coastguard Worker FPDF_EXPORT FPDF_XOBJECT FPDF_CALLCONV
FPDF_NewXObjectFromPage(FPDF_DOCUMENT dest_doc,FPDF_DOCUMENT src_doc,int src_page_index)808*3ac0a46fSAndroid Build Coastguard Worker FPDF_NewXObjectFromPage(FPDF_DOCUMENT dest_doc,
809*3ac0a46fSAndroid Build Coastguard Worker                         FPDF_DOCUMENT src_doc,
810*3ac0a46fSAndroid Build Coastguard Worker                         int src_page_index) {
811*3ac0a46fSAndroid Build Coastguard Worker   CPDF_Document* dest = CPDFDocumentFromFPDFDocument(dest_doc);
812*3ac0a46fSAndroid Build Coastguard Worker   if (!dest)
813*3ac0a46fSAndroid Build Coastguard Worker     return nullptr;
814*3ac0a46fSAndroid Build Coastguard Worker 
815*3ac0a46fSAndroid Build Coastguard Worker   CPDF_Document* src = CPDFDocumentFromFPDFDocument(src_doc);
816*3ac0a46fSAndroid Build Coastguard Worker   if (!src)
817*3ac0a46fSAndroid Build Coastguard Worker     return nullptr;
818*3ac0a46fSAndroid Build Coastguard Worker 
819*3ac0a46fSAndroid Build Coastguard Worker   CPDF_NPageToOneExporter exporter(dest, src);
820*3ac0a46fSAndroid Build Coastguard Worker   std::unique_ptr<XObjectContext> xobject =
821*3ac0a46fSAndroid Build Coastguard Worker       exporter.CreateXObjectContextFromPage(src_page_index);
822*3ac0a46fSAndroid Build Coastguard Worker   return FPDFXObjectFromXObjectContext(xobject.release());
823*3ac0a46fSAndroid Build Coastguard Worker }
824*3ac0a46fSAndroid Build Coastguard Worker 
FPDF_CloseXObject(FPDF_XOBJECT xobject)825*3ac0a46fSAndroid Build Coastguard Worker FPDF_EXPORT void FPDF_CALLCONV FPDF_CloseXObject(FPDF_XOBJECT xobject) {
826*3ac0a46fSAndroid Build Coastguard Worker   std::unique_ptr<XObjectContext> xobject_deleter(
827*3ac0a46fSAndroid Build Coastguard Worker       XObjectContextFromFPDFXObject(xobject));
828*3ac0a46fSAndroid Build Coastguard Worker }
829*3ac0a46fSAndroid Build Coastguard Worker 
830*3ac0a46fSAndroid Build Coastguard Worker FPDF_EXPORT FPDF_PAGEOBJECT FPDF_CALLCONV
FPDF_NewFormObjectFromXObject(FPDF_XOBJECT xobject)831*3ac0a46fSAndroid Build Coastguard Worker FPDF_NewFormObjectFromXObject(FPDF_XOBJECT xobject) {
832*3ac0a46fSAndroid Build Coastguard Worker   XObjectContext* xobj = XObjectContextFromFPDFXObject(xobject);
833*3ac0a46fSAndroid Build Coastguard Worker   if (!xobj)
834*3ac0a46fSAndroid Build Coastguard Worker     return nullptr;
835*3ac0a46fSAndroid Build Coastguard Worker 
836*3ac0a46fSAndroid Build Coastguard Worker   auto form = std::make_unique<CPDF_Form>(xobj->dest_doc, nullptr,
837*3ac0a46fSAndroid Build Coastguard Worker                                           xobj->xobject, nullptr);
838*3ac0a46fSAndroid Build Coastguard Worker   form->ParseContent(nullptr, nullptr, nullptr);
839*3ac0a46fSAndroid Build Coastguard Worker   auto form_object = std::make_unique<CPDF_FormObject>(
840*3ac0a46fSAndroid Build Coastguard Worker       CPDF_PageObject::kNoContentStream, std::move(form), CFX_Matrix());
841*3ac0a46fSAndroid Build Coastguard Worker   return FPDFPageObjectFromCPDFPageObject(form_object.release());
842*3ac0a46fSAndroid Build Coastguard Worker }
843*3ac0a46fSAndroid Build Coastguard Worker 
844*3ac0a46fSAndroid Build Coastguard Worker FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
FPDF_CopyViewerPreferences(FPDF_DOCUMENT dest_doc,FPDF_DOCUMENT src_doc)845*3ac0a46fSAndroid Build Coastguard Worker FPDF_CopyViewerPreferences(FPDF_DOCUMENT dest_doc, FPDF_DOCUMENT src_doc) {
846*3ac0a46fSAndroid Build Coastguard Worker   CPDF_Document* pDstDoc = CPDFDocumentFromFPDFDocument(dest_doc);
847*3ac0a46fSAndroid Build Coastguard Worker   if (!pDstDoc)
848*3ac0a46fSAndroid Build Coastguard Worker     return false;
849*3ac0a46fSAndroid Build Coastguard Worker 
850*3ac0a46fSAndroid Build Coastguard Worker   CPDF_Document* pSrcDoc = CPDFDocumentFromFPDFDocument(src_doc);
851*3ac0a46fSAndroid Build Coastguard Worker   if (!pSrcDoc)
852*3ac0a46fSAndroid Build Coastguard Worker     return false;
853*3ac0a46fSAndroid Build Coastguard Worker 
854*3ac0a46fSAndroid Build Coastguard Worker   RetainPtr<const CPDF_Dictionary> pPrefDict =
855*3ac0a46fSAndroid Build Coastguard Worker       pSrcDoc->GetRoot()->GetDictFor("ViewerPreferences");
856*3ac0a46fSAndroid Build Coastguard Worker   if (!pPrefDict)
857*3ac0a46fSAndroid Build Coastguard Worker     return false;
858*3ac0a46fSAndroid Build Coastguard Worker 
859*3ac0a46fSAndroid Build Coastguard Worker   RetainPtr<CPDF_Dictionary> pDstDict = pDstDoc->GetMutableRoot();
860*3ac0a46fSAndroid Build Coastguard Worker   if (!pDstDict)
861*3ac0a46fSAndroid Build Coastguard Worker     return false;
862*3ac0a46fSAndroid Build Coastguard Worker 
863*3ac0a46fSAndroid Build Coastguard Worker   auto cloned_dict = pdfium::MakeRetain<CPDF_Dictionary>();
864*3ac0a46fSAndroid Build Coastguard Worker   CPDF_DictionaryLocker locker(pPrefDict);
865*3ac0a46fSAndroid Build Coastguard Worker   for (const auto& it : locker) {
866*3ac0a46fSAndroid Build Coastguard Worker     if (IsValidViewerPreferencesObject(it.second)) {
867*3ac0a46fSAndroid Build Coastguard Worker       cloned_dict->SetFor(it.first, it.second->Clone());
868*3ac0a46fSAndroid Build Coastguard Worker     }
869*3ac0a46fSAndroid Build Coastguard Worker   }
870*3ac0a46fSAndroid Build Coastguard Worker 
871*3ac0a46fSAndroid Build Coastguard Worker   pDstDict->SetFor("ViewerPreferences", std::move(cloned_dict));
872*3ac0a46fSAndroid Build Coastguard Worker   return true;
873*3ac0a46fSAndroid Build Coastguard Worker }
874