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