• 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/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