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