1 // Copyright 2016 PDFium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com 6 7 #include "core/fpdfdoc/cpdf_variabletext.h" 8 9 #include <algorithm> 10 #include <utility> 11 12 #include "core/fpdfapi/font/cpdf_font.h" 13 #include "core/fpdfdoc/cline.h" 14 #include "core/fpdfdoc/cpvt_word.h" 15 #include "core/fpdfdoc/cpvt_wordinfo.h" 16 #include "core/fpdfdoc/csection.h" 17 #include "core/fpdfdoc/ipvt_fontmap.h" 18 #include "core/fxcrt/fx_codepage.h" 19 #include "third_party/base/ptr_util.h" 20 #include "third_party/base/stl_util.h" 21 22 namespace { 23 24 const float kFontScale = 0.001f; 25 const uint8_t kReturnLength = 1; 26 const float kScalePercent = 0.01f; 27 28 const uint8_t gFontSizeSteps[] = {4, 6, 8, 9, 10, 12, 14, 18, 20, 29 25, 30, 35, 40, 45, 50, 55, 60, 70, 30 80, 90, 100, 110, 120, 130, 144}; 31 32 } // namespace 33 34 CPDF_VariableText::Provider::Provider(IPVT_FontMap* pFontMap) 35 : m_pFontMap(pFontMap) { 36 ASSERT(m_pFontMap); 37 } 38 39 CPDF_VariableText::Provider::~Provider() {} 40 41 int32_t CPDF_VariableText::Provider::GetCharWidth(int32_t nFontIndex, 42 uint16_t word) { 43 if (CPDF_Font* pPDFFont = m_pFontMap->GetPDFFont(nFontIndex)) { 44 uint32_t charcode = pPDFFont->CharCodeFromUnicode(word); 45 if (charcode != CPDF_Font::kInvalidCharCode) 46 return pPDFFont->GetCharWidthF(charcode); 47 } 48 return 0; 49 } 50 51 int32_t CPDF_VariableText::Provider::GetTypeAscent(int32_t nFontIndex) { 52 if (CPDF_Font* pPDFFont = m_pFontMap->GetPDFFont(nFontIndex)) 53 return pPDFFont->GetTypeAscent(); 54 return 0; 55 } 56 57 int32_t CPDF_VariableText::Provider::GetTypeDescent(int32_t nFontIndex) { 58 if (CPDF_Font* pPDFFont = m_pFontMap->GetPDFFont(nFontIndex)) 59 return pPDFFont->GetTypeDescent(); 60 return 0; 61 } 62 63 int32_t CPDF_VariableText::Provider::GetWordFontIndex(uint16_t word, 64 int32_t charset, 65 int32_t nFontIndex) { 66 if (CPDF_Font* pDefFont = m_pFontMap->GetPDFFont(0)) { 67 if (pDefFont->CharCodeFromUnicode(word) != CPDF_Font::kInvalidCharCode) 68 return 0; 69 } 70 if (CPDF_Font* pSysFont = m_pFontMap->GetPDFFont(1)) { 71 if (pSysFont->CharCodeFromUnicode(word) != CPDF_Font::kInvalidCharCode) 72 return 1; 73 } 74 return -1; 75 } 76 77 bool CPDF_VariableText::Provider::IsLatinWord(uint16_t word) { 78 return (word >= 0x61 && word <= 0x7A) || (word >= 0x41 && word <= 0x5A) || 79 word == 0x2D || word == 0x27; 80 } 81 82 int32_t CPDF_VariableText::Provider::GetDefaultFontIndex() { 83 return 0; 84 } 85 86 CPDF_VariableText::Iterator::Iterator(CPDF_VariableText* pVT) 87 : m_CurPos(-1, -1, -1), m_pVT(pVT) {} 88 89 CPDF_VariableText::Iterator::~Iterator() {} 90 91 void CPDF_VariableText::Iterator::SetAt(int32_t nWordIndex) { 92 m_CurPos = m_pVT->WordIndexToWordPlace(nWordIndex); 93 } 94 95 void CPDF_VariableText::Iterator::SetAt(const CPVT_WordPlace& place) { 96 ASSERT(m_pVT); 97 m_CurPos = place; 98 } 99 100 bool CPDF_VariableText::Iterator::NextWord() { 101 if (m_CurPos == m_pVT->GetEndWordPlace()) 102 return false; 103 104 m_CurPos = m_pVT->GetNextWordPlace(m_CurPos); 105 return true; 106 } 107 108 bool CPDF_VariableText::Iterator::PrevWord() { 109 if (m_CurPos == m_pVT->GetBeginWordPlace()) 110 return false; 111 112 m_CurPos = m_pVT->GetPrevWordPlace(m_CurPos); 113 return true; 114 } 115 116 bool CPDF_VariableText::Iterator::NextLine() { 117 if (!pdfium::IndexInBounds(m_pVT->m_SectionArray, m_CurPos.nSecIndex)) 118 return false; 119 120 CSection* pSection = m_pVT->m_SectionArray[m_CurPos.nSecIndex].get(); 121 if (m_CurPos.nLineIndex < 122 pdfium::CollectionSize<int32_t>(pSection->m_LineArray) - 1) { 123 m_CurPos = CPVT_WordPlace(m_CurPos.nSecIndex, m_CurPos.nLineIndex + 1, -1); 124 return true; 125 } 126 if (m_CurPos.nSecIndex < 127 pdfium::CollectionSize<int32_t>(m_pVT->m_SectionArray) - 1) { 128 m_CurPos = CPVT_WordPlace(m_CurPos.nSecIndex + 1, 0, -1); 129 return true; 130 } 131 return false; 132 } 133 134 bool CPDF_VariableText::Iterator::GetWord(CPVT_Word& word) const { 135 word.WordPlace = m_CurPos; 136 if (!pdfium::IndexInBounds(m_pVT->m_SectionArray, m_CurPos.nSecIndex)) 137 return false; 138 139 CSection* pSection = m_pVT->m_SectionArray[m_CurPos.nSecIndex].get(); 140 if (!pdfium::IndexInBounds(pSection->m_LineArray, m_CurPos.nLineIndex) || 141 !pdfium::IndexInBounds(pSection->m_WordArray, m_CurPos.nWordIndex)) { 142 return false; 143 } 144 145 CPVT_WordInfo* pWord = pSection->m_WordArray[m_CurPos.nWordIndex].get(); 146 word.Word = pWord->Word; 147 word.nCharset = pWord->nCharset; 148 word.fWidth = m_pVT->GetWordWidth(*pWord); 149 word.ptWord = 150 m_pVT->InToOut(CFX_PointF(pWord->fWordX + pSection->m_Rect.left, 151 pWord->fWordY + pSection->m_Rect.top)); 152 word.fAscent = m_pVT->GetWordAscent(*pWord); 153 word.fDescent = m_pVT->GetWordDescent(*pWord); 154 word.nFontIndex = m_pVT->GetWordFontIndex(*pWord); 155 word.fFontSize = m_pVT->GetWordFontSize(); 156 return true; 157 } 158 159 bool CPDF_VariableText::Iterator::GetLine(CPVT_Line& line) const { 160 ASSERT(m_pVT); 161 line.lineplace = CPVT_WordPlace(m_CurPos.nSecIndex, m_CurPos.nLineIndex, -1); 162 if (!pdfium::IndexInBounds(m_pVT->m_SectionArray, m_CurPos.nSecIndex)) 163 return false; 164 165 CSection* pSection = m_pVT->m_SectionArray[m_CurPos.nSecIndex].get(); 166 if (!pdfium::IndexInBounds(pSection->m_LineArray, m_CurPos.nLineIndex)) 167 return false; 168 169 CLine* pLine = pSection->m_LineArray[m_CurPos.nLineIndex].get(); 170 line.ptLine = m_pVT->InToOut( 171 CFX_PointF(pLine->m_LineInfo.fLineX + pSection->m_Rect.left, 172 pLine->m_LineInfo.fLineY + pSection->m_Rect.top)); 173 line.fLineWidth = pLine->m_LineInfo.fLineWidth; 174 line.fLineAscent = pLine->m_LineInfo.fLineAscent; 175 line.fLineDescent = pLine->m_LineInfo.fLineDescent; 176 line.lineEnd = pLine->GetEndWordPlace(); 177 return true; 178 } 179 180 CPDF_VariableText::CPDF_VariableText() 181 : m_nLimitChar(0), 182 m_nCharArray(0), 183 m_bMultiLine(false), 184 m_bLimitWidth(false), 185 m_bAutoFontSize(false), 186 m_nAlignment(0), 187 m_fLineLeading(0.0f), 188 m_fCharSpace(0.0f), 189 m_nHorzScale(100), 190 m_wSubWord(0), 191 m_fFontSize(0.0f), 192 m_bInitialized(false), 193 m_pVTProvider(nullptr) {} 194 195 CPDF_VariableText::~CPDF_VariableText() {} 196 197 void CPDF_VariableText::Initialize() { 198 if (m_bInitialized) 199 return; 200 201 CPVT_WordPlace place; 202 place.nSecIndex = 0; 203 AddSection(place); 204 205 CPVT_LineInfo lineinfo; 206 lineinfo.fLineAscent = GetFontAscent(GetDefaultFontIndex(), GetFontSize()); 207 lineinfo.fLineDescent = GetFontDescent(GetDefaultFontIndex(), GetFontSize()); 208 AddLine(place, lineinfo); 209 210 if (!m_SectionArray.empty()) 211 m_SectionArray.front()->ResetLinePlace(); 212 213 m_bInitialized = true; 214 } 215 216 CPVT_WordPlace CPDF_VariableText::InsertWord(const CPVT_WordPlace& place, 217 uint16_t word, 218 int32_t charset) { 219 int32_t nTotalWords = GetTotalWords(); 220 if (m_nLimitChar > 0 && nTotalWords >= m_nLimitChar) 221 return place; 222 if (m_nCharArray > 0 && nTotalWords >= m_nCharArray) 223 return place; 224 225 CPVT_WordPlace newplace = place; 226 newplace.nWordIndex++; 227 int32_t nFontIndex = 228 GetSubWord() > 0 ? GetDefaultFontIndex() 229 : GetWordFontIndex(word, charset, GetDefaultFontIndex()); 230 return AddWord(newplace, CPVT_WordInfo(word, charset, nFontIndex)); 231 } 232 233 CPVT_WordPlace CPDF_VariableText::InsertSection(const CPVT_WordPlace& place) { 234 int32_t nTotalWords = GetTotalWords(); 235 if (m_nLimitChar > 0 && nTotalWords >= m_nLimitChar) 236 return place; 237 if (m_nCharArray > 0 && nTotalWords >= m_nCharArray) 238 return place; 239 if (!m_bMultiLine) 240 return place; 241 242 CPVT_WordPlace wordplace = place; 243 UpdateWordPlace(wordplace); 244 if (!pdfium::IndexInBounds(m_SectionArray, wordplace.nSecIndex)) 245 return place; 246 247 CSection* pSection = m_SectionArray[wordplace.nSecIndex].get(); 248 CPVT_WordPlace NewPlace(wordplace.nSecIndex + 1, 0, -1); 249 AddSection(NewPlace); 250 CPVT_WordPlace result = NewPlace; 251 if (pdfium::IndexInBounds(m_SectionArray, NewPlace.nSecIndex)) { 252 CSection* pNewSection = m_SectionArray[NewPlace.nSecIndex].get(); 253 for (int32_t w = wordplace.nWordIndex + 1; 254 w < pdfium::CollectionSize<int32_t>(pSection->m_WordArray); ++w) { 255 NewPlace.nWordIndex++; 256 pNewSection->AddWord(NewPlace, *pSection->m_WordArray[w]); 257 } 258 } 259 ClearSectionRightWords(wordplace); 260 return result; 261 } 262 263 CPVT_WordPlace CPDF_VariableText::DeleteWords( 264 const CPVT_WordRange& PlaceRange) { 265 bool bLastSecPos = 266 pdfium::IndexInBounds(m_SectionArray, PlaceRange.EndPos.nSecIndex) && 267 PlaceRange.EndPos == 268 m_SectionArray[PlaceRange.EndPos.nSecIndex]->GetEndWordPlace(); 269 270 ClearWords(PlaceRange); 271 if (PlaceRange.BeginPos.nSecIndex != PlaceRange.EndPos.nSecIndex) { 272 ClearEmptySections(PlaceRange); 273 if (!bLastSecPos) 274 LinkLatterSection(PlaceRange.BeginPos); 275 } 276 return PlaceRange.BeginPos; 277 } 278 279 CPVT_WordPlace CPDF_VariableText::DeleteWord(const CPVT_WordPlace& place) { 280 return ClearRightWord(AdjustLineHeader(place, true)); 281 } 282 283 CPVT_WordPlace CPDF_VariableText::BackSpaceWord(const CPVT_WordPlace& place) { 284 return ClearLeftWord(AdjustLineHeader(place, true)); 285 } 286 287 void CPDF_VariableText::SetText(const WideString& swText) { 288 DeleteWords(CPVT_WordRange(GetBeginWordPlace(), GetEndWordPlace())); 289 CPVT_WordPlace wp(0, 0, -1); 290 if (!m_SectionArray.empty()) 291 m_SectionArray.front()->m_Rect = CPVT_FloatRect(); 292 293 int32_t nCharCount = 0; 294 for (int32_t i = 0, sz = swText.GetLength(); i < sz; i++) { 295 if (m_nLimitChar > 0 && nCharCount >= m_nLimitChar) 296 break; 297 if (m_nCharArray > 0 && nCharCount >= m_nCharArray) 298 break; 299 300 uint16_t word = swText[i]; 301 switch (word) { 302 case 0x0D: 303 if (m_bMultiLine) { 304 if (i + 1 < sz && swText[i + 1] == 0x0A) 305 i++; 306 wp.AdvanceSection(); 307 AddSection(wp); 308 } 309 break; 310 case 0x0A: 311 if (m_bMultiLine) { 312 if (i + 1 < sz && swText[i + 1] == 0x0D) 313 i++; 314 wp.AdvanceSection(); 315 AddSection(wp); 316 } 317 break; 318 case 0x09: 319 word = 0x20; 320 default: 321 wp = InsertWord(wp, word, FX_CHARSET_Default); 322 break; 323 } 324 nCharCount++; 325 } 326 } 327 328 void CPDF_VariableText::UpdateWordPlace(CPVT_WordPlace& place) const { 329 if (place.nSecIndex < 0) 330 place = GetBeginWordPlace(); 331 if (place.nSecIndex >= pdfium::CollectionSize<int32_t>(m_SectionArray)) 332 place = GetEndWordPlace(); 333 334 place = AdjustLineHeader(place, true); 335 if (pdfium::IndexInBounds(m_SectionArray, place.nSecIndex)) 336 m_SectionArray[place.nSecIndex]->UpdateWordPlace(place); 337 } 338 339 int32_t CPDF_VariableText::WordPlaceToWordIndex( 340 const CPVT_WordPlace& place) const { 341 CPVT_WordPlace newplace = place; 342 UpdateWordPlace(newplace); 343 int32_t nIndex = 0; 344 int32_t i = 0; 345 int32_t sz = 0; 346 for (i = 0, sz = pdfium::CollectionSize<int32_t>(m_SectionArray); 347 i < sz && i < newplace.nSecIndex; i++) { 348 CSection* pSection = m_SectionArray[i].get(); 349 nIndex += pdfium::CollectionSize<int32_t>(pSection->m_WordArray); 350 if (i != sz - 1) 351 nIndex += kReturnLength; 352 } 353 if (pdfium::IndexInBounds(m_SectionArray, i)) 354 nIndex += newplace.nWordIndex + kReturnLength; 355 return nIndex; 356 } 357 358 CPVT_WordPlace CPDF_VariableText::WordIndexToWordPlace(int32_t index) const { 359 CPVT_WordPlace place = GetBeginWordPlace(); 360 int32_t nOldIndex = 0; 361 int32_t nIndex = 0; 362 bool bFound = false; 363 for (int32_t i = 0, sz = pdfium::CollectionSize<int32_t>(m_SectionArray); 364 i < sz; i++) { 365 CSection* pSection = m_SectionArray[i].get(); 366 nIndex += pdfium::CollectionSize<int32_t>(pSection->m_WordArray); 367 if (nIndex == index) { 368 place = pSection->GetEndWordPlace(); 369 bFound = true; 370 break; 371 } 372 if (nIndex > index) { 373 place.nSecIndex = i; 374 place.nWordIndex = index - nOldIndex - 1; 375 pSection->UpdateWordPlace(place); 376 bFound = true; 377 break; 378 } 379 if (i != sz - 1) 380 nIndex += kReturnLength; 381 nOldIndex = nIndex; 382 } 383 if (!bFound) 384 place = GetEndWordPlace(); 385 return place; 386 } 387 388 CPVT_WordPlace CPDF_VariableText::GetBeginWordPlace() const { 389 return m_bInitialized ? CPVT_WordPlace(0, 0, -1) : CPVT_WordPlace(); 390 } 391 392 CPVT_WordPlace CPDF_VariableText::GetEndWordPlace() const { 393 if (m_SectionArray.empty()) 394 return CPVT_WordPlace(); 395 return m_SectionArray.back()->GetEndWordPlace(); 396 } 397 398 CPVT_WordPlace CPDF_VariableText::GetPrevWordPlace( 399 const CPVT_WordPlace& place) const { 400 if (place.nSecIndex < 0) 401 return GetBeginWordPlace(); 402 if (place.nSecIndex >= pdfium::CollectionSize<int32_t>(m_SectionArray)) 403 return GetEndWordPlace(); 404 405 CSection* pSection = m_SectionArray[place.nSecIndex].get(); 406 if (place > pSection->GetBeginWordPlace()) 407 return pSection->GetPrevWordPlace(place); 408 if (!pdfium::IndexInBounds(m_SectionArray, place.nSecIndex - 1)) 409 return GetBeginWordPlace(); 410 return m_SectionArray[place.nSecIndex - 1]->GetEndWordPlace(); 411 } 412 413 CPVT_WordPlace CPDF_VariableText::GetNextWordPlace( 414 const CPVT_WordPlace& place) const { 415 if (place.nSecIndex < 0) 416 return GetBeginWordPlace(); 417 if (place.nSecIndex >= pdfium::CollectionSize<int32_t>(m_SectionArray)) 418 return GetEndWordPlace(); 419 420 CSection* pSection = m_SectionArray[place.nSecIndex].get(); 421 if (place < pSection->GetEndWordPlace()) 422 return pSection->GetNextWordPlace(place); 423 if (!pdfium::IndexInBounds(m_SectionArray, place.nSecIndex + 1)) 424 return GetEndWordPlace(); 425 return m_SectionArray[place.nSecIndex + 1]->GetBeginWordPlace(); 426 } 427 428 CPVT_WordPlace CPDF_VariableText::SearchWordPlace( 429 const CFX_PointF& point) const { 430 CFX_PointF pt = OutToIn(point); 431 CPVT_WordPlace place = GetBeginWordPlace(); 432 int32_t nLeft = 0; 433 int32_t nRight = pdfium::CollectionSize<int32_t>(m_SectionArray) - 1; 434 int32_t nMid = pdfium::CollectionSize<int32_t>(m_SectionArray) / 2; 435 bool bUp = true; 436 bool bDown = true; 437 while (nLeft <= nRight) { 438 if (!pdfium::IndexInBounds(m_SectionArray, nMid)) 439 break; 440 CSection* pSection = m_SectionArray[nMid].get(); 441 if (IsFloatBigger(pt.y, pSection->m_Rect.top)) 442 bUp = false; 443 if (IsFloatBigger(pSection->m_Rect.bottom, pt.y)) 444 bDown = false; 445 if (IsFloatSmaller(pt.y, pSection->m_Rect.top)) { 446 nRight = nMid - 1; 447 nMid = (nLeft + nRight) / 2; 448 continue; 449 } 450 if (IsFloatBigger(pt.y, pSection->m_Rect.bottom)) { 451 nLeft = nMid + 1; 452 nMid = (nLeft + nRight) / 2; 453 continue; 454 } 455 place = pSection->SearchWordPlace( 456 CFX_PointF(pt.x - pSection->m_Rect.left, pt.y - pSection->m_Rect.top)); 457 place.nSecIndex = nMid; 458 return place; 459 } 460 if (bUp) 461 place = GetBeginWordPlace(); 462 if (bDown) 463 place = GetEndWordPlace(); 464 return place; 465 } 466 467 CPVT_WordPlace CPDF_VariableText::GetUpWordPlace( 468 const CPVT_WordPlace& place, 469 const CFX_PointF& point) const { 470 if (!pdfium::IndexInBounds(m_SectionArray, place.nSecIndex)) 471 return place; 472 473 CSection* pSection = m_SectionArray[place.nSecIndex].get(); 474 CPVT_WordPlace temp = place; 475 CFX_PointF pt = OutToIn(point); 476 if (temp.nLineIndex-- > 0) { 477 return pSection->SearchWordPlace(pt.x - pSection->m_Rect.left, temp); 478 } 479 if (temp.nSecIndex-- > 0) { 480 if (pdfium::IndexInBounds(m_SectionArray, temp.nSecIndex)) { 481 CSection* pLastSection = m_SectionArray[temp.nSecIndex].get(); 482 temp.nLineIndex = 483 pdfium::CollectionSize<int32_t>(pLastSection->m_LineArray) - 1; 484 return pLastSection->SearchWordPlace(pt.x - pLastSection->m_Rect.left, 485 temp); 486 } 487 } 488 return place; 489 } 490 491 CPVT_WordPlace CPDF_VariableText::GetDownWordPlace( 492 const CPVT_WordPlace& place, 493 const CFX_PointF& point) const { 494 if (!pdfium::IndexInBounds(m_SectionArray, place.nSecIndex)) 495 return place; 496 497 CSection* pSection = m_SectionArray[place.nSecIndex].get(); 498 CPVT_WordPlace temp = place; 499 CFX_PointF pt = OutToIn(point); 500 if (temp.nLineIndex++ < 501 pdfium::CollectionSize<int32_t>(pSection->m_LineArray) - 1) { 502 return pSection->SearchWordPlace(pt.x - pSection->m_Rect.left, temp); 503 } 504 temp.AdvanceSection(); 505 if (!pdfium::IndexInBounds(m_SectionArray, temp.nSecIndex)) 506 return place; 507 508 return m_SectionArray[temp.nSecIndex]->SearchWordPlace( 509 pt.x - pSection->m_Rect.left, temp); 510 } 511 512 CPVT_WordPlace CPDF_VariableText::GetLineBeginPlace( 513 const CPVT_WordPlace& place) const { 514 return CPVT_WordPlace(place.nSecIndex, place.nLineIndex, -1); 515 } 516 517 CPVT_WordPlace CPDF_VariableText::GetLineEndPlace( 518 const CPVT_WordPlace& place) const { 519 if (!pdfium::IndexInBounds(m_SectionArray, place.nSecIndex)) 520 return place; 521 522 CSection* pSection = m_SectionArray[place.nSecIndex].get(); 523 if (!pdfium::IndexInBounds(pSection->m_LineArray, place.nLineIndex)) 524 return place; 525 526 return pSection->m_LineArray[place.nLineIndex]->GetEndWordPlace(); 527 } 528 529 CPVT_WordPlace CPDF_VariableText::GetSectionBeginPlace( 530 const CPVT_WordPlace& place) const { 531 return CPVT_WordPlace(place.nSecIndex, 0, -1); 532 } 533 534 CPVT_WordPlace CPDF_VariableText::GetSectionEndPlace( 535 const CPVT_WordPlace& place) const { 536 if (!pdfium::IndexInBounds(m_SectionArray, place.nSecIndex)) 537 return place; 538 539 return m_SectionArray[place.nSecIndex]->GetEndWordPlace(); 540 } 541 542 int32_t CPDF_VariableText::GetTotalWords() const { 543 int32_t nTotal = 0; 544 for (const auto& pSection : m_SectionArray) { 545 nTotal += 546 pdfium::CollectionSize<int32_t>(pSection->m_WordArray) + kReturnLength; 547 } 548 return nTotal - kReturnLength; 549 } 550 551 CPVT_WordPlace CPDF_VariableText::AddSection(const CPVT_WordPlace& place) { 552 if (IsValid() && !m_bMultiLine) 553 return place; 554 555 int32_t nSecIndex = pdfium::clamp( 556 place.nSecIndex, 0, pdfium::CollectionSize<int32_t>(m_SectionArray)); 557 558 auto pSection = pdfium::MakeUnique<CSection>(this); 559 pSection->m_Rect = CPVT_FloatRect(); 560 pSection->SecPlace.nSecIndex = nSecIndex; 561 m_SectionArray.insert(m_SectionArray.begin() + nSecIndex, 562 std::move(pSection)); 563 return place; 564 } 565 566 CPVT_WordPlace CPDF_VariableText::AddLine(const CPVT_WordPlace& place, 567 const CPVT_LineInfo& lineinfo) { 568 if (!pdfium::IndexInBounds(m_SectionArray, place.nSecIndex)) 569 return place; 570 571 return m_SectionArray[place.nSecIndex]->AddLine(lineinfo); 572 } 573 574 CPVT_WordPlace CPDF_VariableText::AddWord(const CPVT_WordPlace& place, 575 const CPVT_WordInfo& wordinfo) { 576 if (m_SectionArray.empty()) 577 return place; 578 579 CPVT_WordPlace newplace = place; 580 newplace.nSecIndex = 581 pdfium::clamp(newplace.nSecIndex, 0, 582 pdfium::CollectionSize<int32_t>(m_SectionArray) - 1); 583 return m_SectionArray[newplace.nSecIndex]->AddWord(newplace, wordinfo); 584 } 585 586 bool CPDF_VariableText::GetWordInfo(const CPVT_WordPlace& place, 587 CPVT_WordInfo& wordinfo) { 588 if (!pdfium::IndexInBounds(m_SectionArray, place.nSecIndex)) 589 return false; 590 591 CSection* pSection = m_SectionArray[place.nSecIndex].get(); 592 if (!pdfium::IndexInBounds(pSection->m_WordArray, place.nWordIndex)) 593 return false; 594 595 wordinfo = *pSection->m_WordArray[place.nWordIndex]; 596 return true; 597 } 598 599 bool CPDF_VariableText::SetWordInfo(const CPVT_WordPlace& place, 600 const CPVT_WordInfo& wordinfo) { 601 if (!pdfium::IndexInBounds(m_SectionArray, place.nSecIndex)) 602 return false; 603 604 CSection* pSection = m_SectionArray[place.nSecIndex].get(); 605 if (!pdfium::IndexInBounds(pSection->m_WordArray, place.nWordIndex)) 606 return false; 607 608 *pSection->m_WordArray[place.nWordIndex] = wordinfo; 609 return true; 610 } 611 612 bool CPDF_VariableText::GetLineInfo(const CPVT_WordPlace& place, 613 CPVT_LineInfo& lineinfo) { 614 if (!pdfium::IndexInBounds(m_SectionArray, place.nSecIndex)) 615 return false; 616 617 CSection* pSection = m_SectionArray[place.nSecIndex].get(); 618 if (!pdfium::IndexInBounds(pSection->m_LineArray, place.nLineIndex)) 619 return false; 620 621 lineinfo = pSection->m_LineArray[place.nLineIndex]->m_LineInfo; 622 return true; 623 } 624 625 void CPDF_VariableText::SetPlateRect(const CFX_FloatRect& rect) { 626 m_rcPlate = rect; 627 } 628 629 void CPDF_VariableText::SetContentRect(const CPVT_FloatRect& rect) { 630 m_rcContent = rect; 631 } 632 633 CFX_FloatRect CPDF_VariableText::GetContentRect() const { 634 return InToOut(CPVT_FloatRect(m_rcContent)); 635 } 636 637 const CFX_FloatRect& CPDF_VariableText::GetPlateRect() const { 638 return m_rcPlate; 639 } 640 641 float CPDF_VariableText::GetWordFontSize() { 642 return GetFontSize(); 643 } 644 645 int32_t CPDF_VariableText::GetWordFontIndex(const CPVT_WordInfo& WordInfo) { 646 return WordInfo.nFontIndex; 647 } 648 649 float CPDF_VariableText::GetWordWidth(int32_t nFontIndex, 650 uint16_t Word, 651 uint16_t SubWord, 652 float fCharSpace, 653 int32_t nHorzScale, 654 float fFontSize, 655 float fWordTail) { 656 return (GetCharWidth(nFontIndex, Word, SubWord) * fFontSize * kFontScale + 657 fCharSpace) * 658 nHorzScale * kScalePercent + 659 fWordTail; 660 } 661 662 float CPDF_VariableText::GetWordWidth(const CPVT_WordInfo& WordInfo) { 663 return GetWordWidth(GetWordFontIndex(WordInfo), WordInfo.Word, GetSubWord(), 664 GetCharSpace(), GetHorzScale(), GetWordFontSize(), 665 WordInfo.fWordTail); 666 } 667 668 float CPDF_VariableText::GetLineAscent() { 669 return GetFontAscent(GetDefaultFontIndex(), GetFontSize()); 670 } 671 672 float CPDF_VariableText::GetLineDescent() { 673 return GetFontDescent(GetDefaultFontIndex(), GetFontSize()); 674 } 675 676 float CPDF_VariableText::GetFontAscent(int32_t nFontIndex, float fFontSize) { 677 return (float)GetTypeAscent(nFontIndex) * fFontSize * kFontScale; 678 } 679 680 float CPDF_VariableText::GetFontDescent(int32_t nFontIndex, float fFontSize) { 681 return (float)GetTypeDescent(nFontIndex) * fFontSize * kFontScale; 682 } 683 684 float CPDF_VariableText::GetWordAscent(const CPVT_WordInfo& WordInfo, 685 float fFontSize) { 686 return GetFontAscent(GetWordFontIndex(WordInfo), fFontSize); 687 } 688 689 float CPDF_VariableText::GetWordDescent(const CPVT_WordInfo& WordInfo, 690 float fFontSize) { 691 return GetFontDescent(GetWordFontIndex(WordInfo), fFontSize); 692 } 693 694 float CPDF_VariableText::GetWordAscent(const CPVT_WordInfo& WordInfo) { 695 return GetFontAscent(GetWordFontIndex(WordInfo), GetWordFontSize()); 696 } 697 698 float CPDF_VariableText::GetWordDescent(const CPVT_WordInfo& WordInfo) { 699 return GetFontDescent(GetWordFontIndex(WordInfo), GetWordFontSize()); 700 } 701 702 float CPDF_VariableText::GetLineLeading() { 703 return m_fLineLeading; 704 } 705 706 float CPDF_VariableText::GetLineIndent() { 707 return 0.0f; 708 } 709 710 int32_t CPDF_VariableText::GetAlignment() { 711 return m_nAlignment; 712 } 713 714 void CPDF_VariableText::ClearSectionRightWords(const CPVT_WordPlace& place) { 715 CPVT_WordPlace wordplace = AdjustLineHeader(place, true); 716 if (!pdfium::IndexInBounds(m_SectionArray, place.nSecIndex)) 717 return; 718 719 CSection* pSection = m_SectionArray[place.nSecIndex].get(); 720 if (!pdfium::IndexInBounds(pSection->m_WordArray, wordplace.nWordIndex + 1)) 721 return; 722 723 pSection->m_WordArray.erase( 724 pSection->m_WordArray.begin() + wordplace.nWordIndex + 1, 725 pSection->m_WordArray.end()); 726 } 727 728 CPVT_WordPlace CPDF_VariableText::AdjustLineHeader(const CPVT_WordPlace& place, 729 bool bPrevOrNext) const { 730 if (place.nWordIndex < 0 && place.nLineIndex > 0) 731 return bPrevOrNext ? GetPrevWordPlace(place) : GetNextWordPlace(place); 732 return place; 733 } 734 735 bool CPDF_VariableText::ClearEmptySection(const CPVT_WordPlace& place) { 736 if (place.nSecIndex == 0 && m_SectionArray.size() == 1) 737 return false; 738 739 if (!pdfium::IndexInBounds(m_SectionArray, place.nSecIndex)) 740 return false; 741 742 if (!m_SectionArray[place.nSecIndex]->m_WordArray.empty()) 743 return false; 744 745 m_SectionArray.erase(m_SectionArray.begin() + place.nSecIndex); 746 return true; 747 } 748 749 void CPDF_VariableText::ClearEmptySections(const CPVT_WordRange& PlaceRange) { 750 CPVT_WordPlace wordplace; 751 for (int32_t s = PlaceRange.EndPos.nSecIndex; 752 s > PlaceRange.BeginPos.nSecIndex; s--) { 753 wordplace.nSecIndex = s; 754 ClearEmptySection(wordplace); 755 } 756 } 757 758 void CPDF_VariableText::LinkLatterSection(const CPVT_WordPlace& place) { 759 CPVT_WordPlace oldplace = AdjustLineHeader(place, true); 760 if (!pdfium::IndexInBounds(m_SectionArray, place.nSecIndex + 1)) 761 return; 762 763 CSection* pNextSection = m_SectionArray[place.nSecIndex + 1].get(); 764 if (pdfium::IndexInBounds(m_SectionArray, oldplace.nSecIndex)) { 765 CSection* pSection = m_SectionArray[oldplace.nSecIndex].get(); 766 for (auto& pWord : pNextSection->m_WordArray) { 767 oldplace.nWordIndex++; 768 pSection->AddWord(oldplace, *pWord); 769 } 770 } 771 m_SectionArray.erase(m_SectionArray.begin() + place.nSecIndex + 1); 772 } 773 774 void CPDF_VariableText::ClearWords(const CPVT_WordRange& PlaceRange) { 775 CPVT_WordRange NewRange; 776 NewRange.BeginPos = AdjustLineHeader(PlaceRange.BeginPos, true); 777 NewRange.EndPos = AdjustLineHeader(PlaceRange.EndPos, true); 778 for (int32_t s = NewRange.EndPos.nSecIndex; s >= NewRange.BeginPos.nSecIndex; 779 s--) { 780 if (pdfium::IndexInBounds(m_SectionArray, s)) 781 m_SectionArray[s]->ClearWords(NewRange); 782 } 783 } 784 785 CPVT_WordPlace CPDF_VariableText::ClearLeftWord(const CPVT_WordPlace& place) { 786 if (!pdfium::IndexInBounds(m_SectionArray, place.nSecIndex)) 787 return place; 788 789 CSection* pSection = m_SectionArray[place.nSecIndex].get(); 790 CPVT_WordPlace leftplace = GetPrevWordPlace(place); 791 if (leftplace == place) 792 return place; 793 794 if (leftplace.nSecIndex != place.nSecIndex) { 795 if (pSection->m_WordArray.empty()) 796 ClearEmptySection(place); 797 else 798 LinkLatterSection(leftplace); 799 } else { 800 pSection->ClearWord(place); 801 } 802 return leftplace; 803 } 804 805 CPVT_WordPlace CPDF_VariableText::ClearRightWord(const CPVT_WordPlace& place) { 806 if (!pdfium::IndexInBounds(m_SectionArray, place.nSecIndex)) 807 return place; 808 809 CSection* pSection = m_SectionArray[place.nSecIndex].get(); 810 CPVT_WordPlace rightplace = AdjustLineHeader(GetNextWordPlace(place), false); 811 if (rightplace == place) 812 return place; 813 814 if (rightplace.nSecIndex != place.nSecIndex) 815 LinkLatterSection(place); 816 else 817 pSection->ClearWord(rightplace); 818 return place; 819 } 820 821 void CPDF_VariableText::RearrangeAll() { 822 Rearrange(CPVT_WordRange(GetBeginWordPlace(), GetEndWordPlace())); 823 } 824 825 void CPDF_VariableText::RearrangePart(const CPVT_WordRange& PlaceRange) { 826 Rearrange(PlaceRange); 827 } 828 829 CPVT_FloatRect CPDF_VariableText::Rearrange(const CPVT_WordRange& PlaceRange) { 830 CPVT_FloatRect rcRet; 831 if (IsValid()) { 832 if (m_bAutoFontSize) { 833 SetFontSize(GetAutoFontSize()); 834 rcRet = RearrangeSections( 835 CPVT_WordRange(GetBeginWordPlace(), GetEndWordPlace())); 836 } else { 837 rcRet = RearrangeSections(PlaceRange); 838 } 839 } 840 SetContentRect(rcRet); 841 return rcRet; 842 } 843 844 float CPDF_VariableText::GetAutoFontSize() { 845 int32_t nTotal = sizeof(gFontSizeSteps) / sizeof(uint8_t); 846 if (IsMultiLine()) 847 nTotal /= 4; 848 if (nTotal <= 0) 849 return 0; 850 if (GetPlateWidth() <= 0) 851 return 0; 852 853 int32_t nLeft = 0; 854 int32_t nRight = nTotal - 1; 855 int32_t nMid = nTotal / 2; 856 while (nLeft <= nRight) { 857 if (IsBigger(gFontSizeSteps[nMid])) 858 nRight = nMid - 1; 859 else 860 nLeft = nMid + 1; 861 nMid = (nLeft + nRight) / 2; 862 } 863 return (float)gFontSizeSteps[nMid]; 864 } 865 866 bool CPDF_VariableText::IsBigger(float fFontSize) const { 867 CFX_SizeF szTotal; 868 for (const auto& pSection : m_SectionArray) { 869 CFX_SizeF size = pSection->GetSectionSize(fFontSize); 870 szTotal.width = std::max(size.width, szTotal.width); 871 szTotal.height += size.height; 872 if (IsFloatBigger(szTotal.width, GetPlateWidth()) || 873 IsFloatBigger(szTotal.height, GetPlateHeight())) { 874 return true; 875 } 876 } 877 return false; 878 } 879 880 CPVT_FloatRect CPDF_VariableText::RearrangeSections( 881 const CPVT_WordRange& PlaceRange) { 882 CPVT_WordPlace place; 883 float fPosY = 0; 884 float fOldHeight; 885 int32_t nSSecIndex = PlaceRange.BeginPos.nSecIndex; 886 int32_t nESecIndex = PlaceRange.EndPos.nSecIndex; 887 CPVT_FloatRect rcRet; 888 for (int32_t s = 0, sz = pdfium::CollectionSize<int32_t>(m_SectionArray); 889 s < sz; s++) { 890 place.nSecIndex = s; 891 CSection* pSection = m_SectionArray[s].get(); 892 pSection->SecPlace = place; 893 CPVT_FloatRect rcSec = pSection->m_Rect; 894 if (s >= nSSecIndex) { 895 if (s <= nESecIndex) { 896 rcSec = pSection->Rearrange(); 897 rcSec.top += fPosY; 898 rcSec.bottom += fPosY; 899 } else { 900 fOldHeight = pSection->m_Rect.bottom - pSection->m_Rect.top; 901 rcSec.top = fPosY; 902 rcSec.bottom = fPosY + fOldHeight; 903 } 904 pSection->m_Rect = rcSec; 905 pSection->ResetLinePlace(); 906 } 907 if (s == 0) { 908 rcRet = rcSec; 909 } else { 910 rcRet.left = std::min(rcSec.left, rcRet.left); 911 rcRet.top = std::min(rcSec.top, rcRet.top); 912 rcRet.right = std::max(rcSec.right, rcRet.right); 913 rcRet.bottom = std::max(rcSec.bottom, rcRet.bottom); 914 } 915 fPosY += rcSec.Height(); 916 } 917 return rcRet; 918 } 919 920 int32_t CPDF_VariableText::GetCharWidth(int32_t nFontIndex, 921 uint16_t Word, 922 uint16_t SubWord) { 923 if (!m_pVTProvider) 924 return 0; 925 uint16_t word = SubWord ? SubWord : Word; 926 return m_pVTProvider->GetCharWidth(nFontIndex, word); 927 } 928 929 int32_t CPDF_VariableText::GetTypeAscent(int32_t nFontIndex) { 930 return m_pVTProvider ? m_pVTProvider->GetTypeAscent(nFontIndex) : 0; 931 } 932 933 int32_t CPDF_VariableText::GetTypeDescent(int32_t nFontIndex) { 934 return m_pVTProvider ? m_pVTProvider->GetTypeDescent(nFontIndex) : 0; 935 } 936 937 int32_t CPDF_VariableText::GetWordFontIndex(uint16_t word, 938 int32_t charset, 939 int32_t nFontIndex) { 940 return m_pVTProvider 941 ? m_pVTProvider->GetWordFontIndex(word, charset, nFontIndex) 942 : -1; 943 } 944 945 int32_t CPDF_VariableText::GetDefaultFontIndex() { 946 return m_pVTProvider ? m_pVTProvider->GetDefaultFontIndex() : -1; 947 } 948 949 bool CPDF_VariableText::IsLatinWord(uint16_t word) { 950 return m_pVTProvider ? m_pVTProvider->IsLatinWord(word) : false; 951 } 952 953 CPDF_VariableText::Iterator* CPDF_VariableText::GetIterator() { 954 if (!m_pVTIterator) 955 m_pVTIterator = pdfium::MakeUnique<CPDF_VariableText::Iterator>(this); 956 return m_pVTIterator.get(); 957 } 958 959 void CPDF_VariableText::SetProvider(CPDF_VariableText::Provider* pProvider) { 960 m_pVTProvider = pProvider; 961 } 962 963 CFX_PointF CPDF_VariableText::GetBTPoint() const { 964 return CFX_PointF(m_rcPlate.left, m_rcPlate.top); 965 } 966 967 CFX_PointF CPDF_VariableText::GetETPoint() const { 968 return CFX_PointF(m_rcPlate.right, m_rcPlate.bottom); 969 } 970 971 CFX_PointF CPDF_VariableText::InToOut(const CFX_PointF& point) const { 972 return CFX_PointF(point.x + GetBTPoint().x, GetBTPoint().y - point.y); 973 } 974 975 CFX_PointF CPDF_VariableText::OutToIn(const CFX_PointF& point) const { 976 return CFX_PointF(point.x - GetBTPoint().x, GetBTPoint().y - point.y); 977 } 978 979 CFX_FloatRect CPDF_VariableText::InToOut(const CPVT_FloatRect& rect) const { 980 CFX_PointF ptLeftTop = InToOut(CFX_PointF(rect.left, rect.top)); 981 CFX_PointF ptRightBottom = InToOut(CFX_PointF(rect.right, rect.bottom)); 982 return CFX_FloatRect(ptLeftTop.x, ptRightBottom.y, ptRightBottom.x, 983 ptLeftTop.y); 984 } 985 986 CPVT_FloatRect CPDF_VariableText::OutToIn(const CFX_FloatRect& rect) const { 987 CFX_PointF ptLeftTop = OutToIn(CFX_PointF(rect.left, rect.top)); 988 CFX_PointF ptRightBottom = OutToIn(CFX_PointF(rect.right, rect.bottom)); 989 return CPVT_FloatRect(ptLeftTop.x, ptLeftTop.y, ptRightBottom.x, 990 ptRightBottom.y); 991 } 992