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/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 
     18 CFX_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 
     26 CFX_RTFBreak::~CFX_RTFBreak() {}
     27 
     28 void 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 
     35 void 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 
     45 void CFX_RTFBreak::SetUserData(const RetainPtr<CXFA_TextUserData>& pUserData) {
     46   if (m_pUserData == pUserData)
     47     return;
     48 
     49   SetBreakStatus();
     50   m_pUserData = pUserData;
     51 }
     52 
     53 int32_t CFX_RTFBreak::GetLastPositionedTab() const {
     54   return m_PositionedTabs.empty() ? m_iLineStart : m_PositionedTabs.back();
     55 }
     56 
     57 bool 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 
     67 CFX_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 
    123 void 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 
    141 void 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 
    156 CFX_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 
    180 CFX_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 
    225 CFX_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 
    245 CFX_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 
    292 bool 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 
    361 void 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 
    453 void 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 
    530 int32_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 
    627 void 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 
    665 int32_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 
    779 FX_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 
    789 FX_RTFTEXTOBJ::~FX_RTFTEXTOBJ() {}
    790