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