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