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