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