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/ptr_util.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 const float kScalePercent = 0.01f;
27
28 const uint8_t gFontSizeSteps[] = {4, 6, 8, 9, 10, 12, 14, 18, 20,
29 25, 30, 35, 40, 45, 50, 55, 60, 70,
30 80, 90, 100, 110, 120, 130, 144};
31
32 } // namespace
33
Provider(IPVT_FontMap * pFontMap)34 CPDF_VariableText::Provider::Provider(IPVT_FontMap* pFontMap)
35 : m_pFontMap(pFontMap) {
36 ASSERT(m_pFontMap);
37 }
38
~Provider()39 CPDF_VariableText::Provider::~Provider() {}
40
GetCharWidth(int32_t nFontIndex,uint16_t word)41 int32_t CPDF_VariableText::Provider::GetCharWidth(int32_t nFontIndex,
42 uint16_t word) {
43 if (CPDF_Font* pPDFFont = m_pFontMap->GetPDFFont(nFontIndex)) {
44 uint32_t charcode = pPDFFont->CharCodeFromUnicode(word);
45 if (charcode != CPDF_Font::kInvalidCharCode)
46 return pPDFFont->GetCharWidthF(charcode);
47 }
48 return 0;
49 }
50
GetTypeAscent(int32_t nFontIndex)51 int32_t CPDF_VariableText::Provider::GetTypeAscent(int32_t nFontIndex) {
52 if (CPDF_Font* pPDFFont = m_pFontMap->GetPDFFont(nFontIndex))
53 return pPDFFont->GetTypeAscent();
54 return 0;
55 }
56
GetTypeDescent(int32_t nFontIndex)57 int32_t CPDF_VariableText::Provider::GetTypeDescent(int32_t nFontIndex) {
58 if (CPDF_Font* pPDFFont = m_pFontMap->GetPDFFont(nFontIndex))
59 return pPDFFont->GetTypeDescent();
60 return 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 (CPDF_Font* pDefFont = m_pFontMap->GetPDFFont(0)) {
67 if (pDefFont->CharCodeFromUnicode(word) != CPDF_Font::kInvalidCharCode)
68 return 0;
69 }
70 if (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
~Iterator()89 CPDF_VariableText::Iterator::~Iterator() {}
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
CPDF_VariableText()180 CPDF_VariableText::CPDF_VariableText()
181 : m_nLimitChar(0),
182 m_nCharArray(0),
183 m_bMultiLine(false),
184 m_bLimitWidth(false),
185 m_bAutoFontSize(false),
186 m_nAlignment(0),
187 m_fLineLeading(0.0f),
188 m_fCharSpace(0.0f),
189 m_nHorzScale(100),
190 m_wSubWord(0),
191 m_fFontSize(0.0f),
192 m_bInitialized(false),
193 m_pVTProvider(nullptr) {}
194
~CPDF_VariableText()195 CPDF_VariableText::~CPDF_VariableText() {}
196
Initialize()197 void CPDF_VariableText::Initialize() {
198 if (m_bInitialized)
199 return;
200
201 CPVT_WordPlace place;
202 place.nSecIndex = 0;
203 AddSection(place);
204
205 CPVT_LineInfo lineinfo;
206 lineinfo.fLineAscent = GetFontAscent(GetDefaultFontIndex(), GetFontSize());
207 lineinfo.fLineDescent = GetFontDescent(GetDefaultFontIndex(), GetFontSize());
208 AddLine(place, lineinfo);
209
210 if (!m_SectionArray.empty())
211 m_SectionArray.front()->ResetLinePlace();
212
213 m_bInitialized = true;
214 }
215
InsertWord(const CPVT_WordPlace & place,uint16_t word,int32_t charset)216 CPVT_WordPlace CPDF_VariableText::InsertWord(const CPVT_WordPlace& place,
217 uint16_t word,
218 int32_t charset) {
219 int32_t nTotalWords = GetTotalWords();
220 if (m_nLimitChar > 0 && nTotalWords >= m_nLimitChar)
221 return place;
222 if (m_nCharArray > 0 && nTotalWords >= m_nCharArray)
223 return place;
224
225 CPVT_WordPlace newplace = place;
226 newplace.nWordIndex++;
227 int32_t nFontIndex =
228 GetSubWord() > 0 ? GetDefaultFontIndex()
229 : GetWordFontIndex(word, charset, GetDefaultFontIndex());
230 return AddWord(newplace, CPVT_WordInfo(word, charset, nFontIndex));
231 }
232
InsertSection(const CPVT_WordPlace & place)233 CPVT_WordPlace CPDF_VariableText::InsertSection(const CPVT_WordPlace& place) {
234 int32_t nTotalWords = GetTotalWords();
235 if (m_nLimitChar > 0 && nTotalWords >= m_nLimitChar)
236 return place;
237 if (m_nCharArray > 0 && nTotalWords >= m_nCharArray)
238 return place;
239 if (!m_bMultiLine)
240 return place;
241
242 CPVT_WordPlace wordplace = place;
243 UpdateWordPlace(wordplace);
244 if (!pdfium::IndexInBounds(m_SectionArray, wordplace.nSecIndex))
245 return place;
246
247 CSection* pSection = m_SectionArray[wordplace.nSecIndex].get();
248 CPVT_WordPlace NewPlace(wordplace.nSecIndex + 1, 0, -1);
249 AddSection(NewPlace);
250 CPVT_WordPlace result = NewPlace;
251 if (pdfium::IndexInBounds(m_SectionArray, NewPlace.nSecIndex)) {
252 CSection* pNewSection = m_SectionArray[NewPlace.nSecIndex].get();
253 for (int32_t w = wordplace.nWordIndex + 1;
254 w < pdfium::CollectionSize<int32_t>(pSection->m_WordArray); ++w) {
255 NewPlace.nWordIndex++;
256 pNewSection->AddWord(NewPlace, *pSection->m_WordArray[w]);
257 }
258 }
259 ClearSectionRightWords(wordplace);
260 return result;
261 }
262
DeleteWords(const CPVT_WordRange & PlaceRange)263 CPVT_WordPlace CPDF_VariableText::DeleteWords(
264 const CPVT_WordRange& PlaceRange) {
265 bool bLastSecPos =
266 pdfium::IndexInBounds(m_SectionArray, PlaceRange.EndPos.nSecIndex) &&
267 PlaceRange.EndPos ==
268 m_SectionArray[PlaceRange.EndPos.nSecIndex]->GetEndWordPlace();
269
270 ClearWords(PlaceRange);
271 if (PlaceRange.BeginPos.nSecIndex != PlaceRange.EndPos.nSecIndex) {
272 ClearEmptySections(PlaceRange);
273 if (!bLastSecPos)
274 LinkLatterSection(PlaceRange.BeginPos);
275 }
276 return PlaceRange.BeginPos;
277 }
278
DeleteWord(const CPVT_WordPlace & place)279 CPVT_WordPlace CPDF_VariableText::DeleteWord(const CPVT_WordPlace& place) {
280 return ClearRightWord(AdjustLineHeader(place, true));
281 }
282
BackSpaceWord(const CPVT_WordPlace & place)283 CPVT_WordPlace CPDF_VariableText::BackSpaceWord(const CPVT_WordPlace& place) {
284 return ClearLeftWord(AdjustLineHeader(place, true));
285 }
286
SetText(const WideString & swText)287 void CPDF_VariableText::SetText(const WideString& swText) {
288 DeleteWords(CPVT_WordRange(GetBeginWordPlace(), GetEndWordPlace()));
289 CPVT_WordPlace wp(0, 0, -1);
290 if (!m_SectionArray.empty())
291 m_SectionArray.front()->m_Rect = CPVT_FloatRect();
292
293 int32_t nCharCount = 0;
294 for (int32_t i = 0, sz = swText.GetLength(); i < sz; i++) {
295 if (m_nLimitChar > 0 && nCharCount >= m_nLimitChar)
296 break;
297 if (m_nCharArray > 0 && nCharCount >= m_nCharArray)
298 break;
299
300 uint16_t word = swText[i];
301 switch (word) {
302 case 0x0D:
303 if (m_bMultiLine) {
304 if (i + 1 < sz && swText[i + 1] == 0x0A)
305 i++;
306 wp.AdvanceSection();
307 AddSection(wp);
308 }
309 break;
310 case 0x0A:
311 if (m_bMultiLine) {
312 if (i + 1 < sz && swText[i + 1] == 0x0D)
313 i++;
314 wp.AdvanceSection();
315 AddSection(wp);
316 }
317 break;
318 case 0x09:
319 word = 0x20;
320 default:
321 wp = InsertWord(wp, word, FX_CHARSET_Default);
322 break;
323 }
324 nCharCount++;
325 }
326 }
327
UpdateWordPlace(CPVT_WordPlace & place) const328 void CPDF_VariableText::UpdateWordPlace(CPVT_WordPlace& place) const {
329 if (place.nSecIndex < 0)
330 place = GetBeginWordPlace();
331 if (place.nSecIndex >= pdfium::CollectionSize<int32_t>(m_SectionArray))
332 place = GetEndWordPlace();
333
334 place = AdjustLineHeader(place, true);
335 if (pdfium::IndexInBounds(m_SectionArray, place.nSecIndex))
336 m_SectionArray[place.nSecIndex]->UpdateWordPlace(place);
337 }
338
WordPlaceToWordIndex(const CPVT_WordPlace & place) const339 int32_t CPDF_VariableText::WordPlaceToWordIndex(
340 const CPVT_WordPlace& place) const {
341 CPVT_WordPlace newplace = place;
342 UpdateWordPlace(newplace);
343 int32_t nIndex = 0;
344 int32_t i = 0;
345 int32_t sz = 0;
346 for (i = 0, sz = pdfium::CollectionSize<int32_t>(m_SectionArray);
347 i < sz && i < newplace.nSecIndex; i++) {
348 CSection* pSection = m_SectionArray[i].get();
349 nIndex += pdfium::CollectionSize<int32_t>(pSection->m_WordArray);
350 if (i != sz - 1)
351 nIndex += kReturnLength;
352 }
353 if (pdfium::IndexInBounds(m_SectionArray, i))
354 nIndex += newplace.nWordIndex + kReturnLength;
355 return nIndex;
356 }
357
WordIndexToWordPlace(int32_t index) const358 CPVT_WordPlace CPDF_VariableText::WordIndexToWordPlace(int32_t index) const {
359 CPVT_WordPlace place = GetBeginWordPlace();
360 int32_t nOldIndex = 0;
361 int32_t nIndex = 0;
362 bool bFound = false;
363 for (int32_t i = 0, sz = pdfium::CollectionSize<int32_t>(m_SectionArray);
364 i < sz; i++) {
365 CSection* pSection = m_SectionArray[i].get();
366 nIndex += pdfium::CollectionSize<int32_t>(pSection->m_WordArray);
367 if (nIndex == index) {
368 place = pSection->GetEndWordPlace();
369 bFound = true;
370 break;
371 }
372 if (nIndex > index) {
373 place.nSecIndex = i;
374 place.nWordIndex = index - nOldIndex - 1;
375 pSection->UpdateWordPlace(place);
376 bFound = true;
377 break;
378 }
379 if (i != sz - 1)
380 nIndex += kReturnLength;
381 nOldIndex = nIndex;
382 }
383 if (!bFound)
384 place = GetEndWordPlace();
385 return place;
386 }
387
GetBeginWordPlace() const388 CPVT_WordPlace CPDF_VariableText::GetBeginWordPlace() const {
389 return m_bInitialized ? CPVT_WordPlace(0, 0, -1) : CPVT_WordPlace();
390 }
391
GetEndWordPlace() const392 CPVT_WordPlace CPDF_VariableText::GetEndWordPlace() const {
393 if (m_SectionArray.empty())
394 return CPVT_WordPlace();
395 return m_SectionArray.back()->GetEndWordPlace();
396 }
397
GetPrevWordPlace(const CPVT_WordPlace & place) const398 CPVT_WordPlace CPDF_VariableText::GetPrevWordPlace(
399 const CPVT_WordPlace& place) const {
400 if (place.nSecIndex < 0)
401 return GetBeginWordPlace();
402 if (place.nSecIndex >= pdfium::CollectionSize<int32_t>(m_SectionArray))
403 return GetEndWordPlace();
404
405 CSection* pSection = m_SectionArray[place.nSecIndex].get();
406 if (place > pSection->GetBeginWordPlace())
407 return pSection->GetPrevWordPlace(place);
408 if (!pdfium::IndexInBounds(m_SectionArray, place.nSecIndex - 1))
409 return GetBeginWordPlace();
410 return m_SectionArray[place.nSecIndex - 1]->GetEndWordPlace();
411 }
412
GetNextWordPlace(const CPVT_WordPlace & place) const413 CPVT_WordPlace CPDF_VariableText::GetNextWordPlace(
414 const CPVT_WordPlace& place) const {
415 if (place.nSecIndex < 0)
416 return GetBeginWordPlace();
417 if (place.nSecIndex >= pdfium::CollectionSize<int32_t>(m_SectionArray))
418 return GetEndWordPlace();
419
420 CSection* pSection = m_SectionArray[place.nSecIndex].get();
421 if (place < pSection->GetEndWordPlace())
422 return pSection->GetNextWordPlace(place);
423 if (!pdfium::IndexInBounds(m_SectionArray, place.nSecIndex + 1))
424 return GetEndWordPlace();
425 return m_SectionArray[place.nSecIndex + 1]->GetBeginWordPlace();
426 }
427
SearchWordPlace(const CFX_PointF & point) const428 CPVT_WordPlace CPDF_VariableText::SearchWordPlace(
429 const CFX_PointF& point) const {
430 CFX_PointF pt = OutToIn(point);
431 CPVT_WordPlace place = GetBeginWordPlace();
432 int32_t nLeft = 0;
433 int32_t nRight = pdfium::CollectionSize<int32_t>(m_SectionArray) - 1;
434 int32_t nMid = pdfium::CollectionSize<int32_t>(m_SectionArray) / 2;
435 bool bUp = true;
436 bool bDown = true;
437 while (nLeft <= nRight) {
438 if (!pdfium::IndexInBounds(m_SectionArray, nMid))
439 break;
440 CSection* pSection = m_SectionArray[nMid].get();
441 if (IsFloatBigger(pt.y, pSection->m_Rect.top))
442 bUp = false;
443 if (IsFloatBigger(pSection->m_Rect.bottom, pt.y))
444 bDown = false;
445 if (IsFloatSmaller(pt.y, pSection->m_Rect.top)) {
446 nRight = nMid - 1;
447 nMid = (nLeft + nRight) / 2;
448 continue;
449 }
450 if (IsFloatBigger(pt.y, pSection->m_Rect.bottom)) {
451 nLeft = nMid + 1;
452 nMid = (nLeft + nRight) / 2;
453 continue;
454 }
455 place = pSection->SearchWordPlace(
456 CFX_PointF(pt.x - pSection->m_Rect.left, pt.y - pSection->m_Rect.top));
457 place.nSecIndex = nMid;
458 return place;
459 }
460 if (bUp)
461 place = GetBeginWordPlace();
462 if (bDown)
463 place = GetEndWordPlace();
464 return place;
465 }
466
GetUpWordPlace(const CPVT_WordPlace & place,const CFX_PointF & point) const467 CPVT_WordPlace CPDF_VariableText::GetUpWordPlace(
468 const CPVT_WordPlace& place,
469 const CFX_PointF& point) const {
470 if (!pdfium::IndexInBounds(m_SectionArray, place.nSecIndex))
471 return place;
472
473 CSection* pSection = m_SectionArray[place.nSecIndex].get();
474 CPVT_WordPlace temp = place;
475 CFX_PointF pt = OutToIn(point);
476 if (temp.nLineIndex-- > 0) {
477 return pSection->SearchWordPlace(pt.x - pSection->m_Rect.left, temp);
478 }
479 if (temp.nSecIndex-- > 0) {
480 if (pdfium::IndexInBounds(m_SectionArray, temp.nSecIndex)) {
481 CSection* pLastSection = m_SectionArray[temp.nSecIndex].get();
482 temp.nLineIndex =
483 pdfium::CollectionSize<int32_t>(pLastSection->m_LineArray) - 1;
484 return pLastSection->SearchWordPlace(pt.x - pLastSection->m_Rect.left,
485 temp);
486 }
487 }
488 return place;
489 }
490
GetDownWordPlace(const CPVT_WordPlace & place,const CFX_PointF & point) const491 CPVT_WordPlace CPDF_VariableText::GetDownWordPlace(
492 const CPVT_WordPlace& place,
493 const CFX_PointF& point) const {
494 if (!pdfium::IndexInBounds(m_SectionArray, place.nSecIndex))
495 return place;
496
497 CSection* pSection = m_SectionArray[place.nSecIndex].get();
498 CPVT_WordPlace temp = place;
499 CFX_PointF pt = OutToIn(point);
500 if (temp.nLineIndex++ <
501 pdfium::CollectionSize<int32_t>(pSection->m_LineArray) - 1) {
502 return pSection->SearchWordPlace(pt.x - pSection->m_Rect.left, temp);
503 }
504 temp.AdvanceSection();
505 if (!pdfium::IndexInBounds(m_SectionArray, temp.nSecIndex))
506 return place;
507
508 return m_SectionArray[temp.nSecIndex]->SearchWordPlace(
509 pt.x - pSection->m_Rect.left, temp);
510 }
511
GetLineBeginPlace(const CPVT_WordPlace & place) const512 CPVT_WordPlace CPDF_VariableText::GetLineBeginPlace(
513 const CPVT_WordPlace& place) const {
514 return CPVT_WordPlace(place.nSecIndex, place.nLineIndex, -1);
515 }
516
GetLineEndPlace(const CPVT_WordPlace & place) const517 CPVT_WordPlace CPDF_VariableText::GetLineEndPlace(
518 const CPVT_WordPlace& place) const {
519 if (!pdfium::IndexInBounds(m_SectionArray, place.nSecIndex))
520 return place;
521
522 CSection* pSection = m_SectionArray[place.nSecIndex].get();
523 if (!pdfium::IndexInBounds(pSection->m_LineArray, place.nLineIndex))
524 return place;
525
526 return pSection->m_LineArray[place.nLineIndex]->GetEndWordPlace();
527 }
528
GetSectionBeginPlace(const CPVT_WordPlace & place) const529 CPVT_WordPlace CPDF_VariableText::GetSectionBeginPlace(
530 const CPVT_WordPlace& place) const {
531 return CPVT_WordPlace(place.nSecIndex, 0, -1);
532 }
533
GetSectionEndPlace(const CPVT_WordPlace & place) const534 CPVT_WordPlace CPDF_VariableText::GetSectionEndPlace(
535 const CPVT_WordPlace& place) const {
536 if (!pdfium::IndexInBounds(m_SectionArray, place.nSecIndex))
537 return place;
538
539 return m_SectionArray[place.nSecIndex]->GetEndWordPlace();
540 }
541
GetTotalWords() const542 int32_t CPDF_VariableText::GetTotalWords() const {
543 int32_t nTotal = 0;
544 for (const auto& pSection : m_SectionArray) {
545 nTotal +=
546 pdfium::CollectionSize<int32_t>(pSection->m_WordArray) + kReturnLength;
547 }
548 return nTotal - kReturnLength;
549 }
550
AddSection(const CPVT_WordPlace & place)551 CPVT_WordPlace CPDF_VariableText::AddSection(const CPVT_WordPlace& place) {
552 if (IsValid() && !m_bMultiLine)
553 return place;
554
555 int32_t nSecIndex = pdfium::clamp(
556 place.nSecIndex, 0, pdfium::CollectionSize<int32_t>(m_SectionArray));
557
558 auto pSection = pdfium::MakeUnique<CSection>(this);
559 pSection->m_Rect = CPVT_FloatRect();
560 pSection->SecPlace.nSecIndex = nSecIndex;
561 m_SectionArray.insert(m_SectionArray.begin() + nSecIndex,
562 std::move(pSection));
563 return place;
564 }
565
AddLine(const CPVT_WordPlace & place,const CPVT_LineInfo & lineinfo)566 CPVT_WordPlace CPDF_VariableText::AddLine(const CPVT_WordPlace& place,
567 const CPVT_LineInfo& lineinfo) {
568 if (!pdfium::IndexInBounds(m_SectionArray, place.nSecIndex))
569 return place;
570
571 return m_SectionArray[place.nSecIndex]->AddLine(lineinfo);
572 }
573
AddWord(const CPVT_WordPlace & place,const CPVT_WordInfo & wordinfo)574 CPVT_WordPlace CPDF_VariableText::AddWord(const CPVT_WordPlace& place,
575 const CPVT_WordInfo& wordinfo) {
576 if (m_SectionArray.empty())
577 return place;
578
579 CPVT_WordPlace newplace = place;
580 newplace.nSecIndex =
581 pdfium::clamp(newplace.nSecIndex, 0,
582 pdfium::CollectionSize<int32_t>(m_SectionArray) - 1);
583 return m_SectionArray[newplace.nSecIndex]->AddWord(newplace, wordinfo);
584 }
585
GetWordInfo(const CPVT_WordPlace & place,CPVT_WordInfo & wordinfo)586 bool CPDF_VariableText::GetWordInfo(const CPVT_WordPlace& place,
587 CPVT_WordInfo& wordinfo) {
588 if (!pdfium::IndexInBounds(m_SectionArray, place.nSecIndex))
589 return false;
590
591 CSection* pSection = m_SectionArray[place.nSecIndex].get();
592 if (!pdfium::IndexInBounds(pSection->m_WordArray, place.nWordIndex))
593 return false;
594
595 wordinfo = *pSection->m_WordArray[place.nWordIndex];
596 return true;
597 }
598
SetWordInfo(const CPVT_WordPlace & place,const CPVT_WordInfo & wordinfo)599 bool CPDF_VariableText::SetWordInfo(const CPVT_WordPlace& place,
600 const CPVT_WordInfo& wordinfo) {
601 if (!pdfium::IndexInBounds(m_SectionArray, place.nSecIndex))
602 return false;
603
604 CSection* pSection = m_SectionArray[place.nSecIndex].get();
605 if (!pdfium::IndexInBounds(pSection->m_WordArray, place.nWordIndex))
606 return false;
607
608 *pSection->m_WordArray[place.nWordIndex] = wordinfo;
609 return true;
610 }
611
GetLineInfo(const CPVT_WordPlace & place,CPVT_LineInfo & lineinfo)612 bool CPDF_VariableText::GetLineInfo(const CPVT_WordPlace& place,
613 CPVT_LineInfo& lineinfo) {
614 if (!pdfium::IndexInBounds(m_SectionArray, place.nSecIndex))
615 return false;
616
617 CSection* pSection = m_SectionArray[place.nSecIndex].get();
618 if (!pdfium::IndexInBounds(pSection->m_LineArray, place.nLineIndex))
619 return false;
620
621 lineinfo = pSection->m_LineArray[place.nLineIndex]->m_LineInfo;
622 return true;
623 }
624
SetPlateRect(const CFX_FloatRect & rect)625 void CPDF_VariableText::SetPlateRect(const CFX_FloatRect& rect) {
626 m_rcPlate = rect;
627 }
628
SetContentRect(const CPVT_FloatRect & rect)629 void CPDF_VariableText::SetContentRect(const CPVT_FloatRect& rect) {
630 m_rcContent = rect;
631 }
632
GetContentRect() const633 CFX_FloatRect CPDF_VariableText::GetContentRect() const {
634 return InToOut(CPVT_FloatRect(m_rcContent));
635 }
636
GetPlateRect() const637 const CFX_FloatRect& CPDF_VariableText::GetPlateRect() const {
638 return m_rcPlate;
639 }
640
GetWordFontSize()641 float CPDF_VariableText::GetWordFontSize() {
642 return GetFontSize();
643 }
644
GetWordFontIndex(const CPVT_WordInfo & WordInfo)645 int32_t CPDF_VariableText::GetWordFontIndex(const CPVT_WordInfo& WordInfo) {
646 return WordInfo.nFontIndex;
647 }
648
GetWordWidth(int32_t nFontIndex,uint16_t Word,uint16_t SubWord,float fCharSpace,int32_t nHorzScale,float fFontSize,float fWordTail)649 float CPDF_VariableText::GetWordWidth(int32_t nFontIndex,
650 uint16_t Word,
651 uint16_t SubWord,
652 float fCharSpace,
653 int32_t nHorzScale,
654 float fFontSize,
655 float fWordTail) {
656 return (GetCharWidth(nFontIndex, Word, SubWord) * fFontSize * kFontScale +
657 fCharSpace) *
658 nHorzScale * kScalePercent +
659 fWordTail;
660 }
661
GetWordWidth(const CPVT_WordInfo & WordInfo)662 float CPDF_VariableText::GetWordWidth(const CPVT_WordInfo& WordInfo) {
663 return GetWordWidth(GetWordFontIndex(WordInfo), WordInfo.Word, GetSubWord(),
664 GetCharSpace(), GetHorzScale(), GetWordFontSize(),
665 WordInfo.fWordTail);
666 }
667
GetLineAscent()668 float CPDF_VariableText::GetLineAscent() {
669 return GetFontAscent(GetDefaultFontIndex(), GetFontSize());
670 }
671
GetLineDescent()672 float CPDF_VariableText::GetLineDescent() {
673 return GetFontDescent(GetDefaultFontIndex(), GetFontSize());
674 }
675
GetFontAscent(int32_t nFontIndex,float fFontSize)676 float CPDF_VariableText::GetFontAscent(int32_t nFontIndex, float fFontSize) {
677 return (float)GetTypeAscent(nFontIndex) * fFontSize * kFontScale;
678 }
679
GetFontDescent(int32_t nFontIndex,float fFontSize)680 float CPDF_VariableText::GetFontDescent(int32_t nFontIndex, float fFontSize) {
681 return (float)GetTypeDescent(nFontIndex) * fFontSize * kFontScale;
682 }
683
GetWordAscent(const CPVT_WordInfo & WordInfo,float fFontSize)684 float CPDF_VariableText::GetWordAscent(const CPVT_WordInfo& WordInfo,
685 float fFontSize) {
686 return GetFontAscent(GetWordFontIndex(WordInfo), fFontSize);
687 }
688
GetWordDescent(const CPVT_WordInfo & WordInfo,float fFontSize)689 float CPDF_VariableText::GetWordDescent(const CPVT_WordInfo& WordInfo,
690 float fFontSize) {
691 return GetFontDescent(GetWordFontIndex(WordInfo), fFontSize);
692 }
693
GetWordAscent(const CPVT_WordInfo & WordInfo)694 float CPDF_VariableText::GetWordAscent(const CPVT_WordInfo& WordInfo) {
695 return GetFontAscent(GetWordFontIndex(WordInfo), GetWordFontSize());
696 }
697
GetWordDescent(const CPVT_WordInfo & WordInfo)698 float CPDF_VariableText::GetWordDescent(const CPVT_WordInfo& WordInfo) {
699 return GetFontDescent(GetWordFontIndex(WordInfo), GetWordFontSize());
700 }
701
GetLineLeading()702 float CPDF_VariableText::GetLineLeading() {
703 return m_fLineLeading;
704 }
705
GetLineIndent()706 float CPDF_VariableText::GetLineIndent() {
707 return 0.0f;
708 }
709
GetAlignment()710 int32_t CPDF_VariableText::GetAlignment() {
711 return m_nAlignment;
712 }
713
ClearSectionRightWords(const CPVT_WordPlace & place)714 void CPDF_VariableText::ClearSectionRightWords(const CPVT_WordPlace& place) {
715 CPVT_WordPlace wordplace = AdjustLineHeader(place, true);
716 if (!pdfium::IndexInBounds(m_SectionArray, place.nSecIndex))
717 return;
718
719 CSection* pSection = m_SectionArray[place.nSecIndex].get();
720 if (!pdfium::IndexInBounds(pSection->m_WordArray, wordplace.nWordIndex + 1))
721 return;
722
723 pSection->m_WordArray.erase(
724 pSection->m_WordArray.begin() + wordplace.nWordIndex + 1,
725 pSection->m_WordArray.end());
726 }
727
AdjustLineHeader(const CPVT_WordPlace & place,bool bPrevOrNext) const728 CPVT_WordPlace CPDF_VariableText::AdjustLineHeader(const CPVT_WordPlace& place,
729 bool bPrevOrNext) const {
730 if (place.nWordIndex < 0 && place.nLineIndex > 0)
731 return bPrevOrNext ? GetPrevWordPlace(place) : GetNextWordPlace(place);
732 return place;
733 }
734
ClearEmptySection(const CPVT_WordPlace & place)735 bool CPDF_VariableText::ClearEmptySection(const CPVT_WordPlace& place) {
736 if (place.nSecIndex == 0 && m_SectionArray.size() == 1)
737 return false;
738
739 if (!pdfium::IndexInBounds(m_SectionArray, place.nSecIndex))
740 return false;
741
742 if (!m_SectionArray[place.nSecIndex]->m_WordArray.empty())
743 return false;
744
745 m_SectionArray.erase(m_SectionArray.begin() + place.nSecIndex);
746 return true;
747 }
748
ClearEmptySections(const CPVT_WordRange & PlaceRange)749 void CPDF_VariableText::ClearEmptySections(const CPVT_WordRange& PlaceRange) {
750 CPVT_WordPlace wordplace;
751 for (int32_t s = PlaceRange.EndPos.nSecIndex;
752 s > PlaceRange.BeginPos.nSecIndex; s--) {
753 wordplace.nSecIndex = s;
754 ClearEmptySection(wordplace);
755 }
756 }
757
LinkLatterSection(const CPVT_WordPlace & place)758 void CPDF_VariableText::LinkLatterSection(const CPVT_WordPlace& place) {
759 CPVT_WordPlace oldplace = AdjustLineHeader(place, true);
760 if (!pdfium::IndexInBounds(m_SectionArray, place.nSecIndex + 1))
761 return;
762
763 CSection* pNextSection = m_SectionArray[place.nSecIndex + 1].get();
764 if (pdfium::IndexInBounds(m_SectionArray, oldplace.nSecIndex)) {
765 CSection* pSection = m_SectionArray[oldplace.nSecIndex].get();
766 for (auto& pWord : pNextSection->m_WordArray) {
767 oldplace.nWordIndex++;
768 pSection->AddWord(oldplace, *pWord);
769 }
770 }
771 m_SectionArray.erase(m_SectionArray.begin() + place.nSecIndex + 1);
772 }
773
ClearWords(const CPVT_WordRange & PlaceRange)774 void CPDF_VariableText::ClearWords(const CPVT_WordRange& PlaceRange) {
775 CPVT_WordRange NewRange;
776 NewRange.BeginPos = AdjustLineHeader(PlaceRange.BeginPos, true);
777 NewRange.EndPos = AdjustLineHeader(PlaceRange.EndPos, true);
778 for (int32_t s = NewRange.EndPos.nSecIndex; s >= NewRange.BeginPos.nSecIndex;
779 s--) {
780 if (pdfium::IndexInBounds(m_SectionArray, s))
781 m_SectionArray[s]->ClearWords(NewRange);
782 }
783 }
784
ClearLeftWord(const CPVT_WordPlace & place)785 CPVT_WordPlace CPDF_VariableText::ClearLeftWord(const CPVT_WordPlace& place) {
786 if (!pdfium::IndexInBounds(m_SectionArray, place.nSecIndex))
787 return place;
788
789 CSection* pSection = m_SectionArray[place.nSecIndex].get();
790 CPVT_WordPlace leftplace = GetPrevWordPlace(place);
791 if (leftplace == place)
792 return place;
793
794 if (leftplace.nSecIndex != place.nSecIndex) {
795 if (pSection->m_WordArray.empty())
796 ClearEmptySection(place);
797 else
798 LinkLatterSection(leftplace);
799 } else {
800 pSection->ClearWord(place);
801 }
802 return leftplace;
803 }
804
ClearRightWord(const CPVT_WordPlace & place)805 CPVT_WordPlace CPDF_VariableText::ClearRightWord(const CPVT_WordPlace& place) {
806 if (!pdfium::IndexInBounds(m_SectionArray, place.nSecIndex))
807 return place;
808
809 CSection* pSection = m_SectionArray[place.nSecIndex].get();
810 CPVT_WordPlace rightplace = AdjustLineHeader(GetNextWordPlace(place), false);
811 if (rightplace == place)
812 return place;
813
814 if (rightplace.nSecIndex != place.nSecIndex)
815 LinkLatterSection(place);
816 else
817 pSection->ClearWord(rightplace);
818 return place;
819 }
820
RearrangeAll()821 void CPDF_VariableText::RearrangeAll() {
822 Rearrange(CPVT_WordRange(GetBeginWordPlace(), GetEndWordPlace()));
823 }
824
RearrangePart(const CPVT_WordRange & PlaceRange)825 void CPDF_VariableText::RearrangePart(const CPVT_WordRange& PlaceRange) {
826 Rearrange(PlaceRange);
827 }
828
Rearrange(const CPVT_WordRange & PlaceRange)829 CPVT_FloatRect CPDF_VariableText::Rearrange(const CPVT_WordRange& PlaceRange) {
830 CPVT_FloatRect rcRet;
831 if (IsValid()) {
832 if (m_bAutoFontSize) {
833 SetFontSize(GetAutoFontSize());
834 rcRet = RearrangeSections(
835 CPVT_WordRange(GetBeginWordPlace(), GetEndWordPlace()));
836 } else {
837 rcRet = RearrangeSections(PlaceRange);
838 }
839 }
840 SetContentRect(rcRet);
841 return rcRet;
842 }
843
GetAutoFontSize()844 float CPDF_VariableText::GetAutoFontSize() {
845 int32_t nTotal = sizeof(gFontSizeSteps) / sizeof(uint8_t);
846 if (IsMultiLine())
847 nTotal /= 4;
848 if (nTotal <= 0)
849 return 0;
850 if (GetPlateWidth() <= 0)
851 return 0;
852
853 int32_t nLeft = 0;
854 int32_t nRight = nTotal - 1;
855 int32_t nMid = nTotal / 2;
856 while (nLeft <= nRight) {
857 if (IsBigger(gFontSizeSteps[nMid]))
858 nRight = nMid - 1;
859 else
860 nLeft = nMid + 1;
861 nMid = (nLeft + nRight) / 2;
862 }
863 return (float)gFontSizeSteps[nMid];
864 }
865
IsBigger(float fFontSize) const866 bool CPDF_VariableText::IsBigger(float fFontSize) const {
867 CFX_SizeF szTotal;
868 for (const auto& pSection : m_SectionArray) {
869 CFX_SizeF size = pSection->GetSectionSize(fFontSize);
870 szTotal.width = std::max(size.width, szTotal.width);
871 szTotal.height += size.height;
872 if (IsFloatBigger(szTotal.width, GetPlateWidth()) ||
873 IsFloatBigger(szTotal.height, GetPlateHeight())) {
874 return true;
875 }
876 }
877 return false;
878 }
879
RearrangeSections(const CPVT_WordRange & PlaceRange)880 CPVT_FloatRect CPDF_VariableText::RearrangeSections(
881 const CPVT_WordRange& PlaceRange) {
882 CPVT_WordPlace place;
883 float fPosY = 0;
884 float fOldHeight;
885 int32_t nSSecIndex = PlaceRange.BeginPos.nSecIndex;
886 int32_t nESecIndex = PlaceRange.EndPos.nSecIndex;
887 CPVT_FloatRect rcRet;
888 for (int32_t s = 0, sz = pdfium::CollectionSize<int32_t>(m_SectionArray);
889 s < sz; s++) {
890 place.nSecIndex = s;
891 CSection* pSection = m_SectionArray[s].get();
892 pSection->SecPlace = place;
893 CPVT_FloatRect rcSec = pSection->m_Rect;
894 if (s >= nSSecIndex) {
895 if (s <= nESecIndex) {
896 rcSec = pSection->Rearrange();
897 rcSec.top += fPosY;
898 rcSec.bottom += fPosY;
899 } else {
900 fOldHeight = pSection->m_Rect.bottom - pSection->m_Rect.top;
901 rcSec.top = fPosY;
902 rcSec.bottom = fPosY + fOldHeight;
903 }
904 pSection->m_Rect = rcSec;
905 pSection->ResetLinePlace();
906 }
907 if (s == 0) {
908 rcRet = rcSec;
909 } else {
910 rcRet.left = std::min(rcSec.left, rcRet.left);
911 rcRet.top = std::min(rcSec.top, rcRet.top);
912 rcRet.right = std::max(rcSec.right, rcRet.right);
913 rcRet.bottom = std::max(rcSec.bottom, rcRet.bottom);
914 }
915 fPosY += rcSec.Height();
916 }
917 return rcRet;
918 }
919
GetCharWidth(int32_t nFontIndex,uint16_t Word,uint16_t SubWord)920 int32_t CPDF_VariableText::GetCharWidth(int32_t nFontIndex,
921 uint16_t Word,
922 uint16_t SubWord) {
923 if (!m_pVTProvider)
924 return 0;
925 uint16_t word = SubWord ? SubWord : Word;
926 return m_pVTProvider->GetCharWidth(nFontIndex, word);
927 }
928
GetTypeAscent(int32_t nFontIndex)929 int32_t CPDF_VariableText::GetTypeAscent(int32_t nFontIndex) {
930 return m_pVTProvider ? m_pVTProvider->GetTypeAscent(nFontIndex) : 0;
931 }
932
GetTypeDescent(int32_t nFontIndex)933 int32_t CPDF_VariableText::GetTypeDescent(int32_t nFontIndex) {
934 return m_pVTProvider ? m_pVTProvider->GetTypeDescent(nFontIndex) : 0;
935 }
936
GetWordFontIndex(uint16_t word,int32_t charset,int32_t nFontIndex)937 int32_t CPDF_VariableText::GetWordFontIndex(uint16_t word,
938 int32_t charset,
939 int32_t nFontIndex) {
940 return m_pVTProvider
941 ? m_pVTProvider->GetWordFontIndex(word, charset, nFontIndex)
942 : -1;
943 }
944
GetDefaultFontIndex()945 int32_t CPDF_VariableText::GetDefaultFontIndex() {
946 return m_pVTProvider ? m_pVTProvider->GetDefaultFontIndex() : -1;
947 }
948
IsLatinWord(uint16_t word)949 bool CPDF_VariableText::IsLatinWord(uint16_t word) {
950 return m_pVTProvider ? m_pVTProvider->IsLatinWord(word) : false;
951 }
952
GetIterator()953 CPDF_VariableText::Iterator* CPDF_VariableText::GetIterator() {
954 if (!m_pVTIterator)
955 m_pVTIterator = pdfium::MakeUnique<CPDF_VariableText::Iterator>(this);
956 return m_pVTIterator.get();
957 }
958
SetProvider(CPDF_VariableText::Provider * pProvider)959 void CPDF_VariableText::SetProvider(CPDF_VariableText::Provider* pProvider) {
960 m_pVTProvider = pProvider;
961 }
962
GetBTPoint() const963 CFX_PointF CPDF_VariableText::GetBTPoint() const {
964 return CFX_PointF(m_rcPlate.left, m_rcPlate.top);
965 }
966
GetETPoint() const967 CFX_PointF CPDF_VariableText::GetETPoint() const {
968 return CFX_PointF(m_rcPlate.right, m_rcPlate.bottom);
969 }
970
InToOut(const CFX_PointF & point) const971 CFX_PointF CPDF_VariableText::InToOut(const CFX_PointF& point) const {
972 return CFX_PointF(point.x + GetBTPoint().x, GetBTPoint().y - point.y);
973 }
974
OutToIn(const CFX_PointF & point) const975 CFX_PointF CPDF_VariableText::OutToIn(const CFX_PointF& point) const {
976 return CFX_PointF(point.x - GetBTPoint().x, GetBTPoint().y - point.y);
977 }
978
InToOut(const CPVT_FloatRect & rect) const979 CFX_FloatRect CPDF_VariableText::InToOut(const CPVT_FloatRect& rect) const {
980 CFX_PointF ptLeftTop = InToOut(CFX_PointF(rect.left, rect.top));
981 CFX_PointF ptRightBottom = InToOut(CFX_PointF(rect.right, rect.bottom));
982 return CFX_FloatRect(ptLeftTop.x, ptRightBottom.y, ptRightBottom.x,
983 ptLeftTop.y);
984 }
985
OutToIn(const CFX_FloatRect & rect) const986 CPVT_FloatRect CPDF_VariableText::OutToIn(const CFX_FloatRect& rect) const {
987 CFX_PointF ptLeftTop = OutToIn(CFX_PointF(rect.left, rect.top));
988 CFX_PointF ptRightBottom = OutToIn(CFX_PointF(rect.right, rect.bottom));
989 return CPVT_FloatRect(ptLeftTop.x, ptLeftTop.y, ptRightBottom.x,
990 ptRightBottom.y);
991 }
992