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_rtfbreak.h" 8 9 #include <algorithm> 10 11 #include "build/build_config.h" 12 #include "core/fxcrt/fx_safe_types.h" 13 #include "core/fxge/text_char_pos.h" 14 #include "third_party/base/numerics/safe_math.h" 15 #include "third_party/base/stl_util.h" 16 #include "xfa/fgas/font/cfgas_gefont.h" 17 #include "xfa/fgas/layout/cfx_char.h" 18 #include "xfa/fgas/layout/cfx_textpiece.h" 19 #include "xfa/fgas/layout/cfx_textuserdata.h" 20 #include "xfa/fgas/layout/fx_arabic.h" 21 #include "xfa/fgas/layout/fx_linebreak.h" 22 CFX_RTFBreak(uint32_t dwLayoutStyles)23 CFX_RTFBreak::CFX_RTFBreak(uint32_t dwLayoutStyles) 24 : CFX_Break(dwLayoutStyles), 25 m_bPagination(false), 26 m_iAlignment(CFX_RTFLineAlignment::Left) { 27 SetBreakStatus(); 28 m_bPagination = !!(m_dwLayoutStyles & FX_LAYOUTSTYLE_Pagination); 29 } 30 ~CFX_RTFBreak()31 CFX_RTFBreak::~CFX_RTFBreak() {} 32 SetLineStartPos(float fLinePos)33 void CFX_RTFBreak::SetLineStartPos(float fLinePos) { 34 int32_t iLinePos = FXSYS_roundf(fLinePos * kConversionFactor); 35 iLinePos = std::min(iLinePos, m_iLineWidth); 36 iLinePos = std::max(iLinePos, m_iLineStart); 37 m_pCurLine->m_iStart = iLinePos; 38 } 39 AddPositionedTab(float fTabPos)40 void CFX_RTFBreak::AddPositionedTab(float fTabPos) { 41 int32_t iTabPos = std::min( 42 FXSYS_roundf(fTabPos * kConversionFactor) + m_iLineStart, m_iLineWidth); 43 auto it = std::lower_bound(m_PositionedTabs.begin(), m_PositionedTabs.end(), 44 iTabPos); 45 if (it != m_PositionedTabs.end() && *it == iTabPos) 46 return; 47 m_PositionedTabs.insert(it, iTabPos); 48 } 49 SetUserData(const RetainPtr<CFX_TextUserData> & pUserData)50 void CFX_RTFBreak::SetUserData(const RetainPtr<CFX_TextUserData>& pUserData) { 51 if (m_pUserData == pUserData) 52 return; 53 54 SetBreakStatus(); 55 m_pUserData = pUserData; 56 } 57 GetPositionedTab(int32_t * iTabPos) const58 bool CFX_RTFBreak::GetPositionedTab(int32_t* iTabPos) const { 59 auto it = std::upper_bound(m_PositionedTabs.begin(), m_PositionedTabs.end(), 60 *iTabPos); 61 if (it == m_PositionedTabs.end()) 62 return false; 63 64 *iTabPos = *it; 65 return true; 66 } 67 AppendChar(wchar_t wch)68 CFX_BreakType CFX_RTFBreak::AppendChar(wchar_t wch) { 69 ASSERT(m_pCurLine); 70 71 FX_CHARTYPE chartype = FX_GetCharType(wch); 72 m_pCurLine->m_LineChars.emplace_back(wch, m_iHorizontalScale, 73 m_iVerticalScale); 74 CFX_Char* pCurChar = &m_pCurLine->m_LineChars.back(); 75 pCurChar->m_iFontSize = m_iFontSize; 76 pCurChar->m_dwIdentity = m_dwIdentity; 77 pCurChar->m_pUserData = m_pUserData; 78 79 CFX_BreakType dwRet1 = CFX_BreakType::None; 80 if (chartype != FX_CHARTYPE::kCombination && 81 GetUnifiedCharType(m_eCharType) != GetUnifiedCharType(chartype) && 82 m_eCharType != FX_CHARTYPE::kUnknown && 83 IsGreaterThanLineWidth(m_pCurLine->GetLineEnd()) && 84 (m_eCharType != FX_CHARTYPE::kSpace || 85 chartype != FX_CHARTYPE::kControl)) { 86 dwRet1 = EndBreak(CFX_BreakType::Line); 87 if (!m_pCurLine->m_LineChars.empty()) 88 pCurChar = &m_pCurLine->m_LineChars.back(); 89 } 90 91 CFX_BreakType dwRet2 = CFX_BreakType::None; 92 switch (chartype) { 93 case FX_CHARTYPE::kTab: 94 AppendChar_Tab(pCurChar); 95 break; 96 case FX_CHARTYPE::kControl: 97 dwRet2 = AppendChar_Control(pCurChar); 98 break; 99 case FX_CHARTYPE::kCombination: 100 AppendChar_Combination(pCurChar); 101 break; 102 case FX_CHARTYPE::kArabicAlef: 103 case FX_CHARTYPE::kArabicSpecial: 104 case FX_CHARTYPE::kArabicDistortion: 105 case FX_CHARTYPE::kArabicNormal: 106 case FX_CHARTYPE::kArabicForm: 107 case FX_CHARTYPE::kArabic: 108 dwRet2 = AppendChar_Arabic(pCurChar); 109 break; 110 case FX_CHARTYPE::kUnknown: 111 case FX_CHARTYPE::kSpace: 112 case FX_CHARTYPE::kNumeric: 113 case FX_CHARTYPE::kNormal: 114 default: 115 dwRet2 = AppendChar_Others(pCurChar); 116 break; 117 } 118 119 m_eCharType = chartype; 120 return std::max(dwRet1, dwRet2); 121 } 122 AppendChar_Combination(CFX_Char * pCurChar)123 void CFX_RTFBreak::AppendChar_Combination(CFX_Char* pCurChar) { 124 FX_SAFE_INT32 iCharWidth = 0; 125 int32_t iCharWidthOut; 126 if (m_pFont && m_pFont->GetCharWidth(pCurChar->char_code(), &iCharWidthOut)) 127 iCharWidth = iCharWidthOut; 128 129 iCharWidth *= m_iFontSize; 130 iCharWidth *= m_iHorizontalScale; 131 iCharWidth /= 100; 132 CFX_Char* pLastChar = GetLastChar(0, false, true); 133 if (pLastChar && pLastChar->GetCharType() > FX_CHARTYPE::kCombination) 134 iCharWidth *= -1; 135 else 136 m_eCharType = FX_CHARTYPE::kCombination; 137 138 int32_t iCharWidthValid = iCharWidth.ValueOrDefault(0); 139 pCurChar->m_iCharWidth = iCharWidthValid; 140 if (iCharWidthValid > 0) { 141 FX_SAFE_INT32 checked_width = m_pCurLine->m_iWidth; 142 checked_width += iCharWidthValid; 143 if (!checked_width.IsValid()) 144 return; 145 146 m_pCurLine->m_iWidth = checked_width.ValueOrDie(); 147 } 148 } 149 AppendChar_Tab(CFX_Char * pCurChar)150 void CFX_RTFBreak::AppendChar_Tab(CFX_Char* pCurChar) { 151 if (!(m_dwLayoutStyles & FX_LAYOUTSTYLE_ExpandTab)) 152 return; 153 154 int32_t& iLineWidth = m_pCurLine->m_iWidth; 155 int32_t iCharWidth = iLineWidth; 156 FX_SAFE_INT32 iSafeCharWidth; 157 if (GetPositionedTab(&iCharWidth)) { 158 iSafeCharWidth = iCharWidth; 159 } else { 160 // Tab width is >= 160000, so this part does not need to be checked. 161 ASSERT(m_iTabWidth >= kMinimumTabWidth); 162 iSafeCharWidth = iLineWidth / m_iTabWidth + 1; 163 iSafeCharWidth *= m_iTabWidth; 164 } 165 iSafeCharWidth -= iLineWidth; 166 167 iCharWidth = iSafeCharWidth.ValueOrDefault(0); 168 169 pCurChar->m_iCharWidth = iCharWidth; 170 iLineWidth += iCharWidth; 171 } 172 AppendChar_Control(CFX_Char * pCurChar)173 CFX_BreakType CFX_RTFBreak::AppendChar_Control(CFX_Char* pCurChar) { 174 CFX_BreakType dwRet2 = CFX_BreakType::None; 175 switch (pCurChar->char_code()) { 176 case L'\v': 177 case 0x2028: 178 dwRet2 = CFX_BreakType::Line; 179 break; 180 case L'\f': 181 dwRet2 = CFX_BreakType::Page; 182 break; 183 case 0x2029: 184 dwRet2 = CFX_BreakType::Paragraph; 185 break; 186 default: 187 if (pCurChar->char_code() == m_wParagraphBreakChar) 188 dwRet2 = CFX_BreakType::Paragraph; 189 break; 190 } 191 if (dwRet2 != CFX_BreakType::None) 192 dwRet2 = EndBreak(dwRet2); 193 194 return dwRet2; 195 } 196 AppendChar_Arabic(CFX_Char * pCurChar)197 CFX_BreakType CFX_RTFBreak::AppendChar_Arabic(CFX_Char* pCurChar) { 198 m_pCurLine->IncrementArabicCharCount(); 199 200 CFX_Char* pLastChar = nullptr; 201 wchar_t wForm; 202 bool bAlef = false; 203 if (m_eCharType >= FX_CHARTYPE::kArabicAlef && 204 m_eCharType <= FX_CHARTYPE::kArabicDistortion) { 205 pLastChar = GetLastChar(1, false, true); 206 if (pLastChar) { 207 m_pCurLine->m_iWidth -= pLastChar->m_iCharWidth; 208 CFX_Char* pPrevChar = GetLastChar(2, false, true); 209 wForm = pdfium::arabic::GetFormChar(pLastChar, pPrevChar, pCurChar); 210 bAlef = (wForm == 0xFEFF && 211 pLastChar->GetCharType() == FX_CHARTYPE::kArabicAlef); 212 FX_SAFE_INT32 iCharWidth; 213 int32_t iCharWidthOut; 214 if (m_pFont && 215 (m_pFont->GetCharWidth(wForm, &iCharWidthOut) || 216 m_pFont->GetCharWidth(pLastChar->char_code(), &iCharWidthOut))) { 217 iCharWidth = iCharWidthOut; 218 } else { 219 iCharWidth = 0; 220 } 221 222 iCharWidth *= m_iFontSize; 223 iCharWidth *= m_iHorizontalScale; 224 iCharWidth /= 100; 225 226 int iCharWidthValid = iCharWidth.ValueOrDefault(0); 227 pLastChar->m_iCharWidth = iCharWidthValid; 228 229 FX_SAFE_INT32 checked_width = m_pCurLine->m_iWidth; 230 checked_width += iCharWidthValid; 231 if (!checked_width.IsValid()) 232 return CFX_BreakType::None; 233 234 m_pCurLine->m_iWidth = checked_width.ValueOrDie(); 235 iCharWidth = 0; 236 } 237 } 238 239 wForm = pdfium::arabic::GetFormChar(pCurChar, bAlef ? nullptr : pLastChar, 240 nullptr); 241 FX_SAFE_INT32 iCharWidth; 242 int32_t iCharWidthOut; 243 if (m_pFont && 244 (m_pFont->GetCharWidth(wForm, &iCharWidthOut) || 245 m_pFont->GetCharWidth(pCurChar->char_code(), &iCharWidthOut))) { 246 iCharWidth = iCharWidthOut; 247 } else { 248 iCharWidth = 0; 249 } 250 251 iCharWidth *= m_iFontSize; 252 iCharWidth *= m_iHorizontalScale; 253 iCharWidth /= 100; 254 255 int iCharWidthValid = iCharWidth.ValueOrDefault(0); 256 pCurChar->m_iCharWidth = iCharWidthValid; 257 258 FX_SAFE_INT32 checked_width = m_pCurLine->m_iWidth; 259 checked_width += iCharWidthValid; 260 if (!checked_width.IsValid()) 261 return CFX_BreakType::None; 262 263 m_pCurLine->m_iWidth = checked_width.ValueOrDie(); 264 265 if (IsGreaterThanLineWidth(m_pCurLine->GetLineEnd())) 266 return EndBreak(CFX_BreakType::Line); 267 return CFX_BreakType::None; 268 } 269 AppendChar_Others(CFX_Char * pCurChar)270 CFX_BreakType CFX_RTFBreak::AppendChar_Others(CFX_Char* pCurChar) { 271 FX_CHARTYPE chartype = pCurChar->GetCharType(); 272 wchar_t wForm = pCurChar->char_code(); 273 FX_SAFE_INT32 iCharWidth; 274 int32_t iCharWidthOut; 275 if (m_pFont && m_pFont->GetCharWidth(wForm, &iCharWidthOut)) 276 iCharWidth = iCharWidthOut; 277 else 278 iCharWidth = 0; 279 280 iCharWidth *= m_iFontSize; 281 iCharWidth *= m_iHorizontalScale; 282 iCharWidth /= 100; 283 iCharWidth += m_iCharSpace; 284 285 int iCharWidthValid = iCharWidth.ValueOrDefault(0); 286 pCurChar->m_iCharWidth = iCharWidthValid; 287 288 FX_SAFE_INT32 checked_width = m_pCurLine->m_iWidth; 289 checked_width += iCharWidthValid; 290 if (!checked_width.IsValid()) 291 return CFX_BreakType::None; 292 293 m_pCurLine->m_iWidth = checked_width.ValueOrDie(); 294 if (chartype != FX_CHARTYPE::kSpace && 295 IsGreaterThanLineWidth(m_pCurLine->GetLineEnd())) { 296 return EndBreak(CFX_BreakType::Line); 297 } 298 return CFX_BreakType::None; 299 } 300 EndBreak(CFX_BreakType dwStatus)301 CFX_BreakType CFX_RTFBreak::EndBreak(CFX_BreakType dwStatus) { 302 ASSERT(dwStatus != CFX_BreakType::None); 303 304 ++m_dwIdentity; 305 if (!m_pCurLine->m_LinePieces.empty()) { 306 if (dwStatus != CFX_BreakType::Piece) 307 m_pCurLine->m_LinePieces.back().m_dwStatus = dwStatus; 308 return m_pCurLine->m_LinePieces.back().m_dwStatus; 309 } 310 311 if (HasLine()) { 312 if (m_Lines[m_iReadyLineIndex].m_LinePieces.empty()) 313 return CFX_BreakType::None; 314 315 if (dwStatus != CFX_BreakType::Piece) 316 m_Lines[m_iReadyLineIndex].m_LinePieces.back().m_dwStatus = dwStatus; 317 return m_Lines[m_iReadyLineIndex].m_LinePieces.back().m_dwStatus; 318 } 319 320 if (m_pCurLine->m_LineChars.empty()) 321 return CFX_BreakType::None; 322 323 CFX_Char* tc = m_pCurLine->GetChar(m_pCurLine->m_LineChars.size() - 1); 324 tc->m_dwStatus = dwStatus; 325 if (dwStatus == CFX_BreakType::Piece) 326 return dwStatus; 327 328 m_iReadyLineIndex = m_pCurLine == &m_Lines[0] ? 0 : 1; 329 CFX_BreakLine* pNextLine = &m_Lines[1 - m_iReadyLineIndex]; 330 bool bAllChars = m_iAlignment == CFX_RTFLineAlignment::Justified || 331 m_iAlignment == CFX_RTFLineAlignment::Distributed; 332 333 if (!EndBreak_SplitLine(pNextLine, bAllChars, dwStatus)) { 334 std::deque<FX_TPO> tpos; 335 EndBreak_BidiLine(&tpos, dwStatus); 336 if (!m_bPagination && m_iAlignment != CFX_RTFLineAlignment::Left) 337 EndBreak_Alignment(tpos, bAllChars, dwStatus); 338 } 339 m_pCurLine = pNextLine; 340 m_pCurLine->m_iStart = m_iLineStart; 341 342 CFX_Char* pTC = GetLastChar(0, false, true); 343 m_eCharType = pTC ? pTC->GetCharType() : FX_CHARTYPE::kUnknown; 344 return dwStatus; 345 } 346 EndBreak_SplitLine(CFX_BreakLine * pNextLine,bool bAllChars,CFX_BreakType dwStatus)347 bool CFX_RTFBreak::EndBreak_SplitLine(CFX_BreakLine* pNextLine, 348 bool bAllChars, 349 CFX_BreakType dwStatus) { 350 bool bDone = false; 351 if (IsGreaterThanLineWidth(m_pCurLine->GetLineEnd())) { 352 const CFX_Char* tc = 353 m_pCurLine->GetChar(m_pCurLine->m_LineChars.size() - 1); 354 switch (tc->GetCharType()) { 355 case FX_CHARTYPE::kTab: 356 case FX_CHARTYPE::kControl: 357 case FX_CHARTYPE::kSpace: 358 break; 359 default: 360 SplitTextLine(m_pCurLine.Get(), pNextLine, !m_bPagination && bAllChars); 361 bDone = true; 362 break; 363 } 364 } 365 366 if (!m_bPagination) { 367 if (bAllChars && !bDone) { 368 int32_t endPos = m_pCurLine->GetLineEnd(); 369 GetBreakPos(m_pCurLine->m_LineChars, bAllChars, true, &endPos); 370 } 371 return false; 372 } 373 374 const CFX_Char* pCurChars = m_pCurLine->m_LineChars.data(); 375 CFX_BreakPiece tp; 376 tp.m_pChars = &m_pCurLine->m_LineChars; 377 bool bNew = true; 378 uint32_t dwIdentity = static_cast<uint32_t>(-1); 379 int32_t iLast = pdfium::CollectionSize<int32_t>(m_pCurLine->m_LineChars) - 1; 380 int32_t j = 0; 381 for (int32_t i = 0; i <= iLast;) { 382 const CFX_Char* pTC = pCurChars + i; 383 if (bNew) { 384 tp.m_iStartChar = i; 385 tp.m_iStartPos += tp.m_iWidth; 386 tp.m_iWidth = 0; 387 tp.m_dwStatus = pTC->m_dwStatus; 388 tp.m_iFontSize = pTC->m_iFontSize; 389 tp.m_iHorizontalScale = pTC->horizonal_scale(); 390 tp.m_iVerticalScale = pTC->vertical_scale(); 391 dwIdentity = pTC->m_dwIdentity; 392 tp.m_dwIdentity = dwIdentity; 393 tp.m_pUserData = pTC->m_pUserData; 394 j = i; 395 bNew = false; 396 } 397 398 if (i == iLast || pTC->m_dwStatus != CFX_BreakType::None || 399 pTC->m_dwIdentity != dwIdentity) { 400 tp.m_iChars = i - j; 401 if (pTC->m_dwIdentity == dwIdentity) { 402 tp.m_dwStatus = pTC->m_dwStatus; 403 tp.m_iWidth += pTC->m_iCharWidth; 404 tp.m_iChars += 1; 405 ++i; 406 } 407 m_pCurLine->m_LinePieces.push_back(tp); 408 bNew = true; 409 } else { 410 tp.m_iWidth += pTC->m_iCharWidth; 411 ++i; 412 } 413 } 414 return true; 415 } 416 EndBreak_BidiLine(std::deque<FX_TPO> * tpos,CFX_BreakType dwStatus)417 void CFX_RTFBreak::EndBreak_BidiLine(std::deque<FX_TPO>* tpos, 418 CFX_BreakType dwStatus) { 419 CFX_Char* pTC; 420 std::vector<CFX_Char>& chars = m_pCurLine->m_LineChars; 421 if (!m_bPagination && m_pCurLine->HasArabicChar()) { 422 size_t iBidiNum = 0; 423 for (size_t i = 0; i < m_pCurLine->m_LineChars.size(); ++i) { 424 pTC = &chars[i]; 425 pTC->m_iBidiPos = static_cast<int32_t>(i); 426 if (pTC->GetCharType() != FX_CHARTYPE::kControl) 427 iBidiNum = i; 428 if (i == 0) 429 pTC->m_iBidiLevel = 1; 430 } 431 CFX_Char::BidiLine(&chars, iBidiNum + 1); 432 } else { 433 for (size_t i = 0; i < m_pCurLine->m_LineChars.size(); ++i) { 434 pTC = &chars[i]; 435 pTC->m_iBidiLevel = 0; 436 pTC->m_iBidiPos = 0; 437 pTC->m_iBidiOrder = 0; 438 } 439 } 440 441 CFX_BreakPiece tp; 442 tp.m_dwStatus = CFX_BreakType::Piece; 443 tp.m_iStartPos = m_pCurLine->m_iStart; 444 tp.m_pChars = &chars; 445 446 int32_t iBidiLevel = -1; 447 int32_t iCharWidth; 448 FX_TPO tpo; 449 uint32_t dwIdentity = static_cast<uint32_t>(-1); 450 int32_t i = 0; 451 int32_t j = 0; 452 int32_t iCount = pdfium::CollectionSize<int32_t>(m_pCurLine->m_LineChars); 453 while (i < iCount) { 454 pTC = &chars[i]; 455 if (iBidiLevel < 0) { 456 iBidiLevel = pTC->m_iBidiLevel; 457 iCharWidth = pTC->m_iCharWidth; 458 tp.m_iWidth = iCharWidth < 1 ? 0 : iCharWidth; 459 tp.m_iBidiLevel = iBidiLevel; 460 tp.m_iBidiPos = pTC->m_iBidiOrder; 461 tp.m_iFontSize = pTC->m_iFontSize; 462 tp.m_iHorizontalScale = pTC->horizonal_scale(); 463 tp.m_iVerticalScale = pTC->vertical_scale(); 464 dwIdentity = pTC->m_dwIdentity; 465 tp.m_dwIdentity = dwIdentity; 466 tp.m_pUserData = pTC->m_pUserData; 467 tp.m_dwStatus = CFX_BreakType::Piece; 468 ++i; 469 } else if (iBidiLevel != pTC->m_iBidiLevel || 470 pTC->m_dwIdentity != dwIdentity) { 471 tp.m_iChars = i - tp.m_iStartChar; 472 m_pCurLine->m_LinePieces.push_back(tp); 473 474 tp.m_iStartPos += tp.m_iWidth; 475 tp.m_iStartChar = i; 476 tpo.index = j++; 477 tpo.pos = tp.m_iBidiPos; 478 tpos->push_back(tpo); 479 iBidiLevel = -1; 480 } else { 481 iCharWidth = pTC->m_iCharWidth; 482 if (iCharWidth > 0) 483 tp.m_iWidth += iCharWidth; 484 ++i; 485 } 486 } 487 488 if (i > tp.m_iStartChar) { 489 tp.m_dwStatus = dwStatus; 490 tp.m_iChars = i - tp.m_iStartChar; 491 m_pCurLine->m_LinePieces.push_back(tp); 492 493 tpo.index = j; 494 tpo.pos = tp.m_iBidiPos; 495 tpos->push_back(tpo); 496 } 497 498 std::sort(tpos->begin(), tpos->end()); 499 int32_t iStartPos = m_pCurLine->m_iStart; 500 for (const auto& it : *tpos) { 501 CFX_BreakPiece& ttp = m_pCurLine->m_LinePieces[it.index]; 502 ttp.m_iStartPos = iStartPos; 503 iStartPos += ttp.m_iWidth; 504 } 505 } 506 EndBreak_Alignment(const std::deque<FX_TPO> & tpos,bool bAllChars,CFX_BreakType dwStatus)507 void CFX_RTFBreak::EndBreak_Alignment(const std::deque<FX_TPO>& tpos, 508 bool bAllChars, 509 CFX_BreakType dwStatus) { 510 int32_t iNetWidth = m_pCurLine->m_iWidth; 511 int32_t iGapChars = 0; 512 bool bFind = false; 513 for (auto it = tpos.rbegin(); it != tpos.rend(); it++) { 514 CFX_BreakPiece& ttp = m_pCurLine->m_LinePieces[it->index]; 515 if (!bFind) 516 iNetWidth = ttp.GetEndPos(); 517 518 bool bArabic = FX_IsOdd(ttp.m_iBidiLevel); 519 int32_t j = bArabic ? 0 : ttp.m_iChars - 1; 520 while (j > -1 && j < ttp.m_iChars) { 521 const CFX_Char* tc = ttp.GetChar(j); 522 if (tc->m_eLineBreakType == FX_LINEBREAKTYPE::kDIRECT_BRK) 523 ++iGapChars; 524 525 if (!bFind || !bAllChars) { 526 FX_CHARTYPE dwCharType = tc->GetCharType(); 527 if (dwCharType == FX_CHARTYPE::kSpace || 528 dwCharType == FX_CHARTYPE::kControl) { 529 if (!bFind) { 530 int32_t iCharWidth = tc->m_iCharWidth; 531 if (bAllChars && iCharWidth > 0) 532 iNetWidth -= iCharWidth; 533 } 534 } else { 535 bFind = true; 536 if (!bAllChars) 537 break; 538 } 539 } 540 j += bArabic ? 1 : -1; 541 } 542 if (!bAllChars && bFind) 543 break; 544 } 545 546 int32_t iOffset = m_iLineWidth - iNetWidth; 547 if (iGapChars > 0 && (m_iAlignment == CFX_RTFLineAlignment::Distributed || 548 (m_iAlignment == CFX_RTFLineAlignment::Justified && 549 dwStatus != CFX_BreakType::Paragraph))) { 550 int32_t iStart = -1; 551 for (const auto& tpo : tpos) { 552 CFX_BreakPiece& ttp = m_pCurLine->m_LinePieces[tpo.index]; 553 if (iStart < 0) 554 iStart = ttp.m_iStartPos; 555 else 556 ttp.m_iStartPos = iStart; 557 558 for (int32_t j = 0; j < ttp.m_iChars; ++j) { 559 CFX_Char* tc = ttp.GetChar(j); 560 if (tc->m_eLineBreakType != FX_LINEBREAKTYPE::kDIRECT_BRK || 561 tc->m_iCharWidth < 0) { 562 continue; 563 } 564 int32_t k = iOffset / iGapChars; 565 tc->m_iCharWidth += k; 566 ttp.m_iWidth += k; 567 iOffset -= k; 568 --iGapChars; 569 if (iGapChars < 1) 570 break; 571 } 572 iStart += ttp.m_iWidth; 573 } 574 } else if (m_iAlignment == CFX_RTFLineAlignment::Right || 575 m_iAlignment == CFX_RTFLineAlignment::Center) { 576 if (m_iAlignment == CFX_RTFLineAlignment::Center) 577 iOffset /= 2; 578 if (iOffset > 0) { 579 for (auto& ttp : m_pCurLine->m_LinePieces) 580 ttp.m_iStartPos += iOffset; 581 } 582 } 583 } 584 GetBreakPos(std::vector<CFX_Char> & tca,bool bAllChars,bool bOnlyBrk,int32_t * pEndPos)585 int32_t CFX_RTFBreak::GetBreakPos(std::vector<CFX_Char>& tca, 586 bool bAllChars, 587 bool bOnlyBrk, 588 int32_t* pEndPos) { 589 int32_t iLength = pdfium::CollectionSize<int32_t>(tca) - 1; 590 if (iLength < 1) 591 return iLength; 592 593 int32_t iBreak = -1; 594 int32_t iBreakPos = -1; 595 int32_t iIndirect = -1; 596 int32_t iIndirectPos = -1; 597 int32_t iLast = -1; 598 int32_t iLastPos = -1; 599 if (*pEndPos <= m_iLineWidth) { 600 if (!bAllChars) 601 return iLength; 602 603 iBreak = iLength; 604 iBreakPos = *pEndPos; 605 } 606 607 CFX_Char* pCharArray = tca.data(); 608 CFX_Char* pCur = pCharArray + iLength; 609 --iLength; 610 if (bAllChars) 611 pCur->m_eLineBreakType = FX_LINEBREAKTYPE::kUNKNOWN; 612 613 FX_BREAKPROPERTY nNext = FX_GetBreakProperty(pCur->char_code()); 614 int32_t iCharWidth = pCur->m_iCharWidth; 615 if (iCharWidth > 0) 616 *pEndPos -= iCharWidth; 617 618 while (iLength >= 0) { 619 pCur = pCharArray + iLength; 620 FX_BREAKPROPERTY nCur = FX_GetBreakProperty(pCur->char_code()); 621 bool bNeedBreak = false; 622 FX_LINEBREAKTYPE eType; 623 if (nCur == FX_BREAKPROPERTY::kTB) { 624 bNeedBreak = true; 625 eType = nNext == FX_BREAKPROPERTY::kTB 626 ? FX_LINEBREAKTYPE::kPROHIBITED_BRK 627 : GetLineBreakTypeFromPair(nCur, nNext); 628 } else { 629 if (nCur == FX_BREAKPROPERTY::kSP) 630 bNeedBreak = true; 631 632 eType = nNext == FX_BREAKPROPERTY::kSP 633 ? FX_LINEBREAKTYPE::kPROHIBITED_BRK 634 : GetLineBreakTypeFromPair(nCur, nNext); 635 } 636 if (bAllChars) 637 pCur->m_eLineBreakType = eType; 638 639 if (!bOnlyBrk) { 640 iCharWidth = pCur->m_iCharWidth; 641 if (*pEndPos <= m_iLineWidth || bNeedBreak) { 642 if (eType == FX_LINEBREAKTYPE::kDIRECT_BRK && iBreak < 0) { 643 iBreak = iLength; 644 iBreakPos = *pEndPos; 645 if (!bAllChars) 646 return iLength; 647 } else if (eType == FX_LINEBREAKTYPE::kINDIRECT_BRK && iIndirect < 0) { 648 iIndirect = iLength; 649 iIndirectPos = *pEndPos; 650 } 651 if (iLast < 0) { 652 iLast = iLength; 653 iLastPos = *pEndPos; 654 } 655 } 656 if (iCharWidth > 0) 657 *pEndPos -= iCharWidth; 658 } 659 nNext = nCur; 660 --iLength; 661 } 662 if (bOnlyBrk) 663 return 0; 664 665 if (iBreak > -1) { 666 *pEndPos = iBreakPos; 667 return iBreak; 668 } 669 if (iIndirect > -1) { 670 *pEndPos = iIndirectPos; 671 return iIndirect; 672 } 673 if (iLast > -1) { 674 *pEndPos = iLastPos; 675 return iLast; 676 } 677 return 0; 678 } 679 SplitTextLine(CFX_BreakLine * pCurLine,CFX_BreakLine * pNextLine,bool bAllChars)680 void CFX_RTFBreak::SplitTextLine(CFX_BreakLine* pCurLine, 681 CFX_BreakLine* pNextLine, 682 bool bAllChars) { 683 ASSERT(pCurLine); 684 ASSERT(pNextLine); 685 686 if (pCurLine->m_LineChars.size() < 2) 687 return; 688 689 int32_t iEndPos = pCurLine->GetLineEnd(); 690 std::vector<CFX_Char>& curChars = pCurLine->m_LineChars; 691 int32_t iCharPos = GetBreakPos(curChars, bAllChars, false, &iEndPos); 692 if (iCharPos < 0) 693 iCharPos = 0; 694 695 ++iCharPos; 696 if (iCharPos >= pdfium::CollectionSize<int32_t>(pCurLine->m_LineChars)) { 697 pNextLine->Clear(); 698 curChars[iCharPos - 1].m_eLineBreakType = FX_LINEBREAKTYPE::kUNKNOWN; 699 return; 700 } 701 702 pNextLine->m_LineChars = 703 std::vector<CFX_Char>(curChars.begin() + iCharPos, curChars.end()); 704 curChars.erase(curChars.begin() + iCharPos, curChars.end()); 705 pNextLine->m_iStart = pCurLine->m_iStart; 706 pNextLine->m_iWidth = pCurLine->GetLineEnd() - iEndPos; 707 pCurLine->m_iWidth = iEndPos; 708 curChars[iCharPos - 1].m_eLineBreakType = FX_LINEBREAKTYPE::kUNKNOWN; 709 710 for (size_t i = 0; i < pNextLine->m_LineChars.size(); ++i) { 711 if (pNextLine->m_LineChars[i].GetCharType() >= FX_CHARTYPE::kArabicAlef) { 712 pCurLine->DecrementArabicCharCount(); 713 pNextLine->IncrementArabicCharCount(); 714 } 715 pNextLine->m_LineChars[i].m_dwStatus = CFX_BreakType::None; 716 } 717 } 718 GetDisplayPos(const CFX_TextPiece * pPiece,std::vector<TextCharPos> * pCharPos) const719 size_t CFX_RTFBreak::GetDisplayPos(const CFX_TextPiece* pPiece, 720 std::vector<TextCharPos>* pCharPos) const { 721 ASSERT(pPiece->iChars > 0); 722 ASSERT(pPiece->pFont); 723 724 RetainPtr<CFGAS_GEFont> pFont = pPiece->pFont; 725 CFX_RectF rtText(pPiece->rtPiece); 726 bool bRTLPiece = FX_IsOdd(pPiece->iBidiLevel); 727 float fFontSize = pPiece->fFontSize; 728 int32_t iFontSize = FXSYS_roundf(fFontSize * 20.0f); 729 if (iFontSize == 0) 730 return 0; 731 732 int32_t iAscent = pFont->GetAscent(); 733 int32_t iDescent = pFont->GetDescent(); 734 int32_t iMaxHeight = iAscent - iDescent; 735 float fFontHeight = fFontSize; 736 float fAscent = fFontHeight * static_cast<float>(iAscent) / 737 static_cast<float>(iMaxHeight); 738 wchar_t wPrev = 0xFEFF; 739 wchar_t wNext; 740 float fX = rtText.left; 741 int32_t iHorScale = pPiece->iHorScale; 742 int32_t iVerScale = pPiece->iVerScale; 743 if (bRTLPiece) 744 fX = rtText.right(); 745 746 float fY = rtText.top + fAscent; 747 size_t szCount = 0; 748 for (int32_t i = 0; i < pPiece->iChars; ++i) { 749 TextCharPos& current_char_pos = (*pCharPos)[szCount]; 750 wchar_t wch = pPiece->szText[i]; 751 int32_t iWidth = pPiece->Widths[i]; 752 FX_CHARTYPE dwCharType = FX_GetCharType(wch); 753 if (iWidth == 0) { 754 if (dwCharType == FX_CHARTYPE::kArabicAlef) 755 wPrev = 0xFEFF; 756 continue; 757 } 758 759 uint32_t iCharWidth = abs(iWidth); 760 const bool bEmptyChar = (dwCharType >= FX_CHARTYPE::kTab && 761 dwCharType <= FX_CHARTYPE::kControl); 762 if (!bEmptyChar) 763 ++szCount; 764 765 iCharWidth /= iFontSize; 766 wchar_t wForm = wch; 767 if (dwCharType >= FX_CHARTYPE::kArabicAlef) { 768 if (i + 1 < pPiece->iChars) { 769 wNext = pPiece->szText[i + 1]; 770 if (pPiece->Widths[i + 1] < 0 && i + 2 < pPiece->iChars) 771 wNext = pPiece->szText[i + 2]; 772 } else { 773 wNext = 0xFEFF; 774 } 775 wForm = pdfium::arabic::GetFormChar(wch, wPrev, wNext); 776 } else if (bRTLPiece) { 777 wForm = FX_GetMirrorChar(wch); 778 } 779 780 if (!bEmptyChar) { 781 current_char_pos.m_GlyphIndex = pFont->GetGlyphIndex(wForm); 782 if (current_char_pos.m_GlyphIndex == 0xFFFF) 783 current_char_pos.m_GlyphIndex = pFont->GetGlyphIndex(wch); 784 #if defined(OS_MACOSX) 785 current_char_pos.m_ExtGID = current_char_pos.m_GlyphIndex; 786 #endif 787 current_char_pos.m_FontCharWidth = iCharWidth; 788 } 789 790 float fCharWidth = fFontSize * iCharWidth / 1000.0f; 791 if (bRTLPiece && dwCharType != FX_CHARTYPE::kCombination) 792 fX -= fCharWidth; 793 794 if (!bEmptyChar) 795 current_char_pos.m_Origin = CFX_PointF(fX, fY); 796 if (!bRTLPiece && dwCharType != FX_CHARTYPE::kCombination) 797 fX += fCharWidth; 798 799 if (!bEmptyChar) { 800 current_char_pos.m_bGlyphAdjust = true; 801 current_char_pos.m_AdjustMatrix[0] = -1; 802 current_char_pos.m_AdjustMatrix[1] = 0; 803 current_char_pos.m_AdjustMatrix[2] = 0; 804 current_char_pos.m_AdjustMatrix[3] = 1; 805 current_char_pos.m_Origin.y += fAscent * iVerScale / 100.0f; 806 current_char_pos.m_Origin.y -= fAscent; 807 808 if (iHorScale != 100 || iVerScale != 100) { 809 current_char_pos.m_AdjustMatrix[0] = 810 current_char_pos.m_AdjustMatrix[0] * iHorScale / 100.0f; 811 current_char_pos.m_AdjustMatrix[1] = 812 current_char_pos.m_AdjustMatrix[1] * iHorScale / 100.0f; 813 current_char_pos.m_AdjustMatrix[2] = 814 current_char_pos.m_AdjustMatrix[2] * iVerScale / 100.0f; 815 current_char_pos.m_AdjustMatrix[3] = 816 current_char_pos.m_AdjustMatrix[3] * iVerScale / 100.0f; 817 } 818 } 819 if (iWidth > 0) 820 wPrev = wch; 821 } 822 return szCount; 823 } 824