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