• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/containers/adapters.h"
14 #include "core/fxcrt/containers/contains.h"
15 #include "core/fxcrt/span.h"
16 #include "core/fxcrt/stl_util.h"
17 #include "fpdfsdk/cpdfsdk_annot.h"
18 #include "fpdfsdk/cpdfsdk_pageview.h"
19 #include "fpdfsdk/cpdfsdk_widget.h"
20 
21 namespace {
22 
GetAnnotRect(const CPDFSDK_Annot * pAnnot)23 CFX_FloatRect GetAnnotRect(const CPDFSDK_Annot* pAnnot) {
24   return pAnnot->GetPDFAnnot()->GetRect();
25 }
26 
CompareByLeftAscending(const CPDFSDK_Annot * p1,const CPDFSDK_Annot * p2)27 bool CompareByLeftAscending(const CPDFSDK_Annot* p1, const CPDFSDK_Annot* p2) {
28   return GetAnnotRect(p1).left < GetAnnotRect(p2).left;
29 }
30 
CompareByTopDescending(const CPDFSDK_Annot * p1,const CPDFSDK_Annot * p2)31 bool CompareByTopDescending(const CPDFSDK_Annot* p1, const CPDFSDK_Annot* p2) {
32   return GetAnnotRect(p1).top > GetAnnotRect(p2).top;
33 }
34 
35 }  // namespace
36 
CPDFSDK_AnnotIterator(CPDFSDK_PageView * pPageView,const std::vector<CPDF_Annot::Subtype> & subtypes_to_iterate)37 CPDFSDK_AnnotIterator::CPDFSDK_AnnotIterator(
38     CPDFSDK_PageView* pPageView,
39     const std::vector<CPDF_Annot::Subtype>& subtypes_to_iterate)
40     : m_pPageView(pPageView),
41       m_subtypes(subtypes_to_iterate),
42       m_eTabOrder(GetTabOrder(pPageView)) {
43   GenerateResults();
44 }
45 
46 CPDFSDK_AnnotIterator::~CPDFSDK_AnnotIterator() = default;
47 
GetFirstAnnot()48 CPDFSDK_Annot* CPDFSDK_AnnotIterator::GetFirstAnnot() {
49   return m_Annots.empty() ? nullptr : m_Annots.front();
50 }
51 
GetLastAnnot()52 CPDFSDK_Annot* CPDFSDK_AnnotIterator::GetLastAnnot() {
53   return m_Annots.empty() ? nullptr : m_Annots.back();
54 }
55 
GetNextAnnot(CPDFSDK_Annot * pAnnot)56 CPDFSDK_Annot* CPDFSDK_AnnotIterator::GetNextAnnot(CPDFSDK_Annot* pAnnot) {
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 
GetPrevAnnot(CPDFSDK_Annot * pAnnot)66 CPDFSDK_Annot* CPDFSDK_AnnotIterator::GetPrevAnnot(CPDFSDK_Annot* pAnnot) {
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 
CollectAnnots(std::vector<UnownedPtr<CPDFSDK_Annot>> * pArray)73 void 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 
AddToAnnotsList(std::vector<UnownedPtr<CPDFSDK_Annot>> & sa,size_t idx)84 CFX_FloatRect CPDFSDK_AnnotIterator::AddToAnnotsList(
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 
AddSelectedToAnnots(std::vector<UnownedPtr<CPDFSDK_Annot>> & sa,pdfium::span<const size_t> aSelect)94 void 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::Reversed(aSelect)) {
102     sa.erase(sa.begin() + select_idx);
103   }
104 }
105 
106 // static
GetTabOrder(CPDFSDK_PageView * pPageView)107 CPDFSDK_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 
GenerateResults()118 void 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 }
192