• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2016 The PDFium Authors
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/cpvt_variabletext.h"
8 
9 #include <algorithm>
10 #include <utility>
11 
12 #include "core/fpdfapi/font/cpdf_font.h"
13 #include "core/fpdfdoc/cpvt_section.h"
14 #include "core/fpdfdoc/cpvt_word.h"
15 #include "core/fpdfdoc/cpvt_wordinfo.h"
16 #include "core/fpdfdoc/ipvt_fontmap.h"
17 #include "core/fxcrt/fx_codepage.h"
18 #include "core/fxcrt/fx_safe_types.h"
19 #include "core/fxcrt/stl_util.h"
20 #include "third_party/base/check.h"
21 #include "third_party/base/cxx17_backports.h"
22 
23 namespace {
24 
25 constexpr float kFontScale = 0.001f;
26 constexpr uint8_t kReturnLength = 1;
27 
28 constexpr uint8_t kFontSizeSteps[] = {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 CPVT_VariableText::Provider::Provider(IPVT_FontMap* pFontMap)
35     : m_pFontMap(pFontMap) {
36   DCHECK(m_pFontMap);
37 }
38 
39 CPVT_VariableText::Provider::~Provider() = default;
40 
GetCharWidth(int32_t nFontIndex,uint16_t word)41 int CPVT_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 CPVT_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 CPVT_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,FX_Charset charset,int32_t nFontIndex)64 int32_t CPVT_VariableText::Provider::GetWordFontIndex(uint16_t word,
65                                                       FX_Charset 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 
GetDefaultFontIndex()78 int32_t CPVT_VariableText::Provider::GetDefaultFontIndex() {
79   return 0;
80 }
81 
Iterator(CPVT_VariableText * pVT)82 CPVT_VariableText::Iterator::Iterator(CPVT_VariableText* pVT) : m_pVT(pVT) {
83   DCHECK(m_pVT);
84 }
85 
86 CPVT_VariableText::Iterator::~Iterator() = default;
87 
SetAt(int32_t nWordIndex)88 void CPVT_VariableText::Iterator::SetAt(int32_t nWordIndex) {
89   m_CurPos = m_pVT->WordIndexToWordPlace(nWordIndex);
90 }
91 
SetAt(const CPVT_WordPlace & place)92 void CPVT_VariableText::Iterator::SetAt(const CPVT_WordPlace& place) {
93   m_CurPos = place;
94 }
95 
NextWord()96 bool CPVT_VariableText::Iterator::NextWord() {
97   if (m_CurPos == m_pVT->GetEndWordPlace())
98     return false;
99 
100   m_CurPos = m_pVT->GetNextWordPlace(m_CurPos);
101   return true;
102 }
103 
NextLine()104 bool CPVT_VariableText::Iterator::NextLine() {
105   if (!fxcrt::IndexInBounds(m_pVT->m_SectionArray, m_CurPos.nSecIndex))
106     return false;
107 
108   CPVT_Section* pSection = m_pVT->m_SectionArray[m_CurPos.nSecIndex].get();
109   if (m_CurPos.nLineIndex < pSection->GetLineArraySize() - 1) {
110     m_CurPos = CPVT_WordPlace(m_CurPos.nSecIndex, m_CurPos.nLineIndex + 1, -1);
111     return true;
112   }
113   if (m_CurPos.nSecIndex <
114       fxcrt::CollectionSize<int32_t>(m_pVT->m_SectionArray) - 1) {
115     m_CurPos = CPVT_WordPlace(m_CurPos.nSecIndex + 1, 0, -1);
116     return true;
117   }
118   return false;
119 }
120 
GetWord(CPVT_Word & word) const121 bool CPVT_VariableText::Iterator::GetWord(CPVT_Word& word) const {
122   word.WordPlace = m_CurPos;
123   if (!fxcrt::IndexInBounds(m_pVT->m_SectionArray, m_CurPos.nSecIndex))
124     return false;
125 
126   CPVT_Section* pSection = m_pVT->m_SectionArray[m_CurPos.nSecIndex].get();
127   if (!pSection->GetLineFromArray(m_CurPos.nLineIndex))
128     return false;
129 
130   const CPVT_WordInfo* pInfo = pSection->GetWordFromArray(m_CurPos.nWordIndex);
131   if (!pInfo)
132     return false;
133 
134   word.Word = pInfo->Word;
135   word.nCharset = pInfo->nCharset;
136   word.fWidth = m_pVT->GetWordWidth(*pInfo);
137   word.ptWord =
138       m_pVT->InToOut(CFX_PointF(pInfo->fWordX + pSection->GetRect().left,
139                                 pInfo->fWordY + pSection->GetRect().top));
140   word.fAscent = m_pVT->GetWordAscent(*pInfo);
141   word.fDescent = m_pVT->GetWordDescent(*pInfo);
142   word.nFontIndex = pInfo->nFontIndex;
143   word.fFontSize = m_pVT->GetWordFontSize();
144   return true;
145 }
146 
GetLine(CPVT_Line & line) const147 bool CPVT_VariableText::Iterator::GetLine(CPVT_Line& line) const {
148   DCHECK(m_pVT);
149   line.lineplace = CPVT_WordPlace(m_CurPos.nSecIndex, m_CurPos.nLineIndex, -1);
150   if (!fxcrt::IndexInBounds(m_pVT->m_SectionArray, m_CurPos.nSecIndex))
151     return false;
152 
153   CPVT_Section* pSection = m_pVT->m_SectionArray[m_CurPos.nSecIndex].get();
154   const CPVT_Section::Line* pLine =
155       pSection->GetLineFromArray(m_CurPos.nLineIndex);
156   if (!pLine)
157     return false;
158 
159   line.ptLine = m_pVT->InToOut(
160       CFX_PointF(pLine->m_LineInfo.fLineX + pSection->GetRect().left,
161                  pLine->m_LineInfo.fLineY + pSection->GetRect().top));
162   line.fLineWidth = pLine->m_LineInfo.fLineWidth;
163   line.fLineAscent = pLine->m_LineInfo.fLineAscent;
164   line.fLineDescent = pLine->m_LineInfo.fLineDescent;
165   line.lineEnd = pLine->GetEndWordPlace();
166   return true;
167 }
168 
CPVT_VariableText(Provider * pProvider)169 CPVT_VariableText::CPVT_VariableText(Provider* pProvider)
170     : m_pVTProvider(pProvider) {}
171 
172 CPVT_VariableText::~CPVT_VariableText() = default;
173 
Initialize()174 void CPVT_VariableText::Initialize() {
175   if (m_bInitialized)
176     return;
177 
178   CPVT_WordPlace place;
179   place.nSecIndex = 0;
180   AddSection(place);
181 
182   CPVT_LineInfo lineinfo;
183   lineinfo.fLineAscent = GetFontAscent(GetDefaultFontIndex(), GetFontSize());
184   lineinfo.fLineDescent = GetFontDescent(GetDefaultFontIndex(), GetFontSize());
185   AddLine(place, lineinfo);
186 
187   if (!m_SectionArray.empty())
188     m_SectionArray.front()->ResetLinePlace();
189 
190   m_bInitialized = true;
191 }
192 
InsertWord(const CPVT_WordPlace & place,uint16_t word,FX_Charset charset)193 CPVT_WordPlace CPVT_VariableText::InsertWord(const CPVT_WordPlace& place,
194                                              uint16_t word,
195                                              FX_Charset charset) {
196   int32_t nTotalWords = GetTotalWords();
197   if (m_nLimitChar > 0 && nTotalWords >= m_nLimitChar)
198     return place;
199   if (m_nCharArray > 0 && nTotalWords >= m_nCharArray)
200     return place;
201 
202   CPVT_WordPlace newplace = place;
203   newplace.nWordIndex++;
204   int32_t nFontIndex =
205       GetSubWord() > 0 ? GetDefaultFontIndex()
206                        : GetWordFontIndex(word, charset, GetDefaultFontIndex());
207   return AddWord(newplace, CPVT_WordInfo(word, charset, nFontIndex));
208 }
209 
InsertSection(const CPVT_WordPlace & place)210 CPVT_WordPlace CPVT_VariableText::InsertSection(const CPVT_WordPlace& place) {
211   int32_t nTotalWords = GetTotalWords();
212   if (m_nLimitChar > 0 && nTotalWords >= m_nLimitChar)
213     return place;
214   if (m_nCharArray > 0 && nTotalWords >= m_nCharArray)
215     return place;
216   if (!m_bMultiLine)
217     return place;
218 
219   CPVT_WordPlace wordplace = place;
220   UpdateWordPlace(wordplace);
221   if (!fxcrt::IndexInBounds(m_SectionArray, wordplace.nSecIndex))
222     return place;
223 
224   CPVT_Section* pSection = m_SectionArray[wordplace.nSecIndex].get();
225   CPVT_WordPlace NewPlace(wordplace.nSecIndex + 1, 0, -1);
226   AddSection(NewPlace);
227   CPVT_WordPlace result = NewPlace;
228   if (fxcrt::IndexInBounds(m_SectionArray, NewPlace.nSecIndex)) {
229     CPVT_Section* pNewSection = m_SectionArray[NewPlace.nSecIndex].get();
230     for (int32_t w = wordplace.nWordIndex + 1; w < pSection->GetWordArraySize();
231          ++w) {
232       NewPlace.nWordIndex++;
233       pNewSection->AddWord(NewPlace, *pSection->GetWordFromArray(w));
234     }
235   }
236   ClearSectionRightWords(wordplace);
237   return result;
238 }
239 
DeleteWords(const CPVT_WordRange & PlaceRange)240 CPVT_WordPlace CPVT_VariableText::DeleteWords(
241     const CPVT_WordRange& PlaceRange) {
242   bool bLastSecPos =
243       fxcrt::IndexInBounds(m_SectionArray, PlaceRange.EndPos.nSecIndex) &&
244       PlaceRange.EndPos ==
245           m_SectionArray[PlaceRange.EndPos.nSecIndex]->GetEndWordPlace();
246 
247   ClearWords(PlaceRange);
248   if (PlaceRange.BeginPos.nSecIndex != PlaceRange.EndPos.nSecIndex) {
249     ClearEmptySections(PlaceRange);
250     if (!bLastSecPos)
251       LinkLatterSection(PlaceRange.BeginPos);
252   }
253   return PlaceRange.BeginPos;
254 }
255 
DeleteWord(const CPVT_WordPlace & place)256 CPVT_WordPlace CPVT_VariableText::DeleteWord(const CPVT_WordPlace& place) {
257   return ClearRightWord(PrevLineHeaderPlace(place));
258 }
259 
BackSpaceWord(const CPVT_WordPlace & place)260 CPVT_WordPlace CPVT_VariableText::BackSpaceWord(const CPVT_WordPlace& place) {
261   return ClearLeftWord(PrevLineHeaderPlace(place));
262 }
263 
SetText(const WideString & swText)264 void CPVT_VariableText::SetText(const WideString& swText) {
265   DeleteWords(CPVT_WordRange(GetBeginWordPlace(), GetEndWordPlace()));
266   CPVT_WordPlace wp(0, 0, -1);
267   if (!m_SectionArray.empty())
268     m_SectionArray.front()->SetRect(CPVT_FloatRect());
269 
270   FX_SAFE_INT32 nCharCount = 0;
271   for (size_t i = 0, sz = swText.GetLength(); i < sz; i++) {
272     if (m_nLimitChar > 0 && nCharCount.ValueOrDie() >= m_nLimitChar)
273       break;
274     if (m_nCharArray > 0 && nCharCount.ValueOrDie() >= m_nCharArray)
275       break;
276 
277     uint16_t word = swText[i];
278     switch (word) {
279       case 0x0D:
280         if (m_bMultiLine) {
281           if (i + 1 < sz && swText[i + 1] == 0x0A)
282             i++;
283           wp.AdvanceSection();
284           AddSection(wp);
285         }
286         break;
287       case 0x0A:
288         if (m_bMultiLine) {
289           if (i + 1 < sz && swText[i + 1] == 0x0D)
290             i++;
291           wp.AdvanceSection();
292           AddSection(wp);
293         }
294         break;
295       case 0x09:
296         word = 0x20;
297         [[fallthrough]];
298       default:
299         wp = InsertWord(wp, word, FX_Charset::kDefault);
300         break;
301     }
302     nCharCount++;
303   }
304 }
305 
UpdateWordPlace(CPVT_WordPlace & place) const306 void CPVT_VariableText::UpdateWordPlace(CPVT_WordPlace& place) const {
307   if (place.nSecIndex < 0)
308     place = GetBeginWordPlace();
309   if (static_cast<size_t>(place.nSecIndex) >= m_SectionArray.size())
310     place = GetEndWordPlace();
311 
312   place = PrevLineHeaderPlace(place);
313   if (fxcrt::IndexInBounds(m_SectionArray, place.nSecIndex))
314     m_SectionArray[place.nSecIndex]->UpdateWordPlace(place);
315 }
316 
WordPlaceToWordIndex(const CPVT_WordPlace & place) const317 int32_t CPVT_VariableText::WordPlaceToWordIndex(
318     const CPVT_WordPlace& place) const {
319   CPVT_WordPlace newplace = place;
320   UpdateWordPlace(newplace);
321   int32_t nIndex = 0;
322   int32_t i = 0;
323   int32_t sz = 0;
324   for (i = 0, sz = fxcrt::CollectionSize<int32_t>(m_SectionArray);
325        i < sz && i < newplace.nSecIndex; i++) {
326     CPVT_Section* pSection = m_SectionArray[i].get();
327     nIndex += pSection->GetWordArraySize();
328     if (i != sz - 1)
329       nIndex += kReturnLength;
330   }
331   if (fxcrt::IndexInBounds(m_SectionArray, i))
332     nIndex += newplace.nWordIndex + kReturnLength;
333   return nIndex;
334 }
335 
WordIndexToWordPlace(int32_t index) const336 CPVT_WordPlace CPVT_VariableText::WordIndexToWordPlace(int32_t index) const {
337   CPVT_WordPlace place = GetBeginWordPlace();
338   int32_t nOldIndex = 0;
339   int32_t nIndex = 0;
340   bool bFound = false;
341   for (size_t i = 0; i < m_SectionArray.size(); ++i) {
342     CPVT_Section* pSection = m_SectionArray[i].get();
343     nIndex += pSection->GetWordArraySize();
344     if (nIndex == index) {
345       place = pSection->GetEndWordPlace();
346       bFound = true;
347       break;
348     }
349     if (nIndex > index) {
350       place.nSecIndex = pdfium::base::checked_cast<int32_t>(i);
351       place.nWordIndex = index - nOldIndex - 1;
352       pSection->UpdateWordPlace(place);
353       bFound = true;
354       break;
355     }
356     if (i != m_SectionArray.size() - 1)
357       nIndex += kReturnLength;
358     nOldIndex = nIndex;
359   }
360   if (!bFound)
361     place = GetEndWordPlace();
362   return place;
363 }
364 
GetBeginWordPlace() const365 CPVT_WordPlace CPVT_VariableText::GetBeginWordPlace() const {
366   return m_bInitialized ? CPVT_WordPlace(0, 0, -1) : CPVT_WordPlace();
367 }
368 
GetEndWordPlace() const369 CPVT_WordPlace CPVT_VariableText::GetEndWordPlace() const {
370   if (m_SectionArray.empty())
371     return CPVT_WordPlace();
372   return m_SectionArray.back()->GetEndWordPlace();
373 }
374 
GetPrevWordPlace(const CPVT_WordPlace & place) const375 CPVT_WordPlace CPVT_VariableText::GetPrevWordPlace(
376     const CPVT_WordPlace& place) const {
377   if (place.nSecIndex < 0)
378     return GetBeginWordPlace();
379   if (static_cast<size_t>(place.nSecIndex) >= m_SectionArray.size())
380     return GetEndWordPlace();
381 
382   CPVT_Section* pSection = m_SectionArray[place.nSecIndex].get();
383   if (place > pSection->GetBeginWordPlace())
384     return pSection->GetPrevWordPlace(place);
385   if (!fxcrt::IndexInBounds(m_SectionArray, place.nSecIndex - 1))
386     return GetBeginWordPlace();
387   return m_SectionArray[place.nSecIndex - 1]->GetEndWordPlace();
388 }
389 
GetNextWordPlace(const CPVT_WordPlace & place) const390 CPVT_WordPlace CPVT_VariableText::GetNextWordPlace(
391     const CPVT_WordPlace& place) const {
392   if (place.nSecIndex < 0)
393     return GetBeginWordPlace();
394   if (static_cast<size_t>(place.nSecIndex) >= m_SectionArray.size())
395     return GetEndWordPlace();
396 
397   CPVT_Section* pSection = m_SectionArray[place.nSecIndex].get();
398   if (place < pSection->GetEndWordPlace())
399     return pSection->GetNextWordPlace(place);
400   if (!fxcrt::IndexInBounds(m_SectionArray, place.nSecIndex + 1))
401     return GetEndWordPlace();
402   return m_SectionArray[place.nSecIndex + 1]->GetBeginWordPlace();
403 }
404 
SearchWordPlace(const CFX_PointF & point) const405 CPVT_WordPlace CPVT_VariableText::SearchWordPlace(
406     const CFX_PointF& point) const {
407   CFX_PointF pt = OutToIn(point);
408   CPVT_WordPlace place = GetBeginWordPlace();
409   int32_t nLeft = 0;
410   int32_t nRight = fxcrt::CollectionSize<int32_t>(m_SectionArray) - 1;
411   int32_t nMid = fxcrt::CollectionSize<int32_t>(m_SectionArray) / 2;
412   bool bUp = true;
413   bool bDown = true;
414   while (nLeft <= nRight) {
415     if (!fxcrt::IndexInBounds(m_SectionArray, nMid))
416       break;
417     CPVT_Section* pSection = m_SectionArray[nMid].get();
418     if (FXSYS_IsFloatBigger(pt.y, pSection->GetRect().top))
419       bUp = false;
420     if (FXSYS_IsFloatBigger(pSection->GetRect().bottom, pt.y))
421       bDown = false;
422     if (FXSYS_IsFloatSmaller(pt.y, pSection->GetRect().top)) {
423       nRight = nMid - 1;
424       nMid = (nLeft + nRight) / 2;
425       continue;
426     }
427     if (FXSYS_IsFloatBigger(pt.y, pSection->GetRect().bottom)) {
428       nLeft = nMid + 1;
429       nMid = (nLeft + nRight) / 2;
430       continue;
431     }
432     place = pSection->SearchWordPlace(CFX_PointF(
433         pt.x - pSection->GetRect().left, pt.y - pSection->GetRect().top));
434     place.nSecIndex = nMid;
435     return place;
436   }
437   if (bUp)
438     place = GetBeginWordPlace();
439   if (bDown)
440     place = GetEndWordPlace();
441   return place;
442 }
443 
GetUpWordPlace(const CPVT_WordPlace & place,const CFX_PointF & point) const444 CPVT_WordPlace CPVT_VariableText::GetUpWordPlace(
445     const CPVT_WordPlace& place,
446     const CFX_PointF& point) const {
447   if (!fxcrt::IndexInBounds(m_SectionArray, place.nSecIndex))
448     return place;
449 
450   CPVT_Section* pSection = m_SectionArray[place.nSecIndex].get();
451   CPVT_WordPlace temp = place;
452   CFX_PointF pt = OutToIn(point);
453   if (temp.nLineIndex-- > 0) {
454     return pSection->SearchWordPlace(pt.x - pSection->GetRect().left, temp);
455   }
456   if (temp.nSecIndex-- > 0) {
457     if (fxcrt::IndexInBounds(m_SectionArray, temp.nSecIndex)) {
458       CPVT_Section* pLastSection = m_SectionArray[temp.nSecIndex].get();
459       temp.nLineIndex = pLastSection->GetLineArraySize() - 1;
460       return pLastSection->SearchWordPlace(pt.x - pLastSection->GetRect().left,
461                                            temp);
462     }
463   }
464   return place;
465 }
466 
GetDownWordPlace(const CPVT_WordPlace & place,const CFX_PointF & point) const467 CPVT_WordPlace CPVT_VariableText::GetDownWordPlace(
468     const CPVT_WordPlace& place,
469     const CFX_PointF& point) const {
470   if (!fxcrt::IndexInBounds(m_SectionArray, place.nSecIndex))
471     return place;
472 
473   CPVT_Section* pSection = m_SectionArray[place.nSecIndex].get();
474   CPVT_WordPlace temp = place;
475   CFX_PointF pt = OutToIn(point);
476   if (temp.nLineIndex++ < pSection->GetLineArraySize() - 1) {
477     return pSection->SearchWordPlace(pt.x - pSection->GetRect().left, temp);
478   }
479   temp.AdvanceSection();
480   if (!fxcrt::IndexInBounds(m_SectionArray, temp.nSecIndex))
481     return place;
482 
483   return m_SectionArray[temp.nSecIndex]->SearchWordPlace(
484       pt.x - pSection->GetRect().left, temp);
485 }
486 
GetLineBeginPlace(const CPVT_WordPlace & place) const487 CPVT_WordPlace CPVT_VariableText::GetLineBeginPlace(
488     const CPVT_WordPlace& place) const {
489   return CPVT_WordPlace(place.nSecIndex, place.nLineIndex, -1);
490 }
491 
GetLineEndPlace(const CPVT_WordPlace & place) const492 CPVT_WordPlace CPVT_VariableText::GetLineEndPlace(
493     const CPVT_WordPlace& place) const {
494   if (!fxcrt::IndexInBounds(m_SectionArray, place.nSecIndex))
495     return place;
496 
497   CPVT_Section* pSection = m_SectionArray[place.nSecIndex].get();
498   const CPVT_Section::Line* pLine =
499       pSection->GetLineFromArray(place.nLineIndex);
500   if (!pLine)
501     return place;
502 
503   return pLine->GetEndWordPlace();
504 }
505 
GetSectionBeginPlace(const CPVT_WordPlace & place) const506 CPVT_WordPlace CPVT_VariableText::GetSectionBeginPlace(
507     const CPVT_WordPlace& place) const {
508   return CPVT_WordPlace(place.nSecIndex, 0, -1);
509 }
510 
GetSectionEndPlace(const CPVT_WordPlace & place) const511 CPVT_WordPlace CPVT_VariableText::GetSectionEndPlace(
512     const CPVT_WordPlace& place) const {
513   if (!fxcrt::IndexInBounds(m_SectionArray, place.nSecIndex))
514     return place;
515 
516   return m_SectionArray[place.nSecIndex]->GetEndWordPlace();
517 }
518 
GetTotalWords() const519 int32_t CPVT_VariableText::GetTotalWords() const {
520   int32_t nTotal = 0;
521   for (const auto& pSection : m_SectionArray) {
522     nTotal += pSection->GetWordArraySize() + kReturnLength;
523   }
524   return nTotal - kReturnLength;
525 }
526 
AddSection(const CPVT_WordPlace & place)527 CPVT_WordPlace CPVT_VariableText::AddSection(const CPVT_WordPlace& place) {
528   if (IsValid() && !m_bMultiLine)
529     return place;
530 
531   int32_t nSecIndex = pdfium::clamp(
532       place.nSecIndex, 0, fxcrt::CollectionSize<int32_t>(m_SectionArray));
533 
534   auto pSection = std::make_unique<CPVT_Section>(this);
535   pSection->SetRect(CPVT_FloatRect());
536   pSection->SetPlaceIndex(nSecIndex);
537   m_SectionArray.insert(m_SectionArray.begin() + nSecIndex,
538                         std::move(pSection));
539   return place;
540 }
541 
AddLine(const CPVT_WordPlace & place,const CPVT_LineInfo & lineinfo)542 CPVT_WordPlace CPVT_VariableText::AddLine(const CPVT_WordPlace& place,
543                                           const CPVT_LineInfo& lineinfo) {
544   if (!fxcrt::IndexInBounds(m_SectionArray, place.nSecIndex))
545     return place;
546 
547   return m_SectionArray[place.nSecIndex]->AddLine(lineinfo);
548 }
549 
AddWord(const CPVT_WordPlace & place,const CPVT_WordInfo & wordinfo)550 CPVT_WordPlace CPVT_VariableText::AddWord(const CPVT_WordPlace& place,
551                                           const CPVT_WordInfo& wordinfo) {
552   if (m_SectionArray.empty())
553     return place;
554 
555   CPVT_WordPlace newplace = place;
556   newplace.nSecIndex =
557       pdfium::clamp(newplace.nSecIndex, 0,
558                     fxcrt::CollectionSize<int32_t>(m_SectionArray) - 1);
559   return m_SectionArray[newplace.nSecIndex]->AddWord(newplace, wordinfo);
560 }
561 
SetPlateRect(const CFX_FloatRect & rect)562 void CPVT_VariableText::SetPlateRect(const CFX_FloatRect& rect) {
563   m_rcPlate = rect;
564 }
565 
GetContentRect() const566 CFX_FloatRect CPVT_VariableText::GetContentRect() const {
567   return InToOut(m_rcContent);
568 }
569 
GetPlateRect() const570 const CFX_FloatRect& CPVT_VariableText::GetPlateRect() const {
571   return m_rcPlate;
572 }
573 
GetWordFontSize() const574 float CPVT_VariableText::GetWordFontSize() const {
575   return GetFontSize();
576 }
577 
GetWordWidth(int32_t nFontIndex,uint16_t Word,uint16_t SubWord,float fFontSize,float fWordTail) const578 float CPVT_VariableText::GetWordWidth(int32_t nFontIndex,
579                                       uint16_t Word,
580                                       uint16_t SubWord,
581                                       float fFontSize,
582                                       float fWordTail) const {
583   return GetCharWidth(nFontIndex, Word, SubWord) * fFontSize * kFontScale +
584          fWordTail;
585 }
586 
GetWordWidth(const CPVT_WordInfo & WordInfo) const587 float CPVT_VariableText::GetWordWidth(const CPVT_WordInfo& WordInfo) const {
588   return GetWordWidth(WordInfo.nFontIndex, WordInfo.Word, GetSubWord(),
589                       GetWordFontSize(), WordInfo.fWordTail);
590 }
591 
GetLineAscent()592 float CPVT_VariableText::GetLineAscent() {
593   return GetFontAscent(GetDefaultFontIndex(), GetFontSize());
594 }
595 
GetLineDescent()596 float CPVT_VariableText::GetLineDescent() {
597   return GetFontDescent(GetDefaultFontIndex(), GetFontSize());
598 }
599 
GetFontAscent(int32_t nFontIndex,float fFontSize) const600 float CPVT_VariableText::GetFontAscent(int32_t nFontIndex,
601                                        float fFontSize) const {
602   float ascent = m_pVTProvider ? m_pVTProvider->GetTypeAscent(nFontIndex) : 0;
603   return ascent * fFontSize * kFontScale;
604 }
605 
GetFontDescent(int32_t nFontIndex,float fFontSize) const606 float CPVT_VariableText::GetFontDescent(int32_t nFontIndex,
607                                         float fFontSize) const {
608   float descent = m_pVTProvider ? m_pVTProvider->GetTypeDescent(nFontIndex) : 0;
609   return descent * fFontSize * kFontScale;
610 }
611 
GetWordAscent(const CPVT_WordInfo & WordInfo,float fFontSize) const612 float CPVT_VariableText::GetWordAscent(const CPVT_WordInfo& WordInfo,
613                                        float fFontSize) const {
614   return GetFontAscent(WordInfo.nFontIndex, fFontSize);
615 }
616 
GetWordDescent(const CPVT_WordInfo & WordInfo,float fFontSize) const617 float CPVT_VariableText::GetWordDescent(const CPVT_WordInfo& WordInfo,
618                                         float fFontSize) const {
619   return GetFontDescent(WordInfo.nFontIndex, fFontSize);
620 }
621 
GetWordAscent(const CPVT_WordInfo & WordInfo) const622 float CPVT_VariableText::GetWordAscent(const CPVT_WordInfo& WordInfo) const {
623   return GetFontAscent(WordInfo.nFontIndex, GetWordFontSize());
624 }
625 
GetWordDescent(const CPVT_WordInfo & WordInfo) const626 float CPVT_VariableText::GetWordDescent(const CPVT_WordInfo& WordInfo) const {
627   return GetFontDescent(WordInfo.nFontIndex, GetWordFontSize());
628 }
629 
GetLineLeading()630 float CPVT_VariableText::GetLineLeading() {
631   return m_fLineLeading;
632 }
633 
GetLineIndent()634 float CPVT_VariableText::GetLineIndent() {
635   return 0.0f;
636 }
637 
ClearSectionRightWords(const CPVT_WordPlace & place)638 void CPVT_VariableText::ClearSectionRightWords(const CPVT_WordPlace& place) {
639   CPVT_WordPlace wordplace = PrevLineHeaderPlace(place);
640   if (!fxcrt::IndexInBounds(m_SectionArray, place.nSecIndex))
641     return;
642 
643   CPVT_Section* pSection = m_SectionArray[place.nSecIndex].get();
644   pSection->EraseWordsFrom(wordplace.nWordIndex + 1);
645 }
646 
PrevLineHeaderPlace(const CPVT_WordPlace & place) const647 CPVT_WordPlace CPVT_VariableText::PrevLineHeaderPlace(
648     const CPVT_WordPlace& place) const {
649   if (place.nWordIndex < 0 && place.nLineIndex > 0)
650     return GetPrevWordPlace(place);
651   return place;
652 }
653 
NextLineHeaderPlace(const CPVT_WordPlace & place) const654 CPVT_WordPlace CPVT_VariableText::NextLineHeaderPlace(
655     const CPVT_WordPlace& place) const {
656   if (place.nWordIndex < 0 && place.nLineIndex > 0)
657     return GetNextWordPlace(place);
658   return place;
659 }
660 
ClearEmptySection(const CPVT_WordPlace & place)661 bool CPVT_VariableText::ClearEmptySection(const CPVT_WordPlace& place) {
662   if (place.nSecIndex == 0 && m_SectionArray.size() == 1)
663     return false;
664 
665   if (!fxcrt::IndexInBounds(m_SectionArray, place.nSecIndex))
666     return false;
667 
668   if (m_SectionArray[place.nSecIndex]->GetWordArraySize() != 0)
669     return false;
670 
671   m_SectionArray.erase(m_SectionArray.begin() + place.nSecIndex);
672   return true;
673 }
674 
ClearEmptySections(const CPVT_WordRange & PlaceRange)675 void CPVT_VariableText::ClearEmptySections(const CPVT_WordRange& PlaceRange) {
676   CPVT_WordPlace wordplace;
677   for (int32_t s = PlaceRange.EndPos.nSecIndex;
678        s > PlaceRange.BeginPos.nSecIndex; s--) {
679     wordplace.nSecIndex = s;
680     ClearEmptySection(wordplace);
681   }
682 }
683 
LinkLatterSection(const CPVT_WordPlace & place)684 void CPVT_VariableText::LinkLatterSection(const CPVT_WordPlace& place) {
685   CPVT_WordPlace oldplace = PrevLineHeaderPlace(place);
686   if (!fxcrt::IndexInBounds(m_SectionArray, place.nSecIndex + 1))
687     return;
688 
689   CPVT_Section* pNextSection = m_SectionArray[place.nSecIndex + 1].get();
690   if (fxcrt::IndexInBounds(m_SectionArray, oldplace.nSecIndex)) {
691     CPVT_Section* pSection = m_SectionArray[oldplace.nSecIndex].get();
692     for (int32_t i = 0; i < pNextSection->GetWordArraySize(); ++i) {
693       oldplace.nWordIndex++;
694       pSection->AddWord(oldplace, *pNextSection->GetWordFromArray(i));
695     }
696   }
697   m_SectionArray.erase(m_SectionArray.begin() + place.nSecIndex + 1);
698 }
699 
ClearWords(const CPVT_WordRange & PlaceRange)700 void CPVT_VariableText::ClearWords(const CPVT_WordRange& PlaceRange) {
701   CPVT_WordRange NewRange;
702   NewRange.BeginPos = PrevLineHeaderPlace(PlaceRange.BeginPos);
703   NewRange.EndPos = PrevLineHeaderPlace(PlaceRange.EndPos);
704   for (int32_t s = NewRange.EndPos.nSecIndex; s >= NewRange.BeginPos.nSecIndex;
705        s--) {
706     if (fxcrt::IndexInBounds(m_SectionArray, s))
707       m_SectionArray[s]->ClearWords(NewRange);
708   }
709 }
710 
ClearLeftWord(const CPVT_WordPlace & place)711 CPVT_WordPlace CPVT_VariableText::ClearLeftWord(const CPVT_WordPlace& place) {
712   if (!fxcrt::IndexInBounds(m_SectionArray, place.nSecIndex))
713     return place;
714 
715   CPVT_Section* pSection = m_SectionArray[place.nSecIndex].get();
716   CPVT_WordPlace leftplace = GetPrevWordPlace(place);
717   if (leftplace == place)
718     return place;
719 
720   if (leftplace.nSecIndex != place.nSecIndex) {
721     if (pSection->GetWordArraySize() == 0)
722       ClearEmptySection(place);
723     else
724       LinkLatterSection(leftplace);
725   } else {
726     pSection->ClearWord(place);
727   }
728   return leftplace;
729 }
730 
ClearRightWord(const CPVT_WordPlace & place)731 CPVT_WordPlace CPVT_VariableText::ClearRightWord(const CPVT_WordPlace& place) {
732   if (!fxcrt::IndexInBounds(m_SectionArray, place.nSecIndex))
733     return place;
734 
735   CPVT_Section* pSection = m_SectionArray[place.nSecIndex].get();
736   CPVT_WordPlace rightplace = NextLineHeaderPlace(GetNextWordPlace(place));
737   if (rightplace == place)
738     return place;
739 
740   if (rightplace.nSecIndex != place.nSecIndex)
741     LinkLatterSection(place);
742   else
743     pSection->ClearWord(rightplace);
744   return place;
745 }
746 
RearrangeAll()747 void CPVT_VariableText::RearrangeAll() {
748   Rearrange(CPVT_WordRange(GetBeginWordPlace(), GetEndWordPlace()));
749 }
750 
RearrangePart(const CPVT_WordRange & PlaceRange)751 void CPVT_VariableText::RearrangePart(const CPVT_WordRange& PlaceRange) {
752   Rearrange(PlaceRange);
753 }
754 
Rearrange(const CPVT_WordRange & PlaceRange)755 void CPVT_VariableText::Rearrange(const CPVT_WordRange& PlaceRange) {
756   CPVT_FloatRect rcRet;
757   if (IsValid()) {
758     if (m_bAutoFontSize) {
759       SetFontSize(GetAutoFontSize());
760       rcRet = RearrangeSections(
761           CPVT_WordRange(GetBeginWordPlace(), GetEndWordPlace()));
762     } else {
763       rcRet = RearrangeSections(PlaceRange);
764     }
765   }
766   m_rcContent = rcRet;
767 }
768 
GetAutoFontSize()769 float CPVT_VariableText::GetAutoFontSize() {
770   int32_t nTotal = sizeof(kFontSizeSteps) / sizeof(uint8_t);
771   if (IsMultiLine())
772     nTotal /= 4;
773   if (nTotal <= 0)
774     return 0;
775   if (GetPlateWidth() <= 0)
776     return 0;
777 
778   int32_t nLeft = 0;
779   int32_t nRight = nTotal - 1;
780   int32_t nMid = nTotal / 2;
781   while (nLeft <= nRight) {
782     if (IsBigger(kFontSizeSteps[nMid]))
783       nRight = nMid - 1;
784     else
785       nLeft = nMid + 1;
786     nMid = (nLeft + nRight) / 2;
787   }
788   return (float)kFontSizeSteps[nMid];
789 }
790 
IsBigger(float fFontSize) const791 bool CPVT_VariableText::IsBigger(float fFontSize) const {
792   CFX_SizeF szTotal;
793   for (const auto& pSection : m_SectionArray) {
794     CFX_SizeF size = pSection->GetSectionSize(fFontSize);
795     szTotal.width = std::max(size.width, szTotal.width);
796     szTotal.height += size.height;
797     if (FXSYS_IsFloatBigger(szTotal.width, GetPlateWidth()) ||
798         FXSYS_IsFloatBigger(szTotal.height, GetPlateHeight())) {
799       return true;
800     }
801   }
802   return false;
803 }
804 
RearrangeSections(const CPVT_WordRange & PlaceRange)805 CPVT_FloatRect CPVT_VariableText::RearrangeSections(
806     const CPVT_WordRange& PlaceRange) {
807   float fPosY = 0;
808   CPVT_FloatRect rcRet;
809   for (int32_t s = 0, sz = fxcrt::CollectionSize<int32_t>(m_SectionArray);
810        s < sz; s++) {
811     CPVT_WordPlace place;
812     place.nSecIndex = s;
813     CPVT_Section* pSection = m_SectionArray[s].get();
814     pSection->SetPlace(place);
815     CPVT_FloatRect rcSec = pSection->GetRect();
816     if (s >= PlaceRange.BeginPos.nSecIndex) {
817       if (s <= PlaceRange.EndPos.nSecIndex) {
818         rcSec = pSection->Rearrange();
819         rcSec.top += fPosY;
820         rcSec.bottom += fPosY;
821       } else {
822         float fOldHeight = pSection->GetRect().bottom - pSection->GetRect().top;
823         rcSec.top = fPosY;
824         rcSec.bottom = fPosY + fOldHeight;
825       }
826       pSection->SetRect(rcSec);
827       pSection->ResetLinePlace();
828     }
829     if (s == 0) {
830       rcRet = rcSec;
831     } else {
832       rcRet.left = std::min(rcSec.left, rcRet.left);
833       rcRet.top = std::min(rcSec.top, rcRet.top);
834       rcRet.right = std::max(rcSec.right, rcRet.right);
835       rcRet.bottom = std::max(rcSec.bottom, rcRet.bottom);
836     }
837     fPosY += rcSec.Height();
838   }
839   return rcRet;
840 }
841 
GetCharWidth(int32_t nFontIndex,uint16_t Word,uint16_t SubWord) const842 int CPVT_VariableText::GetCharWidth(int32_t nFontIndex,
843                                     uint16_t Word,
844                                     uint16_t SubWord) const {
845   if (!m_pVTProvider)
846     return 0;
847   uint16_t word = SubWord ? SubWord : Word;
848   return m_pVTProvider->GetCharWidth(nFontIndex, word);
849 }
850 
GetWordFontIndex(uint16_t word,FX_Charset charset,int32_t nFontIndex)851 int32_t CPVT_VariableText::GetWordFontIndex(uint16_t word,
852                                             FX_Charset charset,
853                                             int32_t nFontIndex) {
854   return m_pVTProvider
855              ? m_pVTProvider->GetWordFontIndex(word, charset, nFontIndex)
856              : -1;
857 }
858 
GetDefaultFontIndex()859 int32_t CPVT_VariableText::GetDefaultFontIndex() {
860   return m_pVTProvider ? m_pVTProvider->GetDefaultFontIndex() : -1;
861 }
862 
GetIterator()863 CPVT_VariableText::Iterator* CPVT_VariableText::GetIterator() {
864   if (!m_pVTIterator)
865     m_pVTIterator = std::make_unique<CPVT_VariableText::Iterator>(this);
866   return m_pVTIterator.get();
867 }
868 
SetProvider(Provider * pProvider)869 void CPVT_VariableText::SetProvider(Provider* pProvider) {
870   m_pVTProvider = pProvider;
871 }
872 
GetBTPoint() const873 CFX_PointF CPVT_VariableText::GetBTPoint() const {
874   return CFX_PointF(m_rcPlate.left, m_rcPlate.top);
875 }
876 
GetETPoint() const877 CFX_PointF CPVT_VariableText::GetETPoint() const {
878   return CFX_PointF(m_rcPlate.right, m_rcPlate.bottom);
879 }
880 
InToOut(const CFX_PointF & point) const881 CFX_PointF CPVT_VariableText::InToOut(const CFX_PointF& point) const {
882   return CFX_PointF(point.x + GetBTPoint().x, GetBTPoint().y - point.y);
883 }
884 
OutToIn(const CFX_PointF & point) const885 CFX_PointF CPVT_VariableText::OutToIn(const CFX_PointF& point) const {
886   return CFX_PointF(point.x - GetBTPoint().x, GetBTPoint().y - point.y);
887 }
888 
InToOut(const CPVT_FloatRect & rect) const889 CFX_FloatRect CPVT_VariableText::InToOut(const CPVT_FloatRect& rect) const {
890   CFX_PointF ptLeftTop = InToOut(CFX_PointF(rect.left, rect.top));
891   CFX_PointF ptRightBottom = InToOut(CFX_PointF(rect.right, rect.bottom));
892   return CFX_FloatRect(ptLeftTop.x, ptRightBottom.y, ptRightBottom.x,
893                        ptLeftTop.y);
894 }
895