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