blob: 1c20f4c8feea637fa161f276e302fdfc2225e6df [file] [log] [blame]
jaepark611adb82016-08-17 11:34:36 -07001// 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
Dan Sinclaircbf76e62018-03-28 21:00:35 +00007#include "fpdfsdk/cpdfsdk_annotiterator.h"
jaepark611adb82016-08-17 11:34:36 -07008
Dan Sinclair85c8e7f2016-11-21 13:50:32 -05009#include <algorithm>
10
dsinclair41872fa2016-10-04 11:29:35 -070011#include "core/fpdfapi/page/cpdf_page.h"
Lei Zhang81535612018-10-09 21:15:17 +000012#include "core/fpdfapi/parser/cpdf_dictionary.h"
dsinclair114e46a2016-09-29 17:18:21 -070013#include "fpdfsdk/cpdfsdk_annot.h"
14#include "fpdfsdk/cpdfsdk_pageview.h"
Lei Zhang87e3d7a2021-06-17 19:40:28 +000015#include "third_party/base/containers/contains.h"
jaepark611adb82016-08-17 11:34:36 -070016
dsinclair8afe15a2016-10-05 12:00:34 -070017namespace {
18
19CFX_FloatRect GetAnnotRect(const CPDFSDK_Annot* pAnnot) {
20 return pAnnot->GetPDFAnnot()->GetRect();
21}
22
23bool CompareByLeftAscending(const CPDFSDK_Annot* p1, const CPDFSDK_Annot* p2) {
jaepark611adb82016-08-17 11:34:36 -070024 return GetAnnotRect(p1).left < GetAnnotRect(p2).left;
25}
26
dsinclair8afe15a2016-10-05 12:00:34 -070027bool CompareByTopDescending(const CPDFSDK_Annot* p1, const CPDFSDK_Annot* p2) {
jaepark611adb82016-08-17 11:34:36 -070028 return GetAnnotRect(p1).top > GetAnnotRect(p2).top;
29}
30
dsinclair8afe15a2016-10-05 12:00:34 -070031} // namespace
32
Neha Gupta1eb6ddd2020-03-19 08:37:15 +000033CPDFSDK_AnnotIterator::CPDFSDK_AnnotIterator(
34 CPDFSDK_PageView* pPageView,
35 const std::vector<CPDF_Annot::Subtype>& subtypes_to_iterate)
Lei Zhang7fb895f2018-10-09 19:02:24 +000036 : m_pPageView(pPageView),
Neha Gupta1eb6ddd2020-03-19 08:37:15 +000037 m_subtypes(subtypes_to_iterate),
Lei Zhang7fb895f2018-10-09 19:02:24 +000038 m_eTabOrder(GetTabOrder(pPageView)) {
jaepark611adb82016-08-17 11:34:36 -070039 GenerateResults();
40}
41
Lei Zhang81535612018-10-09 21:15:17 +000042CPDFSDK_AnnotIterator::~CPDFSDK_AnnotIterator() = default;
jaepark611adb82016-08-17 11:34:36 -070043
Dan Sinclaircbf76e62018-03-28 21:00:35 +000044CPDFSDK_Annot* CPDFSDK_AnnotIterator::GetFirstAnnot() {
jaepark611adb82016-08-17 11:34:36 -070045 return m_Annots.empty() ? nullptr : m_Annots.front();
46}
47
Dan Sinclaircbf76e62018-03-28 21:00:35 +000048CPDFSDK_Annot* CPDFSDK_AnnotIterator::GetLastAnnot() {
jaepark611adb82016-08-17 11:34:36 -070049 return m_Annots.empty() ? nullptr : m_Annots.back();
50}
51
Dan Sinclaircbf76e62018-03-28 21:00:35 +000052CPDFSDK_Annot* CPDFSDK_AnnotIterator::GetNextAnnot(CPDFSDK_Annot* pAnnot) {
jaepark611adb82016-08-17 11:34:36 -070053 auto iter = std::find(m_Annots.begin(), m_Annots.end(), pAnnot);
54 if (iter == m_Annots.end())
55 return nullptr;
56 ++iter;
57 if (iter == m_Annots.end())
Ankit Kumarafc869e2020-04-07 21:21:51 +000058 return nullptr;
jaepark611adb82016-08-17 11:34:36 -070059 return *iter;
60}
61
Dan Sinclaircbf76e62018-03-28 21:00:35 +000062CPDFSDK_Annot* CPDFSDK_AnnotIterator::GetPrevAnnot(CPDFSDK_Annot* pAnnot) {
jaepark611adb82016-08-17 11:34:36 -070063 auto iter = std::find(m_Annots.begin(), m_Annots.end(), pAnnot);
Ankit Kumarafc869e2020-04-07 21:21:51 +000064 if (iter == m_Annots.begin() || iter == m_Annots.end())
jaepark611adb82016-08-17 11:34:36 -070065 return nullptr;
jaepark611adb82016-08-17 11:34:36 -070066 return *(--iter);
67}
68
Tom Sepez00c19bf2021-04-05 17:38:15 +000069void CPDFSDK_AnnotIterator::CollectAnnots(
70 std::vector<UnownedPtr<CPDFSDK_Annot>>* pArray) {
Lei Zhang375c2762017-03-10 14:37:14 -080071 for (auto* pAnnot : m_pPageView->GetAnnotList()) {
Lei Zhangf245ae62020-05-15 21:49:46 +000072 if (pdfium::Contains(m_subtypes, pAnnot->GetAnnotSubtype()) &&
dsinclair8afe15a2016-10-05 12:00:34 -070073 !pAnnot->IsSignatureWidget()) {
Tom Sepez00c19bf2021-04-05 17:38:15 +000074 pArray->emplace_back(pAnnot);
dsinclair8afe15a2016-10-05 12:00:34 -070075 }
76 }
77}
78
Dan Sinclaircbf76e62018-03-28 21:00:35 +000079CFX_FloatRect CPDFSDK_AnnotIterator::AddToAnnotsList(
Tom Sepez00c19bf2021-04-05 17:38:15 +000080 std::vector<UnownedPtr<CPDFSDK_Annot>>* sa,
dsinclair8afe15a2016-10-05 12:00:34 -070081 size_t idx) {
82 CPDFSDK_Annot* pLeftTopAnnot = sa->at(idx);
83 CFX_FloatRect rcLeftTop = GetAnnotRect(pLeftTopAnnot);
Tom Sepez00c19bf2021-04-05 17:38:15 +000084 m_Annots.emplace_back(pLeftTopAnnot);
dsinclair8afe15a2016-10-05 12:00:34 -070085 sa->erase(sa->begin() + idx);
86 return rcLeftTop;
87}
88
Tom Sepez00c19bf2021-04-05 17:38:15 +000089void CPDFSDK_AnnotIterator::AddSelectedToAnnots(
90 std::vector<UnownedPtr<CPDFSDK_Annot>>* sa,
91 std::vector<size_t>* aSelect) {
dsinclair8afe15a2016-10-05 12:00:34 -070092 for (size_t i = 0; i < aSelect->size(); ++i)
Tom Sepez00c19bf2021-04-05 17:38:15 +000093 m_Annots.emplace_back(sa->at(aSelect->at(i)));
dsinclair8afe15a2016-10-05 12:00:34 -070094
95 for (int i = aSelect->size() - 1; i >= 0; --i)
96 sa->erase(sa->begin() + aSelect->at(i));
97}
98
Lei Zhangb05abe42021-06-07 19:20:55 +000099// static
100CPDFSDK_AnnotIterator::TabOrder CPDFSDK_AnnotIterator::GetTabOrder(
101 CPDFSDK_PageView* pPageView) {
102 CPDF_Page* pPDFPage = pPageView->GetPDFPage();
103 ByteString sTabs = pPDFPage->GetDict()->GetStringFor("Tabs");
104 if (sTabs == "R")
105 return kRow;
106 if (sTabs == "C")
107 return kColumn;
108 return kStructure;
109}
110
Dan Sinclaircbf76e62018-03-28 21:00:35 +0000111void CPDFSDK_AnnotIterator::GenerateResults() {
jaepark611adb82016-08-17 11:34:36 -0700112 switch (m_eTabOrder) {
Lei Zhangb05abe42021-06-07 19:20:55 +0000113 case kStructure:
dsinclair8afe15a2016-10-05 12:00:34 -0700114 CollectAnnots(&m_Annots);
jaepark611adb82016-08-17 11:34:36 -0700115 break;
dsinclair8afe15a2016-10-05 12:00:34 -0700116
Lei Zhangb05abe42021-06-07 19:20:55 +0000117 case kRow: {
Tom Sepez00c19bf2021-04-05 17:38:15 +0000118 std::vector<UnownedPtr<CPDFSDK_Annot>> sa;
dsinclair8afe15a2016-10-05 12:00:34 -0700119 CollectAnnots(&sa);
jaepark611adb82016-08-17 11:34:36 -0700120 std::sort(sa.begin(), sa.end(), CompareByLeftAscending);
dsinclair8afe15a2016-10-05 12:00:34 -0700121
jaepark611adb82016-08-17 11:34:36 -0700122 while (!sa.empty()) {
123 int nLeftTopIndex = -1;
Dan Sinclair05df0752017-03-14 14:43:42 -0400124 float fTop = 0.0f;
jaepark611adb82016-08-17 11:34:36 -0700125 for (int i = sa.size() - 1; i >= 0; i--) {
126 CFX_FloatRect rcAnnot = GetAnnotRect(sa[i]);
127 if (rcAnnot.top > fTop) {
128 nLeftTopIndex = i;
129 fTop = rcAnnot.top;
130 }
131 }
dsinclair8afe15a2016-10-05 12:00:34 -0700132 if (nLeftTopIndex < 0)
133 continue;
jaepark611adb82016-08-17 11:34:36 -0700134
dsinclair8afe15a2016-10-05 12:00:34 -0700135 CFX_FloatRect rcLeftTop = AddToAnnotsList(&sa, nLeftTopIndex);
jaepark611adb82016-08-17 11:34:36 -0700136
dsinclair8afe15a2016-10-05 12:00:34 -0700137 std::vector<size_t> aSelect;
138 for (size_t i = 0; i < sa.size(); ++i) {
139 CFX_FloatRect rcAnnot = GetAnnotRect(sa[i]);
Dan Sinclair05df0752017-03-14 14:43:42 -0400140 float fCenterY = (rcAnnot.top + rcAnnot.bottom) / 2.0f;
dsinclair8afe15a2016-10-05 12:00:34 -0700141 if (fCenterY > rcLeftTop.bottom && fCenterY < rcLeftTop.top)
142 aSelect.push_back(i);
jaepark611adb82016-08-17 11:34:36 -0700143 }
dsinclair8afe15a2016-10-05 12:00:34 -0700144 AddSelectedToAnnots(&sa, &aSelect);
jaepark611adb82016-08-17 11:34:36 -0700145 }
146 break;
147 }
dsinclair8afe15a2016-10-05 12:00:34 -0700148
Lei Zhangb05abe42021-06-07 19:20:55 +0000149 case kColumn: {
Tom Sepez00c19bf2021-04-05 17:38:15 +0000150 std::vector<UnownedPtr<CPDFSDK_Annot>> sa;
dsinclair8afe15a2016-10-05 12:00:34 -0700151 CollectAnnots(&sa);
jaepark611adb82016-08-17 11:34:36 -0700152 std::sort(sa.begin(), sa.end(), CompareByTopDescending);
dsinclair8afe15a2016-10-05 12:00:34 -0700153
jaepark611adb82016-08-17 11:34:36 -0700154 while (!sa.empty()) {
155 int nLeftTopIndex = -1;
Dan Sinclair05df0752017-03-14 14:43:42 -0400156 float fLeft = -1.0f;
jaepark611adb82016-08-17 11:34:36 -0700157 for (int i = sa.size() - 1; i >= 0; --i) {
158 CFX_FloatRect rcAnnot = GetAnnotRect(sa[i]);
159 if (fLeft < 0) {
160 nLeftTopIndex = 0;
161 fLeft = rcAnnot.left;
162 } else if (rcAnnot.left < fLeft) {
163 nLeftTopIndex = i;
164 fLeft = rcAnnot.left;
165 }
166 }
dsinclair8afe15a2016-10-05 12:00:34 -0700167 if (nLeftTopIndex < 0)
168 continue;
jaepark611adb82016-08-17 11:34:36 -0700169
dsinclair8afe15a2016-10-05 12:00:34 -0700170 CFX_FloatRect rcLeftTop = AddToAnnotsList(&sa, nLeftTopIndex);
jaepark611adb82016-08-17 11:34:36 -0700171
dsinclair8afe15a2016-10-05 12:00:34 -0700172 std::vector<size_t> aSelect;
173 for (size_t i = 0; i < sa.size(); ++i) {
174 CFX_FloatRect rcAnnot = GetAnnotRect(sa[i]);
Dan Sinclair05df0752017-03-14 14:43:42 -0400175 float fCenterX = (rcAnnot.left + rcAnnot.right) / 2.0f;
dsinclair8afe15a2016-10-05 12:00:34 -0700176 if (fCenterX > rcLeftTop.left && fCenterX < rcLeftTop.right)
177 aSelect.push_back(i);
jaepark611adb82016-08-17 11:34:36 -0700178 }
dsinclair8afe15a2016-10-05 12:00:34 -0700179 AddSelectedToAnnots(&sa, &aSelect);
jaepark611adb82016-08-17 11:34:36 -0700180 }
181 break;
182 }
183 }
184}