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/cpvt_wordinfo.h"
13
CSection(CPDF_VariableText * pVT)14 CSection::CSection(CPDF_VariableText* pVT) : m_pVT(pVT) {}
15
~CSection()16 CSection::~CSection() {
17 ResetAll();
18 }
19
ResetAll()20 void CSection::ResetAll() {
21 ResetWordArray();
22 ResetLineArray();
23 }
24
ResetLineArray()25 void CSection::ResetLineArray() {
26 m_LineArray.RemoveAll();
27 }
28
ResetWordArray()29 void CSection::ResetWordArray() {
30 for (int32_t i = 0, sz = m_WordArray.GetSize(); i < sz; i++) {
31 delete m_WordArray.GetAt(i);
32 }
33 m_WordArray.RemoveAll();
34 }
35
ResetLinePlace()36 void CSection::ResetLinePlace() {
37 for (int32_t i = 0, sz = m_LineArray.GetSize(); i < sz; i++) {
38 if (CLine* pLine = m_LineArray.GetAt(i)) {
39 pLine->LinePlace = CPVT_WordPlace(SecPlace.nSecIndex, i, -1);
40 }
41 }
42 }
43
AddWord(const CPVT_WordPlace & place,const CPVT_WordInfo & wordinfo)44 CPVT_WordPlace CSection::AddWord(const CPVT_WordPlace& place,
45 const CPVT_WordInfo& wordinfo) {
46 CPVT_WordInfo* pWord = new CPVT_WordInfo(wordinfo);
47 int32_t nWordIndex =
48 std::max(std::min(place.nWordIndex, m_WordArray.GetSize()), 0);
49 if (nWordIndex == m_WordArray.GetSize()) {
50 m_WordArray.Add(pWord);
51 } else {
52 m_WordArray.InsertAt(nWordIndex, pWord);
53 }
54 return place;
55 }
56
AddLine(const CPVT_LineInfo & lineinfo)57 CPVT_WordPlace CSection::AddLine(const CPVT_LineInfo& lineinfo) {
58 return CPVT_WordPlace(SecPlace.nSecIndex, m_LineArray.Add(lineinfo), -1);
59 }
60
Rearrange()61 CPVT_FloatRect CSection::Rearrange() {
62 if (m_pVT->m_nCharArray > 0) {
63 return CTypeset(this).CharArray();
64 }
65 return CTypeset(this).Typeset();
66 }
67
GetSectionSize(FX_FLOAT fFontSize)68 CFX_SizeF CSection::GetSectionSize(FX_FLOAT fFontSize) {
69 return CTypeset(this).GetEditSize(fFontSize);
70 }
71
GetBeginWordPlace() const72 CPVT_WordPlace CSection::GetBeginWordPlace() const {
73 if (CLine* pLine = m_LineArray.GetAt(0)) {
74 return pLine->GetBeginWordPlace();
75 }
76 return SecPlace;
77 }
78
GetEndWordPlace() const79 CPVT_WordPlace CSection::GetEndWordPlace() const {
80 if (CLine* pLine = m_LineArray.GetAt(m_LineArray.GetSize() - 1)) {
81 return pLine->GetEndWordPlace();
82 }
83 return SecPlace;
84 }
85
GetPrevWordPlace(const CPVT_WordPlace & place) const86 CPVT_WordPlace CSection::GetPrevWordPlace(const CPVT_WordPlace& place) const {
87 if (place.nLineIndex < 0) {
88 return GetBeginWordPlace();
89 }
90 if (place.nLineIndex >= m_LineArray.GetSize()) {
91 return GetEndWordPlace();
92 }
93 if (CLine* pLine = m_LineArray.GetAt(place.nLineIndex)) {
94 if (place.nWordIndex == pLine->m_LineInfo.nBeginWordIndex) {
95 return CPVT_WordPlace(place.nSecIndex, place.nLineIndex, -1);
96 }
97 if (place.nWordIndex < pLine->m_LineInfo.nBeginWordIndex) {
98 if (CLine* pPrevLine = m_LineArray.GetAt(place.nLineIndex - 1)) {
99 return pPrevLine->GetEndWordPlace();
100 }
101 } else {
102 return pLine->GetPrevWordPlace(place);
103 }
104 }
105 return place;
106 }
107
GetNextWordPlace(const CPVT_WordPlace & place) const108 CPVT_WordPlace CSection::GetNextWordPlace(const CPVT_WordPlace& place) const {
109 if (place.nLineIndex < 0) {
110 return GetBeginWordPlace();
111 }
112 if (place.nLineIndex >= m_LineArray.GetSize()) {
113 return GetEndWordPlace();
114 }
115 if (CLine* pLine = m_LineArray.GetAt(place.nLineIndex)) {
116 if (place.nWordIndex >= pLine->m_LineInfo.nEndWordIndex) {
117 if (CLine* pNextLine = m_LineArray.GetAt(place.nLineIndex + 1)) {
118 return pNextLine->GetBeginWordPlace();
119 }
120 } else {
121 return pLine->GetNextWordPlace(place);
122 }
123 }
124 return place;
125 }
126
UpdateWordPlace(CPVT_WordPlace & place) const127 void CSection::UpdateWordPlace(CPVT_WordPlace& place) const {
128 int32_t nLeft = 0;
129 int32_t nRight = m_LineArray.GetSize() - 1;
130 int32_t nMid = (nLeft + nRight) / 2;
131 while (nLeft <= nRight) {
132 if (CLine* pLine = m_LineArray.GetAt(nMid)) {
133 if (place.nWordIndex < pLine->m_LineInfo.nBeginWordIndex) {
134 nRight = nMid - 1;
135 nMid = (nLeft + nRight) / 2;
136 } else if (place.nWordIndex > pLine->m_LineInfo.nEndWordIndex) {
137 nLeft = nMid + 1;
138 nMid = (nLeft + nRight) / 2;
139 } else {
140 place.nLineIndex = nMid;
141 return;
142 }
143 } else {
144 break;
145 }
146 }
147 }
148
SearchWordPlace(const CFX_PointF & point) const149 CPVT_WordPlace CSection::SearchWordPlace(const CFX_PointF& point) const {
150 ASSERT(m_pVT);
151 CPVT_WordPlace place = GetBeginWordPlace();
152 bool bUp = true;
153 bool bDown = true;
154 int32_t nLeft = 0;
155 int32_t nRight = m_LineArray.GetSize() - 1;
156 int32_t nMid = m_LineArray.GetSize() / 2;
157 FX_FLOAT fTop = 0;
158 FX_FLOAT fBottom = 0;
159 while (nLeft <= nRight) {
160 if (CLine* pLine = m_LineArray.GetAt(nMid)) {
161 fTop = pLine->m_LineInfo.fLineY - pLine->m_LineInfo.fLineAscent -
162 m_pVT->GetLineLeading(m_SecInfo);
163 fBottom = pLine->m_LineInfo.fLineY - pLine->m_LineInfo.fLineDescent;
164 if (IsFloatBigger(point.y, fTop)) {
165 bUp = false;
166 }
167 if (IsFloatSmaller(point.y, fBottom)) {
168 bDown = false;
169 }
170 if (IsFloatSmaller(point.y, fTop)) {
171 nRight = nMid - 1;
172 nMid = (nLeft + nRight) / 2;
173 continue;
174 } else if (IsFloatBigger(point.y, fBottom)) {
175 nLeft = nMid + 1;
176 nMid = (nLeft + nRight) / 2;
177 continue;
178 } else {
179 place = SearchWordPlace(
180 point.x,
181 CPVT_WordRange(pLine->GetNextWordPlace(pLine->GetBeginWordPlace()),
182 pLine->GetEndWordPlace()));
183 place.nLineIndex = nMid;
184 return place;
185 }
186 }
187 }
188 if (bUp) {
189 place = GetBeginWordPlace();
190 }
191 if (bDown) {
192 place = GetEndWordPlace();
193 }
194 return place;
195 }
196
SearchWordPlace(FX_FLOAT fx,const CPVT_WordPlace & lineplace) const197 CPVT_WordPlace CSection::SearchWordPlace(
198 FX_FLOAT fx,
199 const CPVT_WordPlace& lineplace) const {
200 if (CLine* pLine = m_LineArray.GetAt(lineplace.nLineIndex)) {
201 return SearchWordPlace(
202 fx - m_SecInfo.rcSection.left,
203 CPVT_WordRange(pLine->GetNextWordPlace(pLine->GetBeginWordPlace()),
204 pLine->GetEndWordPlace()));
205 }
206 return GetBeginWordPlace();
207 }
208
SearchWordPlace(FX_FLOAT fx,const CPVT_WordRange & range) const209 CPVT_WordPlace CSection::SearchWordPlace(FX_FLOAT fx,
210 const CPVT_WordRange& range) const {
211 CPVT_WordPlace wordplace = range.BeginPos;
212 wordplace.nWordIndex = -1;
213 if (!m_pVT) {
214 return wordplace;
215 }
216 int32_t nLeft = range.BeginPos.nWordIndex;
217 int32_t nRight = range.EndPos.nWordIndex + 1;
218 int32_t nMid = (nLeft + nRight) / 2;
219 while (nLeft < nRight) {
220 if (nMid == nLeft) {
221 break;
222 }
223 if (nMid == nRight) {
224 nMid--;
225 break;
226 }
227 if (CPVT_WordInfo* pWord = m_WordArray.GetAt(nMid)) {
228 if (fx >
229 pWord->fWordX + m_pVT->GetWordWidth(*pWord) * VARIABLETEXT_HALF) {
230 nLeft = nMid;
231 nMid = (nLeft + nRight) / 2;
232 continue;
233 } else {
234 nRight = nMid;
235 nMid = (nLeft + nRight) / 2;
236 continue;
237 }
238 } else {
239 break;
240 }
241 }
242 if (CPVT_WordInfo* pWord = m_WordArray.GetAt(nMid)) {
243 if (fx > pWord->fWordX + m_pVT->GetWordWidth(*pWord) * VARIABLETEXT_HALF) {
244 wordplace.nWordIndex = nMid;
245 }
246 }
247 return wordplace;
248 }
249
ClearLeftWords(int32_t nWordIndex)250 void CSection::ClearLeftWords(int32_t nWordIndex) {
251 for (int32_t i = nWordIndex; i >= 0; i--) {
252 delete m_WordArray.GetAt(i);
253 m_WordArray.RemoveAt(i);
254 }
255 }
256
ClearRightWords(int32_t nWordIndex)257 void CSection::ClearRightWords(int32_t nWordIndex) {
258 for (int32_t i = m_WordArray.GetSize() - 1; i > nWordIndex; i--) {
259 delete m_WordArray.GetAt(i);
260 m_WordArray.RemoveAt(i);
261 }
262 }
263
ClearMidWords(int32_t nBeginIndex,int32_t nEndIndex)264 void CSection::ClearMidWords(int32_t nBeginIndex, int32_t nEndIndex) {
265 for (int32_t i = nEndIndex; i > nBeginIndex; i--) {
266 delete m_WordArray.GetAt(i);
267 m_WordArray.RemoveAt(i);
268 }
269 }
270
ClearWords(const CPVT_WordRange & PlaceRange)271 void CSection::ClearWords(const CPVT_WordRange& PlaceRange) {
272 CPVT_WordPlace SecBeginPos = GetBeginWordPlace();
273 CPVT_WordPlace SecEndPos = GetEndWordPlace();
274 if (PlaceRange.BeginPos.WordCmp(SecBeginPos) >= 0) {
275 if (PlaceRange.EndPos.WordCmp(SecEndPos) <= 0) {
276 ClearMidWords(PlaceRange.BeginPos.nWordIndex,
277 PlaceRange.EndPos.nWordIndex);
278 } else {
279 ClearRightWords(PlaceRange.BeginPos.nWordIndex);
280 }
281 } else if (PlaceRange.EndPos.WordCmp(SecEndPos) <= 0) {
282 ClearLeftWords(PlaceRange.EndPos.nWordIndex);
283 } else {
284 ResetWordArray();
285 }
286 }
287
ClearWord(const CPVT_WordPlace & place)288 void CSection::ClearWord(const CPVT_WordPlace& place) {
289 delete m_WordArray.GetAt(place.nWordIndex);
290 m_WordArray.RemoveAt(place.nWordIndex);
291 }
292