Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
cpdfsdk_annotiterator.cpp
Go to the documentation of this file.
1// Copyright 2016 The PDFium Authors
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 "core/fxcrt/stl_util.h"
14#include "fpdfsdk/cpdfsdk_annot.h"
15#include "fpdfsdk/cpdfsdk_pageview.h"
16#include "fpdfsdk/cpdfsdk_widget.h"
17#include "third_party/base/containers/adapters.h"
18#include "third_party/base/containers/contains.h"
19#include "third_party/base/containers/span.h"
20
21namespace {
22
23CFX_FloatRect GetAnnotRect(const CPDFSDK_Annot* pAnnot) {
24 return pAnnot->GetPDFAnnot()->GetRect();
25}
26
27bool CompareByLeftAscending(const CPDFSDK_Annot* p1, const CPDFSDK_Annot* p2) {
28 return GetAnnotRect(p1).left < GetAnnotRect(p2).left;
29}
30
31bool CompareByTopDescending(const CPDFSDK_Annot* p1, const CPDFSDK_Annot* p2) {
32 return GetAnnotRect(p1).top > GetAnnotRect(p2).top;
33}
34
35} // namespace
36
38 CPDFSDK_PageView* pPageView,
39 const std::vector<CPDF_Annot::Subtype>& subtypes_to_iterate)
42 m_eTabOrder(GetTabOrder(pPageView)) {
43 GenerateResults();
44}
45
47
49 return m_Annots.empty() ? nullptr : m_Annots.front();
50}
51
53 return m_Annots.empty() ? nullptr : m_Annots.back();
54}
55
57 auto iter = std::find(m_Annots.begin(), m_Annots.end(), pAnnot);
58 if (iter == m_Annots.end())
59 return nullptr;
60 ++iter;
61 if (iter == m_Annots.end())
62 return nullptr;
63 return *iter;
64}
65
67 auto iter = std::find(m_Annots.begin(), m_Annots.end(), pAnnot);
68 if (iter == m_Annots.begin() || iter == m_Annots.end())
69 return nullptr;
70 return *(--iter);
71}
72
73void CPDFSDK_AnnotIterator::CollectAnnots(
74 std::vector<UnownedPtr<CPDFSDK_Annot>>* pArray) {
75 for (auto* pAnnot : m_pPageView->GetAnnotList()) {
76 if (pdfium::Contains(m_subtypes, pAnnot->GetAnnotSubtype())) {
77 CPDFSDK_Widget* pWidget = ToCPDFSDKWidget(pAnnot);
78 if (!pWidget || !pWidget->IsSignatureWidget())
79 pArray->emplace_back(pAnnot);
80 }
81 }
82}
83
85 std::vector<UnownedPtr<CPDFSDK_Annot>>& sa,
86 size_t idx) {
87 CPDFSDK_Annot* pLeftTopAnnot = sa[idx];
88 CFX_FloatRect rcLeftTop = GetAnnotRect(pLeftTopAnnot);
89 m_Annots.emplace_back(pLeftTopAnnot);
90 sa.erase(sa.begin() + idx);
91 return rcLeftTop;
92}
93
94void CPDFSDK_AnnotIterator::AddSelectedToAnnots(
95 std::vector<UnownedPtr<CPDFSDK_Annot>>& sa,
96 pdfium::span<const size_t> aSelect) {
97 for (size_t select_idx : aSelect) {
98 m_Annots.emplace_back(sa[select_idx]);
99 }
100
101 for (size_t select_idx : pdfium::base::Reversed(aSelect)) {
102 sa.erase(sa.begin() + select_idx);
103 }
104}
105
106// static
107CPDFSDK_AnnotIterator::TabOrder CPDFSDK_AnnotIterator::GetTabOrder(
108 CPDFSDK_PageView* pPageView) {
109 CPDF_Page* pPDFPage = pPageView->GetPDFPage();
110 ByteString sTabs = pPDFPage->GetDict()->GetByteStringFor("Tabs");
111 if (sTabs == "R")
112 return TabOrder::kRow;
113 if (sTabs == "C")
114 return TabOrder::kColumn;
115 return TabOrder::kStructure;
116}
117
118void CPDFSDK_AnnotIterator::GenerateResults() {
119 switch (m_eTabOrder) {
120 case TabOrder::kStructure:
121 CollectAnnots(&m_Annots);
122 break;
123
124 case TabOrder::kRow: {
125 std::vector<UnownedPtr<CPDFSDK_Annot>> sa;
126 CollectAnnots(&sa);
127 std::sort(sa.begin(), sa.end(), CompareByLeftAscending);
128
129 while (!sa.empty()) {
130 int nLeftTopIndex = -1;
131 float fTop = 0.0f;
132 for (int i = fxcrt::CollectionSize<int>(sa) - 1; i >= 0; i--) {
133 CFX_FloatRect rcAnnot = GetAnnotRect(sa[i]);
134 if (rcAnnot.top > fTop) {
135 nLeftTopIndex = i;
136 fTop = rcAnnot.top;
137 }
138 }
139 if (nLeftTopIndex < 0)
140 continue;
141
142 CFX_FloatRect rcLeftTop = AddToAnnotsList(sa, nLeftTopIndex);
143
144 std::vector<size_t> aSelect;
145 for (size_t i = 0; i < sa.size(); ++i) {
146 CFX_FloatRect rcAnnot = GetAnnotRect(sa[i]);
147 float fCenterY = (rcAnnot.top + rcAnnot.bottom) / 2.0f;
148 if (fCenterY > rcLeftTop.bottom && fCenterY < rcLeftTop.top)
149 aSelect.push_back(i);
150 }
151 AddSelectedToAnnots(sa, aSelect);
152 }
153 break;
154 }
155
156 case TabOrder::kColumn: {
157 std::vector<UnownedPtr<CPDFSDK_Annot>> sa;
158 CollectAnnots(&sa);
159 std::sort(sa.begin(), sa.end(), CompareByTopDescending);
160
161 while (!sa.empty()) {
162 int nLeftTopIndex = -1;
163 float fLeft = -1.0f;
164 for (int i = fxcrt::CollectionSize<int>(sa) - 1; i >= 0; --i) {
165 CFX_FloatRect rcAnnot = GetAnnotRect(sa[i]);
166 if (fLeft < 0) {
167 nLeftTopIndex = 0;
168 fLeft = rcAnnot.left;
169 } else if (rcAnnot.left < fLeft) {
170 nLeftTopIndex = i;
171 fLeft = rcAnnot.left;
172 }
173 }
174 if (nLeftTopIndex < 0)
175 continue;
176
177 CFX_FloatRect rcLeftTop = AddToAnnotsList(sa, nLeftTopIndex);
178
179 std::vector<size_t> aSelect;
180 for (size_t i = 0; i < sa.size(); ++i) {
181 CFX_FloatRect rcAnnot = GetAnnotRect(sa[i]);
182 float fCenterX = (rcAnnot.left + rcAnnot.right) / 2.0f;
183 if (fCenterX > rcLeftTop.left && fCenterX < rcLeftTop.right)
184 aSelect.push_back(i);
185 }
186 AddSelectedToAnnots(sa, aSelect);
187 }
188 break;
189 }
190 }
191}
CPDFSDK_AnnotIterator(CPDFSDK_PageView *pPageView, const std::vector< CPDF_Annot::Subtype > &subtypes_to_iterate)
CPDFSDK_Annot * GetNextAnnot(CPDFSDK_Annot *pAnnot)
CPDFSDK_Annot * GetPrevAnnot(CPDFSDK_Annot *pAnnot)
virtual CPDF_Annot * GetPDFAnnot() const
CPDF_Page * GetPDFPage() const
CFX_FloatRect GetRect() const
bool operator==(const char *ptr) const