blob: 762f6346c1dba8656f10e1c44c55fa8d67c2843f [file] [log] [blame]
// Copyright 2016 PDFium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
#include "fpdfsdk/cba_annotiterator.h"
#include "core/fpdfapi/fpdf_page/cpdf_page.h"
#include "fpdfsdk/cpdfsdk_annot.h"
#include "fpdfsdk/cpdfsdk_pageview.h"
// static
bool CBA_AnnotIterator::CompareByLeftAscending(const CPDFSDK_Annot* p1,
const CPDFSDK_Annot* p2) {
return GetAnnotRect(p1).left < GetAnnotRect(p2).left;
}
// static
bool CBA_AnnotIterator::CompareByTopDescending(const CPDFSDK_Annot* p1,
const CPDFSDK_Annot* p2) {
return GetAnnotRect(p1).top > GetAnnotRect(p2).top;
}
CBA_AnnotIterator::CBA_AnnotIterator(CPDFSDK_PageView* pPageView,
CPDF_Annot::Subtype nAnnotSubtype)
: m_eTabOrder(STRUCTURE),
m_pPageView(pPageView),
m_nAnnotSubtype(nAnnotSubtype) {
CPDF_Page* pPDFPage = m_pPageView->GetPDFPage();
CFX_ByteString sTabs = pPDFPage->m_pFormDict->GetStringFor("Tabs");
if (sTabs == "R")
m_eTabOrder = ROW;
else if (sTabs == "C")
m_eTabOrder = COLUMN;
GenerateResults();
}
CBA_AnnotIterator::~CBA_AnnotIterator() {}
CPDFSDK_Annot* CBA_AnnotIterator::GetFirstAnnot() {
return m_Annots.empty() ? nullptr : m_Annots.front();
}
CPDFSDK_Annot* CBA_AnnotIterator::GetLastAnnot() {
return m_Annots.empty() ? nullptr : m_Annots.back();
}
CPDFSDK_Annot* CBA_AnnotIterator::GetNextAnnot(CPDFSDK_Annot* pAnnot) {
auto iter = std::find(m_Annots.begin(), m_Annots.end(), pAnnot);
if (iter == m_Annots.end())
return nullptr;
++iter;
if (iter == m_Annots.end())
iter = m_Annots.begin();
return *iter;
}
CPDFSDK_Annot* CBA_AnnotIterator::GetPrevAnnot(CPDFSDK_Annot* pAnnot) {
auto iter = std::find(m_Annots.begin(), m_Annots.end(), pAnnot);
if (iter == m_Annots.end())
return nullptr;
if (iter == m_Annots.begin())
iter = m_Annots.end();
return *(--iter);
}
void CBA_AnnotIterator::GenerateResults() {
switch (m_eTabOrder) {
case STRUCTURE: {
for (size_t i = 0; i < m_pPageView->CountAnnots(); ++i) {
CPDFSDK_Annot* pAnnot = m_pPageView->GetAnnot(i);
if (pAnnot->GetAnnotSubtype() == m_nAnnotSubtype &&
!pAnnot->IsSignatureWidget())
m_Annots.push_back(pAnnot);
}
break;
}
case ROW: {
std::vector<CPDFSDK_Annot*> sa;
for (size_t i = 0; i < m_pPageView->CountAnnots(); ++i) {
CPDFSDK_Annot* pAnnot = m_pPageView->GetAnnot(i);
if (pAnnot->GetAnnotSubtype() == m_nAnnotSubtype &&
!pAnnot->IsSignatureWidget())
sa.push_back(pAnnot);
}
std::sort(sa.begin(), sa.end(), CompareByLeftAscending);
while (!sa.empty()) {
int nLeftTopIndex = -1;
FX_FLOAT fTop = 0.0f;
for (int i = sa.size() - 1; i >= 0; i--) {
CFX_FloatRect rcAnnot = GetAnnotRect(sa[i]);
if (rcAnnot.top > fTop) {
nLeftTopIndex = i;
fTop = rcAnnot.top;
}
}
if (nLeftTopIndex >= 0) {
CPDFSDK_Annot* pLeftTopAnnot = sa[nLeftTopIndex];
CFX_FloatRect rcLeftTop = GetAnnotRect(pLeftTopAnnot);
m_Annots.push_back(pLeftTopAnnot);
sa.erase(sa.begin() + nLeftTopIndex);
std::vector<int> aSelect;
for (size_t i = 0; i < sa.size(); ++i) {
CFX_FloatRect rcAnnot = GetAnnotRect(sa[i]);
FX_FLOAT fCenterY = (rcAnnot.top + rcAnnot.bottom) / 2.0f;
if (fCenterY > rcLeftTop.bottom && fCenterY < rcLeftTop.top)
aSelect.push_back(i);
}
for (size_t i = 0; i < aSelect.size(); ++i)
m_Annots.push_back(sa[aSelect[i]]);
for (int i = aSelect.size() - 1; i >= 0; --i)
sa.erase(sa.begin() + aSelect[i]);
}
}
break;
}
case COLUMN: {
std::vector<CPDFSDK_Annot*> sa;
for (size_t i = 0; i < m_pPageView->CountAnnots(); ++i) {
CPDFSDK_Annot* pAnnot = m_pPageView->GetAnnot(i);
if (pAnnot->GetAnnotSubtype() == m_nAnnotSubtype &&
!pAnnot->IsSignatureWidget())
sa.push_back(pAnnot);
}
std::sort(sa.begin(), sa.end(), CompareByTopDescending);
while (!sa.empty()) {
int nLeftTopIndex = -1;
FX_FLOAT fLeft = -1.0f;
for (int i = sa.size() - 1; i >= 0; --i) {
CFX_FloatRect rcAnnot = GetAnnotRect(sa[i]);
if (fLeft < 0) {
nLeftTopIndex = 0;
fLeft = rcAnnot.left;
} else if (rcAnnot.left < fLeft) {
nLeftTopIndex = i;
fLeft = rcAnnot.left;
}
}
if (nLeftTopIndex >= 0) {
CPDFSDK_Annot* pLeftTopAnnot = sa[nLeftTopIndex];
CFX_FloatRect rcLeftTop = GetAnnotRect(pLeftTopAnnot);
m_Annots.push_back(pLeftTopAnnot);
sa.erase(sa.begin() + nLeftTopIndex);
std::vector<int> aSelect;
for (size_t i = 0; i < sa.size(); ++i) {
CFX_FloatRect rcAnnot = GetAnnotRect(sa[i]);
FX_FLOAT fCenterX = (rcAnnot.left + rcAnnot.right) / 2.0f;
if (fCenterX > rcLeftTop.left && fCenterX < rcLeftTop.right)
aSelect.push_back(i);
}
for (size_t i = 0; i < aSelect.size(); ++i)
m_Annots.push_back(sa[aSelect[i]]);
for (int i = aSelect.size() - 1; i >= 0; --i)
sa.erase(sa.begin() + aSelect[i]);
}
}
break;
}
}
}
CFX_FloatRect CBA_AnnotIterator::GetAnnotRect(const CPDFSDK_Annot* pAnnot) {
return pAnnot->GetPDFAnnot()->GetRect();
}