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