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