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 "core/include/fpdfdoc/fpdf_doc.h"
8
9CPDF_LinkList::CPDF_LinkList() {
10}
11
12CPDF_LinkList::~CPDF_LinkList() {
13}
14
15const std::vector<CPDF_Dictionary*>* CPDF_LinkList::GetPageLinks(
16    CPDF_Page* pPage) {
17  FX_DWORD objnum = pPage->m_pFormDict->GetObjNum();
18  if (objnum == 0)
19    return nullptr;
20
21  auto it = m_PageMap.find(objnum);
22  if (it != m_PageMap.end())
23    return &it->second;
24
25  // std::map::operator[] forces the creation of a map entry.
26  std::vector<CPDF_Dictionary*>& page_link_list = m_PageMap[objnum];
27  LoadPageLinks(pPage, &page_link_list);
28  return &page_link_list;
29}
30
31CPDF_Link CPDF_LinkList::GetLinkAtPoint(CPDF_Page* pPage,
32                                        FX_FLOAT pdf_x,
33                                        FX_FLOAT pdf_y,
34                                        int* z_order) {
35  const std::vector<CPDF_Dictionary*>* pPageLinkList = GetPageLinks(pPage);
36  if (!pPageLinkList)
37    return CPDF_Link();
38
39  for (size_t i = pPageLinkList->size(); i > 0; --i) {
40    size_t annot_index = i - 1;
41    CPDF_Dictionary* pAnnot = (*pPageLinkList)[annot_index];
42    if (!pAnnot)
43      continue;
44
45    CPDF_Link link(pAnnot);
46    CPDF_Rect rect = link.GetRect();
47    if (!rect.Contains(pdf_x, pdf_y))
48      continue;
49
50    if (z_order)
51      *z_order = annot_index;
52    return link;
53  }
54  return CPDF_Link();
55}
56
57void CPDF_LinkList::LoadPageLinks(CPDF_Page* pPage,
58                                  std::vector<CPDF_Dictionary*>* pList) {
59  CPDF_Array* pAnnotList = pPage->m_pFormDict->GetArray("Annots");
60  if (!pAnnotList)
61    return;
62
63  for (FX_DWORD i = 0; i < pAnnotList->GetCount(); ++i) {
64    CPDF_Dictionary* pAnnot = pAnnotList->GetDict(i);
65    bool add_link = (pAnnot && pAnnot->GetString("Subtype") == "Link");
66    // Add non-links as nullptrs to preserve z-order.
67    pList->push_back(add_link ? pAnnot : nullptr);
68  }
69}
70
71CPDF_Rect CPDF_Link::GetRect() {
72  return m_pDict->GetRect("Rect");
73}
74CPDF_Dest CPDF_Link::GetDest(CPDF_Document* pDoc) {
75  CPDF_Object* pDest = m_pDict->GetElementValue("Dest");
76  if (!pDest)
77    return CPDF_Dest();
78
79  if (pDest->IsString() || pDest->IsName()) {
80    CPDF_NameTree name_tree(pDoc, "Dests");
81    CFX_ByteStringC name = pDest->GetString();
82    return CPDF_Dest(name_tree.LookupNamedDest(pDoc, name));
83  }
84  if (CPDF_Array* pArray = pDest->AsArray())
85    return CPDF_Dest(pArray);
86  return CPDF_Dest();
87}
88CPDF_Action CPDF_Link::GetAction() {
89  return CPDF_Action(m_pDict->GetDict("A"));
90}
91