Home | History | Annotate | Download | only in layout
      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 
     17 namespace {
     18 
     19 typedef CFX_RTFBreakType (CFX_RTFBreak::*FX_RTFBreak_LPFAppendChar)(
     20     CFX_RTFChar* pCurChar);
     21 const 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 
     34 CFX_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 
     64 CFX_RTFBreak::~CFX_RTFBreak() {
     65   Reset();
     66 }
     67 
     68 void 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 
     78 void 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 
     85 void 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 
     94 void 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 
    104 void 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 
    117 void CFX_RTFBreak::SetTabWidth(FX_FLOAT fTabWidth) {
    118   m_iTabWidth = FXSYS_round(fTabWidth * 20000.0f);
    119 }
    120 
    121 void 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 
    131 void CFX_RTFBreak::SetLineBreakTolerance(FX_FLOAT fTolerance) {
    132   m_iTolerance = FXSYS_round(fTolerance * 20000.0f);
    133 }
    134 
    135 void 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 
    145 void 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 
    155 void CFX_RTFBreak::SetCharSpace(FX_FLOAT fCharSpace) {
    156   m_iCharSpace = FXSYS_round(fCharSpace * 20000.0f);
    157 }
    158 
    159 void 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 
    167 void 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 
    178 CFX_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 
    196 const 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 
    204 const CFX_RTFPieceArray* CFX_RTFBreak::GetRTFPieces() const {
    205   const CFX_RTFLine* pRTFLine = GetRTFLine();
    206   return pRTFLine ? &pRTFLine->m_LinePieces : nullptr;
    207 }
    208 
    209 inline FX_CHARTYPE CFX_RTFBreak::GetUnifiedCharType(
    210     FX_CHARTYPE chartype) const {
    211   return chartype >= FX_CHARTYPE_ArabicAlef ? FX_CHARTYPE_Arabic : chartype;
    212 }
    213 
    214 int32_t CFX_RTFBreak::GetLastPositionedTab() const {
    215   return m_PositionedTabs.empty() ? m_iBoundaryStart : m_PositionedTabs.back();
    216 }
    217 
    218 bool 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 
    228 CFX_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 
    266 CFX_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 
    286 CFX_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 
    302 CFX_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 
    326 CFX_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 
    371 CFX_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 
    391 CFX_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 
    450 bool 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 
    522 void 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 
    613 void 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 
    701 int32_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 
    796 void 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 
    835 int32_t CFX_RTFBreak::CountBreakPieces() const {
    836   const CFX_RTFPieceArray* pRTFPieces = GetRTFPieces();
    837   return pRTFPieces ? pRTFPieces->GetSize() : 0;
    838 }
    839 
    840 const 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 
    849 void 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 
    856 void CFX_RTFBreak::Reset() {
    857   m_eCharType = FX_CHARTYPE_Unknown;
    858   m_RTFLine1.RemoveAll(true);
    859   m_RTFLine2.RemoveAll(true);
    860 }
    861 
    862 int32_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 
    990 CFX_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 
   1006 CFX_RTFPiece::~CFX_RTFPiece() {
   1007   Reset();
   1008 }
   1009 
   1010 CFX_RTFLine::CFX_RTFLine()
   1011     : m_LinePieces(16),
   1012       m_iStart(0),
   1013       m_iWidth(0),
   1014       m_iArabicChars(0),
   1015       m_iMBCSChars(0) {}
   1016 
   1017 CFX_RTFLine::~CFX_RTFLine() {
   1018   RemoveAll(false);
   1019 }
   1020 
   1021 FX_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 
   1031 FX_RTFTEXTOBJ::~FX_RTFTEXTOBJ() {}
   1032