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