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