1 // Copyright 2014 PDFium Authors. All rights reserved.
\r
2 // Use of this source code is governed by a BSD-style license that can be
\r
3 // found in the LICENSE file.
\r
5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
\r
7 #include "../../../include/fpdfapi/fpdf_parser.h"
\r
8 #include "../../../include/fpdfapi/fpdf_module.h"
\r
9 extern FX_LPVOID PDFPreviewInitCache(CPDF_Document* pDoc);
\r
10 extern void PDFPreviewClearCache(FX_LPVOID pCache);
\r
11 CPDF_Document::CPDF_Document(IPDF_DocParser* pParser) : CPDF_IndirectObjects(pParser)
\r
13 ASSERT(pParser != NULL);
\r
16 m_bLinearized = FALSE;
\r
17 m_dwFirstPageNo = 0;
\r
18 m_dwFirstPageObjNum = 0;
\r
19 m_pDocPage = CPDF_ModuleMgr::Get()->GetPageModule()->CreateDocData(this);
\r
20 m_pDocRender = CPDF_ModuleMgr::Get()->GetRenderModule()->CreateDocData(this);
\r
22 CPDF_DocPageData* CPDF_Document::GetValidatePageData()
\r
27 m_pDocPage = CPDF_ModuleMgr::Get()->GetPageModule()->CreateDocData(this);
\r
30 CPDF_DocRenderData* CPDF_Document::GetValidateRenderData()
\r
33 return m_pDocRender;
\r
35 m_pDocRender = CPDF_ModuleMgr::Get()->GetRenderModule()->CreateDocData(this);
\r
36 return m_pDocRender;
\r
38 void CPDF_Document::LoadDoc()
\r
40 m_LastObjNum = m_pParser->GetLastObjNum();
\r
41 CPDF_Object* pRootObj = GetIndirectObject(m_pParser->GetRootObjNum());
\r
42 if (pRootObj == NULL) {
\r
45 m_pRootDict = pRootObj->GetDict();
\r
46 if (m_pRootDict == NULL) {
\r
49 CPDF_Object* pInfoObj = GetIndirectObject(m_pParser->GetInfoObjNum());
\r
51 m_pInfoDict = pInfoObj->GetDict();
\r
53 CPDF_Array* pIDArray = m_pParser->GetIDArray();
\r
55 m_ID1 = pIDArray->GetString(0);
\r
56 m_ID2 = pIDArray->GetString(1);
\r
58 m_PageList.SetSize(_GetPageCount());
\r
60 void CPDF_Document::LoadAsynDoc(CPDF_Dictionary *pLinearized)
\r
62 m_bLinearized = TRUE;
\r
63 m_LastObjNum = m_pParser->GetLastObjNum();
\r
64 m_pRootDict = GetIndirectObject(m_pParser->GetRootObjNum())->GetDict();
\r
65 if (m_pRootDict == NULL) {
\r
68 m_pInfoDict = GetIndirectObject(m_pParser->GetInfoObjNum())->GetDict();
\r
69 CPDF_Array* pIDArray = m_pParser->GetIDArray();
\r
71 m_ID1 = pIDArray->GetString(0);
\r
72 m_ID2 = pIDArray->GetString(1);
\r
74 FX_DWORD dwPageCount = 0;
\r
75 CPDF_Object *pCount = pLinearized->GetElement(FX_BSTRC("N"));
\r
76 if (pCount && pCount->GetType() == PDFOBJ_NUMBER) {
\r
77 dwPageCount = pCount->GetInteger();
\r
79 m_PageList.SetSize(dwPageCount);
\r
80 CPDF_Object *pNo = pLinearized->GetElement(FX_BSTRC("P"));
\r
81 if (pNo && pNo->GetType() == PDFOBJ_NUMBER) {
\r
82 m_dwFirstPageNo = pNo->GetInteger();
\r
84 CPDF_Object *pObjNum = pLinearized->GetElement(FX_BSTRC("O"));
\r
85 if (pObjNum && pObjNum->GetType() == PDFOBJ_NUMBER) {
\r
86 m_dwFirstPageObjNum = pObjNum->GetInteger();
\r
89 void CPDF_Document::LoadPages()
\r
91 m_PageList.SetSize(_GetPageCount());
\r
93 extern void FPDF_TTFaceMapper_ReleaseDoc(CPDF_Document*);
\r
94 CPDF_Document::~CPDF_Document()
\r
97 CPDF_ModuleMgr::Get()->GetRenderModule()->DestroyDocData(m_pDocRender);
\r
100 CPDF_ModuleMgr::Get()->GetPageModule()->ReleaseDoc(this);
\r
101 CPDF_ModuleMgr::Get()->GetPageModule()->ClearStockFont(this);
\r
104 #define FX_MAX_PAGE_LEVEL 1024
\r
105 CPDF_Dictionary* CPDF_Document::_FindPDFPage(CPDF_Dictionary* pPages, int iPage, int nPagesToGo, int level)
\r
107 CPDF_Array* pKidList = pPages->GetArray(FX_BSTRC("Kids"));
\r
108 if (pKidList == NULL) {
\r
109 if (nPagesToGo == 0) {
\r
114 if (level >= FX_MAX_PAGE_LEVEL) {
\r
117 int nKids = pKidList->GetCount();
\r
118 for (int i = 0; i < nKids; i ++) {
\r
119 CPDF_Dictionary* pKid = pKidList->GetDict(i);
\r
120 if (pKid == NULL) {
\r
124 if (pKid == pPages) {
\r
127 if (!pKid->KeyExist(FX_BSTRC("Kids"))) {
\r
128 if (nPagesToGo == 0) {
\r
131 m_PageList.SetAt(iPage - nPagesToGo, pKid->GetObjNum());
\r
134 int nPages = pKid->GetInteger(FX_BSTRC("Count"));
\r
135 if (nPagesToGo < nPages) {
\r
136 return _FindPDFPage(pKid, iPage, nPagesToGo, level + 1);
\r
138 nPagesToGo -= nPages;
\r
143 CPDF_Dictionary* CPDF_Document::GetPage(int iPage)
\r
145 if (iPage < 0 || iPage >= m_PageList.GetSize()) {
\r
148 if (m_bLinearized && (iPage == (int)m_dwFirstPageNo)) {
\r
149 CPDF_Object* pObj = GetIndirectObject(m_dwFirstPageObjNum);
\r
150 if (pObj && pObj->GetType() == PDFOBJ_DICTIONARY) {
\r
151 return (CPDF_Dictionary*)pObj;
\r
154 int objnum = m_PageList.GetAt(iPage);
\r
156 CPDF_Object* pObj = GetIndirectObject(objnum);
\r
157 ASSERT(pObj->GetType() == PDFOBJ_DICTIONARY);
\r
158 return (CPDF_Dictionary*)pObj;
\r
160 CPDF_Dictionary* pRoot = GetRoot();
\r
161 if (pRoot == NULL) {
\r
164 CPDF_Dictionary* pPages = pRoot->GetDict(FX_BSTRC("Pages"));
\r
165 if (pPages == NULL) {
\r
168 CPDF_Dictionary* pPage = _FindPDFPage(pPages, iPage, iPage, 0);
\r
169 if (pPage == NULL) {
\r
172 m_PageList.SetAt(iPage, pPage->GetObjNum());
\r
175 int CPDF_Document::_FindPageIndex(CPDF_Dictionary* pNode, FX_DWORD& skip_count, FX_DWORD objnum, int& index, int level)
\r
177 if (pNode->KeyExist(FX_BSTRC("Kids"))) {
\r
178 CPDF_Array* pKidList = pNode->GetArray(FX_BSTRC("Kids"));
\r
179 if (pKidList == NULL) {
\r
182 if (level >= FX_MAX_PAGE_LEVEL) {
\r
185 FX_DWORD count = pNode->GetInteger(FX_BSTRC("Count"));
\r
186 if (count <= skip_count) {
\r
187 skip_count -= count;
\r
191 if (count && count == pKidList->GetCount()) {
\r
192 for (FX_DWORD i = 0; i < count; i ++) {
\r
193 CPDF_Reference* pKid = (CPDF_Reference*)pKidList->GetElement(i);
\r
194 if (pKid && pKid->GetType() == PDFOBJ_REFERENCE) {
\r
195 if (pKid->GetRefObjNum() == objnum) {
\r
196 m_PageList.SetAt(index + i, objnum);
\r
202 for (FX_DWORD i = 0; i < pKidList->GetCount(); i ++) {
\r
203 CPDF_Dictionary* pKid = pKidList->GetDict(i);
\r
204 if (pKid == NULL) {
\r
207 if (pKid == pNode) {
\r
210 int found_index = _FindPageIndex(pKid, skip_count, objnum, index, level + 1);
\r
211 if (found_index >= 0) {
\r
212 return found_index;
\r
216 if (objnum == pNode->GetObjNum()) {
\r
226 int CPDF_Document::GetPageIndex(FX_DWORD objnum)
\r
228 FX_DWORD nPages = m_PageList.GetSize();
\r
229 FX_DWORD skip_count = 0;
\r
230 FX_BOOL bSkipped = FALSE;
\r
231 for (FX_DWORD i = 0; i < nPages; i ++) {
\r
232 FX_DWORD objnum1 = m_PageList.GetAt(i);
\r
233 if (objnum1 == objnum) {
\r
236 if (!bSkipped && objnum1 == 0) {
\r
241 CPDF_Dictionary* pRoot = GetRoot();
\r
242 if (pRoot == NULL) {
\r
245 CPDF_Dictionary* pPages = pRoot->GetDict(FX_BSTRC("Pages"));
\r
246 if (pPages == NULL) {
\r
250 return _FindPageIndex(pPages, skip_count, objnum, index);
\r
252 int CPDF_Document::GetPageCount() const
\r
254 return m_PageList.GetSize();
\r
256 static int _CountPages(CPDF_Dictionary* pPages, int level)
\r
261 int count = pPages->GetInteger(FX_BSTRC("Count"));
\r
262 if (count > 0 && count < FPDF_PAGE_MAX_NUM) {
\r
265 CPDF_Array* pKidList = pPages->GetArray(FX_BSTRC("Kids"));
\r
266 if (pKidList == NULL) {
\r
270 for (FX_DWORD i = 0; i < pKidList->GetCount(); i ++) {
\r
271 CPDF_Dictionary* pKid = pKidList->GetDict(i);
\r
272 if (pKid == NULL) {
\r
275 if (!pKid->KeyExist(FX_BSTRC("Kids"))) {
\r
278 count += _CountPages(pKid, level + 1);
\r
281 pPages->SetAtInteger(FX_BSTRC("Count"), count);
\r
284 int CPDF_Document::_GetPageCount() const
\r
286 CPDF_Dictionary* pRoot = GetRoot();
\r
287 if (pRoot == NULL) {
\r
290 CPDF_Dictionary* pPages = pRoot->GetDict(FX_BSTRC("Pages"));
\r
291 if (pPages == NULL) {
\r
294 if (!pPages->KeyExist(FX_BSTRC("Kids"))) {
\r
297 return _CountPages(pPages, 0);
\r
299 static FX_BOOL _EnumPages(CPDF_Dictionary* pPages, IPDF_EnumPageHandler* pHandler)
\r
301 CPDF_Array* pKidList = pPages->GetArray(FX_BSTRC("Kids"));
\r
302 if (pKidList == NULL) {
\r
303 return pHandler->EnumPage(pPages);
\r
305 for (FX_DWORD i = 0; i < pKidList->GetCount(); i ++) {
\r
306 CPDF_Dictionary* pKid = pKidList->GetDict(i);
\r
307 if (pKid == NULL) {
\r
310 if (!pKid->KeyExist(FX_BSTRC("Kids"))) {
\r
311 if (!pHandler->EnumPage(pKid)) {
\r
315 return _EnumPages(pKid, pHandler);
\r
320 void CPDF_Document::EnumPages(IPDF_EnumPageHandler* pHandler)
\r
322 CPDF_Dictionary* pRoot = GetRoot();
\r
323 if (pRoot == NULL) {
\r
326 CPDF_Dictionary* pPages = pRoot->GetDict(FX_BSTRC("Pages"));
\r
327 if (pPages == NULL) {
\r
330 _EnumPages(pPages, pHandler);
\r
332 FX_BOOL CPDF_Document::IsContentUsedElsewhere(FX_DWORD objnum, CPDF_Dictionary* pThisPageDict)
\r
334 for (int i = 0; i < m_PageList.GetSize(); i ++) {
\r
335 CPDF_Dictionary* pPageDict = GetPage(i);
\r
336 if (pPageDict == pThisPageDict) {
\r
339 CPDF_Object* pContents = pPageDict->GetElement(FX_BSTRC("Contents"));
\r
340 if (pContents == NULL) {
\r
343 if (pContents->GetDirectType() == PDFOBJ_ARRAY) {
\r
344 CPDF_Array* pArray = (CPDF_Array*)pContents->GetDirect();
\r
345 for (FX_DWORD j = 0; j < pArray->GetCount(); j ++) {
\r
346 CPDF_Reference* pRef = (CPDF_Reference*)pArray->GetElement(j);
\r
347 if (pRef->GetRefObjNum() == objnum) {
\r
351 } else if (pContents->GetObjNum() == objnum) {
\r
357 FX_DWORD CPDF_Document::GetUserPermissions(FX_BOOL bCheckRevision) const
\r
359 if (m_pParser == NULL) {
\r
360 return (FX_DWORD) - 1;
\r
362 return m_pParser->GetPermissions(bCheckRevision);
\r
364 FX_BOOL CPDF_Document::IsOwner() const
\r
366 if (m_pParser == NULL) {
\r
369 return m_pParser->IsOwner();
\r
371 FX_BOOL CPDF_Document::IsFormStream(FX_DWORD objnum, FX_BOOL& bForm) const
\r
375 if (m_IndirectObjs.Lookup((FX_LPVOID)(FX_UINTPTR)objnum, (FX_LPVOID&)pObj)) {
\r
376 bForm = pObj->GetType() == PDFOBJ_STREAM &&
\r
377 ((CPDF_Stream*)pObj)->GetDict()->GetString(FX_BSTRC("Subtype")) == FX_BSTRC("Form");
\r
381 if (m_pParser == NULL) {
\r
385 return m_pParser->IsFormStream(objnum, bForm);
\r
387 void CPDF_Document::ClearPageData()
\r
390 CPDF_ModuleMgr::Get()->GetPageModule()->ClearDoc(this);
\r
393 void CPDF_Document::ClearRenderData()
\r
395 if (m_pDocRender) {
\r
396 CPDF_ModuleMgr::Get()->GetRenderModule()->ClearDocData(m_pDocRender);
\r