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