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