1 // 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
7 #include "core/fpdfdoc/csection.h"
8
9 #include <algorithm>
10
11 #include "core/fpdfdoc/cline.h"
12 #include "core/fpdfdoc/cpdf_variabletext.h"
13 #include "core/fpdfdoc/cpvt_wordinfo.h"
14 #include "third_party/base/ptr_util.h"
15 #include "third_party/base/stl_util.h"
16
CSection(CPDF_VariableText * pVT)17 CSection::CSection(CPDF_VariableText* pVT) : m_pVT(pVT) {}
18
~CSection()19 CSection::~CSection() {}
20
ResetAll()21 void CSection::ResetAll() {
22 m_WordArray.clear();
23 m_LineArray.clear();
24 }
25
ResetLinePlace()26 void CSection::ResetLinePlace() {
27 int32_t i = 0;
28 for (auto& pLine : m_LineArray) {
29 pLine->LinePlace = CPVT_WordPlace(SecPlace.nSecIndex, i, -1);
30 ++i;
31 }
32 }
33
AddWord(const CPVT_WordPlace & place,const CPVT_WordInfo & wordinfo)34 CPVT_WordPlace CSection::AddWord(const CPVT_WordPlace& place,
35 const CPVT_WordInfo& wordinfo) {
36 int32_t nWordIndex = pdfium::clamp(
37 place.nWordIndex, 0, pdfium::CollectionSize<int32_t>(m_WordArray));
38 m_WordArray.insert(m_WordArray.begin() + nWordIndex,
39 pdfium::MakeUnique<CPVT_WordInfo>(wordinfo));
40 return place;
41 }
42
AddLine(const CPVT_LineInfo & lineinfo)43 CPVT_WordPlace CSection::AddLine(const CPVT_LineInfo& lineinfo) {
44 m_LineArray.push_back(pdfium::MakeUnique<CLine>(lineinfo));
45 return CPVT_WordPlace(SecPlace.nSecIndex, m_LineArray.size() - 1, -1);
46 }
47
Rearrange()48 CPVT_FloatRect CSection::Rearrange() {
49 if (m_pVT->GetCharArray() > 0)
50 return CTypeset(this).CharArray();
51 return CTypeset(this).Typeset();
52 }
53
GetSectionSize(float fFontSize)54 CFX_SizeF CSection::GetSectionSize(float fFontSize) {
55 return CTypeset(this).GetEditSize(fFontSize);
56 }
57
GetBeginWordPlace() const58 CPVT_WordPlace CSection::GetBeginWordPlace() const {
59 if (m_LineArray.empty())
60 return SecPlace;
61 return m_LineArray.front()->GetBeginWordPlace();
62 }
63
GetEndWordPlace() const64 CPVT_WordPlace CSection::GetEndWordPlace() const {
65 if (m_LineArray.empty())
66 return SecPlace;
67 return m_LineArray.back()->GetEndWordPlace();
68 }
69
GetPrevWordPlace(const CPVT_WordPlace & place) const70 CPVT_WordPlace CSection::GetPrevWordPlace(const CPVT_WordPlace& place) const {
71 if (place.nLineIndex < 0)
72 return GetBeginWordPlace();
73
74 if (place.nLineIndex >= pdfium::CollectionSize<int32_t>(m_LineArray))
75 return GetEndWordPlace();
76
77 CLine* pLine = m_LineArray[place.nLineIndex].get();
78 if (place.nWordIndex == pLine->m_LineInfo.nBeginWordIndex)
79 return CPVT_WordPlace(place.nSecIndex, place.nLineIndex, -1);
80
81 if (place.nWordIndex >= pLine->m_LineInfo.nBeginWordIndex)
82 return pLine->GetPrevWordPlace(place);
83
84 if (!pdfium::IndexInBounds(m_LineArray, place.nLineIndex - 1))
85 return place;
86
87 return m_LineArray[place.nLineIndex - 1]->GetEndWordPlace();
88 }
89
GetNextWordPlace(const CPVT_WordPlace & place) const90 CPVT_WordPlace CSection::GetNextWordPlace(const CPVT_WordPlace& place) const {
91 if (place.nLineIndex < 0)
92 return GetBeginWordPlace();
93
94 if (place.nLineIndex >= pdfium::CollectionSize<int32_t>(m_LineArray))
95 return GetEndWordPlace();
96
97 CLine* pLine = m_LineArray[place.nLineIndex].get();
98 if (place.nWordIndex < pLine->m_LineInfo.nEndWordIndex)
99 return pLine->GetNextWordPlace(place);
100
101 if (!pdfium::IndexInBounds(m_LineArray, place.nLineIndex + 1))
102 return place;
103
104 return m_LineArray[place.nLineIndex + 1]->GetBeginWordPlace();
105 }
106
UpdateWordPlace(CPVT_WordPlace & place) const107 void CSection::UpdateWordPlace(CPVT_WordPlace& place) const {
108 int32_t nLeft = 0;
109 int32_t nRight = pdfium::CollectionSize<int32_t>(m_LineArray) - 1;
110 int32_t nMid = (nLeft + nRight) / 2;
111 while (nLeft <= nRight) {
112 CLine* pLine = m_LineArray[nMid].get();
113 if (place.nWordIndex < pLine->m_LineInfo.nBeginWordIndex) {
114 nRight = nMid - 1;
115 nMid = (nLeft + nRight) / 2;
116 } else if (place.nWordIndex > pLine->m_LineInfo.nEndWordIndex) {
117 nLeft = nMid + 1;
118 nMid = (nLeft + nRight) / 2;
119 } else {
120 place.nLineIndex = nMid;
121 return;
122 }
123 }
124 }
125
SearchWordPlace(const CFX_PointF & point) const126 CPVT_WordPlace CSection::SearchWordPlace(const CFX_PointF& point) const {
127 ASSERT(m_pVT);
128 CPVT_WordPlace place = GetBeginWordPlace();
129 bool bUp = true;
130 bool bDown = true;
131 int32_t nLeft = 0;
132 int32_t nRight = pdfium::CollectionSize<int32_t>(m_LineArray) - 1;
133 int32_t nMid = pdfium::CollectionSize<int32_t>(m_LineArray) / 2;
134 while (nLeft <= nRight) {
135 CLine* pLine = m_LineArray[nMid].get();
136 float fTop = pLine->m_LineInfo.fLineY - pLine->m_LineInfo.fLineAscent -
137 m_pVT->GetLineLeading();
138 float fBottom = pLine->m_LineInfo.fLineY - pLine->m_LineInfo.fLineDescent;
139 if (IsFloatBigger(point.y, fTop))
140 bUp = false;
141 if (IsFloatSmaller(point.y, fBottom))
142 bDown = false;
143 if (IsFloatSmaller(point.y, fTop)) {
144 nRight = nMid - 1;
145 nMid = (nLeft + nRight) / 2;
146 continue;
147 }
148 if (IsFloatBigger(point.y, fBottom)) {
149 nLeft = nMid + 1;
150 nMid = (nLeft + nRight) / 2;
151 continue;
152 }
153 place = SearchWordPlace(
154 point.x,
155 CPVT_WordRange(pLine->GetNextWordPlace(pLine->GetBeginWordPlace()),
156 pLine->GetEndWordPlace()));
157 place.nLineIndex = nMid;
158 return place;
159 }
160 if (bUp)
161 place = GetBeginWordPlace();
162 if (bDown)
163 place = GetEndWordPlace();
164 return place;
165 }
166
SearchWordPlace(float fx,const CPVT_WordPlace & lineplace) const167 CPVT_WordPlace CSection::SearchWordPlace(
168 float fx,
169 const CPVT_WordPlace& lineplace) const {
170 if (!pdfium::IndexInBounds(m_LineArray, lineplace.nLineIndex))
171 return GetBeginWordPlace();
172
173 CLine* pLine = m_LineArray[lineplace.nLineIndex].get();
174 return SearchWordPlace(
175 fx - m_Rect.left,
176 CPVT_WordRange(pLine->GetNextWordPlace(pLine->GetBeginWordPlace()),
177 pLine->GetEndWordPlace()));
178 }
179
SearchWordPlace(float fx,const CPVT_WordRange & range) const180 CPVT_WordPlace CSection::SearchWordPlace(float fx,
181 const CPVT_WordRange& range) const {
182 CPVT_WordPlace wordplace = range.BeginPos;
183 wordplace.nWordIndex = -1;
184 if (!m_pVT) {
185 return wordplace;
186 }
187 int32_t nLeft = range.BeginPos.nWordIndex;
188 int32_t nRight = range.EndPos.nWordIndex + 1;
189 int32_t nMid = (nLeft + nRight) / 2;
190 while (nLeft < nRight) {
191 if (nMid == nLeft)
192 break;
193 if (nMid == nRight) {
194 nMid--;
195 break;
196 }
197 if (!pdfium::IndexInBounds(m_WordArray, nMid))
198 break;
199 CPVT_WordInfo* pWord = m_WordArray[nMid].get();
200 if (fx > pWord->fWordX + m_pVT->GetWordWidth(*pWord) * VARIABLETEXT_HALF) {
201 nLeft = nMid;
202 nMid = (nLeft + nRight) / 2;
203 continue;
204 }
205 nRight = nMid;
206 nMid = (nLeft + nRight) / 2;
207 }
208 if (pdfium::IndexInBounds(m_WordArray, nMid)) {
209 CPVT_WordInfo* pWord = m_WordArray[nMid].get();
210 if (fx > pWord->fWordX + m_pVT->GetWordWidth(*pWord) * VARIABLETEXT_HALF)
211 wordplace.nWordIndex = nMid;
212 }
213 return wordplace;
214 }
215
ClearLeftWords(int32_t nWordIndex)216 void CSection::ClearLeftWords(int32_t nWordIndex) {
217 for (int32_t i = nWordIndex; i >= 0; i--) {
218 if (pdfium::IndexInBounds(m_WordArray, i))
219 m_WordArray.erase(m_WordArray.begin() + i);
220 }
221 }
222
ClearRightWords(int32_t nWordIndex)223 void CSection::ClearRightWords(int32_t nWordIndex) {
224 int32_t sz = pdfium::CollectionSize<int32_t>(m_WordArray);
225 for (int32_t i = sz - 1; i > nWordIndex; i--) {
226 if (pdfium::IndexInBounds(m_WordArray, i))
227 m_WordArray.erase(m_WordArray.begin() + i);
228 }
229 }
230
ClearMidWords(int32_t nBeginIndex,int32_t nEndIndex)231 void CSection::ClearMidWords(int32_t nBeginIndex, int32_t nEndIndex) {
232 for (int32_t i = nEndIndex; i > nBeginIndex; i--) {
233 if (pdfium::IndexInBounds(m_WordArray, i))
234 m_WordArray.erase(m_WordArray.begin() + i);
235 }
236 }
237
ClearWords(const CPVT_WordRange & PlaceRange)238 void CSection::ClearWords(const CPVT_WordRange& PlaceRange) {
239 CPVT_WordPlace SecBeginPos = GetBeginWordPlace();
240 CPVT_WordPlace SecEndPos = GetEndWordPlace();
241 if (PlaceRange.BeginPos >= SecBeginPos) {
242 if (PlaceRange.EndPos <= SecEndPos) {
243 ClearMidWords(PlaceRange.BeginPos.nWordIndex,
244 PlaceRange.EndPos.nWordIndex);
245 } else {
246 ClearRightWords(PlaceRange.BeginPos.nWordIndex);
247 }
248 } else if (PlaceRange.EndPos <= SecEndPos) {
249 ClearLeftWords(PlaceRange.EndPos.nWordIndex);
250 } else {
251 m_WordArray.clear();
252 }
253 }
254
ClearWord(const CPVT_WordPlace & place)255 void CSection::ClearWord(const CPVT_WordPlace& place) {
256 if (pdfium::IndexInBounds(m_WordArray, place.nWordIndex))
257 m_WordArray.erase(m_WordArray.begin() + place.nWordIndex);
258 }
259