fgas_rtfbreak.cpp revision 4d3acf4ec42bf6e838f9060103aff98fbf170794
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#include "xfa/fgas/layout/fgas_unicode.h"
17
18CFX_RTFBreak::CFX_RTFBreak(uint32_t dwPolicies)
19    : m_dwPolicies(dwPolicies),
20      m_iBoundaryStart(0),
21      m_iBoundaryEnd(2000000),
22      m_dwLayoutStyles(0),
23      m_bPagination(false),
24      m_bVertical(false),
25      m_bSingleLine(false),
26      m_bCharCode(false),
27      m_pFont(nullptr),
28      m_iFontHeight(240),
29      m_iFontSize(240),
30      m_iTabWidth(720000),
31      m_PositionedTabs(),
32      m_bOrphanLine(false),
33      m_wDefChar(0xFEFF),
34      m_iDefChar(0),
35      m_wLineBreakChar(L'\n'),
36      m_iHorizontalScale(100),
37      m_iVerticalScale(100),
38      m_iLineRotation(0),
39      m_iCharRotation(0),
40      m_iRotation(0),
41      m_iCharSpace(0),
42      m_bWordSpace(false),
43      m_iWordSpace(0),
44      m_bRTL(false),
45      m_iAlignment(FX_RTFLINEALIGNMENT_Left),
46      m_pUserData(nullptr),
47      m_eCharType(FX_CHARTYPE_Unknown),
48      m_dwIdentity(0),
49      m_RTFLine1(),
50      m_RTFLine2(),
51      m_pCurLine(nullptr),
52      m_iReady(0),
53      m_iTolerance(0) {
54  m_pCurLine = &m_RTFLine1;
55}
56
57CFX_RTFBreak::~CFX_RTFBreak() {
58  Reset();
59  m_PositionedTabs.RemoveAll();
60  if (m_pUserData)
61    m_pUserData->Release();
62}
63
64void CFX_RTFBreak::SetLineBoundary(FX_FLOAT fLineStart, FX_FLOAT fLineEnd) {
65  if (fLineStart > fLineEnd)
66    return;
67
68  m_iBoundaryStart = FXSYS_round(fLineStart * 20000.0f);
69  m_iBoundaryEnd = FXSYS_round(fLineEnd * 20000.0f);
70  m_pCurLine->m_iStart = std::min(m_pCurLine->m_iStart, m_iBoundaryEnd);
71  m_pCurLine->m_iStart = std::max(m_pCurLine->m_iStart, m_iBoundaryStart);
72}
73
74void CFX_RTFBreak::SetLineStartPos(FX_FLOAT fLinePos) {
75  int32_t iLinePos = FXSYS_round(fLinePos * 20000.0f);
76  iLinePos = std::min(iLinePos, m_iBoundaryEnd);
77  iLinePos = std::max(iLinePos, m_iBoundaryStart);
78  m_pCurLine->m_iStart = iLinePos;
79}
80
81void CFX_RTFBreak::SetLayoutStyles(uint32_t dwLayoutStyles) {
82  if (m_dwLayoutStyles == dwLayoutStyles)
83    return;
84
85  SetBreakStatus();
86  m_dwLayoutStyles = dwLayoutStyles;
87  m_bPagination = (m_dwLayoutStyles & FX_RTFLAYOUTSTYLE_Pagination) != 0;
88  m_bVertical = (m_dwLayoutStyles & FX_RTFLAYOUTSTYLE_VerticalChars) != 0;
89  m_bSingleLine = (m_dwLayoutStyles & FX_RTFLAYOUTSTYLE_SingleLine) != 0;
90  m_bCharCode = (m_dwLayoutStyles & FX_RTFLAYOUTSTYLE_MBCSCode) != 0;
91  m_iLineRotation = GetLineRotation(m_dwLayoutStyles);
92  m_iRotation = m_iLineRotation + m_iCharRotation;
93  m_iRotation %= 4;
94}
95
96void CFX_RTFBreak::SetFont(const CFX_RetainPtr<CFGAS_GEFont>& pFont) {
97  if (!pFont || pFont == m_pFont)
98    return;
99
100  SetBreakStatus();
101  m_pFont = pFont;
102  m_iDefChar = 0;
103  if (m_pFont) {
104    m_iFontHeight = m_iFontSize;
105    if (m_wDefChar != 0xFEFF) {
106      m_pFont->GetCharWidth(m_wDefChar, m_iDefChar, false);
107      m_iDefChar *= m_iFontSize;
108    }
109  }
110}
111
112void CFX_RTFBreak::SetFontSize(FX_FLOAT fFontSize) {
113  int32_t iFontSize = FXSYS_round(fFontSize * 20.0f);
114  if (m_iFontSize == iFontSize) {
115    return;
116  }
117  SetBreakStatus();
118  m_iFontSize = iFontSize;
119  m_iDefChar = 0;
120  if (m_pFont) {
121    m_iFontHeight = m_iFontSize;
122    if (m_wDefChar != 0xFEFF) {
123      m_pFont->GetCharWidth(m_wDefChar, m_iDefChar, false);
124      m_iDefChar *= m_iFontSize;
125    }
126  }
127}
128void CFX_RTFBreak::SetTabWidth(FX_FLOAT fTabWidth) {
129  m_iTabWidth = FXSYS_round(fTabWidth * 20000.0f);
130}
131void CFX_RTFBreak::AddPositionedTab(FX_FLOAT fTabPos) {
132  int32_t iLineEnd = m_iBoundaryEnd;
133  int32_t iTabPos = FXSYS_round(fTabPos * 20000.0f) + m_iBoundaryStart;
134  if (iTabPos > iLineEnd) {
135    iTabPos = iLineEnd;
136  }
137  if (m_PositionedTabs.Find(iTabPos, 0) > -1) {
138    return;
139  }
140  int32_t iCount = m_PositionedTabs.GetSize();
141  int32_t iFind = 0;
142  for (; iFind < iCount; iFind++) {
143    if (m_PositionedTabs[iFind] > iTabPos) {
144      break;
145    }
146  }
147  m_PositionedTabs.InsertAt(iFind, iTabPos);
148  if (m_dwPolicies & FX_RTFBREAKPOLICY_OrphanPositionedTab) {
149    m_bOrphanLine = GetLastPositionedTab() >= iLineEnd;
150  } else {
151    m_bOrphanLine = false;
152  }
153}
154void CFX_RTFBreak::SetPositionedTabs(const std::vector<FX_FLOAT>& tabs) {
155  m_PositionedTabs.RemoveAll();
156  int32_t iCount = pdfium::CollectionSize<int32_t>(tabs);
157  m_PositionedTabs.SetSize(iCount);
158  int32_t iLineEnd = m_iBoundaryEnd;
159  int32_t iTabPos;
160  for (int32_t i = 0; i < iCount; i++) {
161    iTabPos = FXSYS_round(tabs[i] * 20000.0f) + m_iBoundaryStart;
162    if (iTabPos > iLineEnd) {
163      iTabPos = iLineEnd;
164    }
165    m_PositionedTabs[i] = iTabPos;
166  }
167  if (m_dwPolicies & FX_RTFBREAKPOLICY_OrphanPositionedTab) {
168    m_bOrphanLine = GetLastPositionedTab() >= iLineEnd;
169  } else {
170    m_bOrphanLine = false;
171  }
172}
173void CFX_RTFBreak::ClearPositionedTabs() {
174  m_PositionedTabs.RemoveAll();
175  m_bOrphanLine = false;
176}
177void CFX_RTFBreak::SetDefaultChar(FX_WCHAR wch) {
178  m_wDefChar = wch;
179  m_iDefChar = 0;
180  if (m_wDefChar != 0xFEFF && m_pFont) {
181    m_pFont->GetCharWidth(m_wDefChar, m_iDefChar, false);
182    if (m_iDefChar < 0) {
183      m_iDefChar = 0;
184    } else {
185      m_iDefChar *= m_iFontSize;
186    }
187  }
188}
189void CFX_RTFBreak::SetLineBreakChar(FX_WCHAR wch) {
190  if (wch != L'\r' && wch != L'\n') {
191    return;
192  }
193  m_wLineBreakChar = wch;
194}
195void CFX_RTFBreak::SetLineBreakTolerance(FX_FLOAT fTolerance) {
196  m_iTolerance = FXSYS_round(fTolerance * 20000.0f);
197}
198void CFX_RTFBreak::SetHorizontalScale(int32_t iScale) {
199  if (iScale < 0) {
200    iScale = 0;
201  }
202  if (m_iHorizontalScale == iScale) {
203    return;
204  }
205  SetBreakStatus();
206  m_iHorizontalScale = iScale;
207}
208void CFX_RTFBreak::SetVerticalScale(int32_t iScale) {
209  if (iScale < 0) {
210    iScale = 0;
211  }
212  if (m_iVerticalScale == iScale) {
213    return;
214  }
215  SetBreakStatus();
216  m_iVerticalScale = iScale;
217}
218void CFX_RTFBreak::SetCharRotation(int32_t iCharRotation) {
219  if (iCharRotation < 0) {
220    iCharRotation += (-iCharRotation / 4 + 1) * 4;
221  } else if (iCharRotation > 3) {
222    iCharRotation -= (iCharRotation / 4) * 4;
223  }
224  if (m_iCharRotation == iCharRotation) {
225    return;
226  }
227  SetBreakStatus();
228  m_iCharRotation = iCharRotation;
229  m_iRotation = m_iLineRotation + m_iCharRotation;
230  m_iRotation %= 4;
231}
232void CFX_RTFBreak::SetCharSpace(FX_FLOAT fCharSpace) {
233  m_iCharSpace = FXSYS_round(fCharSpace * 20000.0f);
234}
235void CFX_RTFBreak::SetWordSpace(bool bDefault, FX_FLOAT fWordSpace) {
236  m_bWordSpace = !bDefault;
237  m_iWordSpace = FXSYS_round(fWordSpace * 20000.0f);
238}
239void CFX_RTFBreak::SetReadingOrder(bool bRTL) {
240  m_bRTL = bRTL;
241}
242void CFX_RTFBreak::SetAlignment(int32_t iAlignment) {
243  ASSERT(iAlignment >= FX_RTFLINEALIGNMENT_Left &&
244         iAlignment <= FX_RTFLINEALIGNMENT_Distributed);
245  m_iAlignment = iAlignment;
246}
247void CFX_RTFBreak::SetUserData(IFX_Retainable* pUserData) {
248  if (m_pUserData == pUserData) {
249    return;
250  }
251  SetBreakStatus();
252  if (m_pUserData) {
253    m_pUserData->Release();
254  }
255  m_pUserData = pUserData;
256  if (m_pUserData) {
257    m_pUserData->Retain();
258  }
259}
260static const int32_t gs_FX_RTFLineRotations[8] = {0, 3, 1, 0, 2, 1, 3, 2};
261int32_t CFX_RTFBreak::GetLineRotation(uint32_t dwStyles) const {
262  return gs_FX_RTFLineRotations[(dwStyles & 0x0E) >> 1];
263}
264void CFX_RTFBreak::SetBreakStatus() {
265  m_dwIdentity++;
266  int32_t iCount = m_pCurLine->CountChars();
267  if (iCount < 1) {
268    return;
269  }
270  CFX_RTFChar& tc = m_pCurLine->GetChar(iCount - 1);
271  if (tc.m_dwStatus == 0) {
272    tc.m_dwStatus = FX_RTFBREAK_PieceBreak;
273  }
274}
275CFX_RTFChar* CFX_RTFBreak::GetLastChar(int32_t index) const {
276  CFX_RTFCharArray& tca = m_pCurLine->m_LineChars;
277  int32_t iCount = tca.GetSize();
278  if (index < 0 || index >= iCount) {
279    return nullptr;
280  }
281  CFX_RTFChar* pTC;
282  int32_t iStart = iCount - 1;
283  while (iStart > -1) {
284    pTC = tca.GetDataPtr(iStart--);
285    if (pTC->m_iCharWidth >= 0 ||
286        pTC->GetCharType() != FX_CHARTYPE_Combination) {
287      if (--index < 0) {
288        return pTC;
289      }
290    }
291  }
292  return nullptr;
293}
294CFX_RTFLine* CFX_RTFBreak::GetRTFLine(bool bReady) const {
295  if (bReady) {
296    if (m_iReady == 1) {
297      return (CFX_RTFLine*)&m_RTFLine1;
298    } else if (m_iReady == 2) {
299      return (CFX_RTFLine*)&m_RTFLine2;
300    } else {
301      return nullptr;
302    }
303  }
304  ASSERT(m_pCurLine);
305  return m_pCurLine;
306}
307CFX_RTFPieceArray* CFX_RTFBreak::GetRTFPieces(bool bReady) const {
308  CFX_RTFLine* pRTFLine = GetRTFLine(bReady);
309  return pRTFLine ? &pRTFLine->m_LinePieces : nullptr;
310}
311inline FX_CHARTYPE CFX_RTFBreak::GetUnifiedCharType(
312    FX_CHARTYPE chartype) const {
313  return chartype >= FX_CHARTYPE_ArabicAlef ? FX_CHARTYPE_Arabic : chartype;
314}
315int32_t CFX_RTFBreak::GetLastPositionedTab() const {
316  int32_t iCount = m_PositionedTabs.GetSize();
317  if (iCount < 1) {
318    return m_iBoundaryStart;
319  }
320  return m_PositionedTabs[iCount - 1];
321}
322bool CFX_RTFBreak::GetPositionedTab(int32_t& iTabPos) const {
323  int32_t iCount = m_PositionedTabs.GetSize();
324  for (int32_t i = 0; i < iCount; i++) {
325    if (m_PositionedTabs[i] > iTabPos) {
326      iTabPos = m_PositionedTabs[i];
327      return true;
328    }
329  }
330  return false;
331}
332typedef uint32_t (CFX_RTFBreak::*FX_RTFBreak_LPFAppendChar)(
333    CFX_RTFChar* pCurChar,
334    int32_t iRotation);
335static const FX_RTFBreak_LPFAppendChar g_FX_RTFBreak_lpfAppendChar[16] = {
336    &CFX_RTFBreak::AppendChar_Others,      &CFX_RTFBreak::AppendChar_Tab,
337    &CFX_RTFBreak::AppendChar_Others,      &CFX_RTFBreak::AppendChar_Control,
338    &CFX_RTFBreak::AppendChar_Combination, &CFX_RTFBreak::AppendChar_Others,
339    &CFX_RTFBreak::AppendChar_Others,      &CFX_RTFBreak::AppendChar_Arabic,
340    &CFX_RTFBreak::AppendChar_Arabic,      &CFX_RTFBreak::AppendChar_Arabic,
341    &CFX_RTFBreak::AppendChar_Arabic,      &CFX_RTFBreak::AppendChar_Arabic,
342    &CFX_RTFBreak::AppendChar_Arabic,      &CFX_RTFBreak::AppendChar_Others,
343    &CFX_RTFBreak::AppendChar_Others,      &CFX_RTFBreak::AppendChar_Others,
344};
345uint32_t CFX_RTFBreak::AppendChar(FX_WCHAR wch) {
346  ASSERT(m_pFont && m_pCurLine);
347  if (m_bCharCode)
348    return AppendChar_CharCode(wch);
349
350  uint32_t dwProps = kTextLayoutCodeProperties[(uint16_t)wch];
351  FX_CHARTYPE chartype = GetCharTypeFromProp(dwProps);
352  CFX_RTFCharArray& tca = m_pCurLine->m_LineChars;
353  CFX_RTFChar* pCurChar = tca.AddSpace();
354  pCurChar->m_dwStatus = 0;
355  pCurChar->m_wCharCode = wch;
356  pCurChar->m_dwCharProps = dwProps;
357  pCurChar->m_dwCharStyles = 0;
358  pCurChar->m_dwLayoutStyles = 0;
359  pCurChar->m_iFontSize = m_iFontSize;
360  pCurChar->m_iFontHeight = m_iFontHeight;
361  pCurChar->m_iHorizontalScale = m_iHorizontalScale;
362  pCurChar->m_iVertialScale = m_iVerticalScale;
363  pCurChar->m_nRotation = m_iCharRotation;
364  pCurChar->m_iCharWidth = 0;
365  pCurChar->m_dwIdentity = m_dwIdentity;
366  if (m_pUserData) {
367    m_pUserData->Retain();
368  }
369  pCurChar->m_pUserData = m_pUserData;
370  uint32_t dwRet1 = FX_RTFBREAK_None;
371  if (chartype != FX_CHARTYPE_Combination &&
372      GetUnifiedCharType(m_eCharType) != GetUnifiedCharType(chartype)) {
373    if (!m_bSingleLine && !m_bOrphanLine &&
374        m_eCharType != FX_CHARTYPE_Unknown &&
375        m_pCurLine->GetLineEnd() > m_iBoundaryEnd + m_iTolerance) {
376      if (m_eCharType != FX_CHARTYPE_Space || chartype != FX_CHARTYPE_Control) {
377        dwRet1 = EndBreak(FX_RTFBREAK_LineBreak);
378        int32_t iCount = m_pCurLine->CountChars();
379        if (iCount > 0) {
380          pCurChar = m_pCurLine->m_LineChars.GetDataPtr(iCount - 1);
381        }
382      }
383    }
384  }
385  int32_t iRotation = m_iRotation;
386  if (m_bVertical && (dwProps & 0x8000) != 0) {
387    iRotation = (iRotation + 1) % 4;
388  }
389  uint32_t dwRet2 =
390      (this->*g_FX_RTFBreak_lpfAppendChar[chartype >> FX_CHARTYPEBITS])(
391          pCurChar, iRotation);
392  m_eCharType = chartype;
393  return std::max(dwRet1, dwRet2);
394}
395
396uint32_t CFX_RTFBreak::AppendChar_CharCode(FX_WCHAR wch) {
397  ASSERT(m_pFont && m_pCurLine);
398  ASSERT(m_bCharCode);
399  m_pCurLine->m_iMBCSChars++;
400  CFX_RTFCharArray& tca = m_pCurLine->m_LineChars;
401  CFX_RTFChar* pCurChar = tca.AddSpace();
402  pCurChar->m_dwStatus = 0;
403  pCurChar->m_wCharCode = wch;
404  pCurChar->m_dwCharProps = 0;
405  pCurChar->m_dwCharStyles = 0;
406  pCurChar->m_dwLayoutStyles = m_dwLayoutStyles;
407  pCurChar->m_iFontSize = m_iFontSize;
408  pCurChar->m_iFontHeight = m_iFontHeight;
409  pCurChar->m_iHorizontalScale = m_iHorizontalScale;
410  pCurChar->m_iVertialScale = m_iVerticalScale;
411  pCurChar->m_nRotation = m_iCharRotation;
412  pCurChar->m_iCharWidth = 0;
413  pCurChar->m_dwIdentity = m_dwIdentity;
414  if (m_pUserData)
415    m_pUserData->Retain();
416
417  pCurChar->m_pUserData = m_pUserData;
418  int32_t iCharWidth = 0;
419  if (m_bVertical != FX_IsOdd(m_iRotation)) {
420    iCharWidth = 1000;
421  } else {
422    if (!m_pFont->GetCharWidth(wch, iCharWidth, true)) {
423      iCharWidth = m_iDefChar;
424    }
425  }
426  iCharWidth *= m_iFontSize;
427  iCharWidth = iCharWidth * m_iHorizontalScale / 100;
428  iCharWidth += m_iCharSpace;
429  pCurChar->m_iCharWidth = iCharWidth;
430  m_pCurLine->m_iWidth += iCharWidth;
431  m_eCharType = FX_CHARTYPE_Unknown;
432  if (!m_bSingleLine &&
433      m_pCurLine->GetLineEnd() > m_iBoundaryEnd + m_iTolerance) {
434    return EndBreak(FX_RTFBREAK_LineBreak);
435  }
436  return FX_RTFBREAK_None;
437}
438
439uint32_t CFX_RTFBreak::AppendChar_Combination(CFX_RTFChar* pCurChar,
440                                              int32_t iRotation) {
441  int32_t iCharWidth = 0;
442  if (m_bVertical != FX_IsOdd(iRotation)) {
443    iCharWidth = 1000;
444  } else {
445    if (!m_pFont->GetCharWidth(pCurChar->m_wCharCode, iCharWidth,
446                               m_bCharCode)) {
447      iCharWidth = 0;
448    }
449  }
450  iCharWidth *= m_iFontSize;
451  iCharWidth = iCharWidth * m_iHorizontalScale / 100;
452  CFX_RTFChar* pLastChar = GetLastChar(0);
453  if (pLastChar && pLastChar->GetCharType() > FX_CHARTYPE_Combination) {
454    iCharWidth = -iCharWidth;
455  } else {
456    m_eCharType = FX_CHARTYPE_Combination;
457  }
458  pCurChar->m_iCharWidth = iCharWidth;
459  if (iCharWidth > 0) {
460    m_pCurLine->m_iWidth += iCharWidth;
461  }
462  return FX_RTFBREAK_None;
463}
464uint32_t CFX_RTFBreak::AppendChar_Tab(CFX_RTFChar* pCurChar,
465                                      int32_t iRotation) {
466  if (m_dwLayoutStyles & FX_RTFLAYOUTSTYLE_ExpandTab) {
467    bool bBreak = false;
468    if ((m_dwPolicies & FX_RTFBREAKPOLICY_TabBreak) != 0) {
469      bBreak = (m_pCurLine->GetLineEnd() > m_iBoundaryEnd + m_iTolerance);
470    }
471    int32_t& iLineWidth = m_pCurLine->m_iWidth;
472    int32_t iCharWidth = iLineWidth;
473    if (GetPositionedTab(iCharWidth)) {
474      iCharWidth -= iLineWidth;
475    } else {
476      iCharWidth = m_iTabWidth * (iLineWidth / m_iTabWidth + 1) - iLineWidth;
477    }
478    pCurChar->m_iCharWidth = iCharWidth;
479    iLineWidth += iCharWidth;
480    if (!m_bSingleLine && !m_bOrphanLine && bBreak) {
481      return EndBreak(FX_RTFBREAK_LineBreak);
482    }
483  }
484  return FX_RTFBREAK_None;
485}
486uint32_t CFX_RTFBreak::AppendChar_Control(CFX_RTFChar* pCurChar,
487                                          int32_t iRotation) {
488  uint32_t dwRet2 = FX_RTFBREAK_None;
489  if (!m_bSingleLine) {
490    switch (pCurChar->m_wCharCode) {
491      case L'\v':
492      case 0x2028:
493        dwRet2 = FX_RTFBREAK_LineBreak;
494        break;
495      case L'\f':
496        dwRet2 = FX_RTFBREAK_PageBreak;
497        break;
498      case 0x2029:
499        dwRet2 = FX_RTFBREAK_ParagraphBreak;
500        break;
501      default:
502        if (pCurChar->m_wCharCode == m_wLineBreakChar) {
503          dwRet2 = FX_RTFBREAK_ParagraphBreak;
504        }
505        break;
506    }
507    if (dwRet2 != FX_RTFBREAK_None) {
508      dwRet2 = EndBreak(dwRet2);
509    }
510  }
511  return dwRet2;
512}
513
514uint32_t CFX_RTFBreak::AppendChar_Arabic(CFX_RTFChar* pCurChar,
515                                         int32_t iRotation) {
516  CFX_RTFChar* pLastChar = nullptr;
517  int32_t& iLineWidth = m_pCurLine->m_iWidth;
518  int32_t iCharWidth = 0;
519  FX_WCHAR wForm;
520  bool bAlef = false;
521  if (m_eCharType >= FX_CHARTYPE_ArabicAlef &&
522      m_eCharType <= FX_CHARTYPE_ArabicDistortion) {
523    pLastChar = GetLastChar(1);
524    if (pLastChar) {
525      iLineWidth -= pLastChar->m_iCharWidth;
526      CFX_RTFChar* pPrevChar = GetLastChar(2);
527      wForm = pdfium::arabic::GetFormChar(pLastChar, pPrevChar, pCurChar);
528      bAlef = (wForm == 0xFEFF &&
529               pLastChar->GetCharType() == FX_CHARTYPE_ArabicAlef);
530      int32_t iLastRotation = pLastChar->m_nRotation + m_iLineRotation;
531      if (m_bVertical && (pLastChar->m_dwCharProps & 0x8000) != 0) {
532        iLastRotation++;
533      }
534      if (m_bVertical != FX_IsOdd(iLastRotation)) {
535        iCharWidth = 1000;
536      } else {
537        if (!m_pFont->GetCharWidth(wForm, iCharWidth, m_bCharCode)) {
538          if (!m_pFont->GetCharWidth(pLastChar->m_wCharCode, iCharWidth,
539                                     m_bCharCode)) {
540            iCharWidth = m_iDefChar;
541          }
542        }
543      }
544      iCharWidth *= m_iFontSize;
545      iCharWidth = iCharWidth * m_iHorizontalScale / 100;
546      pLastChar->m_iCharWidth = iCharWidth;
547      iLineWidth += iCharWidth;
548      iCharWidth = 0;
549    }
550  }
551  wForm = pdfium::arabic::GetFormChar(pCurChar, bAlef ? nullptr : pLastChar,
552                                      nullptr);
553  if (m_bVertical != FX_IsOdd(iRotation)) {
554    iCharWidth = 1000;
555  } else if (!m_pFont->GetCharWidth(wForm, iCharWidth, m_bCharCode) &&
556             !m_pFont->GetCharWidth(pCurChar->m_wCharCode, iCharWidth,
557                                    m_bCharCode)) {
558    iCharWidth = m_iDefChar;
559  }
560
561  iCharWidth *= m_iFontSize;
562  iCharWidth = iCharWidth * m_iHorizontalScale / 100;
563  pCurChar->m_iCharWidth = iCharWidth;
564  iLineWidth += iCharWidth;
565  m_pCurLine->m_iArabicChars++;
566  if (!m_bSingleLine && !m_bOrphanLine &&
567      m_pCurLine->GetLineEnd() > m_iBoundaryEnd + m_iTolerance) {
568    return EndBreak(FX_RTFBREAK_LineBreak);
569  }
570  return FX_RTFBREAK_None;
571}
572
573uint32_t CFX_RTFBreak::AppendChar_Others(CFX_RTFChar* pCurChar,
574                                         int32_t iRotation) {
575  FX_CHARTYPE chartype = pCurChar->GetCharType();
576  FX_WCHAR wForm;
577  if (chartype == FX_CHARTYPE_Numeric) {
578    if (m_dwLayoutStyles & FX_RTFLAYOUTSTYLE_ArabicNumber)
579      wForm = pCurChar->m_wCharCode + 0x0630;
580    else
581      wForm = pCurChar->m_wCharCode;
582  } else if (m_bRTL || m_bVertical) {
583    wForm = FX_GetMirrorChar(pCurChar->m_wCharCode, pCurChar->m_dwCharProps,
584                             m_bRTL, m_bVertical);
585  } else {
586    wForm = pCurChar->m_wCharCode;
587  }
588  int32_t iCharWidth = 0;
589  if (m_bVertical == FX_IsOdd(iRotation)) {
590    if (!m_pFont->GetCharWidth(wForm, iCharWidth, m_bCharCode))
591      iCharWidth = m_iDefChar;
592  } else {
593    iCharWidth = 1000;
594  }
595  iCharWidth *= m_iFontSize;
596  iCharWidth *= m_iHorizontalScale / 100;
597  iCharWidth += m_iCharSpace;
598  if (chartype == FX_CHARTYPE_Space && m_bWordSpace)
599    iCharWidth += m_iWordSpace;
600
601  pCurChar->m_iCharWidth = iCharWidth;
602  m_pCurLine->m_iWidth += iCharWidth;
603  bool bBreak = (chartype != FX_CHARTYPE_Space ||
604                 (m_dwPolicies & FX_RTFBREAKPOLICY_SpaceBreak) != 0);
605  if (!m_bSingleLine && !m_bOrphanLine && bBreak &&
606      m_pCurLine->GetLineEnd() > m_iBoundaryEnd + m_iTolerance) {
607    return EndBreak(FX_RTFBREAK_LineBreak);
608  }
609  return FX_RTFBREAK_None;
610}
611
612uint32_t CFX_RTFBreak::EndBreak(uint32_t dwStatus) {
613  ASSERT(dwStatus >= FX_RTFBREAK_PieceBreak &&
614         dwStatus <= FX_RTFBREAK_PageBreak);
615  m_dwIdentity++;
616  CFX_RTFPieceArray* pCurPieces = &m_pCurLine->m_LinePieces;
617  int32_t iCount = pCurPieces->GetSize();
618  if (iCount > 0) {
619    CFX_RTFPiece* pLastPiece = pCurPieces->GetPtrAt(--iCount);
620    if (dwStatus > FX_RTFBREAK_PieceBreak)
621      pLastPiece->m_dwStatus = dwStatus;
622    else
623      dwStatus = pLastPiece->m_dwStatus;
624    return dwStatus;
625  }
626
627  CFX_RTFLine* pLastLine = GetRTFLine(true);
628  if (pLastLine) {
629    pCurPieces = &pLastLine->m_LinePieces;
630    iCount = pCurPieces->GetSize();
631    if (iCount-- > 0) {
632      CFX_RTFPiece* pLastPiece = pCurPieces->GetPtrAt(iCount);
633      if (dwStatus > FX_RTFBREAK_PieceBreak)
634        pLastPiece->m_dwStatus = dwStatus;
635      else
636        dwStatus = pLastPiece->m_dwStatus;
637      return dwStatus;
638    }
639    return FX_RTFBREAK_None;
640  }
641  iCount = m_pCurLine->CountChars();
642  if (iCount < 1)
643    return FX_RTFBREAK_None;
644
645  CFX_RTFChar& tc = m_pCurLine->GetChar(iCount - 1);
646  tc.m_dwStatus = dwStatus;
647  if (dwStatus <= FX_RTFBREAK_PieceBreak)
648    return dwStatus;
649
650  m_iReady = (m_pCurLine == &m_RTFLine1) ? 1 : 2;
651  CFX_RTFLine* pNextLine =
652      (m_pCurLine == &m_RTFLine1) ? &m_RTFLine2 : &m_RTFLine1;
653  bool bAllChars = (m_iAlignment > FX_RTFLINEALIGNMENT_Right);
654  CFX_TPOArray tpos(100);
655  if (!EndBreak_SplitLine(pNextLine, bAllChars, dwStatus)) {
656    if (!m_bCharCode)
657      EndBreak_BidiLine(tpos, dwStatus);
658
659    if (!m_bPagination && m_iAlignment > FX_RTFLINEALIGNMENT_Left)
660      EndBreak_Alignment(tpos, bAllChars, dwStatus);
661  }
662
663  m_pCurLine = pNextLine;
664  m_pCurLine->m_iStart = m_iBoundaryStart;
665  CFX_RTFChar* pTC = GetLastChar(0);
666  m_eCharType = pTC ? pTC->GetCharType() : FX_CHARTYPE_Unknown;
667  return dwStatus;
668}
669
670bool CFX_RTFBreak::EndBreak_SplitLine(CFX_RTFLine* pNextLine,
671                                      bool bAllChars,
672                                      uint32_t dwStatus) {
673  bool bDone = false;
674  if (!m_bSingleLine && !m_bOrphanLine &&
675      m_pCurLine->GetLineEnd() > m_iBoundaryEnd + m_iTolerance) {
676    CFX_RTFChar& tc = m_pCurLine->GetChar(m_pCurLine->CountChars() - 1);
677    switch (tc.GetCharType()) {
678      case FX_CHARTYPE_Tab:
679        if ((m_dwPolicies & FX_RTFBREAKPOLICY_TabBreak) != 0) {
680          SplitTextLine(m_pCurLine, pNextLine, !m_bPagination && bAllChars);
681          bDone = true;
682        }
683        break;
684      case FX_CHARTYPE_Control:
685        break;
686      case FX_CHARTYPE_Space:
687        if ((m_dwPolicies & FX_RTFBREAKPOLICY_SpaceBreak) != 0) {
688          SplitTextLine(m_pCurLine, pNextLine, !m_bPagination && bAllChars);
689          bDone = true;
690        }
691        break;
692      default:
693        SplitTextLine(m_pCurLine, pNextLine, !m_bPagination && bAllChars);
694        bDone = true;
695        break;
696    }
697  }
698  if (m_bPagination || m_pCurLine->m_iMBCSChars > 0) {
699    const CFX_RTFChar* pCurChars = m_pCurLine->m_LineChars.GetData();
700    const CFX_RTFChar* pTC;
701    CFX_RTFPieceArray* pCurPieces = &m_pCurLine->m_LinePieces;
702    CFX_RTFPiece tp;
703    tp.m_pChars = &m_pCurLine->m_LineChars;
704    bool bNew = true;
705    uint32_t dwIdentity = (uint32_t)-1;
706    int32_t iLast = m_pCurLine->CountChars() - 1, j = 0;
707    for (int32_t i = 0; i <= iLast;) {
708      pTC = pCurChars + i;
709      if (bNew) {
710        tp.m_iStartChar = i;
711        tp.m_iStartPos += tp.m_iWidth;
712        tp.m_iWidth = 0;
713        tp.m_dwStatus = pTC->m_dwStatus;
714        tp.m_iFontSize = pTC->m_iFontSize;
715        tp.m_iFontHeight = pTC->m_iFontHeight;
716        tp.m_iHorizontalScale = pTC->m_iHorizontalScale;
717        tp.m_iVerticalScale = pTC->m_iVertialScale;
718        tp.m_dwLayoutStyles = pTC->m_dwLayoutStyles;
719        dwIdentity = pTC->m_dwIdentity;
720        tp.m_dwIdentity = dwIdentity;
721        tp.m_pUserData = pTC->m_pUserData;
722        j = i;
723        bNew = false;
724      }
725      if (i == iLast || pTC->m_dwStatus != FX_RTFBREAK_None ||
726          pTC->m_dwIdentity != dwIdentity) {
727        tp.m_iChars = i - j;
728        if (pTC->m_dwIdentity == dwIdentity) {
729          tp.m_dwStatus = pTC->m_dwStatus;
730          tp.m_iWidth += pTC->m_iCharWidth;
731          tp.m_iChars += 1;
732          i++;
733        }
734        pCurPieces->Add(tp);
735        bNew = true;
736      } else {
737        tp.m_iWidth += pTC->m_iCharWidth;
738        i++;
739      }
740    }
741    return true;
742  }
743  if (bAllChars && !bDone) {
744    int32_t iEndPos = m_pCurLine->GetLineEnd();
745    GetBreakPos(m_pCurLine->m_LineChars, iEndPos, bAllChars, true);
746  }
747  return false;
748}
749void CFX_RTFBreak::EndBreak_BidiLine(CFX_TPOArray& tpos, uint32_t dwStatus) {
750  FX_TPO tpo;
751  CFX_RTFPiece tp;
752  CFX_RTFChar* pTC;
753  int32_t i, j;
754  CFX_RTFCharArray& chars = m_pCurLine->m_LineChars;
755  int32_t iCount = m_pCurLine->CountChars();
756  bool bDone = (!m_bPagination && !m_bCharCode &&
757                (m_pCurLine->m_iArabicChars > 0 || m_bRTL));
758  if (bDone) {
759    int32_t iBidiNum = 0;
760    for (i = 0; i < iCount; i++) {
761      pTC = chars.GetDataPtr(i);
762      pTC->m_iBidiPos = i;
763      if (pTC->GetCharType() != FX_CHARTYPE_Control) {
764        iBidiNum = i;
765      }
766      if (i == 0) {
767        pTC->m_iBidiLevel = 1;
768      }
769    }
770    FX_BidiLine(chars, iBidiNum + 1, m_bRTL ? 1 : 0);
771  } else {
772    for (i = 0; i < iCount; i++) {
773      pTC = chars.GetDataPtr(i);
774      pTC->m_iBidiLevel = 0;
775      pTC->m_iBidiPos = 0;
776      pTC->m_iBidiOrder = 0;
777    }
778  }
779  tp.m_dwStatus = FX_RTFBREAK_PieceBreak;
780  tp.m_iStartPos = m_pCurLine->m_iStart;
781  tp.m_pChars = &chars;
782  CFX_RTFPieceArray* pCurPieces = &m_pCurLine->m_LinePieces;
783  int32_t iBidiLevel = -1, iCharWidth;
784  uint32_t dwIdentity = (uint32_t)-1;
785  i = j = 0;
786  while (i < iCount) {
787    pTC = chars.GetDataPtr(i);
788    if (iBidiLevel < 0) {
789      iBidiLevel = pTC->m_iBidiLevel;
790      iCharWidth = pTC->m_iCharWidth;
791      if (iCharWidth < 1) {
792        tp.m_iWidth = 0;
793      } else {
794        tp.m_iWidth = iCharWidth;
795      }
796      tp.m_iBidiLevel = iBidiLevel;
797      tp.m_iBidiPos = pTC->m_iBidiOrder;
798      tp.m_iFontSize = pTC->m_iFontSize;
799      tp.m_iFontHeight = pTC->m_iFontHeight;
800      tp.m_iHorizontalScale = pTC->m_iHorizontalScale;
801      tp.m_iVerticalScale = pTC->m_iVertialScale;
802      dwIdentity = pTC->m_dwIdentity;
803      tp.m_dwIdentity = dwIdentity;
804      tp.m_pUserData = pTC->m_pUserData;
805      tp.m_dwStatus = FX_RTFBREAK_PieceBreak;
806      i++;
807    } else if (iBidiLevel != pTC->m_iBidiLevel ||
808               pTC->m_dwIdentity != dwIdentity) {
809      tp.m_iChars = i - tp.m_iStartChar;
810      pCurPieces->Add(tp);
811      tp.m_iStartPos += tp.m_iWidth;
812      tp.m_iStartChar = i;
813      tpo.index = j++;
814      tpo.pos = tp.m_iBidiPos;
815      tpos.Add(tpo);
816      iBidiLevel = -1;
817    } else {
818      iCharWidth = pTC->m_iCharWidth;
819      if (iCharWidth > 0) {
820        tp.m_iWidth += iCharWidth;
821      }
822      i++;
823    }
824  }
825  if (i > tp.m_iStartChar) {
826    tp.m_dwStatus = dwStatus;
827    tp.m_iChars = i - tp.m_iStartChar;
828    pCurPieces->Add(tp);
829    tpo.index = j;
830    tpo.pos = tp.m_iBidiPos;
831    tpos.Add(tpo);
832  }
833  if (!m_bCharCode) {
834    j = tpos.GetSize() - 1;
835    FX_TEXTLAYOUT_PieceSort(tpos, 0, j);
836    int32_t iStartPos = m_pCurLine->m_iStart;
837    for (i = 0; i <= j; i++) {
838      tpo = tpos.GetAt(i);
839      CFX_RTFPiece& ttp = pCurPieces->GetAt(tpo.index);
840      ttp.m_iStartPos = iStartPos;
841      iStartPos += ttp.m_iWidth;
842    }
843  }
844}
845void CFX_RTFBreak::EndBreak_Alignment(CFX_TPOArray& tpos,
846                                      bool bAllChars,
847                                      uint32_t dwStatus) {
848  CFX_RTFPieceArray* pCurPieces = &m_pCurLine->m_LinePieces;
849  int32_t iNetWidth = m_pCurLine->m_iWidth, iGapChars = 0, iCharWidth;
850  int32_t iCount = pCurPieces->GetSize();
851  bool bFind = false;
852  uint32_t dwCharType;
853  int32_t i, j;
854  FX_TPO tpo;
855  for (i = iCount - 1; i > -1; i--) {
856    tpo = tpos.GetAt(i);
857    CFX_RTFPiece& ttp = pCurPieces->GetAt(tpo.index);
858    if (!bFind) {
859      iNetWidth = ttp.GetEndPos();
860    }
861    bool bArabic = FX_IsOdd(ttp.m_iBidiLevel);
862    j = bArabic ? 0 : ttp.m_iChars - 1;
863    while (j > -1 && j < ttp.m_iChars) {
864      const CFX_RTFChar& tc = ttp.GetChar(j);
865      if (tc.m_nBreakType == FX_LBT_DIRECT_BRK) {
866        iGapChars++;
867      }
868      if (!bFind || !bAllChars) {
869        dwCharType = tc.GetCharType();
870        if (dwCharType == FX_CHARTYPE_Space ||
871            dwCharType == FX_CHARTYPE_Control) {
872          if (!bFind) {
873            iCharWidth = tc.m_iCharWidth;
874            if (bAllChars && iCharWidth > 0) {
875              iNetWidth -= iCharWidth;
876            }
877          }
878        } else {
879          bFind = true;
880          if (!bAllChars) {
881            break;
882          }
883        }
884      }
885      j += bArabic ? 1 : -1;
886    }
887    if (!bAllChars && bFind) {
888      break;
889    }
890  }
891  int32_t iOffset = m_iBoundaryEnd - iNetWidth;
892  int32_t iLowerAlignment = (m_iAlignment & FX_RTFLINEALIGNMENT_LowerMask);
893  int32_t iHigherAlignment = (m_iAlignment & FX_RTFLINEALIGNMENT_HigherMask);
894  if (iGapChars > 0 && (iHigherAlignment == FX_RTFLINEALIGNMENT_Distributed ||
895                        (iHigherAlignment == FX_RTFLINEALIGNMENT_Justified &&
896                         dwStatus != FX_RTFBREAK_ParagraphBreak))) {
897    int32_t iStart = -1;
898    for (i = 0; i < iCount; i++) {
899      tpo = tpos.GetAt(i);
900      CFX_RTFPiece& ttp = pCurPieces->GetAt(tpo.index);
901      if (iStart < 0) {
902        iStart = ttp.m_iStartPos;
903      } else {
904        ttp.m_iStartPos = iStart;
905      }
906      int32_t k;
907      for (j = 0; j < ttp.m_iChars; j++) {
908        CFX_RTFChar& tc = ttp.GetChar(j);
909        if (tc.m_nBreakType != FX_LBT_DIRECT_BRK || tc.m_iCharWidth < 0) {
910          continue;
911        }
912        k = iOffset / iGapChars;
913        tc.m_iCharWidth += k;
914        ttp.m_iWidth += k;
915        iOffset -= k;
916        iGapChars--;
917        if (iGapChars < 1) {
918          break;
919        }
920      }
921      iStart += ttp.m_iWidth;
922    }
923  } else if (iLowerAlignment > FX_RTFLINEALIGNMENT_Left) {
924    if (iLowerAlignment == FX_RTFLINEALIGNMENT_Center) {
925      iOffset /= 2;
926    }
927    if (iOffset > 0) {
928      for (i = 0; i < iCount; i++) {
929        CFX_RTFPiece& ttp = pCurPieces->GetAt(i);
930        ttp.m_iStartPos += iOffset;
931      }
932    }
933  }
934}
935
936int32_t CFX_RTFBreak::GetBreakPos(CFX_RTFCharArray& tca,
937                                  int32_t& iEndPos,
938                                  bool bAllChars,
939                                  bool bOnlyBrk) {
940  int32_t iLength = tca.GetSize() - 1;
941  if (iLength < 1)
942    return iLength;
943
944  int32_t iBreak = -1, iBreakPos = -1, iIndirect = -1, iIndirectPos = -1,
945          iLast = -1, iLastPos = -1;
946  if (m_bSingleLine || m_bOrphanLine || iEndPos <= m_iBoundaryEnd) {
947    if (!bAllChars || m_bCharCode)
948      return iLength;
949
950    iBreak = iLength;
951    iBreakPos = iEndPos;
952  }
953  CFX_RTFChar* pCharArray = tca.GetData();
954  if (m_bCharCode) {
955    const CFX_RTFChar* pChar;
956    int32_t iCharWidth;
957    while (iLength > 0) {
958      if (iEndPos <= m_iBoundaryEnd)
959        break;
960
961      pChar = pCharArray + iLength--;
962      iCharWidth = pChar->m_iCharWidth;
963      if (iCharWidth > 0)
964        iEndPos -= iCharWidth;
965    }
966    return iLength;
967  }
968  bool bSpaceBreak = (m_dwPolicies & FX_RTFBREAKPOLICY_SpaceBreak) != 0;
969  bool bTabBreak = (m_dwPolicies & FX_RTFBREAKPOLICY_TabBreak) != 0;
970  bool bNumberBreak = (m_dwPolicies & FX_RTFBREAKPOLICY_NumberBreak) != 0;
971  bool bInfixBreak = (m_dwPolicies & FX_RTFBREAKPOLICY_InfixBreak) != 0;
972  FX_LINEBREAKTYPE eType;
973  uint32_t nCodeProp, nCur, nNext;
974  CFX_RTFChar* pCur = pCharArray + iLength--;
975  if (bAllChars) {
976    pCur->m_nBreakType = FX_LBT_UNKNOWN;
977  }
978  nCodeProp = pCur->m_dwCharProps;
979  nNext = nCodeProp & 0x003F;
980  int32_t iCharWidth = pCur->m_iCharWidth;
981  if (iCharWidth > 0) {
982    iEndPos -= iCharWidth;
983  }
984  while (iLength >= 0) {
985    pCur = pCharArray + iLength;
986    nCodeProp = pCur->m_dwCharProps;
987    nCur = nCodeProp & 0x003F;
988    bool bNeedBreak = false;
989    if (nCur == FX_CBP_SP) {
990      bNeedBreak = !bSpaceBreak;
991      if (nNext == FX_CBP_SP) {
992        eType = bSpaceBreak ? FX_LBT_DIRECT_BRK : FX_LBT_PROHIBITED_BRK;
993      } else {
994        eType = gs_FX_LineBreak_PairTable[nCur][nNext];
995      }
996    } else if (nCur == FX_CBP_TB) {
997      bNeedBreak = !bTabBreak;
998      if (nNext == FX_CBP_TB) {
999        eType = bTabBreak ? FX_LBT_DIRECT_BRK : FX_LBT_PROHIBITED_BRK;
1000      } else {
1001        eType = gs_FX_LineBreak_PairTable[nCur][nNext];
1002      }
1003    } else if ((bNumberBreak && nCur == FX_CBP_NU && nNext == FX_CBP_NU) ||
1004               (bInfixBreak && nCur == FX_CBP_IS && nNext == FX_CBP_IS)) {
1005      eType = FX_LBT_DIRECT_BRK;
1006    } else {
1007      if (nNext == FX_CBP_SP) {
1008        eType = FX_LBT_PROHIBITED_BRK;
1009      } else {
1010        eType = gs_FX_LineBreak_PairTable[nCur][nNext];
1011      }
1012    }
1013    if (bAllChars) {
1014      pCur->m_nBreakType = eType;
1015    }
1016    if (!bOnlyBrk) {
1017      iCharWidth = pCur->m_iCharWidth;
1018      bool bBreak = false;
1019      if (nCur == FX_CBP_TB && bTabBreak) {
1020        bBreak = iCharWidth > 0 && iEndPos - iCharWidth <= m_iBoundaryEnd;
1021      } else {
1022        bBreak = iEndPos <= m_iBoundaryEnd;
1023      }
1024      if (m_bSingleLine || m_bOrphanLine || bBreak || bNeedBreak) {
1025        if (eType == FX_LBT_DIRECT_BRK && iBreak < 0) {
1026          iBreak = iLength;
1027          iBreakPos = iEndPos;
1028          if (!bAllChars) {
1029            return iLength;
1030          }
1031        } else if (eType == FX_LBT_INDIRECT_BRK && iIndirect < 0) {
1032          iIndirect = iLength;
1033          iIndirectPos = iEndPos;
1034        }
1035        if (iLast < 0) {
1036          iLast = iLength;
1037          iLastPos = iEndPos;
1038        }
1039      }
1040      if (iCharWidth > 0) {
1041        iEndPos -= iCharWidth;
1042      }
1043    }
1044    nNext = nCodeProp & 0x003F;
1045    iLength--;
1046  }
1047  if (bOnlyBrk)
1048    return 0;
1049
1050  if (iBreak > -1) {
1051    iEndPos = iBreakPos;
1052    return iBreak;
1053  }
1054  if (iIndirect > -1) {
1055    iEndPos = iIndirectPos;
1056    return iIndirect;
1057  }
1058  if (iLast > -1) {
1059    iEndPos = iLastPos;
1060    return iLast;
1061  }
1062  return 0;
1063}
1064
1065void CFX_RTFBreak::SplitTextLine(CFX_RTFLine* pCurLine,
1066                                 CFX_RTFLine* pNextLine,
1067                                 bool bAllChars) {
1068  ASSERT(pCurLine && pNextLine);
1069  int32_t iCount = pCurLine->CountChars();
1070  if (iCount < 2) {
1071    return;
1072  }
1073  int32_t iEndPos = pCurLine->GetLineEnd();
1074  CFX_RTFCharArray& curChars = pCurLine->m_LineChars;
1075  int32_t iCharPos = GetBreakPos(curChars, iEndPos, bAllChars, false);
1076  if (iCharPos < 0) {
1077    iCharPos = 0;
1078  }
1079  iCharPos++;
1080  if (iCharPos >= iCount) {
1081    pNextLine->RemoveAll(true);
1082    CFX_Char* pTC = curChars.GetDataPtr(iCharPos - 1);
1083    pTC->m_nBreakType = FX_LBT_UNKNOWN;
1084    return;
1085  }
1086  CFX_RTFCharArray& nextChars = pNextLine->m_LineChars;
1087  int cur_size = curChars.GetSize();
1088  nextChars.SetSize(cur_size - iCharPos);
1089  FXSYS_memcpy(nextChars.GetData(), curChars.GetDataPtr(iCharPos),
1090               (cur_size - iCharPos) * sizeof(CFX_RTFChar));
1091  iCount -= iCharPos;
1092  cur_size = curChars.GetSize();
1093  curChars.RemoveAt(cur_size - iCount, iCount);
1094  pNextLine->m_iStart = pCurLine->m_iStart;
1095  pNextLine->m_iWidth = pCurLine->GetLineEnd() - iEndPos;
1096  pCurLine->m_iWidth = iEndPos;
1097  curChars.GetDataPtr(iCharPos - 1)->m_nBreakType = FX_LBT_UNKNOWN;
1098  iCount = nextChars.GetSize();
1099  CFX_RTFChar* pNextChars = nextChars.GetData();
1100  for (int32_t i = 0; i < iCount; i++) {
1101    CFX_RTFChar* tc = pNextChars + i;
1102    if (tc->GetCharType() >= FX_CHARTYPE_ArabicAlef) {
1103      pCurLine->m_iArabicChars--;
1104      pNextLine->m_iArabicChars++;
1105    }
1106    if (tc->m_dwLayoutStyles & FX_RTFLAYOUTSTYLE_MBCSCode) {
1107      pCurLine->m_iMBCSChars--;
1108      pNextLine->m_iMBCSChars++;
1109    }
1110    tc->m_dwStatus = 0;
1111  }
1112}
1113
1114int32_t CFX_RTFBreak::CountBreakPieces() const {
1115  CFX_RTFPieceArray* pRTFPieces = GetRTFPieces(true);
1116  return pRTFPieces ? pRTFPieces->GetSize() : 0;
1117}
1118
1119const CFX_RTFPiece* CFX_RTFBreak::GetBreakPiece(int32_t index) const {
1120  CFX_RTFPieceArray* pRTFPieces = GetRTFPieces(true);
1121  if (!pRTFPieces)
1122    return nullptr;
1123
1124  if (index < 0 || index >= pRTFPieces->GetSize())
1125    return nullptr;
1126
1127  return pRTFPieces->GetPtrAt(index);
1128}
1129
1130void CFX_RTFBreak::GetLineRect(CFX_RectF& rect) const {
1131  rect.top = 0;
1132  CFX_RTFLine* pRTFLine = GetRTFLine(true);
1133  if (!pRTFLine) {
1134    rect.left = ((FX_FLOAT)m_iBoundaryStart) / 20000.0f;
1135    rect.width = rect.height = 0;
1136    return;
1137  }
1138  rect.left = ((FX_FLOAT)pRTFLine->m_iStart) / 20000.0f;
1139  rect.width = ((FX_FLOAT)pRTFLine->m_iWidth) / 20000.0f;
1140  CFX_RTFPieceArray& rtfPieces = pRTFLine->m_LinePieces;
1141  int32_t iCount = rtfPieces.GetSize();
1142  if (iCount < 1) {
1143    rect.width = 0;
1144    return;
1145  }
1146  CFX_RTFPiece* pBreakPiece;
1147  int32_t iLineHeight = 0, iMax;
1148  for (int32_t i = 0; i < iCount; i++) {
1149    pBreakPiece = rtfPieces.GetPtrAt(i);
1150    int32_t iFontHeight = FXSYS_round(pBreakPiece->m_iFontHeight *
1151                                      pBreakPiece->m_iVerticalScale / 100.0f);
1152    iMax = std::max(pBreakPiece->m_iFontSize, iFontHeight);
1153    if (i == 0) {
1154      iLineHeight = iMax;
1155    } else if (iLineHeight < iMax) {
1156      iLineHeight = iMax;
1157    }
1158  }
1159  rect.height = ((FX_FLOAT)iLineHeight) / 20.0f;
1160}
1161void CFX_RTFBreak::ClearBreakPieces() {
1162  CFX_RTFLine* pRTFLine = GetRTFLine(true);
1163  if (pRTFLine) {
1164    pRTFLine->RemoveAll(true);
1165  }
1166  m_iReady = 0;
1167}
1168void CFX_RTFBreak::Reset() {
1169  m_eCharType = FX_CHARTYPE_Unknown;
1170  m_RTFLine1.RemoveAll(true);
1171  m_RTFLine2.RemoveAll(true);
1172}
1173int32_t CFX_RTFBreak::GetDisplayPos(const FX_RTFTEXTOBJ* pText,
1174                                    FXTEXT_CHARPOS* pCharPos,
1175                                    bool bCharCode,
1176                                    CFX_WideString* pWSForms,
1177                                    FX_AdjustCharDisplayPos pAdjustPos) const {
1178  if (!pText || pText->iLength < 1) {
1179    return 0;
1180  }
1181  ASSERT(pText->pStr && pText->pWidths && pText->pFont && pText->pRect);
1182  const FX_WCHAR* pStr = pText->pStr;
1183  int32_t* pWidths = pText->pWidths;
1184  int32_t iLength = pText->iLength - 1;
1185  CFX_RetainPtr<CFGAS_GEFont> pFont = pText->pFont;
1186  uint32_t dwStyles = pText->dwLayoutStyles;
1187  CFX_RectF rtText(*pText->pRect);
1188  bool bRTLPiece = FX_IsOdd(pText->iBidiLevel);
1189  FX_FLOAT fFontSize = pText->fFontSize;
1190  int32_t iFontSize = FXSYS_round(fFontSize * 20.0f);
1191  int32_t iAscent = pFont->GetAscent();
1192  int32_t iDescent = pFont->GetDescent();
1193  int32_t iMaxHeight = iAscent - iDescent;
1194  FX_FLOAT fFontHeight = fFontSize;
1195  FX_FLOAT fAscent = fFontHeight * (FX_FLOAT)iAscent / (FX_FLOAT)iMaxHeight;
1196  FX_FLOAT fDescent = fFontHeight * (FX_FLOAT)iDescent / (FX_FLOAT)iMaxHeight;
1197  bool bVerticalDoc = (dwStyles & FX_RTFLAYOUTSTYLE_VerticalLayout) != 0;
1198  bool bVerticalChar = (dwStyles & FX_RTFLAYOUTSTYLE_VerticalChars) != 0;
1199  bool bArabicNumber = (dwStyles & FX_RTFLAYOUTSTYLE_ArabicNumber) != 0;
1200  bool bMBCSCode = (dwStyles & FX_RTFLAYOUTSTYLE_MBCSCode) != 0;
1201  int32_t iRotation = GetLineRotation(dwStyles) + pText->iCharRotation;
1202  int32_t iCharRotation;
1203  FX_WCHAR wch, wPrev = 0xFEFF, wNext, wForm;
1204  int32_t iWidth, iCharWidth, iCharHeight;
1205  FX_FLOAT fX, fY, fCharWidth, fCharHeight;
1206  int32_t iHorScale = pText->iHorizontalScale;
1207  int32_t iVerScale = pText->iVerticalScale;
1208  bool bEmptyChar;
1209  uint32_t dwProps, dwCharType;
1210  fX = rtText.left;
1211  fY = rtText.top;
1212  if (bVerticalDoc) {
1213    fX += (rtText.width - fFontSize) / 2.0f;
1214    if (bRTLPiece) {
1215      fY = rtText.bottom();
1216    }
1217  } else {
1218    if (bRTLPiece) {
1219      fX = rtText.right();
1220    }
1221    fY += fAscent;
1222  }
1223  int32_t iCount = 0;
1224  for (int32_t i = 0; i <= iLength; i++) {
1225    wch = *pStr++;
1226    iWidth = *pWidths++;
1227    if (!bMBCSCode) {
1228      dwProps = FX_GetUnicodeProperties(wch);
1229      dwCharType = (dwProps & FX_CHARTYPEBITSMASK);
1230      if (dwCharType == FX_CHARTYPE_ArabicAlef && iWidth == 0) {
1231        wPrev = 0xFEFF;
1232        continue;
1233      }
1234    } else {
1235      dwProps = 0;
1236      dwCharType = 0;
1237    }
1238    if (iWidth != 0) {
1239      iCharWidth = iWidth;
1240      if (iCharWidth < 0) {
1241        iCharWidth = -iCharWidth;
1242      }
1243      if (!bMBCSCode) {
1244        bEmptyChar = (dwCharType >= FX_CHARTYPE_Tab &&
1245                      dwCharType <= FX_CHARTYPE_Control);
1246      } else {
1247        bEmptyChar = false;
1248      }
1249      if (!bEmptyChar) {
1250        iCount++;
1251      }
1252      if (pCharPos) {
1253        iCharWidth /= iFontSize;
1254        wForm = wch;
1255        if (!bMBCSCode) {
1256          if (dwCharType >= FX_CHARTYPE_ArabicAlef) {
1257            if (i < iLength) {
1258              wNext = *pStr;
1259              if (*pWidths < 0) {
1260                if (i + 1 < iLength) {
1261                  wNext = pStr[1];
1262                }
1263              }
1264            } else {
1265              wNext = 0xFEFF;
1266            }
1267            wForm = pdfium::arabic::GetFormChar(wch, wPrev, wNext);
1268          } else if (bRTLPiece || bVerticalChar) {
1269            wForm = FX_GetMirrorChar(wch, dwProps, bRTLPiece, bVerticalChar);
1270          } else if (dwCharType == FX_CHARTYPE_Numeric && bArabicNumber) {
1271            wForm = wch + 0x0630;
1272          }
1273          dwProps = FX_GetUnicodeProperties(wForm);
1274        }
1275        iCharRotation = iRotation;
1276        if (!bMBCSCode && bVerticalChar && (dwProps & 0x8000) != 0) {
1277          iCharRotation++;
1278          iCharRotation %= 4;
1279        }
1280        if (!bEmptyChar) {
1281          if (bCharCode) {
1282            pCharPos->m_GlyphIndex = wch;
1283          } else {
1284            pCharPos->m_GlyphIndex = pFont->GetGlyphIndex(wForm, bMBCSCode);
1285            if (pCharPos->m_GlyphIndex == 0xFFFF) {
1286              pCharPos->m_GlyphIndex = pFont->GetGlyphIndex(wch, bMBCSCode);
1287            }
1288          }
1289#if _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_
1290          pCharPos->m_ExtGID = pCharPos->m_GlyphIndex;
1291#endif
1292          pCharPos->m_FontCharWidth = iCharWidth;
1293          if (pWSForms) {
1294            *pWSForms += wForm;
1295          }
1296        }
1297        if (bVerticalDoc) {
1298          iCharHeight = iCharWidth;
1299          iCharWidth = 1000;
1300        } else {
1301          iCharHeight = 1000;
1302        }
1303        fCharWidth = fFontSize * iCharWidth / 1000.0f;
1304        fCharHeight = fFontSize * iCharHeight / 1000.0f;
1305        if (!bMBCSCode && bRTLPiece && dwCharType != FX_CHARTYPE_Combination) {
1306          if (bVerticalDoc) {
1307            fY -= fCharHeight;
1308          } else {
1309            fX -= fCharWidth;
1310          }
1311        }
1312        if (!bEmptyChar) {
1313          CFX_PointF ptOffset;
1314          bool bAdjusted = false;
1315          if (pAdjustPos) {
1316            bAdjusted = pAdjustPos(wForm, bMBCSCode, pFont, fFontSize,
1317                                   bVerticalChar, ptOffset);
1318          }
1319          if (!bAdjusted && bVerticalChar && (dwProps & 0x00010000) != 0) {
1320            CFX_Rect rtBBox;
1321            rtBBox.Reset();
1322            if (pFont->GetCharBBox(wForm, &rtBBox, bMBCSCode)) {
1323              ptOffset.x = fFontSize * (850 - rtBBox.right()) / 1000.0f;
1324              ptOffset.y = fFontSize * (1000 - rtBBox.height) / 2000.0f;
1325            }
1326          }
1327          pCharPos->m_OriginX = fX + ptOffset.x;
1328          pCharPos->m_OriginY = fY - ptOffset.y;
1329        }
1330        if (!bRTLPiece && dwCharType != FX_CHARTYPE_Combination) {
1331          if (bVerticalDoc) {
1332            fY += fCharHeight;
1333          } else {
1334            fX += fCharWidth;
1335          }
1336        }
1337        if (!bEmptyChar) {
1338          pCharPos->m_bGlyphAdjust = true;
1339          if (bVerticalDoc) {
1340            if (iCharRotation == 0) {
1341              pCharPos->m_AdjustMatrix[0] = -1;
1342              pCharPos->m_AdjustMatrix[1] = 0;
1343              pCharPos->m_AdjustMatrix[2] = 0;
1344              pCharPos->m_AdjustMatrix[3] = 1;
1345              pCharPos->m_OriginY += fAscent * iVerScale / 100.0f;
1346            } else if (iCharRotation == 1) {
1347              pCharPos->m_AdjustMatrix[0] = 0;
1348              pCharPos->m_AdjustMatrix[1] = -1;
1349              pCharPos->m_AdjustMatrix[2] = -1;
1350              pCharPos->m_AdjustMatrix[3] = 0;
1351              pCharPos->m_OriginX -=
1352                  fDescent + fAscent * iVerScale / 100.0f - fAscent;
1353            } else if (iCharRotation == 2) {
1354              pCharPos->m_AdjustMatrix[0] = 1;
1355              pCharPos->m_AdjustMatrix[1] = 0;
1356              pCharPos->m_AdjustMatrix[2] = 0;
1357              pCharPos->m_AdjustMatrix[3] = -1;
1358              pCharPos->m_OriginX += fCharWidth;
1359              pCharPos->m_OriginY += fAscent;
1360            } else {
1361              pCharPos->m_AdjustMatrix[0] = 0;
1362              pCharPos->m_AdjustMatrix[1] = 1;
1363              pCharPos->m_AdjustMatrix[2] = 1;
1364              pCharPos->m_AdjustMatrix[3] = 0;
1365              pCharPos->m_OriginX += fAscent;
1366              pCharPos->m_OriginY += fCharWidth;
1367            }
1368          } else {
1369            if (iCharRotation == 0) {
1370              pCharPos->m_AdjustMatrix[0] = -1;
1371              pCharPos->m_AdjustMatrix[1] = 0;
1372              pCharPos->m_AdjustMatrix[2] = 0;
1373              pCharPos->m_AdjustMatrix[3] = 1;
1374              pCharPos->m_OriginY += fAscent * iVerScale / 100.0f - fAscent;
1375            } else if (iCharRotation == 1) {
1376              pCharPos->m_AdjustMatrix[0] = 0;
1377              pCharPos->m_AdjustMatrix[1] = -1;
1378              pCharPos->m_AdjustMatrix[2] = -1;
1379              pCharPos->m_AdjustMatrix[3] = 0;
1380              pCharPos->m_OriginX -= fDescent;
1381              pCharPos->m_OriginY -= fAscent + fDescent;
1382            } else if (iCharRotation == 2) {
1383              pCharPos->m_AdjustMatrix[0] = 1;
1384              pCharPos->m_AdjustMatrix[1] = 0;
1385              pCharPos->m_AdjustMatrix[2] = 0;
1386              pCharPos->m_AdjustMatrix[3] = -1;
1387              pCharPos->m_OriginX += fCharWidth;
1388              pCharPos->m_OriginY -= fAscent;
1389            } else {
1390              pCharPos->m_AdjustMatrix[0] = 0;
1391              pCharPos->m_AdjustMatrix[1] = 1;
1392              pCharPos->m_AdjustMatrix[2] = 1;
1393              pCharPos->m_AdjustMatrix[3] = 0;
1394              pCharPos->m_OriginX += fAscent * iVerScale / 100.0f;
1395            }
1396          }
1397          if (iHorScale != 100 || iVerScale != 100) {
1398            pCharPos->m_AdjustMatrix[0] =
1399                pCharPos->m_AdjustMatrix[0] * iHorScale / 100.0f;
1400            pCharPos->m_AdjustMatrix[1] =
1401                pCharPos->m_AdjustMatrix[1] * iHorScale / 100.0f;
1402            pCharPos->m_AdjustMatrix[2] =
1403                pCharPos->m_AdjustMatrix[2] * iVerScale / 100.0f;
1404            pCharPos->m_AdjustMatrix[3] =
1405                pCharPos->m_AdjustMatrix[3] * iVerScale / 100.0f;
1406          }
1407          pCharPos++;
1408        }
1409      }
1410    }
1411    if (iWidth > 0) {
1412      wPrev = wch;
1413    }
1414  }
1415  return iCount;
1416}
1417int32_t CFX_RTFBreak::GetCharRects(const FX_RTFTEXTOBJ* pText,
1418                                   CFX_RectFArray& rtArray,
1419                                   bool bCharBBox) const {
1420  if (!pText || pText->iLength < 1)
1421    return 0;
1422
1423  ASSERT(pText->pStr && pText->pWidths && pText->pFont && pText->pRect);
1424  const FX_WCHAR* pStr = pText->pStr;
1425  int32_t* pWidths = pText->pWidths;
1426  int32_t iLength = pText->iLength;
1427  CFX_RectF rect(*pText->pRect);
1428  bool bRTLPiece = FX_IsOdd(pText->iBidiLevel);
1429  FX_FLOAT fFontSize = pText->fFontSize;
1430  int32_t iFontSize = FXSYS_round(fFontSize * 20.0f);
1431  FX_FLOAT fScale = fFontSize / 1000.0f;
1432  CFX_RetainPtr<CFGAS_GEFont> pFont = pText->pFont;
1433  if (!pFont)
1434    bCharBBox = false;
1435
1436  CFX_Rect bbox;
1437  bbox.Set(0, 0, 0, 0);
1438  if (bCharBBox)
1439    bCharBBox = pFont->GetBBox(&bbox);
1440
1441  FX_FLOAT fLeft = std::max(0.0f, bbox.left * fScale);
1442  FX_FLOAT fHeight = FXSYS_fabs(bbox.height * fScale);
1443  rtArray.RemoveAll();
1444  rtArray.SetSize(iLength);
1445  uint32_t dwStyles = pText->dwLayoutStyles;
1446  bool bVertical = (dwStyles & FX_RTFLAYOUTSTYLE_VerticalLayout) != 0;
1447  bool bSingleLine = (dwStyles & FX_RTFLAYOUTSTYLE_SingleLine) != 0;
1448  bool bCombText = (dwStyles & FX_TXTLAYOUTSTYLE_CombText) != 0;
1449  FX_WCHAR wch, wLineBreakChar = pText->wLineBreakChar;
1450  int32_t iCharSize;
1451  FX_FLOAT fCharSize, fStart;
1452  if (bVertical) {
1453    fStart = bRTLPiece ? rect.bottom() : rect.top;
1454  } else {
1455    fStart = bRTLPiece ? rect.right() : rect.left;
1456  }
1457  for (int32_t i = 0; i < iLength; i++) {
1458    wch = *pStr++;
1459    iCharSize = *pWidths++;
1460    fCharSize = (FX_FLOAT)iCharSize / 20000.0f;
1461    bool bRet = (!bSingleLine && FX_IsCtrlCode(wch));
1462    if (!(wch == L'\v' || wch == L'\f' || wch == 0x2028 || wch == 0x2029 ||
1463          (wLineBreakChar != 0xFEFF && wch == wLineBreakChar))) {
1464      bRet = false;
1465    }
1466    if (bRet) {
1467      iCharSize = iFontSize * 500;
1468      fCharSize = fFontSize / 2.0f;
1469    }
1470    if (bVertical) {
1471      rect.top = fStart;
1472      if (bRTLPiece) {
1473        rect.top -= fCharSize;
1474        fStart -= fCharSize;
1475      } else {
1476        fStart += fCharSize;
1477      }
1478      rect.height = fCharSize;
1479    } else {
1480      rect.left = fStart;
1481      if (bRTLPiece) {
1482        rect.left -= fCharSize;
1483        fStart -= fCharSize;
1484      } else {
1485        fStart += fCharSize;
1486      }
1487      rect.width = fCharSize;
1488    }
1489    if (bCharBBox && !bRet) {
1490      int32_t iCharWidth = 1000;
1491      pFont->GetCharWidth(wch, iCharWidth, false);
1492      FX_FLOAT fRTLeft = 0, fCharWidth = 0;
1493      if (iCharWidth > 0) {
1494        fCharWidth = iCharWidth * fScale;
1495        fRTLeft = fLeft;
1496        if (bCombText) {
1497          fRTLeft = (rect.width - fCharWidth) / 2.0f;
1498        }
1499      }
1500      CFX_RectF rtBBoxF;
1501      if (bVertical) {
1502        rtBBoxF.top = rect.left + fRTLeft;
1503        rtBBoxF.left = rect.top + (rect.height - fHeight) / 2.0f;
1504        rtBBoxF.height = fCharWidth;
1505        rtBBoxF.width = fHeight;
1506        rtBBoxF.left = std::max(rtBBoxF.left, 0.0f);
1507      } else {
1508        rtBBoxF.left = rect.left + fRTLeft;
1509        rtBBoxF.top = rect.top + (rect.height - fHeight) / 2.0f;
1510        rtBBoxF.width = fCharWidth;
1511        rtBBoxF.height = fHeight;
1512        rtBBoxF.top = std::max(rtBBoxF.top, 0.0f);
1513      }
1514      rtArray.SetAt(i, rtBBoxF);
1515      continue;
1516    }
1517    rtArray.SetAt(i, rect);
1518  }
1519  return iLength;
1520}
1521
1522CFX_RTFPiece::CFX_RTFPiece()
1523    : m_dwStatus(FX_RTFBREAK_PieceBreak),
1524      m_iStartPos(0),
1525      m_iWidth(-1),
1526      m_iStartChar(0),
1527      m_iChars(0),
1528      m_iBidiLevel(0),
1529      m_iBidiPos(0),
1530      m_iFontSize(0),
1531      m_iFontHeight(0),
1532      m_iHorizontalScale(100),
1533      m_iVerticalScale(100),
1534      m_dwLayoutStyles(0),
1535      m_dwIdentity(0),
1536      m_pChars(nullptr),
1537      m_pUserData(nullptr) {}
1538
1539CFX_RTFPiece::~CFX_RTFPiece() {
1540  Reset();
1541}
1542
1543CFX_RTFLine::CFX_RTFLine()
1544    : m_LinePieces(16),
1545      m_iStart(0),
1546      m_iWidth(0),
1547      m_iArabicChars(0),
1548      m_iMBCSChars(0) {}
1549
1550CFX_RTFLine::~CFX_RTFLine() {
1551  RemoveAll();
1552}
1553
1554FX_RTFTEXTOBJ::FX_RTFTEXTOBJ()
1555    : pStr(nullptr),
1556      pWidths(nullptr),
1557      iLength(0),
1558      pFont(nullptr),
1559      fFontSize(12.0f),
1560      dwLayoutStyles(0),
1561      iCharRotation(0),
1562      iBidiLevel(0),
1563      pRect(nullptr),
1564      wLineBreakChar(L'\n'),
1565      iHorizontalScale(100),
1566      iVerticalScale(100) {}
1567
1568FX_RTFTEXTOBJ::~FX_RTFTEXTOBJ() {}
1569