• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2016 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 "fpdfsdk/cpdfsdk_annotiterator.h"
8 
9 #include <algorithm>
10 
11 #include "core/fpdfapi/page/cpdf_page.h"
12 #include "core/fpdfapi/parser/cpdf_dictionary.h"
13 #include "fpdfsdk/cpdfsdk_annot.h"
14 #include "fpdfsdk/cpdfsdk_pageview.h"
15 
16 namespace {
17 
GetAnnotRect(const CPDFSDK_Annot * pAnnot)18 CFX_FloatRect GetAnnotRect(const CPDFSDK_Annot* pAnnot) {
19   return pAnnot->GetPDFAnnot()->GetRect();
20 }
21 
CompareByLeftAscending(const CPDFSDK_Annot * p1,const CPDFSDK_Annot * p2)22 bool CompareByLeftAscending(const CPDFSDK_Annot* p1, const CPDFSDK_Annot* p2) {
23   return GetAnnotRect(p1).left < GetAnnotRect(p2).left;
24 }
25 
CompareByTopDescending(const CPDFSDK_Annot * p1,const CPDFSDK_Annot * p2)26 bool CompareByTopDescending(const CPDFSDK_Annot* p1, const CPDFSDK_Annot* p2) {
27   return GetAnnotRect(p1).top > GetAnnotRect(p2).top;
28 }
29 
GetTabOrder(CPDFSDK_PageView * pPageView)30 CPDFSDK_AnnotIterator::TabOrder GetTabOrder(CPDFSDK_PageView* pPageView) {
31   CPDF_Page* pPDFPage = pPageView->GetPDFPage();
32   ByteString sTabs = pPDFPage->GetDict()->GetStringFor("Tabs");
33   if (sTabs == "R")
34     return CPDFSDK_AnnotIterator::ROW;
35   if (sTabs == "C")
36     return CPDFSDK_AnnotIterator::COLUMN;
37   return CPDFSDK_AnnotIterator::STRUCTURE;
38 }
39 
40 }  // namespace
41 
CPDFSDK_AnnotIterator(CPDFSDK_PageView * pPageView,CPDF_Annot::Subtype nAnnotSubtype)42 CPDFSDK_AnnotIterator::CPDFSDK_AnnotIterator(CPDFSDK_PageView* pPageView,
43                                              CPDF_Annot::Subtype nAnnotSubtype)
44     : m_pPageView(pPageView),
45       m_nAnnotSubtype(nAnnotSubtype),
46       m_eTabOrder(GetTabOrder(pPageView)) {
47   GenerateResults();
48 }
49 
50 CPDFSDK_AnnotIterator::~CPDFSDK_AnnotIterator() = default;
51 
GetFirstAnnot()52 CPDFSDK_Annot* CPDFSDK_AnnotIterator::GetFirstAnnot() {
53   return m_Annots.empty() ? nullptr : m_Annots.front();
54 }
55 
GetLastAnnot()56 CPDFSDK_Annot* CPDFSDK_AnnotIterator::GetLastAnnot() {
57   return m_Annots.empty() ? nullptr : m_Annots.back();
58 }
59 
GetNextAnnot(CPDFSDK_Annot * pAnnot)60 CPDFSDK_Annot* CPDFSDK_AnnotIterator::GetNextAnnot(CPDFSDK_Annot* pAnnot) {
61   auto iter = std::find(m_Annots.begin(), m_Annots.end(), pAnnot);
62   if (iter == m_Annots.end())
63     return nullptr;
64   ++iter;
65   if (iter == m_Annots.end())
66     iter = m_Annots.begin();
67   return *iter;
68 }
69 
GetPrevAnnot(CPDFSDK_Annot * pAnnot)70 CPDFSDK_Annot* CPDFSDK_AnnotIterator::GetPrevAnnot(CPDFSDK_Annot* pAnnot) {
71   auto iter = std::find(m_Annots.begin(), m_Annots.end(), pAnnot);
72   if (iter == m_Annots.end())
73     return nullptr;
74   if (iter == m_Annots.begin())
75     iter = m_Annots.end();
76   return *(--iter);
77 }
78 
CollectAnnots(std::vector<CPDFSDK_Annot * > * pArray)79 void CPDFSDK_AnnotIterator::CollectAnnots(std::vector<CPDFSDK_Annot*>* pArray) {
80   for (auto* pAnnot : m_pPageView->GetAnnotList()) {
81     if (pAnnot->GetAnnotSubtype() == m_nAnnotSubtype &&
82         !pAnnot->IsSignatureWidget()) {
83       pArray->push_back(pAnnot);
84     }
85   }
86 }
87 
AddToAnnotsList(std::vector<CPDFSDK_Annot * > * sa,size_t idx)88 CFX_FloatRect CPDFSDK_AnnotIterator::AddToAnnotsList(
89     std::vector<CPDFSDK_Annot*>* sa,
90     size_t idx) {
91   CPDFSDK_Annot* pLeftTopAnnot = sa->at(idx);
92   CFX_FloatRect rcLeftTop = GetAnnotRect(pLeftTopAnnot);
93   m_Annots.push_back(pLeftTopAnnot);
94   sa->erase(sa->begin() + idx);
95   return rcLeftTop;
96 }
97 
AddSelectedToAnnots(std::vector<CPDFSDK_Annot * > * sa,std::vector<size_t> * aSelect)98 void CPDFSDK_AnnotIterator::AddSelectedToAnnots(std::vector<CPDFSDK_Annot*>* sa,
99                                                 std::vector<size_t>* aSelect) {
100   for (size_t i = 0; i < aSelect->size(); ++i)
101     m_Annots.push_back(sa->at(aSelect->at(i)));
102 
103   for (int i = aSelect->size() - 1; i >= 0; --i)
104     sa->erase(sa->begin() + aSelect->at(i));
105 }
106 
GenerateResults()107 void CPDFSDK_AnnotIterator::GenerateResults() {
108   switch (m_eTabOrder) {
109     case STRUCTURE:
110       CollectAnnots(&m_Annots);
111       break;
112 
113     case ROW: {
114       std::vector<CPDFSDK_Annot*> sa;
115       CollectAnnots(&sa);
116       std::sort(sa.begin(), sa.end(), CompareByLeftAscending);
117 
118       while (!sa.empty()) {
119         int nLeftTopIndex = -1;
120         float fTop = 0.0f;
121         for (int i = sa.size() - 1; i >= 0; i--) {
122           CFX_FloatRect rcAnnot = GetAnnotRect(sa[i]);
123           if (rcAnnot.top > fTop) {
124             nLeftTopIndex = i;
125             fTop = rcAnnot.top;
126           }
127         }
128         if (nLeftTopIndex < 0)
129           continue;
130 
131         CFX_FloatRect rcLeftTop = AddToAnnotsList(&sa, nLeftTopIndex);
132 
133         std::vector<size_t> aSelect;
134         for (size_t i = 0; i < sa.size(); ++i) {
135           CFX_FloatRect rcAnnot = GetAnnotRect(sa[i]);
136           float fCenterY = (rcAnnot.top + rcAnnot.bottom) / 2.0f;
137           if (fCenterY > rcLeftTop.bottom && fCenterY < rcLeftTop.top)
138             aSelect.push_back(i);
139         }
140         AddSelectedToAnnots(&sa, &aSelect);
141       }
142       break;
143     }
144 
145     case COLUMN: {
146       std::vector<CPDFSDK_Annot*> sa;
147       CollectAnnots(&sa);
148       std::sort(sa.begin(), sa.end(), CompareByTopDescending);
149 
150       while (!sa.empty()) {
151         int nLeftTopIndex = -1;
152         float fLeft = -1.0f;
153         for (int i = sa.size() - 1; i >= 0; --i) {
154           CFX_FloatRect rcAnnot = GetAnnotRect(sa[i]);
155           if (fLeft < 0) {
156             nLeftTopIndex = 0;
157             fLeft = rcAnnot.left;
158           } else if (rcAnnot.left < fLeft) {
159             nLeftTopIndex = i;
160             fLeft = rcAnnot.left;
161           }
162         }
163         if (nLeftTopIndex < 0)
164           continue;
165 
166         CFX_FloatRect rcLeftTop = AddToAnnotsList(&sa, nLeftTopIndex);
167 
168         std::vector<size_t> aSelect;
169         for (size_t i = 0; i < sa.size(); ++i) {
170           CFX_FloatRect rcAnnot = GetAnnotRect(sa[i]);
171           float fCenterX = (rcAnnot.left + rcAnnot.right) / 2.0f;
172           if (fCenterX > rcLeftTop.left && fCenterX < rcLeftTop.right)
173             aSelect.push_back(i);
174         }
175         AddSelectedToAnnots(&sa, &aSelect);
176       }
177       break;
178     }
179   }
180 }
181