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