Add new public APIs to find the z-order for links and widgets.
[pdfium.git] / core / src / fpdfdoc / doc_tagged.cpp
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 "../../include/fpdfapi/fpdf_parser.h"
8 #include "../../include/fpdfapi/fpdf_page.h"
9 #include "../../include/fpdfdoc/fpdf_tagged.h"
10 #include "tagged_int.h"
11 const int nMaxRecursion = 32;
12 static FX_BOOL IsTagged(const CPDF_Document* pDoc) {
13   CPDF_Dictionary* pCatalog = pDoc->GetRoot();
14   CPDF_Dictionary* pMarkInfo = pCatalog->GetDict(FX_BSTRC("MarkInfo"));
15   return pMarkInfo != NULL && pMarkInfo->GetInteger(FX_BSTRC("Marked"));
16 }
17 CPDF_StructTree* CPDF_StructTree::LoadPage(const CPDF_Document* pDoc,
18                                            const CPDF_Dictionary* pPageDict) {
19   if (!IsTagged(pDoc)) {
20     return NULL;
21   }
22   CPDF_StructTreeImpl* pTree = new CPDF_StructTreeImpl(pDoc);
23   pTree->LoadPageTree(pPageDict);
24   return pTree;
25 }
26 CPDF_StructTree* CPDF_StructTree::LoadDoc(const CPDF_Document* pDoc) {
27   if (!IsTagged(pDoc)) {
28     return NULL;
29   }
30   CPDF_StructTreeImpl* pTree = new CPDF_StructTreeImpl(pDoc);
31   pTree->LoadDocTree();
32   return pTree;
33 }
34 CPDF_StructTreeImpl::CPDF_StructTreeImpl(const CPDF_Document* pDoc) {
35   CPDF_Dictionary* pCatalog = pDoc->GetRoot();
36   m_pTreeRoot = pCatalog->GetDict(FX_BSTRC("StructTreeRoot"));
37   if (m_pTreeRoot == NULL) {
38     return;
39   }
40   m_pRoleMap = m_pTreeRoot->GetDict(FX_BSTRC("RoleMap"));
41 }
42 CPDF_StructTreeImpl::~CPDF_StructTreeImpl() {
43   for (int i = 0; i < m_Kids.GetSize(); i++)
44     if (m_Kids[i]) {
45       m_Kids[i]->Release();
46     }
47 }
48 void CPDF_StructTreeImpl::LoadDocTree() {
49   m_pPage = NULL;
50   if (m_pTreeRoot == NULL) {
51     return;
52   }
53   CPDF_Object* pKids = m_pTreeRoot->GetElementValue(FX_BSTRC("K"));
54   if (pKids == NULL) {
55     return;
56   }
57   if (pKids->GetType() == PDFOBJ_DICTIONARY) {
58     CPDF_StructElementImpl* pStructElementImpl =
59         new CPDF_StructElementImpl(this, NULL, (CPDF_Dictionary*)pKids);
60     m_Kids.Add(pStructElementImpl);
61     return;
62   }
63   if (pKids->GetType() != PDFOBJ_ARRAY) {
64     return;
65   }
66   CPDF_Array* pArray = (CPDF_Array*)pKids;
67   for (FX_DWORD i = 0; i < pArray->GetCount(); i++) {
68     CPDF_Dictionary* pKid = pArray->GetDict(i);
69     CPDF_StructElementImpl* pStructElementImpl =
70         new CPDF_StructElementImpl(this, NULL, pKid);
71     m_Kids.Add(pStructElementImpl);
72   }
73 }
74 void CPDF_StructTreeImpl::LoadPageTree(const CPDF_Dictionary* pPageDict) {
75   m_pPage = pPageDict;
76   if (m_pTreeRoot == NULL) {
77     return;
78   }
79   CPDF_Object* pKids = m_pTreeRoot->GetElementValue(FX_BSTRC("K"));
80   if (pKids == NULL) {
81     return;
82   }
83   FX_DWORD dwKids = 0;
84   if (pKids->GetType() == PDFOBJ_DICTIONARY) {
85     dwKids = 1;
86   } else if (pKids->GetType() == PDFOBJ_ARRAY) {
87     dwKids = ((CPDF_Array*)pKids)->GetCount();
88   } else {
89     return;
90   }
91   FX_DWORD i;
92   m_Kids.SetSize(dwKids);
93   for (i = 0; i < dwKids; i++) {
94     m_Kids[i] = NULL;
95   }
96   CFX_MapPtrToPtr element_map;
97   CPDF_Dictionary* pParentTree = m_pTreeRoot->GetDict(FX_BSTRC("ParentTree"));
98   if (pParentTree == NULL) {
99     return;
100   }
101   CPDF_NumberTree parent_tree(pParentTree);
102   int parents_id = pPageDict->GetInteger(FX_BSTRC("StructParents"), -1);
103   if (parents_id >= 0) {
104     CPDF_Object* pParents = parent_tree.LookupValue(parents_id);
105     if (pParents == NULL || pParents->GetType() != PDFOBJ_ARRAY) {
106       return;
107     }
108     CPDF_Array* pParentArray = (CPDF_Array*)pParents;
109     for (i = 0; i < pParentArray->GetCount(); i++) {
110       CPDF_Dictionary* pParent = pParentArray->GetDict(i);
111       if (pParent == NULL) {
112         continue;
113       }
114       AddPageNode(pParent, element_map);
115     }
116   }
117 }
118 CPDF_StructElementImpl* CPDF_StructTreeImpl::AddPageNode(CPDF_Dictionary* pDict,
119                                                          CFX_MapPtrToPtr& map,
120                                                          int nLevel) {
121   if (nLevel > nMaxRecursion) {
122     return NULL;
123   }
124   CPDF_StructElementImpl* pElement = NULL;
125   if (map.Lookup(pDict, (void*&)pElement)) {
126     return pElement;
127   }
128   pElement = new CPDF_StructElementImpl(this, NULL, pDict);
129   map.SetAt(pDict, pElement);
130   CPDF_Dictionary* pParent = pDict->GetDict(FX_BSTRC("P"));
131   if (pParent == NULL ||
132       pParent->GetString(FX_BSTRC("Type")) == FX_BSTRC("StructTreeRoot")) {
133     if (!AddTopLevelNode(pDict, pElement)) {
134       pElement->Release();
135       map.RemoveKey(pDict);
136     }
137   } else {
138     CPDF_StructElementImpl* pParentElement =
139         AddPageNode(pParent, map, nLevel + 1);
140     FX_BOOL bSave = FALSE;
141     for (int i = 0; i < pParentElement->m_Kids.GetSize(); i++) {
142       if (pParentElement->m_Kids[i].m_Type != CPDF_StructKid::Element) {
143         continue;
144       }
145       if (pParentElement->m_Kids[i].m_Element.m_pDict != pDict) {
146         continue;
147       }
148       pParentElement->m_Kids[i].m_Element.m_pElement = pElement->Retain();
149       bSave = TRUE;
150     }
151     if (!bSave) {
152       pElement->Release();
153       map.RemoveKey(pDict);
154     }
155   }
156   return pElement;
157 }
158 FX_BOOL CPDF_StructTreeImpl::AddTopLevelNode(CPDF_Dictionary* pDict,
159                                              CPDF_StructElementImpl* pElement) {
160   CPDF_Object* pObj = m_pTreeRoot->GetElementValue(FX_BSTRC("K"));
161   if (!pObj) {
162     return FALSE;
163   }
164   if (pObj->GetType() == PDFOBJ_DICTIONARY) {
165     if (pObj->GetObjNum() == pDict->GetObjNum()) {
166       if (m_Kids[0]) {
167         m_Kids[0]->Release();
168       }
169       m_Kids[0] = pElement->Retain();
170     } else {
171       return FALSE;
172     }
173   }
174   if (pObj->GetType() == PDFOBJ_ARRAY) {
175     CPDF_Array* pTopKids = (CPDF_Array*)pObj;
176     FX_DWORD i;
177     FX_BOOL bSave = FALSE;
178     for (i = 0; i < pTopKids->GetCount(); i++) {
179       CPDF_Object* pKidRef = pTopKids->GetElement(i);
180       if (pKidRef == NULL || pKidRef->GetType() != PDFOBJ_REFERENCE) {
181         continue;
182       }
183       if (((CPDF_Reference*)pKidRef)->GetRefObjNum() != pDict->GetObjNum()) {
184         continue;
185       }
186       if (m_Kids[i]) {
187         m_Kids[i]->Release();
188       }
189       m_Kids[i] = pElement->Retain();
190       bSave = TRUE;
191     }
192     if (!bSave) {
193       return FALSE;
194     }
195   }
196   return TRUE;
197 }
198 CPDF_StructElementImpl::CPDF_StructElementImpl(CPDF_StructTreeImpl* pTree,
199                                                CPDF_StructElementImpl* pParent,
200                                                CPDF_Dictionary* pDict)
201     : m_RefCount(0) {
202   m_pTree = pTree;
203   m_pDict = pDict;
204   m_Type = pDict->GetString(FX_BSTRC("S"));
205   if (pTree->m_pRoleMap) {
206     CFX_ByteString mapped = pTree->m_pRoleMap->GetString(m_Type);
207     if (!mapped.IsEmpty()) {
208       m_Type = mapped;
209     }
210   }
211   m_pParent = pParent;
212   LoadKids(pDict);
213 }
214 CPDF_StructElementImpl::~CPDF_StructElementImpl() {
215   for (int i = 0; i < m_Kids.GetSize(); i++) {
216     if (m_Kids[i].m_Type == CPDF_StructKid::Element &&
217         m_Kids[i].m_Element.m_pElement) {
218       ((CPDF_StructElementImpl*)m_Kids[i].m_Element.m_pElement)->Release();
219     }
220   }
221 }
222 CPDF_StructElementImpl* CPDF_StructElementImpl::Retain() {
223   m_RefCount++;
224   return this;
225 }
226 void CPDF_StructElementImpl::Release() {
227   if (--m_RefCount < 1) {
228     delete this;
229   }
230 }
231 void CPDF_StructElementImpl::LoadKids(CPDF_Dictionary* pDict) {
232   CPDF_Object* pObj = pDict->GetElement(FX_BSTRC("Pg"));
233   FX_DWORD PageObjNum = 0;
234   if (pObj && pObj->GetType() == PDFOBJ_REFERENCE) {
235     PageObjNum = ((CPDF_Reference*)pObj)->GetRefObjNum();
236   }
237   CPDF_Object* pKids = pDict->GetElementValue(FX_BSTRC("K"));
238   if (pKids == NULL) {
239     return;
240   }
241   if (pKids->GetType() == PDFOBJ_ARRAY) {
242     CPDF_Array* pArray = (CPDF_Array*)pKids;
243     m_Kids.SetSize(pArray->GetCount());
244     for (FX_DWORD i = 0; i < pArray->GetCount(); i++) {
245       CPDF_Object* pKid = pArray->GetElementValue(i);
246       LoadKid(PageObjNum, pKid, &m_Kids[i]);
247     }
248   } else {
249     m_Kids.SetSize(1);
250     LoadKid(PageObjNum, pKids, &m_Kids[0]);
251   }
252 }
253 void CPDF_StructElementImpl::LoadKid(FX_DWORD PageObjNum,
254                                      CPDF_Object* pKidObj,
255                                      CPDF_StructKid* pKid) {
256   pKid->m_Type = CPDF_StructKid::Invalid;
257   if (pKidObj == NULL) {
258     return;
259   }
260   if (pKidObj->GetType() == PDFOBJ_NUMBER) {
261     if (m_pTree->m_pPage && m_pTree->m_pPage->GetObjNum() != PageObjNum) {
262       return;
263     }
264     pKid->m_Type = CPDF_StructKid::PageContent;
265     pKid->m_PageContent.m_ContentId = pKidObj->GetInteger();
266     pKid->m_PageContent.m_PageObjNum = PageObjNum;
267     return;
268   }
269   if (pKidObj->GetType() != PDFOBJ_DICTIONARY) {
270     return;
271   }
272   CPDF_Dictionary* pKidDict = (CPDF_Dictionary*)pKidObj;
273   CPDF_Object* pPageObj = pKidDict->GetElement(FX_BSTRC("Pg"));
274   if (pPageObj && pPageObj->GetType() == PDFOBJ_REFERENCE) {
275     PageObjNum = ((CPDF_Reference*)pPageObj)->GetRefObjNum();
276   }
277   CFX_ByteString type = pKidDict->GetString(FX_BSTRC("Type"));
278   if (type == FX_BSTRC("MCR")) {
279     if (m_pTree->m_pPage && m_pTree->m_pPage->GetObjNum() != PageObjNum) {
280       return;
281     }
282     pKid->m_Type = CPDF_StructKid::StreamContent;
283     CPDF_Object* pStreamObj = pKidDict->GetElement(FX_BSTRC("Stm"));
284     if (pStreamObj && pStreamObj->GetType() == PDFOBJ_REFERENCE) {
285       pKid->m_StreamContent.m_RefObjNum =
286           ((CPDF_Reference*)pStreamObj)->GetRefObjNum();
287     } else {
288       pKid->m_StreamContent.m_RefObjNum = 0;
289     }
290     pKid->m_StreamContent.m_PageObjNum = PageObjNum;
291     pKid->m_StreamContent.m_ContentId = pKidDict->GetInteger(FX_BSTRC("MCID"));
292   } else if (type == FX_BSTRC("OBJR")) {
293     if (m_pTree->m_pPage && m_pTree->m_pPage->GetObjNum() != PageObjNum) {
294       return;
295     }
296     pKid->m_Type = CPDF_StructKid::Object;
297     CPDF_Object* pObj = pKidDict->GetElement(FX_BSTRC("Obj"));
298     if (pObj && pObj->GetType() == PDFOBJ_REFERENCE) {
299       pKid->m_Object.m_RefObjNum = ((CPDF_Reference*)pObj)->GetRefObjNum();
300     } else {
301       pKid->m_Object.m_RefObjNum = 0;
302     }
303     pKid->m_Object.m_PageObjNum = PageObjNum;
304   } else {
305     pKid->m_Type = CPDF_StructKid::Element;
306     pKid->m_Element.m_pDict = pKidDict;
307     if (m_pTree->m_pPage == NULL) {
308       pKid->m_Element.m_pElement =
309           new CPDF_StructElementImpl(m_pTree, this, pKidDict);
310     } else {
311       pKid->m_Element.m_pElement = NULL;
312     }
313   }
314 }
315 static CPDF_Dictionary* FindAttrDict(CPDF_Object* pAttrs,
316                                      const CFX_ByteStringC& owner,
317                                      FX_FLOAT nLevel = 0.0F) {
318   if (nLevel > nMaxRecursion) {
319     return NULL;
320   }
321   if (pAttrs == NULL) {
322     return NULL;
323   }
324   CPDF_Dictionary* pDict = NULL;
325   if (pAttrs->GetType() == PDFOBJ_DICTIONARY) {
326     pDict = (CPDF_Dictionary*)pAttrs;
327   } else if (pAttrs->GetType() == PDFOBJ_STREAM) {
328     pDict = ((CPDF_Stream*)pAttrs)->GetDict();
329   } else if (pAttrs->GetType() == PDFOBJ_ARRAY) {
330     CPDF_Array* pArray = (CPDF_Array*)pAttrs;
331     for (FX_DWORD i = 0; i < pArray->GetCount(); i++) {
332       CPDF_Object* pElement = pArray->GetElementValue(i);
333       pDict = FindAttrDict(pElement, owner, nLevel + 1);
334       if (pDict) {
335         return pDict;
336       }
337     }
338   }
339   if (pDict && pDict->GetString(FX_BSTRC("O")) == owner) {
340     return pDict;
341   }
342   return NULL;
343 }
344 CPDF_Object* CPDF_StructElementImpl::GetAttr(const CFX_ByteStringC& owner,
345                                              const CFX_ByteStringC& name,
346                                              FX_BOOL bInheritable,
347                                              FX_FLOAT fLevel) {
348   if (fLevel > nMaxRecursion) {
349     return NULL;
350   }
351   if (bInheritable) {
352     CPDF_Object* pAttr = GetAttr(owner, name, FALSE);
353     if (pAttr) {
354       return pAttr;
355     }
356     if (m_pParent == NULL) {
357       return NULL;
358     }
359     return m_pParent->GetAttr(owner, name, TRUE, fLevel + 1);
360   }
361   CPDF_Object* pA = m_pDict->GetElementValue(FX_BSTRC("A"));
362   if (pA) {
363     CPDF_Dictionary* pAttrDict = FindAttrDict(pA, owner);
364     if (pAttrDict) {
365       CPDF_Object* pAttr = pAttrDict->GetElementValue(name);
366       if (pAttr) {
367         return pAttr;
368       }
369     }
370   }
371   CPDF_Object* pC = m_pDict->GetElementValue(FX_BSTRC("C"));
372   if (pC == NULL) {
373     return NULL;
374   }
375   CPDF_Dictionary* pClassMap =
376       m_pTree->m_pTreeRoot->GetDict(FX_BSTRC("ClassMap"));
377   if (pClassMap == NULL) {
378     return NULL;
379   }
380   if (pC->GetType() == PDFOBJ_ARRAY) {
381     CPDF_Array* pArray = (CPDF_Array*)pC;
382     for (FX_DWORD i = 0; i < pArray->GetCount(); i++) {
383       CFX_ByteString class_name = pArray->GetString(i);
384       CPDF_Dictionary* pClassDict = pClassMap->GetDict(class_name);
385       if (pClassDict && pClassDict->GetString(FX_BSTRC("O")) == owner) {
386         return pClassDict->GetElementValue(name);
387       }
388     }
389     return NULL;
390   }
391   CFX_ByteString class_name = pC->GetString();
392   CPDF_Dictionary* pClassDict = pClassMap->GetDict(class_name);
393   if (pClassDict && pClassDict->GetString(FX_BSTRC("O")) == owner) {
394     return pClassDict->GetElementValue(name);
395   }
396   return NULL;
397 }
398 CPDF_Object* CPDF_StructElementImpl::GetAttr(const CFX_ByteStringC& owner,
399                                              const CFX_ByteStringC& name,
400                                              FX_BOOL bInheritable,
401                                              int subindex) {
402   CPDF_Object* pAttr = GetAttr(owner, name, bInheritable);
403   if (pAttr == NULL || subindex == -1 || pAttr->GetType() != PDFOBJ_ARRAY) {
404     return pAttr;
405   }
406   CPDF_Array* pArray = (CPDF_Array*)pAttr;
407   if (subindex >= (int)pArray->GetCount()) {
408     return pAttr;
409   }
410   return pArray->GetElementValue(subindex);
411 }
412 CFX_ByteString CPDF_StructElementImpl::GetName(
413     const CFX_ByteStringC& owner,
414     const CFX_ByteStringC& name,
415     const CFX_ByteStringC& default_value,
416     FX_BOOL bInheritable,
417     int subindex) {
418   CPDF_Object* pAttr = GetAttr(owner, name, bInheritable, subindex);
419   if (pAttr == NULL || pAttr->GetType() != PDFOBJ_NAME) {
420     return default_value;
421   }
422   return pAttr->GetString();
423 }
424 FX_ARGB CPDF_StructElementImpl::GetColor(const CFX_ByteStringC& owner,
425                                          const CFX_ByteStringC& name,
426                                          FX_ARGB default_value,
427                                          FX_BOOL bInheritable,
428                                          int subindex) {
429   CPDF_Object* pAttr = GetAttr(owner, name, bInheritable, subindex);
430   if (pAttr == NULL || pAttr->GetType() != PDFOBJ_ARRAY) {
431     return default_value;
432   }
433   CPDF_Array* pArray = (CPDF_Array*)pAttr;
434   return 0xff000000 | ((int)(pArray->GetNumber(0) * 255) << 16) |
435          ((int)(pArray->GetNumber(1) * 255) << 8) |
436          (int)(pArray->GetNumber(2) * 255);
437 }
438 FX_FLOAT CPDF_StructElementImpl::GetNumber(const CFX_ByteStringC& owner,
439                                            const CFX_ByteStringC& name,
440                                            FX_FLOAT default_value,
441                                            FX_BOOL bInheritable,
442                                            int subindex) {
443   CPDF_Object* pAttr = GetAttr(owner, name, bInheritable, subindex);
444   if (pAttr == NULL || pAttr->GetType() != PDFOBJ_NUMBER) {
445     return default_value;
446   }
447   return pAttr->GetNumber();
448 }
449 int CPDF_StructElementImpl::GetInteger(const CFX_ByteStringC& owner,
450                                        const CFX_ByteStringC& name,
451                                        int default_value,
452                                        FX_BOOL bInheritable,
453                                        int subindex) {
454   CPDF_Object* pAttr = GetAttr(owner, name, bInheritable, subindex);
455   if (pAttr == NULL || pAttr->GetType() != PDFOBJ_NUMBER) {
456     return default_value;
457   }
458   return pAttr->GetInteger();
459 }