blob: 58ec0838368c91e9ef7be86e17c8f99d4fd6e07c [file] [log] [blame]
K. Moon832a6942022-10-31 20:11:31 +00001// Copyright 2016 The PDFium Authors
jaepark611adb82016-08-17 11:34:36 -07002// 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"
Tom Sepez5ea5fa92022-03-08 00:15:23 +000013#include "core/fxcrt/stl_util.h"
dsinclair114e46a2016-09-29 17:18:21 -070014#include "fpdfsdk/cpdfsdk_annot.h"
15#include "fpdfsdk/cpdfsdk_pageview.h"
Tom Sepez63150f12021-09-23 01:28:39 +000016#include "fpdfsdk/cpdfsdk_widget.h"
Lei Zhang87e3d7a2021-06-17 19:40:28 +000017#include "third_party/base/containers/contains.h"
jaepark611adb82016-08-17 11:34:36 -070018
dsinclair8afe15a2016-10-05 12:00:34 -070019namespace {
20
21CFX_FloatRect GetAnnotRect(const CPDFSDK_Annot* pAnnot) {
22 return pAnnot->GetPDFAnnot()->GetRect();
23}
24
25bool CompareByLeftAscending(const CPDFSDK_Annot* p1, const CPDFSDK_Annot* p2) {
jaepark611adb82016-08-17 11:34:36 -070026 return GetAnnotRect(p1).left < GetAnnotRect(p2).left;
27}
28
dsinclair8afe15a2016-10-05 12:00:34 -070029bool CompareByTopDescending(const CPDFSDK_Annot* p1, const CPDFSDK_Annot* p2) {
jaepark611adb82016-08-17 11:34:36 -070030 return GetAnnotRect(p1).top > GetAnnotRect(p2).top;
31}
32
dsinclair8afe15a2016-10-05 12:00:34 -070033} // namespace
34
Neha Gupta1eb6ddd2020-03-19 08:37:15 +000035CPDFSDK_AnnotIterator::CPDFSDK_AnnotIterator(
36 CPDFSDK_PageView* pPageView,
37 const std::vector<CPDF_Annot::Subtype>& subtypes_to_iterate)
Lei Zhang7fb895f2018-10-09 19:02:24 +000038 : m_pPageView(pPageView),
Neha Gupta1eb6ddd2020-03-19 08:37:15 +000039 m_subtypes(subtypes_to_iterate),
Lei Zhang7fb895f2018-10-09 19:02:24 +000040 m_eTabOrder(GetTabOrder(pPageView)) {
jaepark611adb82016-08-17 11:34:36 -070041 GenerateResults();
42}
43
Lei Zhang81535612018-10-09 21:15:17 +000044CPDFSDK_AnnotIterator::~CPDFSDK_AnnotIterator() = default;
jaepark611adb82016-08-17 11:34:36 -070045
Dan Sinclaircbf76e62018-03-28 21:00:35 +000046CPDFSDK_Annot* CPDFSDK_AnnotIterator::GetFirstAnnot() {
jaepark611adb82016-08-17 11:34:36 -070047 return m_Annots.empty() ? nullptr : m_Annots.front();
48}
49
Dan Sinclaircbf76e62018-03-28 21:00:35 +000050CPDFSDK_Annot* CPDFSDK_AnnotIterator::GetLastAnnot() {
jaepark611adb82016-08-17 11:34:36 -070051 return m_Annots.empty() ? nullptr : m_Annots.back();
52}
53
Dan Sinclaircbf76e62018-03-28 21:00:35 +000054CPDFSDK_Annot* CPDFSDK_AnnotIterator::GetNextAnnot(CPDFSDK_Annot* pAnnot) {
jaepark611adb82016-08-17 11:34:36 -070055 auto iter = std::find(m_Annots.begin(), m_Annots.end(), pAnnot);
56 if (iter == m_Annots.end())
57 return nullptr;
58 ++iter;
59 if (iter == m_Annots.end())
Ankit Kumarafc869e2020-04-07 21:21:51 +000060 return nullptr;
jaepark611adb82016-08-17 11:34:36 -070061 return *iter;
62}
63
Dan Sinclaircbf76e62018-03-28 21:00:35 +000064CPDFSDK_Annot* CPDFSDK_AnnotIterator::GetPrevAnnot(CPDFSDK_Annot* pAnnot) {
jaepark611adb82016-08-17 11:34:36 -070065 auto iter = std::find(m_Annots.begin(), m_Annots.end(), pAnnot);
Ankit Kumarafc869e2020-04-07 21:21:51 +000066 if (iter == m_Annots.begin() || iter == m_Annots.end())
jaepark611adb82016-08-17 11:34:36 -070067 return nullptr;
jaepark611adb82016-08-17 11:34:36 -070068 return *(--iter);
69}
70
Tom Sepez00c19bf2021-04-05 17:38:15 +000071void CPDFSDK_AnnotIterator::CollectAnnots(
72 std::vector<UnownedPtr<CPDFSDK_Annot>>* pArray) {
Lei Zhang375c2762017-03-10 14:37:14 -080073 for (auto* pAnnot : m_pPageView->GetAnnotList()) {
Tom Sepez63150f12021-09-23 01:28:39 +000074 if (pdfium::Contains(m_subtypes, pAnnot->GetAnnotSubtype())) {
75 CPDFSDK_Widget* pWidget = ToCPDFSDKWidget(pAnnot);
76 if (!pWidget || !pWidget->IsSignatureWidget())
77 pArray->emplace_back(pAnnot);
dsinclair8afe15a2016-10-05 12:00:34 -070078 }
79 }
80}
81
Dan Sinclaircbf76e62018-03-28 21:00:35 +000082CFX_FloatRect CPDFSDK_AnnotIterator::AddToAnnotsList(
Tom Sepez00c19bf2021-04-05 17:38:15 +000083 std::vector<UnownedPtr<CPDFSDK_Annot>>* sa,
dsinclair8afe15a2016-10-05 12:00:34 -070084 size_t idx) {
85 CPDFSDK_Annot* pLeftTopAnnot = sa->at(idx);
86 CFX_FloatRect rcLeftTop = GetAnnotRect(pLeftTopAnnot);
Tom Sepez00c19bf2021-04-05 17:38:15 +000087 m_Annots.emplace_back(pLeftTopAnnot);
dsinclair8afe15a2016-10-05 12:00:34 -070088 sa->erase(sa->begin() + idx);
89 return rcLeftTop;
90}
91
Tom Sepez00c19bf2021-04-05 17:38:15 +000092void CPDFSDK_AnnotIterator::AddSelectedToAnnots(
93 std::vector<UnownedPtr<CPDFSDK_Annot>>* sa,
94 std::vector<size_t>* aSelect) {
dsinclair8afe15a2016-10-05 12:00:34 -070095 for (size_t i = 0; i < aSelect->size(); ++i)
Tom Sepez00c19bf2021-04-05 17:38:15 +000096 m_Annots.emplace_back(sa->at(aSelect->at(i)));
dsinclair8afe15a2016-10-05 12:00:34 -070097
Tom Sepez5ea5fa92022-03-08 00:15:23 +000098 for (size_t i = aSelect->size(); i > 0; --i)
99 sa->erase(sa->begin() + aSelect->at(i - 1));
dsinclair8afe15a2016-10-05 12:00:34 -0700100}
101
Lei Zhangb05abe42021-06-07 19:20:55 +0000102// static
103CPDFSDK_AnnotIterator::TabOrder CPDFSDK_AnnotIterator::GetTabOrder(
104 CPDFSDK_PageView* pPageView) {
105 CPDF_Page* pPDFPage = pPageView->GetPDFPage();
Tom Sepez27151a62022-09-14 19:48:59 +0000106 ByteString sTabs = pPDFPage->GetDict()->GetByteStringFor("Tabs");
Lei Zhangb05abe42021-06-07 19:20:55 +0000107 if (sTabs == "R")
108 return kRow;
109 if (sTabs == "C")
110 return kColumn;
111 return kStructure;
112}
113
Dan Sinclaircbf76e62018-03-28 21:00:35 +0000114void CPDFSDK_AnnotIterator::GenerateResults() {
jaepark611adb82016-08-17 11:34:36 -0700115 switch (m_eTabOrder) {
Lei Zhangb05abe42021-06-07 19:20:55 +0000116 case kStructure:
dsinclair8afe15a2016-10-05 12:00:34 -0700117 CollectAnnots(&m_Annots);
jaepark611adb82016-08-17 11:34:36 -0700118 break;
dsinclair8afe15a2016-10-05 12:00:34 -0700119
Lei Zhangb05abe42021-06-07 19:20:55 +0000120 case kRow: {
Tom Sepez00c19bf2021-04-05 17:38:15 +0000121 std::vector<UnownedPtr<CPDFSDK_Annot>> sa;
dsinclair8afe15a2016-10-05 12:00:34 -0700122 CollectAnnots(&sa);
jaepark611adb82016-08-17 11:34:36 -0700123 std::sort(sa.begin(), sa.end(), CompareByLeftAscending);
dsinclair8afe15a2016-10-05 12:00:34 -0700124
jaepark611adb82016-08-17 11:34:36 -0700125 while (!sa.empty()) {
126 int nLeftTopIndex = -1;
Dan Sinclair05df0752017-03-14 14:43:42 -0400127 float fTop = 0.0f;
Tom Sepez5ea5fa92022-03-08 00:15:23 +0000128 for (int i = fxcrt::CollectionSize<int>(sa) - 1; i >= 0; i--) {
jaepark611adb82016-08-17 11:34:36 -0700129 CFX_FloatRect rcAnnot = GetAnnotRect(sa[i]);
130 if (rcAnnot.top > fTop) {
131 nLeftTopIndex = i;
132 fTop = rcAnnot.top;
133 }
134 }
dsinclair8afe15a2016-10-05 12:00:34 -0700135 if (nLeftTopIndex < 0)
136 continue;
jaepark611adb82016-08-17 11:34:36 -0700137
dsinclair8afe15a2016-10-05 12:00:34 -0700138 CFX_FloatRect rcLeftTop = AddToAnnotsList(&sa, nLeftTopIndex);
jaepark611adb82016-08-17 11:34:36 -0700139
dsinclair8afe15a2016-10-05 12:00:34 -0700140 std::vector<size_t> aSelect;
141 for (size_t i = 0; i < sa.size(); ++i) {
142 CFX_FloatRect rcAnnot = GetAnnotRect(sa[i]);
Dan Sinclair05df0752017-03-14 14:43:42 -0400143 float fCenterY = (rcAnnot.top + rcAnnot.bottom) / 2.0f;
dsinclair8afe15a2016-10-05 12:00:34 -0700144 if (fCenterY > rcLeftTop.bottom && fCenterY < rcLeftTop.top)
145 aSelect.push_back(i);
jaepark611adb82016-08-17 11:34:36 -0700146 }
dsinclair8afe15a2016-10-05 12:00:34 -0700147 AddSelectedToAnnots(&sa, &aSelect);
jaepark611adb82016-08-17 11:34:36 -0700148 }
149 break;
150 }
dsinclair8afe15a2016-10-05 12:00:34 -0700151
Lei Zhangb05abe42021-06-07 19:20:55 +0000152 case kColumn: {
Tom Sepez00c19bf2021-04-05 17:38:15 +0000153 std::vector<UnownedPtr<CPDFSDK_Annot>> sa;
dsinclair8afe15a2016-10-05 12:00:34 -0700154 CollectAnnots(&sa);
jaepark611adb82016-08-17 11:34:36 -0700155 std::sort(sa.begin(), sa.end(), CompareByTopDescending);
dsinclair8afe15a2016-10-05 12:00:34 -0700156
jaepark611adb82016-08-17 11:34:36 -0700157 while (!sa.empty()) {
158 int nLeftTopIndex = -1;
Dan Sinclair05df0752017-03-14 14:43:42 -0400159 float fLeft = -1.0f;
Tom Sepez5ea5fa92022-03-08 00:15:23 +0000160 for (int i = fxcrt::CollectionSize<int>(sa) - 1; i >= 0; --i) {
jaepark611adb82016-08-17 11:34:36 -0700161 CFX_FloatRect rcAnnot = GetAnnotRect(sa[i]);
162 if (fLeft < 0) {
163 nLeftTopIndex = 0;
164 fLeft = rcAnnot.left;
165 } else if (rcAnnot.left < fLeft) {
166 nLeftTopIndex = i;
167 fLeft = rcAnnot.left;
168 }
169 }
dsinclair8afe15a2016-10-05 12:00:34 -0700170 if (nLeftTopIndex < 0)
171 continue;
jaepark611adb82016-08-17 11:34:36 -0700172
dsinclair8afe15a2016-10-05 12:00:34 -0700173 CFX_FloatRect rcLeftTop = AddToAnnotsList(&sa, nLeftTopIndex);
jaepark611adb82016-08-17 11:34:36 -0700174
dsinclair8afe15a2016-10-05 12:00:34 -0700175 std::vector<size_t> aSelect;
176 for (size_t i = 0; i < sa.size(); ++i) {
177 CFX_FloatRect rcAnnot = GetAnnotRect(sa[i]);
Dan Sinclair05df0752017-03-14 14:43:42 -0400178 float fCenterX = (rcAnnot.left + rcAnnot.right) / 2.0f;
dsinclair8afe15a2016-10-05 12:00:34 -0700179 if (fCenterX > rcLeftTop.left && fCenterX < rcLeftTop.right)
180 aSelect.push_back(i);
jaepark611adb82016-08-17 11:34:36 -0700181 }
dsinclair8afe15a2016-10-05 12:00:34 -0700182 AddSelectedToAnnots(&sa, &aSelect);
jaepark611adb82016-08-17 11:34:36 -0700183 }
184 break;
185 }
186 }
187}