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