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