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