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/cpdf_variabletext.h"
8
9 #include <algorithm>
10 #include <utility>
11
12 #include "core/fpdfapi/font/cpdf_font.h"
13 #include "core/fpdfdoc/cline.h"
14 #include "core/fpdfdoc/cpvt_word.h"
15 #include "core/fpdfdoc/cpvt_wordinfo.h"
16 #include "core/fpdfdoc/csection.h"
17 #include "core/fpdfdoc/ipvt_fontmap.h"
18 #include "core/fxcrt/fx_codepage.h"
19 #include "third_party/base/compiler_specific.h"
20 #include "third_party/base/stl_util.h"
21
22 namespace {
23
24 const float kFontScale = 0.001f;
25 const uint8_t kReturnLength = 1;
26
27 const uint8_t gFontSizeSteps[] = {4, 6, 8, 9, 10, 12, 14, 18, 20,
28 25, 30, 35, 40, 45, 50, 55, 60, 70,
29 80, 90, 100, 110, 120, 130, 144};
30
31 } // namespace
32
Provider(IPVT_FontMap * pFontMap)33 CPDF_VariableText::Provider::Provider(IPVT_FontMap* pFontMap)
34 : m_pFontMap(pFontMap) {
35 ASSERT(m_pFontMap);
36 }
37
38 CPDF_VariableText::Provider::~Provider() = default;
39
GetCharWidth(int32_t nFontIndex,uint16_t word)40 int CPDF_VariableText::Provider::GetCharWidth(int32_t nFontIndex,
41 uint16_t word) {
42 RetainPtr<CPDF_Font> pPDFFont = m_pFontMap->GetPDFFont(nFontIndex);
43 if (!pPDFFont)
44 return 0;
45
46 uint32_t charcode = pPDFFont->CharCodeFromUnicode(word);
47 if (charcode == CPDF_Font::kInvalidCharCode)
48 return 0;
49
50 return pPDFFont->GetCharWidthF(charcode);
51 }
52
GetTypeAscent(int32_t nFontIndex)53 int32_t CPDF_VariableText::Provider::GetTypeAscent(int32_t nFontIndex) {
54 RetainPtr<CPDF_Font> pPDFFont = m_pFontMap->GetPDFFont(nFontIndex);
55 return pPDFFont ? pPDFFont->GetTypeAscent() : 0;
56 }
57
GetTypeDescent(int32_t nFontIndex)58 int32_t CPDF_VariableText::Provider::GetTypeDescent(int32_t nFontIndex) {
59 RetainPtr<CPDF_Font> pPDFFont = m_pFontMap->GetPDFFont(nFontIndex);
60 return pPDFFont ? pPDFFont->GetTypeDescent() : 0;
61 }
62
GetWordFontIndex(uint16_t word,int32_t charset,int32_t nFontIndex)63 int32_t CPDF_VariableText::Provider::GetWordFontIndex(uint16_t word,
64 int32_t charset,
65 int32_t nFontIndex) {
66 if (RetainPtr<CPDF_Font> pDefFont = m_pFontMap->GetPDFFont(0)) {
67 if (pDefFont->CharCodeFromUnicode(word) != CPDF_Font::kInvalidCharCode)
68 return 0;
69 }
70 if (RetainPtr<CPDF_Font> pSysFont = m_pFontMap->GetPDFFont(1)) {
71 if (pSysFont->CharCodeFromUnicode(word) != CPDF_Font::kInvalidCharCode)
72 return 1;
73 }
74 return -1;
75 }
76
IsLatinWord(uint16_t word)77 bool CPDF_VariableText::Provider::IsLatinWord(uint16_t word) {
78 return (word >= 0x61 && word <= 0x7A) || (word >= 0x41 && word <= 0x5A) ||
79 word == 0x2D || word == 0x27;
80 }
81
GetDefaultFontIndex()82 int32_t CPDF_VariableText::Provider::GetDefaultFontIndex() {
83 return 0;
84 }
85
Iterator(CPDF_VariableText * pVT)86 CPDF_VariableText::Iterator::Iterator(CPDF_VariableText* pVT)
87 : m_CurPos(-1, -1, -1), m_pVT(pVT) {}
88
89 CPDF_VariableText::Iterator::~Iterator() = default;
90
SetAt(int32_t nWordIndex)91 void CPDF_VariableText::Iterator::SetAt(int32_t nWordIndex) {
92 m_CurPos = m_pVT->WordIndexToWordPlace(nWordIndex);
93 }
94
SetAt(const CPVT_WordPlace & place)95 void CPDF_VariableText::Iterator::SetAt(const CPVT_WordPlace& place) {
96 ASSERT(m_pVT);
97 m_CurPos = place;
98 }
99
NextWord()100 bool CPDF_VariableText::Iterator::NextWord() {
101 if (m_CurPos == m_pVT->GetEndWordPlace())
102 return false;
103
104 m_CurPos = m_pVT->GetNextWordPlace(m_CurPos);
105 return true;
106 }
107
PrevWord()108 bool CPDF_VariableText::Iterator::PrevWord() {
109 if (m_CurPos == m_pVT->GetBeginWordPlace())
110 return false;
111
112 m_CurPos = m_pVT->GetPrevWordPlace(m_CurPos);
113 return true;
114 }
115
NextLine()116 bool CPDF_VariableText::Iterator::NextLine() {
117 if (!pdfium::IndexInBounds(m_pVT->m_SectionArray, m_CurPos.nSecIndex))
118 return false;
119
120 CSection* pSection = m_pVT->m_SectionArray[m_CurPos.nSecIndex].get();
121 if (m_CurPos.nLineIndex <
122 pdfium::CollectionSize<int32_t>(pSection->m_LineArray) - 1) {
123 m_CurPos = CPVT_WordPlace(m_CurPos.nSecIndex, m_CurPos.nLineIndex + 1, -1);
124 return true;
125 }
126 if (m_CurPos.nSecIndex <
127 pdfium::CollectionSize<int32_t>(m_pVT->m_SectionArray) - 1) {
128 m_CurPos = CPVT_WordPlace(m_CurPos.nSecIndex + 1, 0, -1);
129 return true;
130 }
131 return false;
132 }
133
GetWord(CPVT_Word & word) const134 bool CPDF_VariableText::Iterator::GetWord(CPVT_Word& word) const {
135 word.WordPlace = m_CurPos;
136 if (!pdfium::IndexInBounds(m_pVT->m_SectionArray, m_CurPos.nSecIndex))
137 return false;
138
139 CSection* pSection = m_pVT->m_SectionArray[m_CurPos.nSecIndex].get();
140 if (!pdfium::IndexInBounds(pSection->m_LineArray, m_CurPos.nLineIndex) ||
141 !pdfium::IndexInBounds(pSection->m_WordArray, m_CurPos.nWordIndex)) {
142 return false;
143 }
144
145 CPVT_WordInfo* pWord = pSection->m_WordArray[m_CurPos.nWordIndex].get();
146 word.Word = pWord->Word;
147 word.nCharset = pWord->nCharset;
148 word.fWidth = m_pVT->GetWordWidth(*pWord);
149 word.ptWord =
150 m_pVT->InToOut(CFX_PointF(pWord->fWordX + pSection->m_Rect.left,
151 pWord->fWordY + pSection->m_Rect.top));
152 word.fAscent = m_pVT->GetWordAscent(*pWord);
153 word.fDescent = m_pVT->GetWordDescent(*pWord);
154 word.nFontIndex = m_pVT->GetWordFontIndex(*pWord);
155 word.fFontSize = m_pVT->GetWordFontSize();
156 return true;
157 }
158
GetLine(CPVT_Line & line) const159 bool CPDF_VariableText::Iterator::GetLine(CPVT_Line& line) const {
160 ASSERT(m_pVT);
161 line.lineplace = CPVT_WordPlace(m_CurPos.nSecIndex, m_CurPos.nLineIndex, -1);
162 if (!pdfium::IndexInBounds(m_pVT->m_SectionArray, m_CurPos.nSecIndex))
163 return false;
164
165 CSection* pSection = m_pVT->m_SectionArray[m_CurPos.nSecIndex].get();
166 if (!pdfium::IndexInBounds(pSection->m_LineArray, m_CurPos.nLineIndex))
167 return false;
168
169 CLine* pLine = pSection->m_LineArray[m_CurPos.nLineIndex].get();
170 line.ptLine = m_pVT->InToOut(
171 CFX_PointF(pLine->m_LineInfo.fLineX + pSection->m_Rect.left,
172 pLine->m_LineInfo.fLineY + pSection->m_Rect.top));
173 line.fLineWidth = pLine->m_LineInfo.fLineWidth;
174 line.fLineAscent = pLine->m_LineInfo.fLineAscent;
175 line.fLineDescent = pLine->m_LineInfo.fLineDescent;
176 line.lineEnd = pLine->GetEndWordPlace();
177 return true;
178 }
179
180 CPDF_VariableText::CPDF_VariableText() = default;
181
182 CPDF_VariableText::~CPDF_VariableText() = default;
183
Initialize()184 void CPDF_VariableText::Initialize() {
185 if (m_bInitialized)
186 return;
187
188 CPVT_WordPlace place;
189 place.nSecIndex = 0;
190 AddSection(place);
191
192 CPVT_LineInfo lineinfo;
193 lineinfo.fLineAscent = GetFontAscent(GetDefaultFontIndex(), GetFontSize());
194 lineinfo.fLineDescent = GetFontDescent(GetDefaultFontIndex(), GetFontSize());
195 AddLine(place, lineinfo);
196
197 if (!m_SectionArray.empty())
198 m_SectionArray.front()->ResetLinePlace();
199
200 m_bInitialized = true;
201 }
202
InsertWord(const CPVT_WordPlace & place,uint16_t word,int32_t charset)203 CPVT_WordPlace CPDF_VariableText::InsertWord(const CPVT_WordPlace& place,
204 uint16_t word,
205 int32_t charset) {
206 int32_t nTotalWords = GetTotalWords();
207 if (m_nLimitChar > 0 && nTotalWords >= m_nLimitChar)
208 return place;
209 if (m_nCharArray > 0 && nTotalWords >= m_nCharArray)
210 return place;
211
212 CPVT_WordPlace newplace = place;
213 newplace.nWordIndex++;
214 int32_t nFontIndex =
215 GetSubWord() > 0 ? GetDefaultFontIndex()
216 : GetWordFontIndex(word, charset, GetDefaultFontIndex());
217 return AddWord(newplace, CPVT_WordInfo(word, charset, nFontIndex));
218 }
219
InsertSection(const CPVT_WordPlace & place)220 CPVT_WordPlace CPDF_VariableText::InsertSection(const CPVT_WordPlace& place) {
221 int32_t nTotalWords = GetTotalWords();
222 if (m_nLimitChar > 0 && nTotalWords >= m_nLimitChar)
223 return place;
224 if (m_nCharArray > 0 && nTotalWords >= m_nCharArray)
225 return place;
226 if (!m_bMultiLine)
227 return place;
228
229 CPVT_WordPlace wordplace = place;
230 UpdateWordPlace(wordplace);
231 if (!pdfium::IndexInBounds(m_SectionArray, wordplace.nSecIndex))
232 return place;
233
234 CSection* pSection = m_SectionArray[wordplace.nSecIndex].get();
235 CPVT_WordPlace NewPlace(wordplace.nSecIndex + 1, 0, -1);
236 AddSection(NewPlace);
237 CPVT_WordPlace result = NewPlace;
238 if (pdfium::IndexInBounds(m_SectionArray, NewPlace.nSecIndex)) {
239 CSection* pNewSection = m_SectionArray[NewPlace.nSecIndex].get();
240 for (int32_t w = wordplace.nWordIndex + 1;
241 w < pdfium::CollectionSize<int32_t>(pSection->m_WordArray); ++w) {
242 NewPlace.nWordIndex++;
243 pNewSection->AddWord(NewPlace, *pSection->m_WordArray[w]);
244 }
245 }
246 ClearSectionRightWords(wordplace);
247 return result;
248 }
249
DeleteWords(const CPVT_WordRange & PlaceRange)250 CPVT_WordPlace CPDF_VariableText::DeleteWords(
251 const CPVT_WordRange& PlaceRange) {
252 bool bLastSecPos =
253 pdfium::IndexInBounds(m_SectionArray, PlaceRange.EndPos.nSecIndex) &&
254 PlaceRange.EndPos ==
255 m_SectionArray[PlaceRange.EndPos.nSecIndex]->GetEndWordPlace();
256
257 ClearWords(PlaceRange);
258 if (PlaceRange.BeginPos.nSecIndex != PlaceRange.EndPos.nSecIndex) {
259 ClearEmptySections(PlaceRange);
260 if (!bLastSecPos)
261 LinkLatterSection(PlaceRange.BeginPos);
262 }
263 return PlaceRange.BeginPos;
264 }
265
DeleteWord(const CPVT_WordPlace & place)266 CPVT_WordPlace CPDF_VariableText::DeleteWord(const CPVT_WordPlace& place) {
267 return ClearRightWord(AdjustLineHeader(place, true));
268 }
269
BackSpaceWord(const CPVT_WordPlace & place)270 CPVT_WordPlace CPDF_VariableText::BackSpaceWord(const CPVT_WordPlace& place) {
271 return ClearLeftWord(AdjustLineHeader(place, true));
272 }
273
SetText(const WideString & swText)274 void CPDF_VariableText::SetText(const WideString& swText) {
275 DeleteWords(CPVT_WordRange(GetBeginWordPlace(), GetEndWordPlace()));
276 CPVT_WordPlace wp(0, 0, -1);
277 if (!m_SectionArray.empty())
278 m_SectionArray.front()->m_Rect = CPVT_FloatRect();
279
280 int32_t nCharCount = 0;
281 for (int32_t i = 0, sz = swText.GetLength(); i < sz; i++) {
282 if (m_nLimitChar > 0 && nCharCount >= m_nLimitChar)
283 break;
284 if (m_nCharArray > 0 && nCharCount >= m_nCharArray)
285 break;
286
287 uint16_t word = swText[i];
288 switch (word) {
289 case 0x0D:
290 if (m_bMultiLine) {
291 if (i + 1 < sz && swText[i + 1] == 0x0A)
292 i++;
293 wp.AdvanceSection();
294 AddSection(wp);
295 }
296 break;
297 case 0x0A:
298 if (m_bMultiLine) {
299 if (i + 1 < sz && swText[i + 1] == 0x0D)
300 i++;
301 wp.AdvanceSection();
302 AddSection(wp);
303 }
304 break;
305 case 0x09:
306 word = 0x20;
307 FALLTHROUGH;
308 default:
309 wp = InsertWord(wp, word, FX_CHARSET_Default);
310 break;
311 }
312 nCharCount++;
313 }
314 }
315
UpdateWordPlace(CPVT_WordPlace & place) const316 void CPDF_VariableText::UpdateWordPlace(CPVT_WordPlace& place) const {
317 if (place.nSecIndex < 0)
318 place = GetBeginWordPlace();
319 if (place.nSecIndex >= pdfium::CollectionSize<int32_t>(m_SectionArray))
320 place = GetEndWordPlace();
321
322 place = AdjustLineHeader(place, true);
323 if (pdfium::IndexInBounds(m_SectionArray, place.nSecIndex))
324 m_SectionArray[place.nSecIndex]->UpdateWordPlace(place);
325 }
326
WordPlaceToWordIndex(const CPVT_WordPlace & place) const327 int32_t CPDF_VariableText::WordPlaceToWordIndex(
328 const CPVT_WordPlace& place) const {
329 CPVT_WordPlace newplace = place;
330 UpdateWordPlace(newplace);
331 int32_t nIndex = 0;
332 int32_t i = 0;
333 int32_t sz = 0;
334 for (i = 0, sz = pdfium::CollectionSize<int32_t>(m_SectionArray);
335 i < sz && i < newplace.nSecIndex; i++) {
336 CSection* pSection = m_SectionArray[i].get();
337 nIndex += pdfium::CollectionSize<int32_t>(pSection->m_WordArray);
338 if (i != sz - 1)
339 nIndex += kReturnLength;
340 }
341 if (pdfium::IndexInBounds(m_SectionArray, i))
342 nIndex += newplace.nWordIndex + kReturnLength;
343 return nIndex;
344 }
345
WordIndexToWordPlace(int32_t index) const346 CPVT_WordPlace CPDF_VariableText::WordIndexToWordPlace(int32_t index) const {
347 CPVT_WordPlace place = GetBeginWordPlace();
348 int32_t nOldIndex = 0;
349 int32_t nIndex = 0;
350 bool bFound = false;
351 for (int32_t i = 0, sz = pdfium::CollectionSize<int32_t>(m_SectionArray);
352 i < sz; i++) {
353 CSection* pSection = m_SectionArray[i].get();
354 nIndex += pdfium::CollectionSize<int32_t>(pSection->m_WordArray);
355 if (nIndex == index) {
356 place = pSection->GetEndWordPlace();
357 bFound = true;
358 break;
359 }
360 if (nIndex > index) {
361 place.nSecIndex = i;
362 place.nWordIndex = index - nOldIndex - 1;
363 pSection->UpdateWordPlace(place);
364 bFound = true;
365 break;
366 }
367 if (i != sz - 1)
368 nIndex += kReturnLength;
369 nOldIndex = nIndex;
370 }
371 if (!bFound)
372 place = GetEndWordPlace();
373 return place;
374 }
375
GetBeginWordPlace() const376 CPVT_WordPlace CPDF_VariableText::GetBeginWordPlace() const {
377 return m_bInitialized ? CPVT_WordPlace(0, 0, -1) : CPVT_WordPlace();
378 }
379
GetEndWordPlace() const380 CPVT_WordPlace CPDF_VariableText::GetEndWordPlace() const {
381 if (m_SectionArray.empty())
382 return CPVT_WordPlace();
383 return m_SectionArray.back()->GetEndWordPlace();
384 }
385
GetPrevWordPlace(const CPVT_WordPlace & place) const386 CPVT_WordPlace CPDF_VariableText::GetPrevWordPlace(
387 const CPVT_WordPlace& place) const {
388 if (place.nSecIndex < 0)
389 return GetBeginWordPlace();
390 if (place.nSecIndex >= pdfium::CollectionSize<int32_t>(m_SectionArray))
391 return GetEndWordPlace();
392
393 CSection* pSection = m_SectionArray[place.nSecIndex].get();
394 if (place > pSection->GetBeginWordPlace())
395 return pSection->GetPrevWordPlace(place);
396 if (!pdfium::IndexInBounds(m_SectionArray, place.nSecIndex - 1))
397 return GetBeginWordPlace();
398 return m_SectionArray[place.nSecIndex - 1]->GetEndWordPlace();
399 }
400
GetNextWordPlace(const CPVT_WordPlace & place) const401 CPVT_WordPlace CPDF_VariableText::GetNextWordPlace(
402 const CPVT_WordPlace& place) const {
403 if (place.nSecIndex < 0)
404 return GetBeginWordPlace();
405 if (place.nSecIndex >= pdfium::CollectionSize<int32_t>(m_SectionArray))
406 return GetEndWordPlace();
407
408 CSection* pSection = m_SectionArray[place.nSecIndex].get();
409 if (place < pSection->GetEndWordPlace())
410 return pSection->GetNextWordPlace(place);
411 if (!pdfium::IndexInBounds(m_SectionArray, place.nSecIndex + 1))
412 return GetEndWordPlace();
413 return m_SectionArray[place.nSecIndex + 1]->GetBeginWordPlace();
414 }
415
SearchWordPlace(const CFX_PointF & point) const416 CPVT_WordPlace CPDF_VariableText::SearchWordPlace(
417 const CFX_PointF& point) const {
418 CFX_PointF pt = OutToIn(point);
419 CPVT_WordPlace place = GetBeginWordPlace();
420 int32_t nLeft = 0;
421 int32_t nRight = pdfium::CollectionSize<int32_t>(m_SectionArray) - 1;
422 int32_t nMid = pdfium::CollectionSize<int32_t>(m_SectionArray) / 2;
423 bool bUp = true;
424 bool bDown = true;
425 while (nLeft <= nRight) {
426 if (!pdfium::IndexInBounds(m_SectionArray, nMid))
427 break;
428 CSection* pSection = m_SectionArray[nMid].get();
429 if (IsFloatBigger(pt.y, pSection->m_Rect.top))
430 bUp = false;
431 if (IsFloatBigger(pSection->m_Rect.bottom, pt.y))
432 bDown = false;
433 if (IsFloatSmaller(pt.y, pSection->m_Rect.top)) {
434 nRight = nMid - 1;
435 nMid = (nLeft + nRight) / 2;
436 continue;
437 }
438 if (IsFloatBigger(pt.y, pSection->m_Rect.bottom)) {
439 nLeft = nMid + 1;
440 nMid = (nLeft + nRight) / 2;
441 continue;
442 }
443 place = pSection->SearchWordPlace(
444 CFX_PointF(pt.x - pSection->m_Rect.left, pt.y - pSection->m_Rect.top));
445 place.nSecIndex = nMid;
446 return place;
447 }
448 if (bUp)
449 place = GetBeginWordPlace();
450 if (bDown)
451 place = GetEndWordPlace();
452 return place;
453 }
454
GetUpWordPlace(const CPVT_WordPlace & place,const CFX_PointF & point) const455 CPVT_WordPlace CPDF_VariableText::GetUpWordPlace(
456 const CPVT_WordPlace& place,
457 const CFX_PointF& point) const {
458 if (!pdfium::IndexInBounds(m_SectionArray, place.nSecIndex))
459 return place;
460
461 CSection* pSection = m_SectionArray[place.nSecIndex].get();
462 CPVT_WordPlace temp = place;
463 CFX_PointF pt = OutToIn(point);
464 if (temp.nLineIndex-- > 0) {
465 return pSection->SearchWordPlace(pt.x - pSection->m_Rect.left, temp);
466 }
467 if (temp.nSecIndex-- > 0) {
468 if (pdfium::IndexInBounds(m_SectionArray, temp.nSecIndex)) {
469 CSection* pLastSection = m_SectionArray[temp.nSecIndex].get();
470 temp.nLineIndex =
471 pdfium::CollectionSize<int32_t>(pLastSection->m_LineArray) - 1;
472 return pLastSection->SearchWordPlace(pt.x - pLastSection->m_Rect.left,
473 temp);
474 }
475 }
476 return place;
477 }
478
GetDownWordPlace(const CPVT_WordPlace & place,const CFX_PointF & point) const479 CPVT_WordPlace CPDF_VariableText::GetDownWordPlace(
480 const CPVT_WordPlace& place,
481 const CFX_PointF& point) const {
482 if (!pdfium::IndexInBounds(m_SectionArray, place.nSecIndex))
483 return place;
484
485 CSection* pSection = m_SectionArray[place.nSecIndex].get();
486 CPVT_WordPlace temp = place;
487 CFX_PointF pt = OutToIn(point);
488 if (temp.nLineIndex++ <
489 pdfium::CollectionSize<int32_t>(pSection->m_LineArray) - 1) {
490 return pSection->SearchWordPlace(pt.x - pSection->m_Rect.left, temp);
491 }
492 temp.AdvanceSection();
493 if (!pdfium::IndexInBounds(m_SectionArray, temp.nSecIndex))
494 return place;
495
496 return m_SectionArray[temp.nSecIndex]->SearchWordPlace(
497 pt.x - pSection->m_Rect.left, temp);
498 }
499
GetLineBeginPlace(const CPVT_WordPlace & place) const500 CPVT_WordPlace CPDF_VariableText::GetLineBeginPlace(
501 const CPVT_WordPlace& place) const {
502 return CPVT_WordPlace(place.nSecIndex, place.nLineIndex, -1);
503 }
504
GetLineEndPlace(const CPVT_WordPlace & place) const505 CPVT_WordPlace CPDF_VariableText::GetLineEndPlace(
506 const CPVT_WordPlace& place) const {
507 if (!pdfium::IndexInBounds(m_SectionArray, place.nSecIndex))
508 return place;
509
510 CSection* pSection = m_SectionArray[place.nSecIndex].get();
511 if (!pdfium::IndexInBounds(pSection->m_LineArray, place.nLineIndex))
512 return place;
513
514 return pSection->m_LineArray[place.nLineIndex]->GetEndWordPlace();
515 }
516
GetSectionBeginPlace(const CPVT_WordPlace & place) const517 CPVT_WordPlace CPDF_VariableText::GetSectionBeginPlace(
518 const CPVT_WordPlace& place) const {
519 return CPVT_WordPlace(place.nSecIndex, 0, -1);
520 }
521
GetSectionEndPlace(const CPVT_WordPlace & place) const522 CPVT_WordPlace CPDF_VariableText::GetSectionEndPlace(
523 const CPVT_WordPlace& place) const {
524 if (!pdfium::IndexInBounds(m_SectionArray, place.nSecIndex))
525 return place;
526
527 return m_SectionArray[place.nSecIndex]->GetEndWordPlace();
528 }
529
GetTotalWords() const530 int32_t CPDF_VariableText::GetTotalWords() const {
531 int32_t nTotal = 0;
532 for (const auto& pSection : m_SectionArray) {
533 nTotal +=
534 pdfium::CollectionSize<int32_t>(pSection->m_WordArray) + kReturnLength;
535 }
536 return nTotal - kReturnLength;
537 }
538
AddSection(const CPVT_WordPlace & place)539 CPVT_WordPlace CPDF_VariableText::AddSection(const CPVT_WordPlace& place) {
540 if (IsValid() && !m_bMultiLine)
541 return place;
542
543 int32_t nSecIndex = pdfium::clamp(
544 place.nSecIndex, 0, pdfium::CollectionSize<int32_t>(m_SectionArray));
545
546 auto pSection = std::make_unique<CSection>(this);
547 pSection->m_Rect = CPVT_FloatRect();
548 pSection->SecPlace.nSecIndex = nSecIndex;
549 m_SectionArray.insert(m_SectionArray.begin() + nSecIndex,
550 std::move(pSection));
551 return place;
552 }
553
AddLine(const CPVT_WordPlace & place,const CPVT_LineInfo & lineinfo)554 CPVT_WordPlace CPDF_VariableText::AddLine(const CPVT_WordPlace& place,
555 const CPVT_LineInfo& lineinfo) {
556 if (!pdfium::IndexInBounds(m_SectionArray, place.nSecIndex))
557 return place;
558
559 return m_SectionArray[place.nSecIndex]->AddLine(lineinfo);
560 }
561
AddWord(const CPVT_WordPlace & place,const CPVT_WordInfo & wordinfo)562 CPVT_WordPlace CPDF_VariableText::AddWord(const CPVT_WordPlace& place,
563 const CPVT_WordInfo& wordinfo) {
564 if (m_SectionArray.empty())
565 return place;
566
567 CPVT_WordPlace newplace = place;
568 newplace.nSecIndex =
569 pdfium::clamp(newplace.nSecIndex, 0,
570 pdfium::CollectionSize<int32_t>(m_SectionArray) - 1);
571 return m_SectionArray[newplace.nSecIndex]->AddWord(newplace, wordinfo);
572 }
573
SetPlateRect(const CFX_FloatRect & rect)574 void CPDF_VariableText::SetPlateRect(const CFX_FloatRect& rect) {
575 m_rcPlate = rect;
576 }
577
SetContentRect(const CPVT_FloatRect & rect)578 void CPDF_VariableText::SetContentRect(const CPVT_FloatRect& rect) {
579 m_rcContent = rect;
580 }
581
GetContentRect() const582 CFX_FloatRect CPDF_VariableText::GetContentRect() const {
583 return InToOut(CPVT_FloatRect(m_rcContent));
584 }
585
GetPlateRect() const586 const CFX_FloatRect& CPDF_VariableText::GetPlateRect() const {
587 return m_rcPlate;
588 }
589
GetWordFontSize()590 float CPDF_VariableText::GetWordFontSize() {
591 return GetFontSize();
592 }
593
GetWordFontIndex(const CPVT_WordInfo & WordInfo)594 int32_t CPDF_VariableText::GetWordFontIndex(const CPVT_WordInfo& WordInfo) {
595 return WordInfo.nFontIndex;
596 }
597
GetWordWidth(int32_t nFontIndex,uint16_t Word,uint16_t SubWord,float fCharSpace,float fFontSize,float fWordTail)598 float CPDF_VariableText::GetWordWidth(int32_t nFontIndex,
599 uint16_t Word,
600 uint16_t SubWord,
601 float fCharSpace,
602 float fFontSize,
603 float fWordTail) {
604 return GetCharWidth(nFontIndex, Word, SubWord) * fFontSize * kFontScale +
605 fCharSpace + fWordTail;
606 }
607
GetWordWidth(const CPVT_WordInfo & WordInfo)608 float CPDF_VariableText::GetWordWidth(const CPVT_WordInfo& WordInfo) {
609 return GetWordWidth(GetWordFontIndex(WordInfo), WordInfo.Word, GetSubWord(),
610 GetCharSpace(), GetWordFontSize(), WordInfo.fWordTail);
611 }
612
GetLineAscent()613 float CPDF_VariableText::GetLineAscent() {
614 return GetFontAscent(GetDefaultFontIndex(), GetFontSize());
615 }
616
GetLineDescent()617 float CPDF_VariableText::GetLineDescent() {
618 return GetFontDescent(GetDefaultFontIndex(), GetFontSize());
619 }
620
GetFontAscent(int32_t nFontIndex,float fFontSize)621 float CPDF_VariableText::GetFontAscent(int32_t nFontIndex, float fFontSize) {
622 return (float)GetTypeAscent(nFontIndex) * fFontSize * kFontScale;
623 }
624
GetFontDescent(int32_t nFontIndex,float fFontSize)625 float CPDF_VariableText::GetFontDescent(int32_t nFontIndex, float fFontSize) {
626 return (float)GetTypeDescent(nFontIndex) * fFontSize * kFontScale;
627 }
628
GetWordAscent(const CPVT_WordInfo & WordInfo,float fFontSize)629 float CPDF_VariableText::GetWordAscent(const CPVT_WordInfo& WordInfo,
630 float fFontSize) {
631 return GetFontAscent(GetWordFontIndex(WordInfo), fFontSize);
632 }
633
GetWordDescent(const CPVT_WordInfo & WordInfo,float fFontSize)634 float CPDF_VariableText::GetWordDescent(const CPVT_WordInfo& WordInfo,
635 float fFontSize) {
636 return GetFontDescent(GetWordFontIndex(WordInfo), fFontSize);
637 }
638
GetWordAscent(const CPVT_WordInfo & WordInfo)639 float CPDF_VariableText::GetWordAscent(const CPVT_WordInfo& WordInfo) {
640 return GetFontAscent(GetWordFontIndex(WordInfo), GetWordFontSize());
641 }
642
GetWordDescent(const CPVT_WordInfo & WordInfo)643 float CPDF_VariableText::GetWordDescent(const CPVT_WordInfo& WordInfo) {
644 return GetFontDescent(GetWordFontIndex(WordInfo), GetWordFontSize());
645 }
646
GetLineLeading()647 float CPDF_VariableText::GetLineLeading() {
648 return m_fLineLeading;
649 }
650
GetLineIndent()651 float CPDF_VariableText::GetLineIndent() {
652 return 0.0f;
653 }
654
GetAlignment()655 int32_t CPDF_VariableText::GetAlignment() {
656 return m_nAlignment;
657 }
658
ClearSectionRightWords(const CPVT_WordPlace & place)659 void CPDF_VariableText::ClearSectionRightWords(const CPVT_WordPlace& place) {
660 CPVT_WordPlace wordplace = AdjustLineHeader(place, true);
661 if (!pdfium::IndexInBounds(m_SectionArray, place.nSecIndex))
662 return;
663
664 CSection* pSection = m_SectionArray[place.nSecIndex].get();
665 if (!pdfium::IndexInBounds(pSection->m_WordArray, wordplace.nWordIndex + 1))
666 return;
667
668 pSection->m_WordArray.erase(
669 pSection->m_WordArray.begin() + wordplace.nWordIndex + 1,
670 pSection->m_WordArray.end());
671 }
672
AdjustLineHeader(const CPVT_WordPlace & place,bool bPrevOrNext) const673 CPVT_WordPlace CPDF_VariableText::AdjustLineHeader(const CPVT_WordPlace& place,
674 bool bPrevOrNext) const {
675 if (place.nWordIndex < 0 && place.nLineIndex > 0)
676 return bPrevOrNext ? GetPrevWordPlace(place) : GetNextWordPlace(place);
677 return place;
678 }
679
ClearEmptySection(const CPVT_WordPlace & place)680 bool CPDF_VariableText::ClearEmptySection(const CPVT_WordPlace& place) {
681 if (place.nSecIndex == 0 && m_SectionArray.size() == 1)
682 return false;
683
684 if (!pdfium::IndexInBounds(m_SectionArray, place.nSecIndex))
685 return false;
686
687 if (!m_SectionArray[place.nSecIndex]->m_WordArray.empty())
688 return false;
689
690 m_SectionArray.erase(m_SectionArray.begin() + place.nSecIndex);
691 return true;
692 }
693
ClearEmptySections(const CPVT_WordRange & PlaceRange)694 void CPDF_VariableText::ClearEmptySections(const CPVT_WordRange& PlaceRange) {
695 CPVT_WordPlace wordplace;
696 for (int32_t s = PlaceRange.EndPos.nSecIndex;
697 s > PlaceRange.BeginPos.nSecIndex; s--) {
698 wordplace.nSecIndex = s;
699 ClearEmptySection(wordplace);
700 }
701 }
702
LinkLatterSection(const CPVT_WordPlace & place)703 void CPDF_VariableText::LinkLatterSection(const CPVT_WordPlace& place) {
704 CPVT_WordPlace oldplace = AdjustLineHeader(place, true);
705 if (!pdfium::IndexInBounds(m_SectionArray, place.nSecIndex + 1))
706 return;
707
708 CSection* pNextSection = m_SectionArray[place.nSecIndex + 1].get();
709 if (pdfium::IndexInBounds(m_SectionArray, oldplace.nSecIndex)) {
710 CSection* pSection = m_SectionArray[oldplace.nSecIndex].get();
711 for (auto& pWord : pNextSection->m_WordArray) {
712 oldplace.nWordIndex++;
713 pSection->AddWord(oldplace, *pWord);
714 }
715 }
716 m_SectionArray.erase(m_SectionArray.begin() + place.nSecIndex + 1);
717 }
718
ClearWords(const CPVT_WordRange & PlaceRange)719 void CPDF_VariableText::ClearWords(const CPVT_WordRange& PlaceRange) {
720 CPVT_WordRange NewRange;
721 NewRange.BeginPos = AdjustLineHeader(PlaceRange.BeginPos, true);
722 NewRange.EndPos = AdjustLineHeader(PlaceRange.EndPos, true);
723 for (int32_t s = NewRange.EndPos.nSecIndex; s >= NewRange.BeginPos.nSecIndex;
724 s--) {
725 if (pdfium::IndexInBounds(m_SectionArray, s))
726 m_SectionArray[s]->ClearWords(NewRange);
727 }
728 }
729
ClearLeftWord(const CPVT_WordPlace & place)730 CPVT_WordPlace CPDF_VariableText::ClearLeftWord(const CPVT_WordPlace& place) {
731 if (!pdfium::IndexInBounds(m_SectionArray, place.nSecIndex))
732 return place;
733
734 CSection* pSection = m_SectionArray[place.nSecIndex].get();
735 CPVT_WordPlace leftplace = GetPrevWordPlace(place);
736 if (leftplace == place)
737 return place;
738
739 if (leftplace.nSecIndex != place.nSecIndex) {
740 if (pSection->m_WordArray.empty())
741 ClearEmptySection(place);
742 else
743 LinkLatterSection(leftplace);
744 } else {
745 pSection->ClearWord(place);
746 }
747 return leftplace;
748 }
749
ClearRightWord(const CPVT_WordPlace & place)750 CPVT_WordPlace CPDF_VariableText::ClearRightWord(const CPVT_WordPlace& place) {
751 if (!pdfium::IndexInBounds(m_SectionArray, place.nSecIndex))
752 return place;
753
754 CSection* pSection = m_SectionArray[place.nSecIndex].get();
755 CPVT_WordPlace rightplace = AdjustLineHeader(GetNextWordPlace(place), false);
756 if (rightplace == place)
757 return place;
758
759 if (rightplace.nSecIndex != place.nSecIndex)
760 LinkLatterSection(place);
761 else
762 pSection->ClearWord(rightplace);
763 return place;
764 }
765
RearrangeAll()766 void CPDF_VariableText::RearrangeAll() {
767 Rearrange(CPVT_WordRange(GetBeginWordPlace(), GetEndWordPlace()));
768 }
769
RearrangePart(const CPVT_WordRange & PlaceRange)770 void CPDF_VariableText::RearrangePart(const CPVT_WordRange& PlaceRange) {
771 Rearrange(PlaceRange);
772 }
773
Rearrange(const CPVT_WordRange & PlaceRange)774 CPVT_FloatRect CPDF_VariableText::Rearrange(const CPVT_WordRange& PlaceRange) {
775 CPVT_FloatRect rcRet;
776 if (IsValid()) {
777 if (m_bAutoFontSize) {
778 SetFontSize(GetAutoFontSize());
779 rcRet = RearrangeSections(
780 CPVT_WordRange(GetBeginWordPlace(), GetEndWordPlace()));
781 } else {
782 rcRet = RearrangeSections(PlaceRange);
783 }
784 }
785 SetContentRect(rcRet);
786 return rcRet;
787 }
788
GetAutoFontSize()789 float CPDF_VariableText::GetAutoFontSize() {
790 int32_t nTotal = sizeof(gFontSizeSteps) / sizeof(uint8_t);
791 if (IsMultiLine())
792 nTotal /= 4;
793 if (nTotal <= 0)
794 return 0;
795 if (GetPlateWidth() <= 0)
796 return 0;
797
798 int32_t nLeft = 0;
799 int32_t nRight = nTotal - 1;
800 int32_t nMid = nTotal / 2;
801 while (nLeft <= nRight) {
802 if (IsBigger(gFontSizeSteps[nMid]))
803 nRight = nMid - 1;
804 else
805 nLeft = nMid + 1;
806 nMid = (nLeft + nRight) / 2;
807 }
808 return (float)gFontSizeSteps[nMid];
809 }
810
IsBigger(float fFontSize) const811 bool CPDF_VariableText::IsBigger(float fFontSize) const {
812 CFX_SizeF szTotal;
813 for (const auto& pSection : m_SectionArray) {
814 CFX_SizeF size = pSection->GetSectionSize(fFontSize);
815 szTotal.width = std::max(size.width, szTotal.width);
816 szTotal.height += size.height;
817 if (IsFloatBigger(szTotal.width, GetPlateWidth()) ||
818 IsFloatBigger(szTotal.height, GetPlateHeight())) {
819 return true;
820 }
821 }
822 return false;
823 }
824
RearrangeSections(const CPVT_WordRange & PlaceRange)825 CPVT_FloatRect CPDF_VariableText::RearrangeSections(
826 const CPVT_WordRange& PlaceRange) {
827 CPVT_WordPlace place;
828 float fPosY = 0;
829 float fOldHeight;
830 int32_t nSSecIndex = PlaceRange.BeginPos.nSecIndex;
831 int32_t nESecIndex = PlaceRange.EndPos.nSecIndex;
832 CPVT_FloatRect rcRet;
833 for (int32_t s = 0, sz = pdfium::CollectionSize<int32_t>(m_SectionArray);
834 s < sz; s++) {
835 place.nSecIndex = s;
836 CSection* pSection = m_SectionArray[s].get();
837 pSection->SecPlace = place;
838 CPVT_FloatRect rcSec = pSection->m_Rect;
839 if (s >= nSSecIndex) {
840 if (s <= nESecIndex) {
841 rcSec = pSection->Rearrange();
842 rcSec.top += fPosY;
843 rcSec.bottom += fPosY;
844 } else {
845 fOldHeight = pSection->m_Rect.bottom - pSection->m_Rect.top;
846 rcSec.top = fPosY;
847 rcSec.bottom = fPosY + fOldHeight;
848 }
849 pSection->m_Rect = rcSec;
850 pSection->ResetLinePlace();
851 }
852 if (s == 0) {
853 rcRet = rcSec;
854 } else {
855 rcRet.left = std::min(rcSec.left, rcRet.left);
856 rcRet.top = std::min(rcSec.top, rcRet.top);
857 rcRet.right = std::max(rcSec.right, rcRet.right);
858 rcRet.bottom = std::max(rcSec.bottom, rcRet.bottom);
859 }
860 fPosY += rcSec.Height();
861 }
862 return rcRet;
863 }
864
GetCharWidth(int32_t nFontIndex,uint16_t Word,uint16_t SubWord)865 int CPDF_VariableText::GetCharWidth(int32_t nFontIndex,
866 uint16_t Word,
867 uint16_t SubWord) {
868 if (!m_pVTProvider)
869 return 0;
870 uint16_t word = SubWord ? SubWord : Word;
871 return m_pVTProvider->GetCharWidth(nFontIndex, word);
872 }
873
GetTypeAscent(int32_t nFontIndex)874 int32_t CPDF_VariableText::GetTypeAscent(int32_t nFontIndex) {
875 return m_pVTProvider ? m_pVTProvider->GetTypeAscent(nFontIndex) : 0;
876 }
877
GetTypeDescent(int32_t nFontIndex)878 int32_t CPDF_VariableText::GetTypeDescent(int32_t nFontIndex) {
879 return m_pVTProvider ? m_pVTProvider->GetTypeDescent(nFontIndex) : 0;
880 }
881
GetWordFontIndex(uint16_t word,int32_t charset,int32_t nFontIndex)882 int32_t CPDF_VariableText::GetWordFontIndex(uint16_t word,
883 int32_t charset,
884 int32_t nFontIndex) {
885 return m_pVTProvider
886 ? m_pVTProvider->GetWordFontIndex(word, charset, nFontIndex)
887 : -1;
888 }
889
GetDefaultFontIndex()890 int32_t CPDF_VariableText::GetDefaultFontIndex() {
891 return m_pVTProvider ? m_pVTProvider->GetDefaultFontIndex() : -1;
892 }
893
IsLatinWord(uint16_t word)894 bool CPDF_VariableText::IsLatinWord(uint16_t word) {
895 return m_pVTProvider && m_pVTProvider->IsLatinWord(word);
896 }
897
GetIterator()898 CPDF_VariableText::Iterator* CPDF_VariableText::GetIterator() {
899 if (!m_pVTIterator)
900 m_pVTIterator = std::make_unique<CPDF_VariableText::Iterator>(this);
901 return m_pVTIterator.get();
902 }
903
SetProvider(CPDF_VariableText::Provider * pProvider)904 void CPDF_VariableText::SetProvider(CPDF_VariableText::Provider* pProvider) {
905 m_pVTProvider = pProvider;
906 }
907
GetBTPoint() const908 CFX_PointF CPDF_VariableText::GetBTPoint() const {
909 return CFX_PointF(m_rcPlate.left, m_rcPlate.top);
910 }
911
GetETPoint() const912 CFX_PointF CPDF_VariableText::GetETPoint() const {
913 return CFX_PointF(m_rcPlate.right, m_rcPlate.bottom);
914 }
915
InToOut(const CFX_PointF & point) const916 CFX_PointF CPDF_VariableText::InToOut(const CFX_PointF& point) const {
917 return CFX_PointF(point.x + GetBTPoint().x, GetBTPoint().y - point.y);
918 }
919
OutToIn(const CFX_PointF & point) const920 CFX_PointF CPDF_VariableText::OutToIn(const CFX_PointF& point) const {
921 return CFX_PointF(point.x - GetBTPoint().x, GetBTPoint().y - point.y);
922 }
923
InToOut(const CPVT_FloatRect & rect) const924 CFX_FloatRect CPDF_VariableText::InToOut(const CPVT_FloatRect& rect) const {
925 CFX_PointF ptLeftTop = InToOut(CFX_PointF(rect.left, rect.top));
926 CFX_PointF ptRightBottom = InToOut(CFX_PointF(rect.right, rect.bottom));
927 return CFX_FloatRect(ptLeftTop.x, ptRightBottom.y, ptRightBottom.x,
928 ptLeftTop.y);
929 }
930
OutToIn(const CFX_FloatRect & rect) const931 CPVT_FloatRect CPDF_VariableText::OutToIn(const CFX_FloatRect& rect) const {
932 CFX_PointF ptLeftTop = OutToIn(CFX_PointF(rect.left, rect.top));
933 CFX_PointF ptRightBottom = OutToIn(CFX_PointF(rect.right, rect.bottom));
934 return CPVT_FloatRect(ptLeftTop.x, ptLeftTop.y, ptRightBottom.x,
935 ptRightBottom.y);
936 }
937