1// Copyright 2014 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 "xfa/fgas/layout/cfx_txtbreak.h" 8 9#include <algorithm> 10 11#include "core/fxcrt/fx_arabic.h" 12#include "core/fxcrt/fx_bidi.h" 13#include "core/fxcrt/fx_memory.h" 14#include "third_party/base/ptr_util.h" 15#include "xfa/fde/cfde_texteditengine.h" 16#include "xfa/fgas/font/cfgas_gefont.h" 17#include "xfa/fgas/layout/cfx_linebreak.h" 18 19namespace { 20 21bool IsCtrlCode(wchar_t ch) { 22 uint32_t dwRet = (FX_GetUnicodeProperties(ch) & FX_CHARTYPEBITSMASK); 23 return dwRet == FX_CHARTYPE_Tab || dwRet == FX_CHARTYPE_Control; 24} 25 26} // namespace 27 28CFX_TxtBreak::CFX_TxtBreak() 29 : CFX_Break(FX_LAYOUTSTYLE_None), 30 m_iAlignment(CFX_TxtLineAlignment_Left), 31 m_iCombWidth(360000) {} 32 33CFX_TxtBreak::~CFX_TxtBreak() {} 34 35void CFX_TxtBreak::SetLineWidth(float fLineWidth) { 36 m_iLineWidth = FXSYS_round(fLineWidth * 20000.0f); 37 ASSERT(m_iLineWidth >= 20000); 38} 39 40void CFX_TxtBreak::SetAlignment(int32_t iAlignment) { 41 ASSERT(iAlignment >= CFX_TxtLineAlignment_Left && 42 iAlignment <= CFX_TxtLineAlignment_Justified); 43 m_iAlignment = iAlignment; 44} 45 46void CFX_TxtBreak::SetCombWidth(float fCombWidth) { 47 m_iCombWidth = FXSYS_round(fCombWidth * 20000.0f); 48} 49 50void CFX_TxtBreak::AppendChar_Combination(CFX_Char* pCurChar) { 51 wchar_t wch = pCurChar->char_code(); 52 wchar_t wForm; 53 int32_t iCharWidth = 0; 54 pCurChar->m_iCharWidth = -1; 55 if (m_bCombText) { 56 iCharWidth = m_iCombWidth; 57 } else { 58 wForm = wch; 59 CFX_Char* pLastChar = GetLastChar(0, false, false); 60 if (pLastChar && 61 (pLastChar->m_dwCharStyles & FX_TXTCHARSTYLE_ArabicShadda) == 0) { 62 bool bShadda = false; 63 if (wch == 0x0651) { 64 wchar_t wLast = pLastChar->char_code(); 65 if (wLast >= 0x064C && wLast <= 0x0650) { 66 wForm = FX_GetArabicFromShaddaTable(wLast); 67 bShadda = true; 68 } 69 } else if (wch >= 0x064C && wch <= 0x0650) { 70 if (pLastChar->char_code() == 0x0651) { 71 wForm = FX_GetArabicFromShaddaTable(wch); 72 bShadda = true; 73 } 74 } 75 if (bShadda) { 76 pLastChar->m_dwCharStyles |= FX_TXTCHARSTYLE_ArabicShadda; 77 pLastChar->m_iCharWidth = 0; 78 pCurChar->m_dwCharStyles |= FX_TXTCHARSTYLE_ArabicShadda; 79 } 80 } 81 if (!m_pFont->GetCharWidth(wForm, iCharWidth)) 82 iCharWidth = 0; 83 84 iCharWidth *= m_iFontSize; 85 iCharWidth = iCharWidth * m_iHorizontalScale / 100; 86 } 87 pCurChar->m_iCharWidth = -iCharWidth; 88} 89 90void CFX_TxtBreak::AppendChar_Tab(CFX_Char* pCurChar) { 91 m_eCharType = FX_CHARTYPE_Tab; 92} 93 94CFX_BreakType CFX_TxtBreak::AppendChar_Control(CFX_Char* pCurChar) { 95 m_eCharType = FX_CHARTYPE_Control; 96 CFX_BreakType dwRet = CFX_BreakType::None; 97 if (!m_bSingleLine) { 98 wchar_t wch = pCurChar->char_code(); 99 switch (wch) { 100 case L'\v': 101 case 0x2028: 102 dwRet = CFX_BreakType::Line; 103 break; 104 case L'\f': 105 dwRet = CFX_BreakType::Page; 106 break; 107 case 0x2029: 108 dwRet = CFX_BreakType::Paragraph; 109 break; 110 default: 111 if (wch == m_wParagraphBreakChar) 112 dwRet = CFX_BreakType::Paragraph; 113 break; 114 } 115 if (dwRet != CFX_BreakType::None) 116 dwRet = EndBreak(dwRet); 117 } 118 return dwRet; 119} 120 121CFX_BreakType CFX_TxtBreak::AppendChar_Arabic(CFX_Char* pCurChar) { 122 FX_CHARTYPE chartype = pCurChar->GetCharType(); 123 int32_t& iLineWidth = m_pCurLine->m_iWidth; 124 wchar_t wForm; 125 int32_t iCharWidth = 0; 126 CFX_Char* pLastChar = nullptr; 127 bool bAlef = false; 128 if (!m_bCombText && m_eCharType >= FX_CHARTYPE_ArabicAlef && 129 m_eCharType <= FX_CHARTYPE_ArabicDistortion) { 130 pLastChar = GetLastChar(1, true, false); 131 if (pLastChar) { 132 iCharWidth = pLastChar->m_iCharWidth; 133 if (iCharWidth > 0) 134 iLineWidth -= iCharWidth; 135 136 CFX_Char* pPrevChar = GetLastChar(2, true, false); 137 wForm = pdfium::arabic::GetFormChar(pLastChar, pPrevChar, pCurChar); 138 bAlef = (wForm == 0xFEFF && 139 pLastChar->GetCharType() == FX_CHARTYPE_ArabicAlef); 140 m_pFont->GetCharWidth(wForm, iCharWidth); 141 142 if (wForm == 0xFEFF) 143 iCharWidth = m_iDefChar; 144 145 iCharWidth *= m_iFontSize; 146 iCharWidth = iCharWidth * m_iHorizontalScale / 100; 147 pLastChar->m_iCharWidth = iCharWidth; 148 iLineWidth += iCharWidth; 149 iCharWidth = 0; 150 } 151 } 152 153 m_eCharType = chartype; 154 wForm = pdfium::arabic::GetFormChar(pCurChar, bAlef ? nullptr : pLastChar, 155 nullptr); 156 if (m_bCombText) { 157 iCharWidth = m_iCombWidth; 158 } else { 159 m_pFont->GetCharWidth(wForm, iCharWidth); 160 161 if (wForm == 0xFEFF) 162 iCharWidth = m_iDefChar; 163 164 iCharWidth *= m_iFontSize; 165 iCharWidth = iCharWidth * m_iHorizontalScale / 100; 166 } 167 pCurChar->m_iCharWidth = iCharWidth; 168 iLineWidth += iCharWidth; 169 m_pCurLine->m_iArabicChars++; 170 if (!m_bSingleLine && iLineWidth > m_iLineWidth + m_iTolerance) 171 return EndBreak(CFX_BreakType::Line); 172 return CFX_BreakType::None; 173} 174 175CFX_BreakType CFX_TxtBreak::AppendChar_Others(CFX_Char* pCurChar) { 176 FX_CHARTYPE chartype = pCurChar->GetCharType(); 177 int32_t& iLineWidth = m_pCurLine->m_iWidth; 178 int32_t iCharWidth = 0; 179 m_eCharType = chartype; 180 wchar_t wch = pCurChar->char_code(); 181 wchar_t wForm = wch; 182 183 if (m_bCombText) { 184 iCharWidth = m_iCombWidth; 185 } else { 186 if (!m_pFont->GetCharWidth(wForm, iCharWidth)) 187 iCharWidth = m_iDefChar; 188 189 iCharWidth *= m_iFontSize; 190 iCharWidth = iCharWidth * m_iHorizontalScale / 100; 191 } 192 193 iCharWidth += m_iCharSpace; 194 pCurChar->m_iCharWidth = iCharWidth; 195 iLineWidth += iCharWidth; 196 if (!m_bSingleLine && chartype != FX_CHARTYPE_Space && 197 iLineWidth > m_iLineWidth + m_iTolerance) { 198 return EndBreak(CFX_BreakType::Line); 199 } 200 201 return CFX_BreakType::None; 202} 203 204CFX_BreakType CFX_TxtBreak::AppendChar(wchar_t wch) { 205 uint32_t dwProps = FX_GetUnicodeProperties(wch); 206 FX_CHARTYPE chartype = GetCharTypeFromProp(dwProps); 207 m_pCurLine->m_LineChars.emplace_back(wch, dwProps, m_iHorizontalScale, 208 m_iVerticalScale); 209 CFX_Char* pCurChar = &m_pCurLine->m_LineChars.back(); 210 pCurChar->m_dwCharStyles = m_iAlignment | (1 << 8); 211 212 CFX_BreakType dwRet1 = CFX_BreakType::None; 213 if (chartype != FX_CHARTYPE_Combination && 214 GetUnifiedCharType(m_eCharType) != GetUnifiedCharType(chartype) && 215 m_eCharType != FX_CHARTYPE_Unknown && 216 m_pCurLine->m_iWidth > m_iLineWidth + m_iTolerance && !m_bSingleLine && 217 (m_eCharType != FX_CHARTYPE_Space || chartype != FX_CHARTYPE_Control)) { 218 dwRet1 = EndBreak(CFX_BreakType::Line); 219 int32_t iCount = m_pCurLine->CountChars(); 220 if (iCount > 0) 221 pCurChar = &m_pCurLine->m_LineChars[iCount - 1]; 222 } 223 224 CFX_BreakType dwRet2 = CFX_BreakType::None; 225 if (wch == m_wParagraphBreakChar) { 226 // This is handled in AppendChar_Control, but it seems like \n and \r 227 // don't get matched as control characters so we go into AppendChar_other 228 // and never detect the new paragraph ... 229 dwRet2 = CFX_BreakType::Paragraph; 230 } else { 231 switch (chartype) { 232 case FX_CHARTYPE_Tab: 233 AppendChar_Tab(pCurChar); 234 break; 235 case FX_CHARTYPE_Control: 236 dwRet2 = AppendChar_Control(pCurChar); 237 break; 238 case FX_CHARTYPE_Combination: 239 AppendChar_Combination(pCurChar); 240 break; 241 case FX_CHARTYPE_ArabicAlef: 242 case FX_CHARTYPE_ArabicSpecial: 243 case FX_CHARTYPE_ArabicDistortion: 244 case FX_CHARTYPE_ArabicNormal: 245 case FX_CHARTYPE_ArabicForm: 246 case FX_CHARTYPE_Arabic: 247 dwRet2 = AppendChar_Arabic(pCurChar); 248 break; 249 case FX_CHARTYPE_Unknown: 250 case FX_CHARTYPE_Space: 251 case FX_CHARTYPE_Numeric: 252 case FX_CHARTYPE_Normal: 253 default: 254 dwRet2 = AppendChar_Others(pCurChar); 255 break; 256 } 257 } 258 return std::max(dwRet1, dwRet2); 259} 260 261bool CFX_TxtBreak::EndBreak_SplitLine(CFX_BreakLine* pNextLine, 262 bool bAllChars) { 263 int32_t iCount = m_pCurLine->CountChars(); 264 bool bDone = false; 265 CFX_Char* pTC; 266 if (!m_bSingleLine && m_pCurLine->m_iWidth > m_iLineWidth + m_iTolerance) { 267 pTC = m_pCurLine->GetChar(iCount - 1); 268 switch (pTC->GetCharType()) { 269 case FX_CHARTYPE_Tab: 270 case FX_CHARTYPE_Control: 271 case FX_CHARTYPE_Space: 272 break; 273 default: 274 SplitTextLine(m_pCurLine, pNextLine, bAllChars); 275 bDone = true; 276 break; 277 } 278 } 279 280 iCount = m_pCurLine->CountChars(); 281 CFX_BreakPiece tp; 282 if (bAllChars && !bDone) { 283 int32_t iEndPos = m_pCurLine->m_iWidth; 284 GetBreakPos(m_pCurLine->m_LineChars, iEndPos, bAllChars, true); 285 } 286 return false; 287} 288 289void CFX_TxtBreak::EndBreak_BidiLine(std::deque<FX_TPO>* tpos, 290 CFX_BreakType dwStatus) { 291 CFX_BreakPiece tp; 292 FX_TPO tpo; 293 CFX_Char* pTC; 294 std::vector<CFX_Char>& chars = m_pCurLine->m_LineChars; 295 int32_t iCount = m_pCurLine->CountChars(); 296 bool bDone = m_pCurLine->m_iArabicChars > 0; 297 if (bDone) { 298 ASSERT(iCount >= 0); 299 300 size_t iBidiNum = 0; 301 for (size_t i = 0; i < static_cast<size_t>(iCount); ++i) { 302 pTC = &chars[i]; 303 pTC->m_iBidiPos = static_cast<int32_t>(i); 304 if (pTC->GetCharType() != FX_CHARTYPE_Control) 305 iBidiNum = i; 306 if (i == 0) 307 pTC->m_iBidiLevel = 1; 308 } 309 FX_BidiLine(&chars, iBidiNum + 1); 310 } 311 312 if (bDone) { 313 tp.m_dwStatus = CFX_BreakType::Piece; 314 tp.m_iStartPos = m_pCurLine->m_iStart; 315 tp.m_pChars = &m_pCurLine->m_LineChars; 316 int32_t iBidiLevel = -1; 317 int32_t iCharWidth; 318 int32_t i = 0; 319 int32_t j = -1; 320 while (i < iCount) { 321 pTC = &chars[i]; 322 if (iBidiLevel < 0) { 323 iBidiLevel = pTC->m_iBidiLevel; 324 tp.m_iWidth = 0; 325 tp.m_iBidiLevel = iBidiLevel; 326 tp.m_iBidiPos = pTC->m_iBidiOrder; 327 tp.m_dwCharStyles = pTC->m_dwCharStyles; 328 tp.m_iHorizontalScale = pTC->horizonal_scale(); 329 tp.m_iVerticalScale = pTC->vertical_scale(); 330 tp.m_dwStatus = CFX_BreakType::Piece; 331 } 332 if (iBidiLevel != pTC->m_iBidiLevel || 333 pTC->m_dwStatus != CFX_BreakType::None) { 334 if (iBidiLevel == pTC->m_iBidiLevel) { 335 tp.m_dwStatus = pTC->m_dwStatus; 336 iCharWidth = pTC->m_iCharWidth; 337 if (iCharWidth > 0) 338 tp.m_iWidth += iCharWidth; 339 340 i++; 341 } 342 tp.m_iChars = i - tp.m_iStartChar; 343 m_pCurLine->m_LinePieces.push_back(tp); 344 tp.m_iStartPos += tp.m_iWidth; 345 tp.m_iStartChar = i; 346 tpo.index = ++j; 347 tpo.pos = tp.m_iBidiPos; 348 tpos->push_back(tpo); 349 iBidiLevel = -1; 350 } else { 351 iCharWidth = pTC->m_iCharWidth; 352 if (iCharWidth > 0) 353 tp.m_iWidth += iCharWidth; 354 355 i++; 356 } 357 } 358 if (i > tp.m_iStartChar) { 359 tp.m_dwStatus = dwStatus; 360 tp.m_iChars = i - tp.m_iStartChar; 361 m_pCurLine->m_LinePieces.push_back(tp); 362 tpo.index = ++j; 363 tpo.pos = tp.m_iBidiPos; 364 tpos->push_back(tpo); 365 } 366 if (j > -1) { 367 if (j > 0) { 368 std::sort(tpos->begin(), tpos->end()); 369 int32_t iStartPos = 0; 370 for (i = 0; i <= j; i++) { 371 tpo = (*tpos)[i]; 372 CFX_BreakPiece& ttp = m_pCurLine->m_LinePieces[tpo.index]; 373 ttp.m_iStartPos = iStartPos; 374 iStartPos += ttp.m_iWidth; 375 } 376 } 377 m_pCurLine->m_LinePieces[j].m_dwStatus = dwStatus; 378 } 379 } else { 380 tp.m_dwStatus = dwStatus; 381 tp.m_iStartPos = m_pCurLine->m_iStart; 382 tp.m_iWidth = m_pCurLine->m_iWidth; 383 tp.m_iStartChar = 0; 384 tp.m_iChars = iCount; 385 tp.m_pChars = &m_pCurLine->m_LineChars; 386 pTC = &chars[0]; 387 tp.m_dwCharStyles = pTC->m_dwCharStyles; 388 tp.m_iHorizontalScale = pTC->horizonal_scale(); 389 tp.m_iVerticalScale = pTC->vertical_scale(); 390 m_pCurLine->m_LinePieces.push_back(tp); 391 tpos->push_back({0, 0}); 392 } 393} 394 395void CFX_TxtBreak::EndBreak_Alignment(const std::deque<FX_TPO>& tpos, 396 bool bAllChars, 397 CFX_BreakType dwStatus) { 398 int32_t iNetWidth = m_pCurLine->m_iWidth; 399 int32_t iGapChars = 0; 400 bool bFind = false; 401 for (auto it = tpos.rbegin(); it != tpos.rend(); ++it) { 402 CFX_BreakPiece& ttp = m_pCurLine->m_LinePieces[it->index]; 403 if (!bFind) 404 iNetWidth = ttp.GetEndPos(); 405 406 bool bArabic = FX_IsOdd(ttp.m_iBidiLevel); 407 int32_t j = bArabic ? 0 : ttp.m_iChars - 1; 408 while (j > -1 && j < ttp.m_iChars) { 409 const CFX_Char* pTC = ttp.GetChar(j); 410 if (pTC->m_nBreakType == FX_LBT_DIRECT_BRK) 411 iGapChars++; 412 if (!bFind || !bAllChars) { 413 FX_CHARTYPE chartype = pTC->GetCharType(); 414 if (chartype == FX_CHARTYPE_Space || chartype == FX_CHARTYPE_Control) { 415 if (!bFind && bAllChars && pTC->m_iCharWidth > 0) 416 iNetWidth -= pTC->m_iCharWidth; 417 } else { 418 bFind = true; 419 if (!bAllChars) 420 break; 421 } 422 } 423 j += bArabic ? 1 : -1; 424 } 425 if (!bAllChars && bFind) 426 break; 427 } 428 429 int32_t iOffset = m_iLineWidth - iNetWidth; 430 if (iGapChars > 0 && m_iAlignment & CFX_TxtLineAlignment_Justified && 431 dwStatus != CFX_BreakType::Paragraph) { 432 int32_t iStart = -1; 433 for (auto& tpo : tpos) { 434 CFX_BreakPiece& ttp = m_pCurLine->m_LinePieces[tpo.index]; 435 if (iStart < -1) 436 iStart = ttp.m_iStartPos; 437 else 438 ttp.m_iStartPos = iStart; 439 440 for (int32_t j = 0; j < ttp.m_iChars; j++) { 441 CFX_Char* pTC = ttp.GetChar(j); 442 if (pTC->m_nBreakType != FX_LBT_DIRECT_BRK || pTC->m_iCharWidth < 0) 443 continue; 444 445 int32_t k = iOffset / iGapChars; 446 pTC->m_iCharWidth += k; 447 ttp.m_iWidth += k; 448 iOffset -= k; 449 iGapChars--; 450 if (iGapChars < 1) 451 break; 452 } 453 iStart += ttp.m_iWidth; 454 } 455 } else if (m_iAlignment & CFX_TxtLineAlignment_Center || 456 m_iAlignment & CFX_TxtLineAlignment_Right) { 457 if (m_iAlignment & CFX_TxtLineAlignment_Center && 458 !(m_iAlignment & CFX_TxtLineAlignment_Right)) { 459 iOffset /= 2; 460 } 461 if (iOffset > 0) { 462 for (auto& ttp : m_pCurLine->m_LinePieces) 463 ttp.m_iStartPos += iOffset; 464 } 465 } 466} 467 468CFX_BreakType CFX_TxtBreak::EndBreak(CFX_BreakType dwStatus) { 469 ASSERT(dwStatus != CFX_BreakType::None); 470 471 if (!m_pCurLine->m_LinePieces.empty()) { 472 if (dwStatus != CFX_BreakType::Piece) 473 m_pCurLine->m_LinePieces.back().m_dwStatus = dwStatus; 474 return m_pCurLine->m_LinePieces.back().m_dwStatus; 475 } 476 477 if (HasLine()) { 478 if (!m_Line[m_iReadyLineIndex].m_LinePieces.empty()) { 479 if (dwStatus != CFX_BreakType::Piece) 480 m_Line[m_iReadyLineIndex].m_LinePieces.back().m_dwStatus = dwStatus; 481 return m_Line[m_iReadyLineIndex].m_LinePieces.back().m_dwStatus; 482 } 483 return CFX_BreakType::None; 484 } 485 486 int32_t iCount = m_pCurLine->CountChars(); 487 if (iCount < 1) 488 return CFX_BreakType::None; 489 490 m_pCurLine->GetChar(iCount - 1)->m_dwStatus = dwStatus; 491 if (dwStatus == CFX_BreakType::Piece) 492 return dwStatus; 493 494 m_iReadyLineIndex = m_pCurLine == &m_Line[0] ? 0 : 1; 495 CFX_BreakLine* pNextLine = &m_Line[1 - m_iReadyLineIndex]; 496 bool bAllChars = m_iAlignment > CFX_TxtLineAlignment_Right; 497 if (!EndBreak_SplitLine(pNextLine, bAllChars)) { 498 std::deque<FX_TPO> tpos; 499 EndBreak_BidiLine(&tpos, dwStatus); 500 if (m_iAlignment > CFX_TxtLineAlignment_Left) 501 EndBreak_Alignment(tpos, bAllChars, dwStatus); 502 } 503 504 m_pCurLine = pNextLine; 505 CFX_Char* pTC = GetLastChar(0, false, false); 506 m_eCharType = pTC ? pTC->GetCharType() : FX_CHARTYPE_Unknown; 507 508 return dwStatus; 509} 510 511int32_t CFX_TxtBreak::GetBreakPos(std::vector<CFX_Char>& ca, 512 int32_t& iEndPos, 513 bool bAllChars, 514 bool bOnlyBrk) { 515 int32_t iLength = pdfium::CollectionSize<int32_t>(ca) - 1; 516 if (iLength < 1) 517 return iLength; 518 519 int32_t iBreak = -1; 520 int32_t iBreakPos = -1; 521 int32_t iIndirect = -1; 522 int32_t iIndirectPos = -1; 523 int32_t iLast = -1; 524 int32_t iLastPos = -1; 525 if (m_bSingleLine || iEndPos <= m_iLineWidth) { 526 if (!bAllChars) 527 return iLength; 528 529 iBreak = iLength; 530 iBreakPos = iEndPos; 531 } 532 533 FX_LINEBREAKTYPE eType; 534 uint32_t nCodeProp; 535 uint32_t nCur; 536 uint32_t nNext; 537 CFX_Char* pCur = &ca[iLength--]; 538 if (bAllChars) 539 pCur->m_nBreakType = FX_LBT_UNKNOWN; 540 541 nCodeProp = pCur->char_props(); 542 nNext = nCodeProp & 0x003F; 543 int32_t iCharWidth = pCur->m_iCharWidth; 544 if (iCharWidth > 0) 545 iEndPos -= iCharWidth; 546 547 while (iLength >= 0) { 548 pCur = &ca[iLength]; 549 nCodeProp = pCur->char_props(); 550 nCur = nCodeProp & 0x003F; 551 if (nNext == kBreakPropertySpace) 552 eType = FX_LBT_PROHIBITED_BRK; 553 else 554 eType = gs_FX_LineBreak_PairTable[nCur][nNext]; 555 if (bAllChars) 556 pCur->m_nBreakType = static_cast<uint8_t>(eType); 557 if (!bOnlyBrk) { 558 if (m_bSingleLine || iEndPos <= m_iLineWidth || 559 nCur == kBreakPropertySpace) { 560 if (eType == FX_LBT_DIRECT_BRK && iBreak < 0) { 561 iBreak = iLength; 562 iBreakPos = iEndPos; 563 if (!bAllChars) 564 return iLength; 565 } else if (eType == FX_LBT_INDIRECT_BRK && iIndirect < 0) { 566 iIndirect = iLength; 567 iIndirectPos = iEndPos; 568 } 569 if (iLast < 0) { 570 iLast = iLength; 571 iLastPos = iEndPos; 572 } 573 } 574 iCharWidth = pCur->m_iCharWidth; 575 if (iCharWidth > 0) 576 iEndPos -= iCharWidth; 577 } 578 nNext = nCodeProp & 0x003F; 579 iLength--; 580 } 581 if (bOnlyBrk) 582 return 0; 583 if (iBreak > -1) { 584 iEndPos = iBreakPos; 585 return iBreak; 586 } 587 if (iIndirect > -1) { 588 iEndPos = iIndirectPos; 589 return iIndirect; 590 } 591 if (iLast > -1) { 592 iEndPos = iLastPos; 593 return iLast; 594 } 595 return 0; 596} 597 598void CFX_TxtBreak::SplitTextLine(CFX_BreakLine* pCurLine, 599 CFX_BreakLine* pNextLine, 600 bool bAllChars) { 601 ASSERT(pCurLine && pNextLine); 602 int32_t iCount = pCurLine->CountChars(); 603 if (iCount < 2) 604 return; 605 606 int32_t iEndPos = pCurLine->m_iWidth; 607 std::vector<CFX_Char>& curChars = pCurLine->m_LineChars; 608 int32_t iCharPos = GetBreakPos(curChars, iEndPos, bAllChars, false); 609 if (iCharPos < 0) 610 iCharPos = 0; 611 612 iCharPos++; 613 if (iCharPos >= iCount) { 614 pNextLine->Clear(); 615 CFX_Char* pTC = &curChars[iCharPos - 1]; 616 pTC->m_nBreakType = FX_LBT_UNKNOWN; 617 return; 618 } 619 620 pNextLine->m_LineChars = 621 std::vector<CFX_Char>(curChars.begin() + iCharPos, curChars.end()); 622 curChars.erase(curChars.begin() + iCharPos, curChars.end()); 623 pCurLine->m_iWidth = iEndPos; 624 CFX_Char* pTC = &curChars[iCharPos - 1]; 625 pTC->m_nBreakType = FX_LBT_UNKNOWN; 626 iCount = pdfium::CollectionSize<int>(pNextLine->m_LineChars); 627 int32_t iWidth = 0; 628 for (int32_t i = 0; i < iCount; i++) { 629 if (pNextLine->m_LineChars[i].GetCharType() >= FX_CHARTYPE_ArabicAlef) { 630 pCurLine->m_iArabicChars--; 631 pNextLine->m_iArabicChars++; 632 } 633 iWidth += std::max(0, pNextLine->m_LineChars[i].m_iCharWidth); 634 pNextLine->m_LineChars[i].m_dwStatus = CFX_BreakType::None; 635 } 636 pNextLine->m_iWidth = iWidth; 637} 638 639struct FX_FORMCHAR { 640 uint16_t wch; 641 uint16_t wForm; 642 int32_t iWidth; 643}; 644 645int32_t CFX_TxtBreak::GetDisplayPos(const FX_TXTRUN* pTxtRun, 646 FXTEXT_CHARPOS* pCharPos) const { 647 if (!pTxtRun || pTxtRun->iLength < 1) 648 return 0; 649 650 CFDE_TextEditEngine* pEngine = pTxtRun->pEdtEngine; 651 const wchar_t* pStr = pTxtRun->wsStr.c_str(); 652 int32_t* pWidths = pTxtRun->pWidths; 653 int32_t iLength = pTxtRun->iLength - 1; 654 RetainPtr<CFGAS_GEFont> pFont = pTxtRun->pFont; 655 uint32_t dwStyles = pTxtRun->dwStyles; 656 CFX_RectF rtText(*pTxtRun->pRect); 657 bool bRTLPiece = (pTxtRun->dwCharStyles & FX_TXTCHARSTYLE_OddBidiLevel) != 0; 658 float fFontSize = pTxtRun->fFontSize; 659 int32_t iFontSize = FXSYS_round(fFontSize * 20.0f); 660 int32_t iAscent = pFont->GetAscent(); 661 int32_t iDescent = pFont->GetDescent(); 662 int32_t iMaxHeight = iAscent - iDescent; 663 float fFontHeight = fFontSize; 664 float fAscent = fFontHeight * (float)iAscent / (float)iMaxHeight; 665 float fX = rtText.left; 666 float fY; 667 float fCharWidth; 668 int32_t iHorScale = pTxtRun->iHorizontalScale; 669 int32_t iVerScale = pTxtRun->iVerticalScale; 670 bool bSkipSpace = pTxtRun->bSkipSpace; 671 FX_FORMCHAR formChars[3]; 672 float fYBase; 673 674 if (bRTLPiece) 675 fX = rtText.right(); 676 677 fYBase = rtText.top + (rtText.height - fFontSize) / 2.0f; 678 fY = fYBase + fAscent; 679 680 int32_t iCount = 0; 681 int32_t iNext = 0; 682 wchar_t wPrev = 0xFEFF; 683 wchar_t wNext = 0xFEFF; 684 wchar_t wForm = 0xFEFF; 685 wchar_t wLast = 0xFEFF; 686 bool bShadda = false; 687 bool bLam = false; 688 for (int32_t i = 0; i <= iLength; i++) { 689 int32_t iWidth; 690 wchar_t wch; 691 if (pEngine) { 692 wch = pEngine->GetChar(i); 693 iWidth = pEngine->GetWidthOfChar(i); 694 } else { 695 wch = *pStr++; 696 iWidth = *pWidths++; 697 } 698 699 uint32_t dwProps = FX_GetUnicodeProperties(wch); 700 FX_CHARTYPE chartype = GetCharTypeFromProp(dwProps); 701 if (chartype == FX_CHARTYPE_ArabicAlef && iWidth == 0) { 702 wPrev = 0xFEFF; 703 wLast = wch; 704 continue; 705 } 706 707 if (chartype >= FX_CHARTYPE_ArabicAlef) { 708 if (i < iLength) { 709 if (pEngine) { 710 iNext = i + 1; 711 while (iNext <= iLength) { 712 wNext = pEngine->GetChar(iNext); 713 dwProps = FX_GetUnicodeProperties(wNext); 714 if ((dwProps & FX_CHARTYPEBITSMASK) != FX_CHARTYPE_Combination) 715 break; 716 717 iNext++; 718 } 719 if (iNext > iLength) 720 wNext = 0xFEFF; 721 } else { 722 int32_t j = -1; 723 do { 724 j++; 725 if (i + j >= iLength) 726 break; 727 728 wNext = pStr[j]; 729 dwProps = FX_GetUnicodeProperties(wNext); 730 } while ((dwProps & FX_CHARTYPEBITSMASK) == FX_CHARTYPE_Combination); 731 if (i + j >= iLength) 732 wNext = 0xFEFF; 733 } 734 } else { 735 wNext = 0xFEFF; 736 } 737 738 wForm = pdfium::arabic::GetFormChar(wch, wPrev, wNext); 739 bLam = (wPrev == 0x0644 && wch == 0x0644 && wNext == 0x0647); 740 } else if (chartype == FX_CHARTYPE_Combination) { 741 wForm = wch; 742 if (wch >= 0x064C && wch <= 0x0651) { 743 if (bShadda) { 744 wForm = 0xFEFF; 745 bShadda = false; 746 } else { 747 wNext = 0xFEFF; 748 if (pEngine) { 749 iNext = i + 1; 750 if (iNext <= iLength) 751 wNext = pEngine->GetChar(iNext); 752 } else { 753 if (i < iLength) 754 wNext = *pStr; 755 } 756 if (wch == 0x0651) { 757 if (wNext >= 0x064C && wNext <= 0x0650) { 758 wForm = FX_GetArabicFromShaddaTable(wNext); 759 bShadda = true; 760 } 761 } else { 762 if (wNext == 0x0651) { 763 wForm = FX_GetArabicFromShaddaTable(wch); 764 bShadda = true; 765 } 766 } 767 } 768 } else { 769 bShadda = false; 770 } 771 } else if (chartype == FX_CHARTYPE_Numeric) { 772 wForm = wch; 773 } else if (wch == L'.') { 774 wForm = wch; 775 } else if (wch == L',') { 776 wForm = wch; 777 } else if (bRTLPiece) { 778 wForm = FX_GetMirrorChar(wch, dwProps); 779 } else { 780 wForm = wch; 781 } 782 if (chartype != FX_CHARTYPE_Combination) 783 bShadda = false; 784 if (chartype < FX_CHARTYPE_ArabicAlef) 785 bLam = false; 786 787 dwProps = FX_GetUnicodeProperties(wForm); 788 bool bEmptyChar = 789 (chartype >= FX_CHARTYPE_Tab && chartype <= FX_CHARTYPE_Control); 790 if (wForm == 0xFEFF) 791 bEmptyChar = true; 792 793 int32_t iForms = bLam ? 3 : 1; 794 iCount += (bEmptyChar && bSkipSpace) ? 0 : iForms; 795 if (!pCharPos) { 796 if (iWidth > 0) 797 wPrev = wch; 798 wLast = wch; 799 continue; 800 } 801 802 int32_t iCharWidth = iWidth; 803 if (iCharWidth < 0) 804 iCharWidth = -iCharWidth; 805 806 iCharWidth /= iFontSize; 807 formChars[0].wch = wch; 808 formChars[0].wForm = wForm; 809 formChars[0].iWidth = iCharWidth; 810 if (bLam) { 811 formChars[1].wForm = 0x0651; 812 iCharWidth = 0; 813 pFont->GetCharWidth(0x0651, iCharWidth); 814 formChars[1].iWidth = iCharWidth; 815 formChars[2].wForm = 0x0670; 816 iCharWidth = 0; 817 pFont->GetCharWidth(0x0670, iCharWidth); 818 formChars[2].iWidth = iCharWidth; 819 } 820 821 for (int32_t j = 0; j < iForms; j++) { 822 wForm = (wchar_t)formChars[j].wForm; 823 iCharWidth = formChars[j].iWidth; 824 if (j > 0) { 825 chartype = FX_CHARTYPE_Combination; 826 wch = wForm; 827 wLast = (wchar_t)formChars[j - 1].wForm; 828 } 829 if (!bEmptyChar || (bEmptyChar && !bSkipSpace)) { 830 pCharPos->m_GlyphIndex = pFont->GetGlyphIndex(wForm); 831#if _FX_PLATFORM_ == _FX_PLATFORM_APPLE_ 832 pCharPos->m_ExtGID = pCharPos->m_GlyphIndex; 833#endif 834 pCharPos->m_FontCharWidth = iCharWidth; 835 } 836 837 fCharWidth = fFontSize * iCharWidth / 1000.0f; 838 if (bRTLPiece && chartype != FX_CHARTYPE_Combination) 839 fX -= fCharWidth; 840 841 if (!bEmptyChar || (bEmptyChar && !bSkipSpace)) { 842 pCharPos->m_Origin = CFX_PointF(fX, fY); 843 844 if ((dwStyles & FX_LAYOUTSTYLE_CombText) != 0) { 845 int32_t iFormWidth = iCharWidth; 846 pFont->GetCharWidth(wForm, iFormWidth); 847 float fOffset = fFontSize * (iCharWidth - iFormWidth) / 2000.0f; 848 pCharPos->m_Origin.x += fOffset; 849 } 850 851 if (chartype == FX_CHARTYPE_Combination) { 852 CFX_Rect rtBBox; 853 if (pFont->GetCharBBox(wForm, &rtBBox)) { 854 pCharPos->m_Origin.y = 855 fYBase + fFontSize - 856 fFontSize * (float)rtBBox.height / (float)iMaxHeight; 857 } 858 if (wForm == wch && wLast != 0xFEFF) { 859 uint32_t dwLastProps = FX_GetUnicodeProperties(wLast); 860 if ((dwLastProps & FX_CHARTYPEBITSMASK) == 861 FX_CHARTYPE_Combination) { 862 CFX_Rect rtBox; 863 if (pFont->GetCharBBox(wLast, &rtBox)) 864 pCharPos->m_Origin.y -= fFontSize * rtBox.height / iMaxHeight; 865 } 866 } 867 } 868 } 869 if (!bRTLPiece && chartype != FX_CHARTYPE_Combination) 870 fX += fCharWidth; 871 872 if (!bEmptyChar || (bEmptyChar && !bSkipSpace)) { 873 pCharPos->m_bGlyphAdjust = true; 874 pCharPos->m_AdjustMatrix[0] = -1; 875 pCharPos->m_AdjustMatrix[1] = 0; 876 pCharPos->m_AdjustMatrix[2] = 0; 877 pCharPos->m_AdjustMatrix[3] = 1; 878 879 if (iHorScale != 100 || iVerScale != 100) { 880 pCharPos->m_AdjustMatrix[0] = 881 pCharPos->m_AdjustMatrix[0] * iHorScale / 100.0f; 882 pCharPos->m_AdjustMatrix[1] = 883 pCharPos->m_AdjustMatrix[1] * iHorScale / 100.0f; 884 pCharPos->m_AdjustMatrix[2] = 885 pCharPos->m_AdjustMatrix[2] * iVerScale / 100.0f; 886 pCharPos->m_AdjustMatrix[3] = 887 pCharPos->m_AdjustMatrix[3] * iVerScale / 100.0f; 888 } 889 pCharPos++; 890 } 891 } 892 if (iWidth > 0) 893 wPrev = static_cast<wchar_t>(formChars[0].wch); 894 wLast = wch; 895 } 896 return iCount; 897} 898 899std::vector<CFX_RectF> CFX_TxtBreak::GetCharRects(const FX_TXTRUN* pTxtRun, 900 bool bCharBBox) const { 901 if (!pTxtRun || pTxtRun->iLength < 1) 902 return std::vector<CFX_RectF>(); 903 904 CFDE_TextEditEngine* pEngine = pTxtRun->pEdtEngine; 905 const wchar_t* pStr = pTxtRun->wsStr.c_str(); 906 int32_t* pWidths = pTxtRun->pWidths; 907 int32_t iLength = pTxtRun->iLength; 908 CFX_RectF rect(*pTxtRun->pRect); 909 float fFontSize = pTxtRun->fFontSize; 910 int32_t iFontSize = FXSYS_round(fFontSize * 20.0f); 911 float fScale = fFontSize / 1000.0f; 912 RetainPtr<CFGAS_GEFont> pFont = pTxtRun->pFont; 913 if (!pFont) 914 bCharBBox = false; 915 916 CFX_Rect bbox; 917 if (bCharBBox) 918 bCharBBox = pFont->GetBBox(&bbox); 919 920 float fLeft = std::max(0.0f, bbox.left * fScale); 921 float fHeight = fabs(bbox.height * fScale); 922 bool bRTLPiece = !!(pTxtRun->dwCharStyles & FX_TXTCHARSTYLE_OddBidiLevel); 923 bool bSingleLine = !!(pTxtRun->dwStyles & FX_LAYOUTSTYLE_SingleLine); 924 bool bCombText = !!(pTxtRun->dwStyles & FX_LAYOUTSTYLE_CombText); 925 wchar_t wch; 926 int32_t iCharSize; 927 float fCharSize; 928 float fStart = bRTLPiece ? rect.right() : rect.left; 929 930 std::vector<CFX_RectF> rtArray(iLength); 931 for (int32_t i = 0; i < iLength; i++) { 932 if (pEngine) { 933 wch = pEngine->GetChar(i); 934 iCharSize = pEngine->GetWidthOfChar(i); 935 } else { 936 wch = *pStr++; 937 iCharSize = *pWidths++; 938 } 939 fCharSize = static_cast<float>(iCharSize) / 20000.0f; 940 bool bRet = (!bSingleLine && IsCtrlCode(wch)); 941 if (!(wch == L'\v' || wch == L'\f' || wch == 0x2028 || wch == 0x2029 || 942 wch == L'\n')) { 943 bRet = false; 944 } 945 if (bRet) { 946 iCharSize = iFontSize * 500; 947 fCharSize = fFontSize / 2.0f; 948 } 949 rect.left = fStart; 950 if (bRTLPiece) { 951 rect.left -= fCharSize; 952 fStart -= fCharSize; 953 } else { 954 fStart += fCharSize; 955 } 956 rect.width = fCharSize; 957 958 if (bCharBBox && !bRet) { 959 int32_t iCharWidth = 1000; 960 pFont->GetCharWidth(wch, iCharWidth); 961 float fRTLeft = 0, fCharWidth = 0; 962 if (iCharWidth > 0) { 963 fCharWidth = iCharWidth * fScale; 964 fRTLeft = fLeft; 965 if (bCombText) 966 fRTLeft = (rect.width - fCharWidth) / 2.0f; 967 } 968 CFX_RectF rtBBoxF; 969 rtBBoxF.left = rect.left + fRTLeft; 970 rtBBoxF.top = rect.top + (rect.height - fHeight) / 2.0f; 971 rtBBoxF.width = fCharWidth; 972 rtBBoxF.height = fHeight; 973 rtBBoxF.top = std::max(rtBBoxF.top, 0.0f); 974 rtArray[i] = rtBBoxF; 975 continue; 976 } 977 rtArray[i] = rect; 978 } 979 return rtArray; 980} 981 982FX_TXTRUN::FX_TXTRUN() 983 : pEdtEngine(nullptr), 984 pIdentity(nullptr), 985 pWidths(nullptr), 986 iLength(0), 987 pFont(nullptr), 988 fFontSize(12), 989 dwStyles(0), 990 iHorizontalScale(100), 991 iVerticalScale(100), 992 dwCharStyles(0), 993 pRect(nullptr), 994 bSkipSpace(true) {} 995 996FX_TXTRUN::~FX_TXTRUN() {} 997 998FX_TXTRUN::FX_TXTRUN(const FX_TXTRUN& other) = default; 999