blob: 6e36da1b6848db4b38d8b48cf73659d0da551490 [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
dsinclaira52ab742016-09-29 13:59:29 -070011#include "core/fxcrt/fx_arabic.h"
dsinclaira52ab742016-09-29 13:59:29 -070012#include "core/fxcrt/fx_memory.h"
tsepeza9caab92016-12-14 05:57:10 -080013#include "third_party/base/ptr_util.h"
npm4b91a2d2016-11-21 15:19:44 -080014#include "xfa/fgas/font/cfgas_gefont.h"
Dan Sinclair1770c022016-03-14 14:14:16 -040015#include "xfa/fgas/layout/fgas_linebreak.h"
Dan Sinclair1770c022016-03-14 14:14:16 -040016
tsepez215507d2016-06-09 19:05:47 -070017namespace {
18
Dan Sinclairc36fe072017-03-09 16:58:12 -050019typedef CFX_BreakType (CFX_TxtBreak::*FX_TxtBreak_LPFAppendChar)(
Dan Sinclair893822a2017-03-13 15:32:07 -040020 CFX_Char* pCurChar);
tsepez215507d2016-06-09 19:05:47 -070021const FX_TxtBreak_LPFAppendChar g_FX_TxtBreak_lpfAppendChar[16] = {
22 &CFX_TxtBreak::AppendChar_Others, &CFX_TxtBreak::AppendChar_Tab,
23 &CFX_TxtBreak::AppendChar_Others, &CFX_TxtBreak::AppendChar_Control,
24 &CFX_TxtBreak::AppendChar_Combination, &CFX_TxtBreak::AppendChar_Others,
25 &CFX_TxtBreak::AppendChar_Others, &CFX_TxtBreak::AppendChar_Arabic,
26 &CFX_TxtBreak::AppendChar_Arabic, &CFX_TxtBreak::AppendChar_Arabic,
27 &CFX_TxtBreak::AppendChar_Arabic, &CFX_TxtBreak::AppendChar_Arabic,
28 &CFX_TxtBreak::AppendChar_Arabic, &CFX_TxtBreak::AppendChar_Others,
29 &CFX_TxtBreak::AppendChar_Others, &CFX_TxtBreak::AppendChar_Others,
30};
31
Dan Sinclair812e96c2017-03-13 16:43:37 -040032bool IsCtrlCode(wchar_t ch) {
Dan Sinclairfc9b9882017-03-07 09:18:18 -050033 uint32_t dwRet = (FX_GetUnicodeProperties(ch) & FX_CHARTYPEBITSMASK);
34 return dwRet == FX_CHARTYPE_Tab || dwRet == FX_CHARTYPE_Control;
35}
36
tsepez215507d2016-06-09 19:05:47 -070037} // namespace
38
Dan Sinclair52c73c22017-03-09 13:27:29 -050039CFX_TxtBreak::CFX_TxtBreak()
Dan Sinclaire533b932017-03-16 11:47:20 -040040 : CFX_Break(FX_LAYOUTSTYLE_None),
Dan Sinclair1770c022016-03-14 14:14:16 -040041 m_iArabicContext(1),
42 m_iCurArabicContext(1),
Dan Sinclair9e9bab62017-03-09 16:59:12 -050043 m_iAlignment(CFX_TxtLineAlignment_Left),
Dan Sinclair1770c022016-03-14 14:14:16 -040044 m_dwContextCharStyles(0),
Dan Sinclaire533b932017-03-16 11:47:20 -040045 m_iCombWidth(360000) {
Dan Sinclair1770c022016-03-14 14:14:16 -040046 ResetArabicContext();
47}
weili1b4f6b32016-08-04 16:37:48 -070048
dan sinclair6fcea1f2017-03-13 13:06:05 -040049CFX_TxtBreak::~CFX_TxtBreak() {}
weili1b4f6b32016-08-04 16:37:48 -070050
Dan Sinclair05df0752017-03-14 14:43:42 -040051void CFX_TxtBreak::SetLineWidth(float fLineWidth) {
Dan Sinclair1770c022016-03-14 14:14:16 -040052 m_iLineWidth = FXSYS_round(fLineWidth * 20000.0f);
dsinclair43854a52016-04-27 12:26:00 -070053 ASSERT(m_iLineWidth >= 20000);
Dan Sinclair1770c022016-03-14 14:14:16 -040054}
weili1b4f6b32016-08-04 16:37:48 -070055
weili1b4f6b32016-08-04 16:37:48 -070056
Dan Sinclair1770c022016-03-14 14:14:16 -040057void CFX_TxtBreak::SetAlignment(int32_t iAlignment) {
Dan Sinclair9e9bab62017-03-09 16:59:12 -050058 ASSERT(iAlignment >= CFX_TxtLineAlignment_Left &&
59 iAlignment <= CFX_TxtLineAlignment_Justified);
Dan Sinclair1770c022016-03-14 14:14:16 -040060 m_iAlignment = iAlignment;
61 ResetArabicContext();
62}
weili1b4f6b32016-08-04 16:37:48 -070063
Dan Sinclair05df0752017-03-14 14:43:42 -040064void CFX_TxtBreak::SetCombWidth(float fCombWidth) {
Dan Sinclair1770c022016-03-14 14:14:16 -040065 m_iCombWidth = FXSYS_round(fCombWidth * 20000.0f);
66}
weili1b4f6b32016-08-04 16:37:48 -070067
Dan Sinclair1770c022016-03-14 14:14:16 -040068void CFX_TxtBreak::SetBreakStatus() {
Dan Sinclair1770c022016-03-14 14:14:16 -040069 int32_t iCount = m_pCurLine->CountChars();
Dan Sinclair17f31182017-03-01 09:31:51 -050070 if (iCount < 1)
Dan Sinclair1770c022016-03-14 14:14:16 -040071 return;
Dan Sinclair17f31182017-03-01 09:31:51 -050072
Dan Sinclair893822a2017-03-13 15:32:07 -040073 CFX_Char* pTC = m_pCurLine->GetChar(iCount - 1);
Dan Sinclairc36fe072017-03-09 16:58:12 -050074 if (pTC->m_dwStatus == CFX_BreakType::None)
75 pTC->m_dwStatus = CFX_BreakType::Piece;
Dan Sinclair1770c022016-03-14 14:14:16 -040076}
Dan Sinclair893822a2017-03-13 15:32:07 -040077CFX_Char* CFX_TxtBreak::GetLastChar(int32_t index, bool bOmitChar) const {
78 std::vector<CFX_Char>& ca = m_pCurLine->m_LineChars;
tsepez33316fc2017-01-24 12:17:40 -080079 int32_t iCount = pdfium::CollectionSize<int32_t>(ca);
Dan Sinclair17f31182017-03-01 09:31:51 -050080 if (index < 0 || index >= iCount)
dsinclair85d1f2c2016-06-23 12:40:16 -070081 return nullptr;
Dan Sinclair17f31182017-03-01 09:31:51 -050082
Dan Sinclair1770c022016-03-14 14:14:16 -040083 int32_t iStart = iCount - 1;
84 while (iStart > -1) {
Dan Sinclair893822a2017-03-13 15:32:07 -040085 CFX_Char* pTC = &ca[iStart--];
Dan Sinclair17f31182017-03-01 09:31:51 -050086 if (bOmitChar && pTC->GetCharType() == FX_CHARTYPE_Combination)
Dan Sinclair1770c022016-03-14 14:14:16 -040087 continue;
Dan Sinclair17f31182017-03-01 09:31:51 -050088 if (--index < 0)
Dan Sinclair1770c022016-03-14 14:14:16 -040089 return pTC;
Dan Sinclair1770c022016-03-14 14:14:16 -040090 }
dsinclair85d1f2c2016-06-23 12:40:16 -070091 return nullptr;
Dan Sinclair1770c022016-03-14 14:14:16 -040092}
weili1b4f6b32016-08-04 16:37:48 -070093
weilia2c06e42016-05-20 17:09:48 -070094inline FX_CHARTYPE CFX_TxtBreak::GetUnifiedCharType(
95 FX_CHARTYPE chartype) const {
96 return chartype >= FX_CHARTYPE_ArabicAlef ? FX_CHARTYPE_Arabic : chartype;
Dan Sinclair1770c022016-03-14 14:14:16 -040097}
weili1b4f6b32016-08-04 16:37:48 -070098
Dan Sinclair1770c022016-03-14 14:14:16 -040099void CFX_TxtBreak::ResetArabicContext() {
Dan Sinclaira5a3de92017-03-13 10:14:21 -0400100 m_iCurAlignment = m_iAlignment;
Dan Sinclaire533b932017-03-16 11:47:20 -0400101 m_dwContextCharStyles = m_iAlignment;
102 m_dwContextCharStyles |= (m_iArabicContext << 8);
Dan Sinclair1770c022016-03-14 14:14:16 -0400103}
weili1b4f6b32016-08-04 16:37:48 -0700104
Dan Sinclair893822a2017-03-13 15:32:07 -0400105void CFX_TxtBreak::AppendChar_PageLoad(CFX_Char* pCurChar, uint32_t dwProps) {
Dan Sinclairc36fe072017-03-09 16:58:12 -0500106 pCurChar->m_dwStatus = CFX_BreakType::None;
Dan Sinclair1770c022016-03-14 14:14:16 -0400107 pCurChar->m_dwCharStyles = m_dwContextCharStyles;
108}
weili1b4f6b32016-08-04 16:37:48 -0700109
Dan Sinclair893822a2017-03-13 15:32:07 -0400110CFX_BreakType CFX_TxtBreak::AppendChar_Combination(CFX_Char* pCurChar) {
Dan Sinclair812e96c2017-03-13 16:43:37 -0400111 wchar_t wch = pCurChar->m_wCharCode;
112 wchar_t wForm;
Dan Sinclair1770c022016-03-14 14:14:16 -0400113 int32_t iCharWidth = 0;
Dan Sinclair1770c022016-03-14 14:14:16 -0400114 pCurChar->m_iCharWidth = -1;
115 if (m_bCombText) {
116 iCharWidth = m_iCombWidth;
117 } else {
Dan Sinclair068d3442017-03-13 10:15:36 -0400118 wForm = wch;
Dan Sinclair893822a2017-03-13 15:32:07 -0400119 CFX_Char* pLastChar = GetLastChar(0, false);
Dan Sinclair068d3442017-03-13 10:15:36 -0400120 if (pLastChar &&
121 (pLastChar->m_dwCharStyles & FX_TXTCHARSTYLE_ArabicShadda) == 0) {
122 bool bShadda = false;
123 if (wch == 0x0651) {
Dan Sinclair812e96c2017-03-13 16:43:37 -0400124 wchar_t wLast = pLastChar->m_wCharCode;
Dan Sinclair068d3442017-03-13 10:15:36 -0400125 if (wLast >= 0x064C && wLast <= 0x0650) {
126 wForm = FX_GetArabicFromShaddaTable(wLast);
127 bShadda = true;
Dan Sinclair1770c022016-03-14 14:14:16 -0400128 }
Dan Sinclair068d3442017-03-13 10:15:36 -0400129 } else if (wch >= 0x064C && wch <= 0x0650) {
130 if (pLastChar->m_wCharCode == 0x0651) {
131 wForm = FX_GetArabicFromShaddaTable(wch);
132 bShadda = true;
Dan Sinclair52c73c22017-03-09 13:27:29 -0500133 }
Dan Sinclair1770c022016-03-14 14:14:16 -0400134 }
Dan Sinclair068d3442017-03-13 10:15:36 -0400135 if (bShadda) {
136 pLastChar->m_dwCharStyles |= FX_TXTCHARSTYLE_ArabicShadda;
137 pLastChar->m_iCharWidth = 0;
138 pCurChar->m_dwCharStyles |= FX_TXTCHARSTYLE_ArabicShadda;
139 }
Dan Sinclair1770c022016-03-14 14:14:16 -0400140 }
Dan Sinclair068d3442017-03-13 10:15:36 -0400141 if (!m_pFont->GetCharWidth(wForm, iCharWidth, false))
142 iCharWidth = 0;
143
Dan Sinclair1770c022016-03-14 14:14:16 -0400144 iCharWidth *= m_iFontSize;
Dan Sinclaire533b932017-03-16 11:47:20 -0400145 iCharWidth = iCharWidth * m_iHorizontalScale / 100;
Dan Sinclair1770c022016-03-14 14:14:16 -0400146 }
147 pCurChar->m_iCharWidth = -iCharWidth;
Dan Sinclairc36fe072017-03-09 16:58:12 -0500148 return CFX_BreakType::None;
Dan Sinclair1770c022016-03-14 14:14:16 -0400149}
weili1b4f6b32016-08-04 16:37:48 -0700150
Dan Sinclair893822a2017-03-13 15:32:07 -0400151CFX_BreakType CFX_TxtBreak::AppendChar_Tab(CFX_Char* pCurChar) {
weilia2c06e42016-05-20 17:09:48 -0700152 m_eCharType = FX_CHARTYPE_Tab;
Dan Sinclairc36fe072017-03-09 16:58:12 -0500153 return CFX_BreakType::None;
Dan Sinclair1770c022016-03-14 14:14:16 -0400154}
weili1b4f6b32016-08-04 16:37:48 -0700155
Dan Sinclair893822a2017-03-13 15:32:07 -0400156CFX_BreakType CFX_TxtBreak::AppendChar_Control(CFX_Char* pCurChar) {
weilia2c06e42016-05-20 17:09:48 -0700157 m_eCharType = FX_CHARTYPE_Control;
Dan Sinclairc36fe072017-03-09 16:58:12 -0500158 CFX_BreakType dwRet = CFX_BreakType::None;
Dan Sinclair1770c022016-03-14 14:14:16 -0400159 if (!m_bSingleLine) {
Dan Sinclair812e96c2017-03-13 16:43:37 -0400160 wchar_t wch = pCurChar->m_wCharCode;
Dan Sinclair1770c022016-03-14 14:14:16 -0400161 switch (wch) {
162 case L'\v':
163 case 0x2028:
Dan Sinclairc36fe072017-03-09 16:58:12 -0500164 dwRet = CFX_BreakType::Line;
Dan Sinclair1770c022016-03-14 14:14:16 -0400165 break;
166 case L'\f':
Dan Sinclairc36fe072017-03-09 16:58:12 -0500167 dwRet = CFX_BreakType::Page;
Dan Sinclair1770c022016-03-14 14:14:16 -0400168 break;
169 case 0x2029:
Dan Sinclairc36fe072017-03-09 16:58:12 -0500170 dwRet = CFX_BreakType::Paragraph;
Dan Sinclair1770c022016-03-14 14:14:16 -0400171 break;
172 default:
Dan Sinclaire533b932017-03-16 11:47:20 -0400173 if (wch == m_wParagraphBreakChar)
Dan Sinclairc36fe072017-03-09 16:58:12 -0500174 dwRet = CFX_BreakType::Paragraph;
Dan Sinclair1770c022016-03-14 14:14:16 -0400175 break;
176 }
Dan Sinclairc36fe072017-03-09 16:58:12 -0500177 if (dwRet != CFX_BreakType::None)
Dan Sinclair1770c022016-03-14 14:14:16 -0400178 dwRet = EndBreak(dwRet);
Dan Sinclair1770c022016-03-14 14:14:16 -0400179 }
180 return dwRet;
181}
weili1b4f6b32016-08-04 16:37:48 -0700182
Dan Sinclair893822a2017-03-13 15:32:07 -0400183CFX_BreakType CFX_TxtBreak::AppendChar_Arabic(CFX_Char* pCurChar) {
weilia2c06e42016-05-20 17:09:48 -0700184 FX_CHARTYPE chartype = pCurChar->GetCharType();
Dan Sinclair1770c022016-03-14 14:14:16 -0400185 int32_t& iLineWidth = m_pCurLine->m_iWidth;
Dan Sinclair812e96c2017-03-13 16:43:37 -0400186 wchar_t wForm;
Dan Sinclair1770c022016-03-14 14:14:16 -0400187 int32_t iCharWidth = 0;
Dan Sinclair893822a2017-03-13 15:32:07 -0400188 CFX_Char* pLastChar = nullptr;
tsepezd19e9122016-11-02 15:43:18 -0700189 bool bAlef = false;
weilia2c06e42016-05-20 17:09:48 -0700190 if (!m_bCombText && m_eCharType >= FX_CHARTYPE_ArabicAlef &&
191 m_eCharType <= FX_CHARTYPE_ArabicDistortion) {
Dan Sinclair1770c022016-03-14 14:14:16 -0400192 pLastChar = GetLastChar(1);
dsinclair85d1f2c2016-06-23 12:40:16 -0700193 if (pLastChar) {
Dan Sinclair1770c022016-03-14 14:14:16 -0400194 iCharWidth = pLastChar->m_iCharWidth;
Dan Sinclair17f31182017-03-01 09:31:51 -0500195 if (iCharWidth > 0)
Dan Sinclair1770c022016-03-14 14:14:16 -0400196 iLineWidth -= iCharWidth;
Dan Sinclair17f31182017-03-01 09:31:51 -0500197
Dan Sinclair1770c022016-03-14 14:14:16 -0400198 CFX_Char* pPrevChar = GetLastChar(2);
tsepeze00f75c2016-05-06 13:15:46 -0700199 wForm = pdfium::arabic::GetFormChar(pLastChar, pPrevChar, pCurChar);
Dan Sinclair1770c022016-03-14 14:14:16 -0400200 bAlef = (wForm == 0xFEFF &&
201 pLastChar->GetCharType() == FX_CHARTYPE_ArabicAlef);
Dan Sinclair068d3442017-03-13 10:15:36 -0400202 m_pFont->GetCharWidth(wForm, iCharWidth, false);
Dan Sinclair17f31182017-03-01 09:31:51 -0500203
204 if (wForm == 0xFEFF)
Dan Sinclair1770c022016-03-14 14:14:16 -0400205 iCharWidth = m_iDefChar;
Dan Sinclair17f31182017-03-01 09:31:51 -0500206
Dan Sinclair1770c022016-03-14 14:14:16 -0400207 iCharWidth *= m_iFontSize;
Dan Sinclaire533b932017-03-16 11:47:20 -0400208 iCharWidth = iCharWidth * m_iHorizontalScale / 100;
Dan Sinclair1770c022016-03-14 14:14:16 -0400209 pLastChar->m_iCharWidth = iCharWidth;
210 iLineWidth += iCharWidth;
211 iCharWidth = 0;
212 }
213 }
Dan Sinclair17f31182017-03-01 09:31:51 -0500214
weilia2c06e42016-05-20 17:09:48 -0700215 m_eCharType = chartype;
dsinclair85d1f2c2016-06-23 12:40:16 -0700216 wForm = pdfium::arabic::GetFormChar(pCurChar, bAlef ? nullptr : pLastChar,
217 nullptr);
Dan Sinclair1770c022016-03-14 14:14:16 -0400218 if (m_bCombText) {
219 iCharWidth = m_iCombWidth;
220 } else {
Dan Sinclair068d3442017-03-13 10:15:36 -0400221 m_pFont->GetCharWidth(wForm, iCharWidth, false);
Dan Sinclair17f31182017-03-01 09:31:51 -0500222
223 if (wForm == 0xFEFF)
Dan Sinclair1770c022016-03-14 14:14:16 -0400224 iCharWidth = m_iDefChar;
Dan Sinclair17f31182017-03-01 09:31:51 -0500225
Dan Sinclair1770c022016-03-14 14:14:16 -0400226 iCharWidth *= m_iFontSize;
Dan Sinclaire533b932017-03-16 11:47:20 -0400227 iCharWidth = iCharWidth * m_iHorizontalScale / 100;
Dan Sinclair1770c022016-03-14 14:14:16 -0400228 }
229 pCurChar->m_iCharWidth = iCharWidth;
230 iLineWidth += iCharWidth;
231 m_pCurLine->m_iArabicChars++;
Dan Sinclair17f31182017-03-01 09:31:51 -0500232 if (!m_bSingleLine && iLineWidth > m_iLineWidth + m_iTolerance)
Dan Sinclairc36fe072017-03-09 16:58:12 -0500233 return EndBreak(CFX_BreakType::Line);
234 return CFX_BreakType::None;
Dan Sinclair1770c022016-03-14 14:14:16 -0400235}
weili1b4f6b32016-08-04 16:37:48 -0700236
Dan Sinclair893822a2017-03-13 15:32:07 -0400237CFX_BreakType CFX_TxtBreak::AppendChar_Others(CFX_Char* pCurChar) {
weilia2c06e42016-05-20 17:09:48 -0700238 FX_CHARTYPE chartype = pCurChar->GetCharType();
Dan Sinclair1770c022016-03-14 14:14:16 -0400239 int32_t& iLineWidth = m_pCurLine->m_iWidth;
240 int32_t iCharWidth = 0;
weilia2c06e42016-05-20 17:09:48 -0700241 m_eCharType = chartype;
Dan Sinclair812e96c2017-03-13 16:43:37 -0400242 wchar_t wch = pCurChar->m_wCharCode;
243 wchar_t wForm = wch;
Dan Sinclair17f31182017-03-01 09:31:51 -0500244
Dan Sinclair1770c022016-03-14 14:14:16 -0400245 if (m_bCombText) {
246 iCharWidth = m_iCombWidth;
247 } else {
Dan Sinclair068d3442017-03-13 10:15:36 -0400248 if (!m_pFont->GetCharWidth(wForm, iCharWidth, false))
Dan Sinclair1770c022016-03-14 14:14:16 -0400249 iCharWidth = m_iDefChar;
Dan Sinclair17f31182017-03-01 09:31:51 -0500250
Dan Sinclair1770c022016-03-14 14:14:16 -0400251 iCharWidth *= m_iFontSize;
Dan Sinclaire533b932017-03-16 11:47:20 -0400252 iCharWidth = iCharWidth * m_iHorizontalScale / 100;
Dan Sinclair1770c022016-03-14 14:14:16 -0400253 }
Dan Sinclair17f31182017-03-01 09:31:51 -0500254
Dan Sinclair1770c022016-03-14 14:14:16 -0400255 iCharWidth += m_iCharSpace;
256 pCurChar->m_iCharWidth = iCharWidth;
257 iLineWidth += iCharWidth;
Dan Sinclair52c73c22017-03-09 13:27:29 -0500258 if (!m_bSingleLine && chartype != FX_CHARTYPE_Space &&
259 iLineWidth > m_iLineWidth + m_iTolerance) {
Dan Sinclairc36fe072017-03-09 16:58:12 -0500260 return EndBreak(CFX_BreakType::Line);
Dan Sinclair52c73c22017-03-09 13:27:29 -0500261 }
Dan Sinclair17f31182017-03-01 09:31:51 -0500262
Dan Sinclairc36fe072017-03-09 16:58:12 -0500263 return CFX_BreakType::None;
Dan Sinclair1770c022016-03-14 14:14:16 -0400264}
tsepez215507d2016-06-09 19:05:47 -0700265
Dan Sinclair812e96c2017-03-13 16:43:37 -0400266CFX_BreakType CFX_TxtBreak::AppendChar(wchar_t wch) {
Dan Sinclair17f31182017-03-01 09:31:51 -0500267 uint32_t dwProps = kTextLayoutCodeProperties[static_cast<uint16_t>(wch)];
weilia2c06e42016-05-20 17:09:48 -0700268 FX_CHARTYPE chartype = GetCharTypeFromProp(dwProps);
Dan Sinclair52c73c22017-03-09 13:27:29 -0500269 m_pCurLine->m_LineChars.emplace_back();
Dan Sinclair17f31182017-03-01 09:31:51 -0500270
Dan Sinclair893822a2017-03-13 15:32:07 -0400271 CFX_Char* pCurChar = &m_pCurLine->m_LineChars.back();
Dan Sinclair17f31182017-03-01 09:31:51 -0500272 pCurChar->m_wCharCode = static_cast<uint16_t>(wch);
Dan Sinclair1770c022016-03-14 14:14:16 -0400273 pCurChar->m_dwCharProps = dwProps;
274 pCurChar->m_dwCharStyles = 0;
275 pCurChar->m_iCharWidth = 0;
Dan Sinclaire533b932017-03-16 11:47:20 -0400276 pCurChar->m_iHorizontalScale = m_iHorizontalScale;
Dan Sinclair70719432017-02-28 14:48:51 -0500277 pCurChar->m_iVerticalScale = 100;
Dan Sinclairc36fe072017-03-09 16:58:12 -0500278 pCurChar->m_dwStatus = CFX_BreakType::None;
Dan Sinclair1770c022016-03-14 14:14:16 -0400279 pCurChar->m_iBidiClass = 0;
280 pCurChar->m_iBidiLevel = 0;
281 pCurChar->m_iBidiPos = 0;
282 pCurChar->m_iBidiOrder = 0;
Dan Sinclair1c97fd12017-03-09 16:58:55 -0500283
Dan Sinclair1770c022016-03-14 14:14:16 -0400284 AppendChar_PageLoad(pCurChar, dwProps);
Dan Sinclairc36fe072017-03-09 16:58:12 -0500285 CFX_BreakType dwRet1 = CFX_BreakType::None;
weilia2c06e42016-05-20 17:09:48 -0700286 if (chartype != FX_CHARTYPE_Combination &&
Dan Sinclair17f31182017-03-01 09:31:51 -0500287 GetUnifiedCharType(m_eCharType) != GetUnifiedCharType(chartype) &&
288 m_eCharType != FX_CHARTYPE_Unknown &&
289 m_pCurLine->m_iWidth > m_iLineWidth + m_iTolerance && !m_bSingleLine &&
290 (m_eCharType != FX_CHARTYPE_Space || chartype != FX_CHARTYPE_Control)) {
Dan Sinclairc36fe072017-03-09 16:58:12 -0500291 dwRet1 = EndBreak(CFX_BreakType::Line);
Dan Sinclair17f31182017-03-01 09:31:51 -0500292 int32_t iCount = m_pCurLine->CountChars();
293 if (iCount > 0)
Dan Sinclair52c73c22017-03-09 13:27:29 -0500294 pCurChar = &m_pCurLine->m_LineChars[iCount - 1];
Dan Sinclair1770c022016-03-14 14:14:16 -0400295 }
Dan Sinclair17f31182017-03-01 09:31:51 -0500296
Dan Sinclairc36fe072017-03-09 16:58:12 -0500297 CFX_BreakType dwRet2 =
weilia2c06e42016-05-20 17:09:48 -0700298 (this->*g_FX_TxtBreak_lpfAppendChar[chartype >> FX_CHARTYPEBITS])(
Dan Sinclair068d3442017-03-13 10:15:36 -0400299 pCurChar);
Dan Sinclair1770c022016-03-14 14:14:16 -0400300 return std::max(dwRet1, dwRet2);
301}
weili1b4f6b32016-08-04 16:37:48 -0700302
Dan Sinclair893822a2017-03-13 15:32:07 -0400303bool CFX_TxtBreak::EndBreak_SplitLine(CFX_BreakLine* pNextLine,
304 bool bAllChars) {
Dan Sinclair1770c022016-03-14 14:14:16 -0400305 int32_t iCount = m_pCurLine->CountChars();
tsepezd19e9122016-11-02 15:43:18 -0700306 bool bDone = false;
Dan Sinclair893822a2017-03-13 15:32:07 -0400307 CFX_Char* pTC;
Dan Sinclair1770c022016-03-14 14:14:16 -0400308 if (!m_bSingleLine && m_pCurLine->m_iWidth > m_iLineWidth + m_iTolerance) {
Dan Sinclair893822a2017-03-13 15:32:07 -0400309 pTC = m_pCurLine->GetChar(iCount - 1);
Dan Sinclair1770c022016-03-14 14:14:16 -0400310 switch (pTC->GetCharType()) {
311 case FX_CHARTYPE_Tab:
312 case FX_CHARTYPE_Control:
Dan Sinclair1770c022016-03-14 14:14:16 -0400313 case FX_CHARTYPE_Space:
Dan Sinclair1770c022016-03-14 14:14:16 -0400314 break;
315 default:
Dan Sinclair52c73c22017-03-09 13:27:29 -0500316 SplitTextLine(m_pCurLine, pNextLine, bAllChars);
tsepezd19e9122016-11-02 15:43:18 -0700317 bDone = true;
Dan Sinclair1770c022016-03-14 14:14:16 -0400318 break;
319 }
320 }
Dan Sinclair17f31182017-03-01 09:31:51 -0500321
Dan Sinclair1770c022016-03-14 14:14:16 -0400322 iCount = m_pCurLine->CountChars();
Dan Sinclair893822a2017-03-13 15:32:07 -0400323 CFX_BreakPiece tp;
Dan Sinclair1770c022016-03-14 14:14:16 -0400324 if (bAllChars && !bDone) {
325 int32_t iEndPos = m_pCurLine->m_iWidth;
Dan Sinclair52c73c22017-03-09 13:27:29 -0500326 GetBreakPos(m_pCurLine->m_LineChars, iEndPos, bAllChars, true);
Dan Sinclair1770c022016-03-14 14:14:16 -0400327 }
tsepezd19e9122016-11-02 15:43:18 -0700328 return false;
Dan Sinclair1770c022016-03-14 14:14:16 -0400329}
weili1b4f6b32016-08-04 16:37:48 -0700330
Tom Sepez4a211142017-03-01 14:41:25 -0800331void CFX_TxtBreak::EndBreak_BidiLine(std::deque<FX_TPO>* tpos,
Dan Sinclairc36fe072017-03-09 16:58:12 -0500332 CFX_BreakType dwStatus) {
Dan Sinclair893822a2017-03-13 15:32:07 -0400333 CFX_BreakPiece tp;
Dan Sinclair1770c022016-03-14 14:14:16 -0400334 FX_TPO tpo;
Dan Sinclair893822a2017-03-13 15:32:07 -0400335 CFX_Char* pTC;
Dan Sinclair17f31182017-03-01 09:31:51 -0500336 int32_t i;
337 int32_t j;
Dan Sinclair893822a2017-03-13 15:32:07 -0400338 std::vector<CFX_Char>& chars = m_pCurLine->m_LineChars;
Dan Sinclair1770c022016-03-14 14:14:16 -0400339 int32_t iCount = m_pCurLine->CountChars();
Dan Sinclaira5a3de92017-03-13 10:14:21 -0400340 bool bDone = m_pCurLine->m_iArabicChars > 0;
Dan Sinclair52c73c22017-03-09 13:27:29 -0500341 if (bDone) {
Dan Sinclair1770c022016-03-14 14:14:16 -0400342 int32_t iBidiNum = 0;
343 for (i = 0; i < iCount; i++) {
tsepez33316fc2017-01-24 12:17:40 -0800344 pTC = &chars[i];
Dan Sinclair1770c022016-03-14 14:14:16 -0400345 pTC->m_iBidiPos = i;
Dan Sinclair17f31182017-03-01 09:31:51 -0500346 if (pTC->GetCharType() != FX_CHARTYPE_Control)
Dan Sinclair1770c022016-03-14 14:14:16 -0400347 iBidiNum = i;
Dan Sinclair17f31182017-03-01 09:31:51 -0500348 if (i == 0)
Dan Sinclair1770c022016-03-14 14:14:16 -0400349 pTC->m_iBidiLevel = 1;
Dan Sinclair1770c022016-03-14 14:14:16 -0400350 }
Dan Sinclair42059a32017-03-15 12:22:48 -0400351 FX_BidiLine(&chars, iBidiNum + 1);
Dan Sinclair1770c022016-03-14 14:14:16 -0400352 }
Dan Sinclair17f31182017-03-01 09:31:51 -0500353
Dan Sinclaira5a3de92017-03-13 10:14:21 -0400354 if (bDone) {
Dan Sinclairc36fe072017-03-09 16:58:12 -0500355 tp.m_dwStatus = CFX_BreakType::Piece;
Dan Sinclair1770c022016-03-14 14:14:16 -0400356 tp.m_iStartPos = m_pCurLine->m_iStart;
Dan Sinclair52c73c22017-03-09 13:27:29 -0500357 tp.m_pChars = &m_pCurLine->m_LineChars;
Dan Sinclair17f31182017-03-01 09:31:51 -0500358 int32_t iBidiLevel = -1;
359 int32_t iCharWidth;
360 i = 0;
361 j = -1;
Dan Sinclair1770c022016-03-14 14:14:16 -0400362 while (i < iCount) {
tsepez33316fc2017-01-24 12:17:40 -0800363 pTC = &chars[i];
Dan Sinclair1770c022016-03-14 14:14:16 -0400364 if (iBidiLevel < 0) {
365 iBidiLevel = pTC->m_iBidiLevel;
366 tp.m_iWidth = 0;
367 tp.m_iBidiLevel = iBidiLevel;
368 tp.m_iBidiPos = pTC->m_iBidiOrder;
369 tp.m_dwCharStyles = pTC->m_dwCharStyles;
Dan Sinclair1770c022016-03-14 14:14:16 -0400370 tp.m_iHorizontalScale = pTC->m_iHorizontalScale;
Dan Sinclair70719432017-02-28 14:48:51 -0500371 tp.m_iVerticalScale = pTC->m_iVerticalScale;
Dan Sinclairc36fe072017-03-09 16:58:12 -0500372 tp.m_dwStatus = CFX_BreakType::Piece;
Dan Sinclair1770c022016-03-14 14:14:16 -0400373 }
Dan Sinclairc36fe072017-03-09 16:58:12 -0500374 if (iBidiLevel != pTC->m_iBidiLevel ||
375 pTC->m_dwStatus != CFX_BreakType::None) {
Dan Sinclair1770c022016-03-14 14:14:16 -0400376 if (iBidiLevel == pTC->m_iBidiLevel) {
377 tp.m_dwStatus = pTC->m_dwStatus;
378 iCharWidth = pTC->m_iCharWidth;
Dan Sinclair17f31182017-03-01 09:31:51 -0500379 if (iCharWidth > 0)
Dan Sinclair1770c022016-03-14 14:14:16 -0400380 tp.m_iWidth += iCharWidth;
Dan Sinclair17f31182017-03-01 09:31:51 -0500381
Dan Sinclair1770c022016-03-14 14:14:16 -0400382 i++;
383 }
384 tp.m_iChars = i - tp.m_iStartChar;
dan sinclair6fcea1f2017-03-13 13:06:05 -0400385 m_pCurLine->m_LinePieces.push_back(tp);
Dan Sinclair1770c022016-03-14 14:14:16 -0400386 tp.m_iStartPos += tp.m_iWidth;
387 tp.m_iStartChar = i;
388 tpo.index = ++j;
389 tpo.pos = tp.m_iBidiPos;
Tom Sepez4a211142017-03-01 14:41:25 -0800390 tpos->push_back(tpo);
Dan Sinclair1770c022016-03-14 14:14:16 -0400391 iBidiLevel = -1;
392 } else {
393 iCharWidth = pTC->m_iCharWidth;
Dan Sinclair17f31182017-03-01 09:31:51 -0500394 if (iCharWidth > 0)
Dan Sinclair1770c022016-03-14 14:14:16 -0400395 tp.m_iWidth += iCharWidth;
Dan Sinclair17f31182017-03-01 09:31:51 -0500396
Dan Sinclair1770c022016-03-14 14:14:16 -0400397 i++;
398 }
399 }
400 if (i > tp.m_iStartChar) {
401 tp.m_dwStatus = dwStatus;
402 tp.m_iChars = i - tp.m_iStartChar;
dan sinclair6fcea1f2017-03-13 13:06:05 -0400403 m_pCurLine->m_LinePieces.push_back(tp);
Dan Sinclair1770c022016-03-14 14:14:16 -0400404 tpo.index = ++j;
405 tpo.pos = tp.m_iBidiPos;
Tom Sepez4a211142017-03-01 14:41:25 -0800406 tpos->push_back(tpo);
Dan Sinclair1770c022016-03-14 14:14:16 -0400407 }
408 if (j > -1) {
409 if (j > 0) {
Tom Sepez4a211142017-03-01 14:41:25 -0800410 std::sort(tpos->begin(), tpos->end());
Dan Sinclair1770c022016-03-14 14:14:16 -0400411 int32_t iStartPos = 0;
412 for (i = 0; i <= j; i++) {
Tom Sepez4a211142017-03-01 14:41:25 -0800413 tpo = (*tpos)[i];
Dan Sinclair893822a2017-03-13 15:32:07 -0400414 CFX_BreakPiece& ttp = m_pCurLine->m_LinePieces[tpo.index];
Dan Sinclair1770c022016-03-14 14:14:16 -0400415 ttp.m_iStartPos = iStartPos;
416 iStartPos += ttp.m_iWidth;
417 }
418 }
dan sinclair6fcea1f2017-03-13 13:06:05 -0400419 m_pCurLine->m_LinePieces[j].m_dwStatus = dwStatus;
Dan Sinclair1770c022016-03-14 14:14:16 -0400420 }
421 } else {
422 tp.m_dwStatus = dwStatus;
423 tp.m_iStartPos = m_pCurLine->m_iStart;
424 tp.m_iWidth = m_pCurLine->m_iWidth;
425 tp.m_iStartChar = 0;
426 tp.m_iChars = iCount;
Dan Sinclair52c73c22017-03-09 13:27:29 -0500427 tp.m_pChars = &m_pCurLine->m_LineChars;
tsepez33316fc2017-01-24 12:17:40 -0800428 pTC = &chars[0];
Dan Sinclair1770c022016-03-14 14:14:16 -0400429 tp.m_dwCharStyles = pTC->m_dwCharStyles;
430 tp.m_iHorizontalScale = pTC->m_iHorizontalScale;
Dan Sinclair70719432017-02-28 14:48:51 -0500431 tp.m_iVerticalScale = pTC->m_iVerticalScale;
dan sinclair6fcea1f2017-03-13 13:06:05 -0400432 m_pCurLine->m_LinePieces.push_back(tp);
Tom Sepez4a211142017-03-01 14:41:25 -0800433 tpos->push_back({0, 0});
Dan Sinclair1770c022016-03-14 14:14:16 -0400434 }
435}
weili1b4f6b32016-08-04 16:37:48 -0700436
Tom Sepez4a211142017-03-01 14:41:25 -0800437void CFX_TxtBreak::EndBreak_Alignment(const std::deque<FX_TPO>& tpos,
tsepezd19e9122016-11-02 15:43:18 -0700438 bool bAllChars,
Dan Sinclairc36fe072017-03-09 16:58:12 -0500439 CFX_BreakType dwStatus) {
Dan Sinclair17f31182017-03-01 09:31:51 -0500440 int32_t iNetWidth = m_pCurLine->m_iWidth;
441 int32_t iGapChars = 0;
tsepezd19e9122016-11-02 15:43:18 -0700442 bool bFind = false;
dan sinclair6fcea1f2017-03-13 13:06:05 -0400443 for (auto it = tpos.rbegin(); it != tpos.rend(); ++it) {
Dan Sinclair893822a2017-03-13 15:32:07 -0400444 CFX_BreakPiece& ttp = m_pCurLine->m_LinePieces[it->index];
Dan Sinclair17f31182017-03-01 09:31:51 -0500445 if (!bFind)
Dan Sinclair1770c022016-03-14 14:14:16 -0400446 iNetWidth = ttp.GetEndPos();
Dan Sinclair17f31182017-03-01 09:31:51 -0500447
tsepezd19e9122016-11-02 15:43:18 -0700448 bool bArabic = FX_IsOdd(ttp.m_iBidiLevel);
dan sinclair6fcea1f2017-03-13 13:06:05 -0400449 int32_t j = bArabic ? 0 : ttp.m_iChars - 1;
Dan Sinclair1770c022016-03-14 14:14:16 -0400450 while (j > -1 && j < ttp.m_iChars) {
Dan Sinclair893822a2017-03-13 15:32:07 -0400451 const CFX_Char* pTC = ttp.GetChar(j);
452 if (pTC->m_nBreakType == FX_LBT_DIRECT_BRK)
Dan Sinclair1770c022016-03-14 14:14:16 -0400453 iGapChars++;
Dan Sinclair1770c022016-03-14 14:14:16 -0400454 if (!bFind || !bAllChars) {
Dan Sinclair893822a2017-03-13 15:32:07 -0400455 FX_CHARTYPE chartype = pTC->GetCharType();
weilia2c06e42016-05-20 17:09:48 -0700456 if (chartype == FX_CHARTYPE_Space || chartype == FX_CHARTYPE_Control) {
Dan Sinclair893822a2017-03-13 15:32:07 -0400457 if (!bFind && bAllChars && pTC->m_iCharWidth > 0)
458 iNetWidth -= pTC->m_iCharWidth;
Dan Sinclair1770c022016-03-14 14:14:16 -0400459 } else {
tsepezd19e9122016-11-02 15:43:18 -0700460 bFind = true;
Dan Sinclair17f31182017-03-01 09:31:51 -0500461 if (!bAllChars)
Dan Sinclair1770c022016-03-14 14:14:16 -0400462 break;
Dan Sinclair1770c022016-03-14 14:14:16 -0400463 }
464 }
465 j += bArabic ? 1 : -1;
466 }
Dan Sinclair17f31182017-03-01 09:31:51 -0500467 if (!bAllChars && bFind)
Dan Sinclair1770c022016-03-14 14:14:16 -0400468 break;
Dan Sinclair1770c022016-03-14 14:14:16 -0400469 }
Dan Sinclair17f31182017-03-01 09:31:51 -0500470
Dan Sinclair1770c022016-03-14 14:14:16 -0400471 int32_t iOffset = m_iLineWidth - iNetWidth;
Dan Sinclair9e9bab62017-03-09 16:59:12 -0500472 if (iGapChars > 0 && m_iCurAlignment & CFX_TxtLineAlignment_Justified &&
473 dwStatus != CFX_BreakType::Paragraph) {
Dan Sinclair1770c022016-03-14 14:14:16 -0400474 int32_t iStart = -1;
dan sinclair6fcea1f2017-03-13 13:06:05 -0400475 for (auto& tpo : tpos) {
Dan Sinclair893822a2017-03-13 15:32:07 -0400476 CFX_BreakPiece& ttp = m_pCurLine->m_LinePieces[tpo.index];
Dan Sinclair17f31182017-03-01 09:31:51 -0500477 if (iStart < -1)
Dan Sinclair1770c022016-03-14 14:14:16 -0400478 iStart = ttp.m_iStartPos;
Dan Sinclair17f31182017-03-01 09:31:51 -0500479 else
Dan Sinclair1770c022016-03-14 14:14:16 -0400480 ttp.m_iStartPos = iStart;
Dan Sinclair17f31182017-03-01 09:31:51 -0500481
dan sinclair6fcea1f2017-03-13 13:06:05 -0400482 for (int32_t j = 0; j < ttp.m_iChars; j++) {
Dan Sinclair893822a2017-03-13 15:32:07 -0400483 CFX_Char* pTC = ttp.GetChar(j);
484 if (pTC->m_nBreakType != FX_LBT_DIRECT_BRK || pTC->m_iCharWidth < 0)
Dan Sinclair1770c022016-03-14 14:14:16 -0400485 continue;
Dan Sinclair17f31182017-03-01 09:31:51 -0500486
487 int32_t k = iOffset / iGapChars;
Dan Sinclair893822a2017-03-13 15:32:07 -0400488 pTC->m_iCharWidth += k;
Dan Sinclair1770c022016-03-14 14:14:16 -0400489 ttp.m_iWidth += k;
490 iOffset -= k;
491 iGapChars--;
Dan Sinclair17f31182017-03-01 09:31:51 -0500492 if (iGapChars < 1)
Dan Sinclair1770c022016-03-14 14:14:16 -0400493 break;
Dan Sinclair1770c022016-03-14 14:14:16 -0400494 }
495 iStart += ttp.m_iWidth;
496 }
Dan Sinclair9e9bab62017-03-09 16:59:12 -0500497 } else if (m_iCurAlignment & CFX_TxtLineAlignment_Center ||
498 m_iCurAlignment & CFX_TxtLineAlignment_Right) {
499 if (m_iCurAlignment & CFX_TxtLineAlignment_Center &&
500 !(m_iCurAlignment & CFX_TxtLineAlignment_Right)) {
Dan Sinclair1770c022016-03-14 14:14:16 -0400501 iOffset /= 2;
Dan Sinclair9e9bab62017-03-09 16:59:12 -0500502 }
Dan Sinclair1770c022016-03-14 14:14:16 -0400503 if (iOffset > 0) {
dan sinclair6fcea1f2017-03-13 13:06:05 -0400504 for (auto& ttp : m_pCurLine->m_LinePieces)
Dan Sinclair1770c022016-03-14 14:14:16 -0400505 ttp.m_iStartPos += iOffset;
Dan Sinclair1770c022016-03-14 14:14:16 -0400506 }
507 }
508}
weili1b4f6b32016-08-04 16:37:48 -0700509
Dan Sinclairc36fe072017-03-09 16:58:12 -0500510CFX_BreakType CFX_TxtBreak::EndBreak(CFX_BreakType dwStatus) {
511 ASSERT(dwStatus != CFX_BreakType::None);
dan sinclair6fcea1f2017-03-13 13:06:05 -0400512
513 if (!m_pCurLine->m_LinePieces.empty()) {
Dan Sinclairc36fe072017-03-09 16:58:12 -0500514 if (dwStatus != CFX_BreakType::Piece)
dan sinclair6fcea1f2017-03-13 13:06:05 -0400515 m_pCurLine->m_LinePieces.back().m_dwStatus = dwStatus;
516 return m_pCurLine->m_LinePieces.back().m_dwStatus;
Dan Sinclair1770c022016-03-14 14:14:16 -0400517 }
Dan Sinclair17f31182017-03-01 09:31:51 -0500518
dan sinclair6fcea1f2017-03-13 13:06:05 -0400519 if (HasTxtLine()) {
Dan Sinclaire533b932017-03-16 11:47:20 -0400520 if (!m_Line[m_iReadyLineIndex].m_LinePieces.empty()) {
dan sinclair6fcea1f2017-03-13 13:06:05 -0400521 if (dwStatus != CFX_BreakType::Piece)
Dan Sinclaire533b932017-03-16 11:47:20 -0400522 m_Line[m_iReadyLineIndex].m_LinePieces.back().m_dwStatus = dwStatus;
523 return m_Line[m_iReadyLineIndex].m_LinePieces.back().m_dwStatus;
dan sinclair6fcea1f2017-03-13 13:06:05 -0400524 }
525 return CFX_BreakType::None;
526 }
527
528 int32_t iCount = m_pCurLine->CountChars();
529 if (iCount < 1)
530 return CFX_BreakType::None;
531
Dan Sinclair893822a2017-03-13 15:32:07 -0400532 m_pCurLine->GetChar(iCount - 1)->m_dwStatus = dwStatus;
dan sinclair6fcea1f2017-03-13 13:06:05 -0400533 if (dwStatus == CFX_BreakType::Piece)
534 return dwStatus;
535
Dan Sinclaire533b932017-03-16 11:47:20 -0400536 m_iReadyLineIndex = m_pCurLine == &m_Line[0] ? 0 : 1;
537 CFX_BreakLine* pNextLine = &m_Line[1 - m_iReadyLineIndex];
Dan Sinclair9e9bab62017-03-09 16:59:12 -0500538 bool bAllChars = m_iCurAlignment > CFX_TxtLineAlignment_Right;
Dan Sinclairc36fe072017-03-09 16:58:12 -0500539 if (!EndBreak_SplitLine(pNextLine, bAllChars)) {
Tom Sepez4a211142017-03-01 14:41:25 -0800540 std::deque<FX_TPO> tpos;
541 EndBreak_BidiLine(&tpos, dwStatus);
Dan Sinclair9e9bab62017-03-09 16:59:12 -0500542 if (m_iCurAlignment > CFX_TxtLineAlignment_Left)
Dan Sinclair17f31182017-03-01 09:31:51 -0500543 EndBreak_Alignment(tpos, bAllChars, dwStatus);
Dan Sinclair1770c022016-03-14 14:14:16 -0400544 }
Dan Sinclair17f31182017-03-01 09:31:51 -0500545
Dan Sinclair1770c022016-03-14 14:14:16 -0400546 m_pCurLine = pNextLine;
Tom Sepez4a211142017-03-01 14:41:25 -0800547 CFX_Char* pTC = GetLastChar(0, false);
weilia2c06e42016-05-20 17:09:48 -0700548 m_eCharType = pTC ? pTC->GetCharType() : FX_CHARTYPE_Unknown;
Dan Sinclairc36fe072017-03-09 16:58:12 -0500549 if (dwStatus == CFX_BreakType::Paragraph) {
Dan Sinclair1770c022016-03-14 14:14:16 -0400550 m_iArabicContext = m_iCurArabicContext = 1;
551 ResetArabicContext();
552 }
553 return dwStatus;
554}
weili1b4f6b32016-08-04 16:37:48 -0700555
Dan Sinclair893822a2017-03-13 15:32:07 -0400556int32_t CFX_TxtBreak::GetBreakPos(std::vector<CFX_Char>& ca,
Dan Sinclair1770c022016-03-14 14:14:16 -0400557 int32_t& iEndPos,
tsepezd19e9122016-11-02 15:43:18 -0700558 bool bAllChars,
559 bool bOnlyBrk) {
tsepez33316fc2017-01-24 12:17:40 -0800560 int32_t iLength = pdfium::CollectionSize<int32_t>(ca) - 1;
Dan Sinclair17f31182017-03-01 09:31:51 -0500561 if (iLength < 1)
Dan Sinclair1770c022016-03-14 14:14:16 -0400562 return iLength;
Dan Sinclair17f31182017-03-01 09:31:51 -0500563
564 int32_t iBreak = -1;
565 int32_t iBreakPos = -1;
566 int32_t iIndirect = -1;
567 int32_t iIndirectPos = -1;
568 int32_t iLast = -1;
569 int32_t iLastPos = -1;
Dan Sinclair1770c022016-03-14 14:14:16 -0400570 if (m_bSingleLine || iEndPos <= m_iLineWidth) {
Dan Sinclair17f31182017-03-01 09:31:51 -0500571 if (!bAllChars)
Dan Sinclair1770c022016-03-14 14:14:16 -0400572 return iLength;
Dan Sinclair17f31182017-03-01 09:31:51 -0500573
Dan Sinclair1770c022016-03-14 14:14:16 -0400574 iBreak = iLength;
575 iBreakPos = iEndPos;
576 }
Dan Sinclair17f31182017-03-01 09:31:51 -0500577
Dan Sinclair1770c022016-03-14 14:14:16 -0400578 FX_LINEBREAKTYPE eType;
Dan Sinclair17f31182017-03-01 09:31:51 -0500579 uint32_t nCodeProp;
580 uint32_t nCur;
581 uint32_t nNext;
tsepez33316fc2017-01-24 12:17:40 -0800582 CFX_Char* pCur = &ca[iLength--];
Dan Sinclair17f31182017-03-01 09:31:51 -0500583 if (bAllChars)
Dan Sinclair1770c022016-03-14 14:14:16 -0400584 pCur->m_nBreakType = FX_LBT_UNKNOWN;
Dan Sinclair17f31182017-03-01 09:31:51 -0500585
Dan Sinclair1770c022016-03-14 14:14:16 -0400586 nCodeProp = pCur->m_dwCharProps;
587 nNext = nCodeProp & 0x003F;
588 int32_t iCharWidth = pCur->m_iCharWidth;
Dan Sinclair17f31182017-03-01 09:31:51 -0500589 if (iCharWidth > 0)
Dan Sinclair1770c022016-03-14 14:14:16 -0400590 iEndPos -= iCharWidth;
Dan Sinclair17f31182017-03-01 09:31:51 -0500591
Dan Sinclair1770c022016-03-14 14:14:16 -0400592 while (iLength >= 0) {
tsepez33316fc2017-01-24 12:17:40 -0800593 pCur = &ca[iLength];
Dan Sinclair1770c022016-03-14 14:14:16 -0400594 nCodeProp = pCur->m_dwCharProps;
595 nCur = nCodeProp & 0x003F;
596 if (nCur == FX_CBP_SP) {
Dan Sinclair17f31182017-03-01 09:31:51 -0500597 if (nNext == FX_CBP_SP)
Dan Sinclair52c73c22017-03-09 13:27:29 -0500598 eType = FX_LBT_PROHIBITED_BRK;
Dan Sinclair17f31182017-03-01 09:31:51 -0500599 else
tsepezf49747f2016-06-10 15:24:47 -0700600 eType = gs_FX_LineBreak_PairTable[nCur][nNext];
Dan Sinclair1770c022016-03-14 14:14:16 -0400601 } else {
Dan Sinclair17f31182017-03-01 09:31:51 -0500602 if (nNext == FX_CBP_SP)
Dan Sinclair1770c022016-03-14 14:14:16 -0400603 eType = FX_LBT_PROHIBITED_BRK;
Dan Sinclair17f31182017-03-01 09:31:51 -0500604 else
tsepezf49747f2016-06-10 15:24:47 -0700605 eType = gs_FX_LineBreak_PairTable[nCur][nNext];
Dan Sinclair1770c022016-03-14 14:14:16 -0400606 }
Dan Sinclair17f31182017-03-01 09:31:51 -0500607 if (bAllChars)
608 pCur->m_nBreakType = static_cast<uint8_t>(eType);
Dan Sinclair1770c022016-03-14 14:14:16 -0400609 if (!bOnlyBrk) {
Dan Sinclair52c73c22017-03-09 13:27:29 -0500610 if (m_bSingleLine || iEndPos <= m_iLineWidth || nCur == FX_CBP_SP) {
Dan Sinclair1770c022016-03-14 14:14:16 -0400611 if (eType == FX_LBT_DIRECT_BRK && iBreak < 0) {
612 iBreak = iLength;
613 iBreakPos = iEndPos;
Dan Sinclair17f31182017-03-01 09:31:51 -0500614 if (!bAllChars)
Dan Sinclair1770c022016-03-14 14:14:16 -0400615 return iLength;
Dan Sinclair1770c022016-03-14 14:14:16 -0400616 } else if (eType == FX_LBT_INDIRECT_BRK && iIndirect < 0) {
617 iIndirect = iLength;
618 iIndirectPos = iEndPos;
619 }
620 if (iLast < 0) {
621 iLast = iLength;
622 iLastPos = iEndPos;
623 }
624 }
625 iCharWidth = pCur->m_iCharWidth;
Dan Sinclair17f31182017-03-01 09:31:51 -0500626 if (iCharWidth > 0)
Dan Sinclair1770c022016-03-14 14:14:16 -0400627 iEndPos -= iCharWidth;
Dan Sinclair1770c022016-03-14 14:14:16 -0400628 }
629 nNext = nCodeProp & 0x003F;
630 iLength--;
631 }
Dan Sinclair17f31182017-03-01 09:31:51 -0500632 if (bOnlyBrk)
Dan Sinclair1770c022016-03-14 14:14:16 -0400633 return 0;
Dan Sinclair1770c022016-03-14 14:14:16 -0400634 if (iBreak > -1) {
635 iEndPos = iBreakPos;
636 return iBreak;
637 }
638 if (iIndirect > -1) {
639 iEndPos = iIndirectPos;
640 return iIndirect;
641 }
642 if (iLast > -1) {
643 iEndPos = iLastPos;
644 return iLast;
645 }
646 return 0;
647}
weili1b4f6b32016-08-04 16:37:48 -0700648
Dan Sinclair893822a2017-03-13 15:32:07 -0400649void CFX_TxtBreak::SplitTextLine(CFX_BreakLine* pCurLine,
650 CFX_BreakLine* pNextLine,
tsepezd19e9122016-11-02 15:43:18 -0700651 bool bAllChars) {
dsinclair85d1f2c2016-06-23 12:40:16 -0700652 ASSERT(pCurLine && pNextLine);
Dan Sinclair1770c022016-03-14 14:14:16 -0400653 int32_t iCount = pCurLine->CountChars();
Dan Sinclair17f31182017-03-01 09:31:51 -0500654 if (iCount < 2)
Dan Sinclair1770c022016-03-14 14:14:16 -0400655 return;
Dan Sinclair17f31182017-03-01 09:31:51 -0500656
Dan Sinclair1770c022016-03-14 14:14:16 -0400657 int32_t iEndPos = pCurLine->m_iWidth;
Dan Sinclair893822a2017-03-13 15:32:07 -0400658 std::vector<CFX_Char>& curChars = pCurLine->m_LineChars;
tsepezd19e9122016-11-02 15:43:18 -0700659 int32_t iCharPos = GetBreakPos(curChars, iEndPos, bAllChars, false);
Dan Sinclair17f31182017-03-01 09:31:51 -0500660 if (iCharPos < 0)
Dan Sinclair1770c022016-03-14 14:14:16 -0400661 iCharPos = 0;
Dan Sinclair17f31182017-03-01 09:31:51 -0500662
Dan Sinclair1770c022016-03-14 14:14:16 -0400663 iCharPos++;
664 if (iCharPos >= iCount) {
dan sinclair6fcea1f2017-03-13 13:06:05 -0400665 pNextLine->Clear();
tsepez33316fc2017-01-24 12:17:40 -0800666 CFX_Char* pTC = &curChars[iCharPos - 1];
Dan Sinclair1770c022016-03-14 14:14:16 -0400667 pTC->m_nBreakType = FX_LBT_UNKNOWN;
668 return;
669 }
Dan Sinclair17f31182017-03-01 09:31:51 -0500670
Dan Sinclair52c73c22017-03-09 13:27:29 -0500671 pNextLine->m_LineChars =
Dan Sinclair893822a2017-03-13 15:32:07 -0400672 std::vector<CFX_Char>(curChars.begin() + iCharPos, curChars.end());
tsepez33316fc2017-01-24 12:17:40 -0800673 curChars.erase(curChars.begin() + iCharPos, curChars.end());
Dan Sinclair1770c022016-03-14 14:14:16 -0400674 pCurLine->m_iWidth = iEndPos;
Dan Sinclair893822a2017-03-13 15:32:07 -0400675 CFX_Char* pTC = &curChars[iCharPos - 1];
Dan Sinclair1770c022016-03-14 14:14:16 -0400676 pTC->m_nBreakType = FX_LBT_UNKNOWN;
Dan Sinclair52c73c22017-03-09 13:27:29 -0500677 iCount = pdfium::CollectionSize<int>(pNextLine->m_LineChars);
tsepez33316fc2017-01-24 12:17:40 -0800678 int32_t iWidth = 0;
Dan Sinclair1770c022016-03-14 14:14:16 -0400679 for (int32_t i = 0; i < iCount; i++) {
Dan Sinclair52c73c22017-03-09 13:27:29 -0500680 if (pNextLine->m_LineChars[i].GetCharType() >= FX_CHARTYPE_ArabicAlef) {
Dan Sinclair1770c022016-03-14 14:14:16 -0400681 pCurLine->m_iArabicChars--;
682 pNextLine->m_iArabicChars++;
683 }
Dan Sinclair52c73c22017-03-09 13:27:29 -0500684 iWidth += std::max(0, pNextLine->m_LineChars[i].m_iCharWidth);
Dan Sinclairc36fe072017-03-09 16:58:12 -0500685 pNextLine->m_LineChars[i].m_dwStatus = CFX_BreakType::None;
Dan Sinclair1770c022016-03-14 14:14:16 -0400686 }
687 pNextLine->m_iWidth = iWidth;
688}
weili1b4f6b32016-08-04 16:37:48 -0700689
Dan Sinclair1770c022016-03-14 14:14:16 -0400690int32_t CFX_TxtBreak::CountBreakPieces() const {
dan sinclair6fcea1f2017-03-13 13:06:05 -0400691 return HasTxtLine() ? pdfium::CollectionSize<int32_t>(
Dan Sinclaire533b932017-03-16 11:47:20 -0400692 m_Line[m_iReadyLineIndex].m_LinePieces)
dan sinclair6fcea1f2017-03-13 13:06:05 -0400693 : 0;
Dan Sinclair1770c022016-03-14 14:14:16 -0400694}
weili1b4f6b32016-08-04 16:37:48 -0700695
Dan Sinclair893822a2017-03-13 15:32:07 -0400696const CFX_BreakPiece* CFX_TxtBreak::GetBreakPiece(int32_t index) const {
dan sinclair8f03b422017-03-13 12:30:42 -0400697 if (!HasTxtLine())
dsinclair85d1f2c2016-06-23 12:40:16 -0700698 return nullptr;
Tom Sepez193e6ca2017-03-14 15:53:36 -0700699
Dan Sinclaire533b932017-03-16 11:47:20 -0400700 if (!pdfium::IndexInBounds(m_Line[m_iReadyLineIndex].m_LinePieces, index))
dsinclair85d1f2c2016-06-23 12:40:16 -0700701 return nullptr;
Tom Sepez193e6ca2017-03-14 15:53:36 -0700702
Dan Sinclaire533b932017-03-16 11:47:20 -0400703 return &m_Line[m_iReadyLineIndex].m_LinePieces[index];
Dan Sinclair1770c022016-03-14 14:14:16 -0400704}
weili1b4f6b32016-08-04 16:37:48 -0700705
Dan Sinclair1770c022016-03-14 14:14:16 -0400706void CFX_TxtBreak::ClearBreakPieces() {
dan sinclair8f03b422017-03-13 12:30:42 -0400707 if (HasTxtLine())
Dan Sinclaire533b932017-03-16 11:47:20 -0400708 m_Line[m_iReadyLineIndex].Clear();
dan sinclair8f03b422017-03-13 12:30:42 -0400709 m_iReadyLineIndex = -1;
Dan Sinclair1770c022016-03-14 14:14:16 -0400710}
weili1b4f6b32016-08-04 16:37:48 -0700711
Dan Sinclair1770c022016-03-14 14:14:16 -0400712void CFX_TxtBreak::Reset() {
weilia2c06e42016-05-20 17:09:48 -0700713 m_eCharType = FX_CHARTYPE_Unknown;
Dan Sinclair17f31182017-03-01 09:31:51 -0500714 m_iArabicContext = 1;
715 m_iCurArabicContext = 1;
Dan Sinclair1770c022016-03-14 14:14:16 -0400716 ResetArabicContext();
Dan Sinclaire533b932017-03-16 11:47:20 -0400717 m_Line[0].Clear();
718 m_Line[1].Clear();
Dan Sinclair1770c022016-03-14 14:14:16 -0400719}
720
721struct FX_FORMCHAR {
Tom Sepez62a70f92016-03-21 15:00:20 -0700722 uint16_t wch;
723 uint16_t wForm;
Dan Sinclair1770c022016-03-14 14:14:16 -0400724 int32_t iWidth;
725};
726
727int32_t CFX_TxtBreak::GetDisplayPos(const FX_TXTRUN* pTxtRun,
728 FXTEXT_CHARPOS* pCharPos,
tsepezd19e9122016-11-02 15:43:18 -0700729 bool bCharCode,
Tom Sepeze65d62c2017-03-01 13:18:50 -0800730 CFX_WideString* pWSForms) const {
Dan Sinclair17f31182017-03-01 09:31:51 -0500731 if (!pTxtRun || pTxtRun->iLength < 1)
Dan Sinclair1770c022016-03-14 14:14:16 -0400732 return 0;
Dan Sinclair17f31182017-03-01 09:31:51 -0500733
Dan Sinclair575898e2017-03-13 10:16:05 -0400734 CFDE_TxtEdtPage* pAccess = pTxtRun->pAccess;
dsinclair705f8292016-06-07 10:10:45 -0700735 const FDE_TEXTEDITPIECE* pIdentity = pTxtRun->pIdentity;
Dan Sinclair812e96c2017-03-13 16:43:37 -0400736 const wchar_t* pStr = pTxtRun->wsStr.c_str();
Dan Sinclair1770c022016-03-14 14:14:16 -0400737 int32_t* pWidths = pTxtRun->pWidths;
738 int32_t iLength = pTxtRun->iLength - 1;
tsepeze6477992017-01-05 12:57:00 -0800739 CFX_RetainPtr<CFGAS_GEFont> pFont = pTxtRun->pFont;
tsepez736f28a2016-03-25 14:19:51 -0700740 uint32_t dwStyles = pTxtRun->dwStyles;
Dan Sinclair1770c022016-03-14 14:14:16 -0400741 CFX_RectF rtText(*pTxtRun->pRect);
tsepezd19e9122016-11-02 15:43:18 -0700742 bool bRTLPiece = (pTxtRun->dwCharStyles & FX_TXTCHARSTYLE_OddBidiLevel) != 0;
Dan Sinclair05df0752017-03-14 14:43:42 -0400743 float fFontSize = pTxtRun->fFontSize;
Dan Sinclair1770c022016-03-14 14:14:16 -0400744 int32_t iFontSize = FXSYS_round(fFontSize * 20.0f);
745 int32_t iAscent = pFont->GetAscent();
746 int32_t iDescent = pFont->GetDescent();
747 int32_t iMaxHeight = iAscent - iDescent;
Dan Sinclair05df0752017-03-14 14:43:42 -0400748 float fFontHeight = fFontSize;
749 float fAscent = fFontHeight * (float)iAscent / (float)iMaxHeight;
750 float fX = rtText.left;
751 float fY;
752 float fCharWidth;
753 float fCharHeight;
Dan Sinclair1770c022016-03-14 14:14:16 -0400754 int32_t iHorScale = pTxtRun->iHorizontalScale;
755 int32_t iVerScale = pTxtRun->iVerticalScale;
tsepezd19e9122016-11-02 15:43:18 -0700756 bool bSkipSpace = pTxtRun->bSkipSpace;
Dan Sinclair1770c022016-03-14 14:14:16 -0400757 FX_FORMCHAR formChars[3];
Dan Sinclair05df0752017-03-14 14:43:42 -0400758 float fYBase;
Dan Sinclair17f31182017-03-01 09:31:51 -0500759
Dan Sinclaira5a3de92017-03-13 10:14:21 -0400760 if (bRTLPiece)
761 fX = rtText.right();
Dan Sinclair17f31182017-03-01 09:31:51 -0500762
Dan Sinclaira5a3de92017-03-13 10:14:21 -0400763 fYBase = rtText.top + (rtText.height - fFontSize) / 2.0f;
764 fY = fYBase + fAscent;
Dan Sinclair17f31182017-03-01 09:31:51 -0500765
weili038aa532016-05-20 15:38:29 -0700766 int32_t iCount = 0;
767 int32_t iNext = 0;
Dan Sinclair812e96c2017-03-13 16:43:37 -0400768 wchar_t wPrev = 0xFEFF;
769 wchar_t wNext = 0xFEFF;
770 wchar_t wForm = 0xFEFF;
771 wchar_t wLast = 0xFEFF;
tsepezd19e9122016-11-02 15:43:18 -0700772 bool bShadda = false;
773 bool bLam = false;
Dan Sinclair1770c022016-03-14 14:14:16 -0400774 for (int32_t i = 0; i <= iLength; i++) {
weili038aa532016-05-20 15:38:29 -0700775 int32_t iWidth;
Dan Sinclair812e96c2017-03-13 16:43:37 -0400776 wchar_t wch;
dsinclair85d1f2c2016-06-23 12:40:16 -0700777 if (pAccess) {
Dan Sinclair1770c022016-03-14 14:14:16 -0400778 wch = pAccess->GetChar(pIdentity, i);
779 iWidth = pAccess->GetWidth(pIdentity, i);
780 } else {
781 wch = *pStr++;
782 iWidth = *pWidths++;
783 }
Dan Sinclair17f31182017-03-01 09:31:51 -0500784
weili038aa532016-05-20 15:38:29 -0700785 uint32_t dwProps = FX_GetUnicodeProperties(wch);
weilia2c06e42016-05-20 17:09:48 -0700786 FX_CHARTYPE chartype = GetCharTypeFromProp(dwProps);
787 if (chartype == FX_CHARTYPE_ArabicAlef && iWidth == 0) {
Dan Sinclair1770c022016-03-14 14:14:16 -0400788 wPrev = 0xFEFF;
789 wLast = wch;
790 continue;
791 }
Dan Sinclair17f31182017-03-01 09:31:51 -0500792
weilia2c06e42016-05-20 17:09:48 -0700793 if (chartype >= FX_CHARTYPE_ArabicAlef) {
Dan Sinclair1770c022016-03-14 14:14:16 -0400794 if (i < iLength) {
dsinclair85d1f2c2016-06-23 12:40:16 -0700795 if (pAccess) {
Dan Sinclair1770c022016-03-14 14:14:16 -0400796 iNext = i + 1;
797 while (iNext <= iLength) {
798 wNext = pAccess->GetChar(pIdentity, iNext);
799 dwProps = FX_GetUnicodeProperties(wNext);
Dan Sinclair17f31182017-03-01 09:31:51 -0500800 if ((dwProps & FX_CHARTYPEBITSMASK) != FX_CHARTYPE_Combination)
Dan Sinclair1770c022016-03-14 14:14:16 -0400801 break;
Dan Sinclair17f31182017-03-01 09:31:51 -0500802
Dan Sinclair1770c022016-03-14 14:14:16 -0400803 iNext++;
804 }
Dan Sinclair17f31182017-03-01 09:31:51 -0500805 if (iNext > iLength)
Dan Sinclair1770c022016-03-14 14:14:16 -0400806 wNext = 0xFEFF;
Dan Sinclair1770c022016-03-14 14:14:16 -0400807 } else {
808 int32_t j = -1;
809 do {
810 j++;
Dan Sinclair17f31182017-03-01 09:31:51 -0500811 if (i + j >= iLength)
Dan Sinclair1770c022016-03-14 14:14:16 -0400812 break;
Dan Sinclair17f31182017-03-01 09:31:51 -0500813
Dan Sinclair1770c022016-03-14 14:14:16 -0400814 wNext = pStr[j];
815 dwProps = FX_GetUnicodeProperties(wNext);
816 } while ((dwProps & FX_CHARTYPEBITSMASK) == FX_CHARTYPE_Combination);
Dan Sinclair17f31182017-03-01 09:31:51 -0500817 if (i + j >= iLength)
Dan Sinclair1770c022016-03-14 14:14:16 -0400818 wNext = 0xFEFF;
Dan Sinclair1770c022016-03-14 14:14:16 -0400819 }
820 } else {
821 wNext = 0xFEFF;
822 }
Dan Sinclair17f31182017-03-01 09:31:51 -0500823
tsepeze00f75c2016-05-06 13:15:46 -0700824 wForm = pdfium::arabic::GetFormChar(wch, wPrev, wNext);
Dan Sinclair1770c022016-03-14 14:14:16 -0400825 bLam = (wPrev == 0x0644 && wch == 0x0644 && wNext == 0x0647);
weilia2c06e42016-05-20 17:09:48 -0700826 } else if (chartype == FX_CHARTYPE_Combination) {
Dan Sinclair1770c022016-03-14 14:14:16 -0400827 wForm = wch;
828 if (wch >= 0x064C && wch <= 0x0651) {
829 if (bShadda) {
830 wForm = 0xFEFF;
tsepezd19e9122016-11-02 15:43:18 -0700831 bShadda = false;
Dan Sinclair1770c022016-03-14 14:14:16 -0400832 } else {
833 wNext = 0xFEFF;
dsinclair85d1f2c2016-06-23 12:40:16 -0700834 if (pAccess) {
Dan Sinclair1770c022016-03-14 14:14:16 -0400835 iNext = i + 1;
Dan Sinclair17f31182017-03-01 09:31:51 -0500836 if (iNext <= iLength)
Dan Sinclair1770c022016-03-14 14:14:16 -0400837 wNext = pAccess->GetChar(pIdentity, iNext);
Dan Sinclair1770c022016-03-14 14:14:16 -0400838 } else {
Dan Sinclair17f31182017-03-01 09:31:51 -0500839 if (i < iLength)
Dan Sinclair1770c022016-03-14 14:14:16 -0400840 wNext = *pStr;
Dan Sinclair1770c022016-03-14 14:14:16 -0400841 }
842 if (wch == 0x0651) {
843 if (wNext >= 0x064C && wNext <= 0x0650) {
844 wForm = FX_GetArabicFromShaddaTable(wNext);
tsepezd19e9122016-11-02 15:43:18 -0700845 bShadda = true;
Dan Sinclair1770c022016-03-14 14:14:16 -0400846 }
847 } else {
848 if (wNext == 0x0651) {
849 wForm = FX_GetArabicFromShaddaTable(wch);
tsepezd19e9122016-11-02 15:43:18 -0700850 bShadda = true;
Dan Sinclair1770c022016-03-14 14:14:16 -0400851 }
852 }
853 }
854 } else {
tsepezd19e9122016-11-02 15:43:18 -0700855 bShadda = false;
Dan Sinclair1770c022016-03-14 14:14:16 -0400856 }
weilia2c06e42016-05-20 17:09:48 -0700857 } else if (chartype == FX_CHARTYPE_Numeric) {
Dan Sinclair1770c022016-03-14 14:14:16 -0400858 wForm = wch;
Dan Sinclair1770c022016-03-14 14:14:16 -0400859 } else if (wch == L'.') {
860 wForm = wch;
Dan Sinclair1770c022016-03-14 14:14:16 -0400861 } else if (wch == L',') {
862 wForm = wch;
Dan Sinclaira5a3de92017-03-13 10:14:21 -0400863 } else if (bRTLPiece) {
864 wForm = FX_GetMirrorChar(wch, dwProps, bRTLPiece, false);
Dan Sinclair1770c022016-03-14 14:14:16 -0400865 } else {
866 wForm = wch;
867 }
Dan Sinclair17f31182017-03-01 09:31:51 -0500868 if (chartype != FX_CHARTYPE_Combination)
tsepezd19e9122016-11-02 15:43:18 -0700869 bShadda = false;
Dan Sinclair17f31182017-03-01 09:31:51 -0500870 if (chartype < FX_CHARTYPE_ArabicAlef)
tsepezd19e9122016-11-02 15:43:18 -0700871 bLam = false;
Dan Sinclair17f31182017-03-01 09:31:51 -0500872
Dan Sinclair1770c022016-03-14 14:14:16 -0400873 dwProps = FX_GetUnicodeProperties(wForm);
tsepezd19e9122016-11-02 15:43:18 -0700874 bool bEmptyChar =
weilia2c06e42016-05-20 17:09:48 -0700875 (chartype >= FX_CHARTYPE_Tab && chartype <= FX_CHARTYPE_Control);
Dan Sinclair17f31182017-03-01 09:31:51 -0500876 if (wForm == 0xFEFF)
tsepezd19e9122016-11-02 15:43:18 -0700877 bEmptyChar = true;
Dan Sinclair17f31182017-03-01 09:31:51 -0500878
weili038aa532016-05-20 15:38:29 -0700879 int32_t iForms = bLam ? 3 : 1;
Dan Sinclair1770c022016-03-14 14:14:16 -0400880 iCount += (bEmptyChar && bSkipSpace) ? 0 : iForms;
dsinclair85d1f2c2016-06-23 12:40:16 -0700881 if (!pCharPos) {
Dan Sinclair17f31182017-03-01 09:31:51 -0500882 if (iWidth > 0)
Dan Sinclair1770c022016-03-14 14:14:16 -0400883 wPrev = wch;
Dan Sinclair1770c022016-03-14 14:14:16 -0400884 wLast = wch;
885 continue;
886 }
Dan Sinclair17f31182017-03-01 09:31:51 -0500887
weili038aa532016-05-20 15:38:29 -0700888 int32_t iCharWidth = iWidth;
Dan Sinclair17f31182017-03-01 09:31:51 -0500889 if (iCharWidth < 0)
Dan Sinclair1770c022016-03-14 14:14:16 -0400890 iCharWidth = -iCharWidth;
Dan Sinclair17f31182017-03-01 09:31:51 -0500891
Dan Sinclair1770c022016-03-14 14:14:16 -0400892 iCharWidth /= iFontSize;
893 formChars[0].wch = wch;
894 formChars[0].wForm = wForm;
895 formChars[0].iWidth = iCharWidth;
896 if (bLam) {
897 formChars[1].wForm = 0x0651;
898 iCharWidth = 0;
tsepezd19e9122016-11-02 15:43:18 -0700899 pFont->GetCharWidth(0x0651, iCharWidth, false);
Dan Sinclair1770c022016-03-14 14:14:16 -0400900 formChars[1].iWidth = iCharWidth;
901 formChars[2].wForm = 0x0670;
902 iCharWidth = 0;
tsepezd19e9122016-11-02 15:43:18 -0700903 pFont->GetCharWidth(0x0670, iCharWidth, false);
Dan Sinclair1770c022016-03-14 14:14:16 -0400904 formChars[2].iWidth = iCharWidth;
905 }
Dan Sinclair17f31182017-03-01 09:31:51 -0500906
Dan Sinclair1770c022016-03-14 14:14:16 -0400907 for (int32_t j = 0; j < iForms; j++) {
Dan Sinclair812e96c2017-03-13 16:43:37 -0400908 wForm = (wchar_t)formChars[j].wForm;
Dan Sinclair1770c022016-03-14 14:14:16 -0400909 iCharWidth = formChars[j].iWidth;
910 if (j > 0) {
weilia2c06e42016-05-20 17:09:48 -0700911 chartype = FX_CHARTYPE_Combination;
Dan Sinclair1770c022016-03-14 14:14:16 -0400912 wch = wForm;
Dan Sinclair812e96c2017-03-13 16:43:37 -0400913 wLast = (wchar_t)formChars[j - 1].wForm;
Dan Sinclair1770c022016-03-14 14:14:16 -0400914 }
915 if (!bEmptyChar || (bEmptyChar && !bSkipSpace)) {
916 pCharPos->m_GlyphIndex =
tsepezd19e9122016-11-02 15:43:18 -0700917 bCharCode ? wch : pFont->GetGlyphIndex(wForm, false);
thestigec51ac32016-06-20 10:38:52 -0700918#if _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_
Dan Sinclair1770c022016-03-14 14:14:16 -0400919 pCharPos->m_ExtGID = pCharPos->m_GlyphIndex;
thestigec51ac32016-06-20 10:38:52 -0700920#endif
Dan Sinclair1770c022016-03-14 14:14:16 -0400921 pCharPos->m_FontCharWidth = iCharWidth;
Dan Sinclair17f31182017-03-01 09:31:51 -0500922 if (pWSForms)
Dan Sinclair1770c022016-03-14 14:14:16 -0400923 *pWSForms += wForm;
Dan Sinclair1770c022016-03-14 14:14:16 -0400924 }
Dan Sinclair17f31182017-03-01 09:31:51 -0500925
Dan Sinclaira5a3de92017-03-13 10:14:21 -0400926 int32_t iCharHeight = 1000;
Dan Sinclair17f31182017-03-01 09:31:51 -0500927
Dan Sinclair1770c022016-03-14 14:14:16 -0400928 fCharWidth = fFontSize * iCharWidth / 1000.0f;
929 fCharHeight = fFontSize * iCharHeight / 1000.0f;
Dan Sinclaira5a3de92017-03-13 10:14:21 -0400930 if (bRTLPiece && chartype != FX_CHARTYPE_Combination)
931 fX -= fCharWidth;
932
Dan Sinclair1770c022016-03-14 14:14:16 -0400933 if (!bEmptyChar || (bEmptyChar && !bSkipSpace)) {
Dan Sinclair2c02fae2017-02-16 13:42:11 -0500934 pCharPos->m_Origin = CFX_PointF(fX, fY);
Dan Sinclaire533b932017-03-16 11:47:20 -0400935 if ((dwStyles & FX_LAYOUTSTYLE_CombText) != 0) {
Dan Sinclair1770c022016-03-14 14:14:16 -0400936 int32_t iFormWidth = iCharWidth;
tsepezd19e9122016-11-02 15:43:18 -0700937 pFont->GetCharWidth(wForm, iFormWidth, false);
Dan Sinclair05df0752017-03-14 14:43:42 -0400938 float fOffset = fFontSize * (iCharWidth - iFormWidth) / 2000.0f;
Dan Sinclaira5a3de92017-03-13 10:14:21 -0400939 pCharPos->m_Origin.x += fOffset;
Dan Sinclair1770c022016-03-14 14:14:16 -0400940 }
Dan Sinclair2c02fae2017-02-16 13:42:11 -0500941
weilia2c06e42016-05-20 17:09:48 -0700942 if (chartype == FX_CHARTYPE_Combination) {
Dan Sinclair1770c022016-03-14 14:14:16 -0400943 CFX_Rect rtBBox;
tsepez6fd07ef2017-01-06 09:48:18 -0800944 if (pFont->GetCharBBox(wForm, &rtBBox, false)) {
Dan Sinclair2c02fae2017-02-16 13:42:11 -0500945 pCharPos->m_Origin.y =
Dan Sinclair1770c022016-03-14 14:14:16 -0400946 fYBase + fFontSize -
Dan Sinclair05df0752017-03-14 14:43:42 -0400947 fFontSize * (float)rtBBox.height / (float)iMaxHeight;
Dan Sinclair1770c022016-03-14 14:14:16 -0400948 }
949 if (wForm == wch && wLast != 0xFEFF) {
tsepez736f28a2016-03-25 14:19:51 -0700950 uint32_t dwLastProps = FX_GetUnicodeProperties(wLast);
Dan Sinclair1770c022016-03-14 14:14:16 -0400951 if ((dwLastProps & FX_CHARTYPEBITSMASK) ==
952 FX_CHARTYPE_Combination) {
weilidb444d22016-06-02 15:48:15 -0700953 CFX_Rect rtBox;
Dan Sinclair2c02fae2017-02-16 13:42:11 -0500954 if (pFont->GetCharBBox(wLast, &rtBox, false))
955 pCharPos->m_Origin.y -= fFontSize * rtBox.height / iMaxHeight;
Dan Sinclair1770c022016-03-14 14:14:16 -0400956 }
957 }
958 }
959 CFX_PointF ptOffset;
Dan Sinclair2c02fae2017-02-16 13:42:11 -0500960 pCharPos->m_Origin.x += ptOffset.x;
961 pCharPos->m_Origin.y -= ptOffset.y;
Dan Sinclair1770c022016-03-14 14:14:16 -0400962 }
Dan Sinclaira5a3de92017-03-13 10:14:21 -0400963 if (!bRTLPiece && chartype != FX_CHARTYPE_Combination)
964 fX += fCharWidth;
Dan Sinclair17f31182017-03-01 09:31:51 -0500965
Dan Sinclair1770c022016-03-14 14:14:16 -0400966 if (!bEmptyChar || (bEmptyChar && !bSkipSpace)) {
tsepezd19e9122016-11-02 15:43:18 -0700967 pCharPos->m_bGlyphAdjust = true;
Dan Sinclair068d3442017-03-13 10:15:36 -0400968 pCharPos->m_AdjustMatrix[0] = -1;
969 pCharPos->m_AdjustMatrix[1] = 0;
970 pCharPos->m_AdjustMatrix[2] = 0;
971 pCharPos->m_AdjustMatrix[3] = 1;
Dan Sinclaira5a3de92017-03-13 10:14:21 -0400972
Dan Sinclair1770c022016-03-14 14:14:16 -0400973 if (iHorScale != 100 || iVerScale != 100) {
974 pCharPos->m_AdjustMatrix[0] =
975 pCharPos->m_AdjustMatrix[0] * iHorScale / 100.0f;
976 pCharPos->m_AdjustMatrix[1] =
977 pCharPos->m_AdjustMatrix[1] * iHorScale / 100.0f;
978 pCharPos->m_AdjustMatrix[2] =
979 pCharPos->m_AdjustMatrix[2] * iVerScale / 100.0f;
980 pCharPos->m_AdjustMatrix[3] =
981 pCharPos->m_AdjustMatrix[3] * iVerScale / 100.0f;
982 }
983 pCharPos++;
984 }
985 }
Dan Sinclair17f31182017-03-01 09:31:51 -0500986 if (iWidth > 0)
Dan Sinclair812e96c2017-03-13 16:43:37 -0400987 wPrev = static_cast<wchar_t>(formChars[0].wch);
Dan Sinclair1770c022016-03-14 14:14:16 -0400988 wLast = wch;
989 }
990 return iCount;
991}
weili1b4f6b32016-08-04 16:37:48 -0700992
Tom Sepezc803cbc2017-03-02 12:21:15 -0800993std::vector<CFX_RectF> CFX_TxtBreak::GetCharRects(const FX_TXTRUN* pTxtRun,
994 bool bCharBBox) const {
tsepeze6477992017-01-05 12:57:00 -0800995 if (!pTxtRun || pTxtRun->iLength < 1)
Tom Sepezc803cbc2017-03-02 12:21:15 -0800996 return std::vector<CFX_RectF>();
tsepeze6477992017-01-05 12:57:00 -0800997
Dan Sinclair575898e2017-03-13 10:16:05 -0400998 CFDE_TxtEdtPage* pAccess = pTxtRun->pAccess;
dsinclair705f8292016-06-07 10:10:45 -0700999 const FDE_TEXTEDITPIECE* pIdentity = pTxtRun->pIdentity;
Dan Sinclair812e96c2017-03-13 16:43:37 -04001000 const wchar_t* pStr = pTxtRun->wsStr.c_str();
Dan Sinclair1770c022016-03-14 14:14:16 -04001001 int32_t* pWidths = pTxtRun->pWidths;
1002 int32_t iLength = pTxtRun->iLength;
1003 CFX_RectF rect(*pTxtRun->pRect);
Dan Sinclair05df0752017-03-14 14:43:42 -04001004 float fFontSize = pTxtRun->fFontSize;
Dan Sinclair1770c022016-03-14 14:14:16 -04001005 int32_t iFontSize = FXSYS_round(fFontSize * 20.0f);
Dan Sinclair05df0752017-03-14 14:43:42 -04001006 float fScale = fFontSize / 1000.0f;
tsepeze6477992017-01-05 12:57:00 -08001007 CFX_RetainPtr<CFGAS_GEFont> pFont = pTxtRun->pFont;
1008 if (!pFont)
tsepezd19e9122016-11-02 15:43:18 -07001009 bCharBBox = false;
tsepeze6477992017-01-05 12:57:00 -08001010
Dan Sinclair1770c022016-03-14 14:14:16 -04001011 CFX_Rect bbox;
tsepeze6477992017-01-05 12:57:00 -08001012 if (bCharBBox)
tsepez6fd07ef2017-01-06 09:48:18 -08001013 bCharBBox = pFont->GetBBox(&bbox);
tsepeze6477992017-01-05 12:57:00 -08001014
Dan Sinclair05df0752017-03-14 14:43:42 -04001015 float fLeft = std::max(0.0f, bbox.left * fScale);
1016 float fHeight = FXSYS_fabs(bbox.height * fScale);
Tom Sepezc803cbc2017-03-02 12:21:15 -08001017 bool bRTLPiece = !!(pTxtRun->dwCharStyles & FX_TXTCHARSTYLE_OddBidiLevel);
Dan Sinclaire533b932017-03-16 11:47:20 -04001018 bool bSingleLine = !!(pTxtRun->dwStyles & FX_LAYOUTSTYLE_SingleLine);
1019 bool bCombText = !!(pTxtRun->dwStyles & FX_LAYOUTSTYLE_CombText);
Dan Sinclair812e96c2017-03-13 16:43:37 -04001020 wchar_t wch;
1021 wchar_t wLineBreakChar = pTxtRun->wLineBreakChar;
Dan Sinclair1770c022016-03-14 14:14:16 -04001022 int32_t iCharSize;
Dan Sinclair05df0752017-03-14 14:43:42 -04001023 float fCharSize;
1024 float fStart = bRTLPiece ? rect.right() : rect.left;
Dan Sinclair17f31182017-03-01 09:31:51 -05001025
Tom Sepezc803cbc2017-03-02 12:21:15 -08001026 std::vector<CFX_RectF> rtArray(iLength);
Dan Sinclair1770c022016-03-14 14:14:16 -04001027 for (int32_t i = 0; i < iLength; i++) {
dsinclair85d1f2c2016-06-23 12:40:16 -07001028 if (pAccess) {
Dan Sinclair1770c022016-03-14 14:14:16 -04001029 wch = pAccess->GetChar(pIdentity, i);
1030 iCharSize = pAccess->GetWidth(pIdentity, i);
1031 } else {
1032 wch = *pStr++;
1033 iCharSize = *pWidths++;
1034 }
Dan Sinclair05df0752017-03-14 14:43:42 -04001035 fCharSize = static_cast<float>(iCharSize) / 20000.0f;
Dan Sinclairfc9b9882017-03-07 09:18:18 -05001036 bool bRet = (!bSingleLine && IsCtrlCode(wch));
Dan Sinclair1770c022016-03-14 14:14:16 -04001037 if (!(wch == L'\v' || wch == L'\f' || wch == 0x2028 || wch == 0x2029 ||
1038 (wLineBreakChar != 0xFEFF && wch == wLineBreakChar))) {
tsepezd19e9122016-11-02 15:43:18 -07001039 bRet = false;
Dan Sinclair1770c022016-03-14 14:14:16 -04001040 }
1041 if (bRet) {
1042 iCharSize = iFontSize * 500;
1043 fCharSize = fFontSize / 2.0f;
1044 }
Dan Sinclaira5a3de92017-03-13 10:14:21 -04001045 rect.left = fStart;
1046 if (bRTLPiece) {
1047 rect.left -= fCharSize;
1048 fStart -= fCharSize;
Dan Sinclair1770c022016-03-14 14:14:16 -04001049 } else {
Dan Sinclaira5a3de92017-03-13 10:14:21 -04001050 fStart += fCharSize;
Dan Sinclair1770c022016-03-14 14:14:16 -04001051 }
Dan Sinclaira5a3de92017-03-13 10:14:21 -04001052 rect.width = fCharSize;
Dan Sinclair17f31182017-03-01 09:31:51 -05001053
Dan Sinclair1770c022016-03-14 14:14:16 -04001054 if (bCharBBox && !bRet) {
1055 int32_t iCharWidth = 1000;
thestig2c065322016-09-26 14:16:43 -07001056 pFont->GetCharWidth(wch, iCharWidth, false);
Dan Sinclair05df0752017-03-14 14:43:42 -04001057 float fRTLeft = 0, fCharWidth = 0;
Dan Sinclair1770c022016-03-14 14:14:16 -04001058 if (iCharWidth > 0) {
1059 fCharWidth = iCharWidth * fScale;
1060 fRTLeft = fLeft;
Dan Sinclair17f31182017-03-01 09:31:51 -05001061 if (bCombText)
Dan Sinclair1770c022016-03-14 14:14:16 -04001062 fRTLeft = (rect.width - fCharWidth) / 2.0f;
Dan Sinclair1770c022016-03-14 14:14:16 -04001063 }
1064 CFX_RectF rtBBoxF;
Dan Sinclaira5a3de92017-03-13 10:14:21 -04001065 rtBBoxF.left = rect.left + fRTLeft;
1066 rtBBoxF.top = rect.top + (rect.height - fHeight) / 2.0f;
1067 rtBBoxF.width = fCharWidth;
1068 rtBBoxF.height = fHeight;
1069 rtBBoxF.top = std::max(rtBBoxF.top, 0.0f);
Tom Sepezc803cbc2017-03-02 12:21:15 -08001070 rtArray[i] = rtBBoxF;
Dan Sinclair1770c022016-03-14 14:14:16 -04001071 continue;
1072 }
Tom Sepezc803cbc2017-03-02 12:21:15 -08001073 rtArray[i] = rect;
Dan Sinclair1770c022016-03-14 14:14:16 -04001074 }
Tom Sepezc803cbc2017-03-02 12:21:15 -08001075 return rtArray;
Dan Sinclair1770c022016-03-14 14:14:16 -04001076}
weilieec3a362016-06-18 06:25:37 -07001077
1078FX_TXTRUN::FX_TXTRUN()
1079 : pAccess(nullptr),
1080 pIdentity(nullptr),
1081 pWidths(nullptr),
1082 iLength(0),
1083 pFont(nullptr),
1084 fFontSize(12),
1085 dwStyles(0),
1086 iHorizontalScale(100),
1087 iVerticalScale(100),
weilieec3a362016-06-18 06:25:37 -07001088 dwCharStyles(0),
1089 pRect(nullptr),
1090 wLineBreakChar(L'\n'),
tsepezd19e9122016-11-02 15:43:18 -07001091 bSkipSpace(true) {}
weilieec3a362016-06-18 06:25:37 -07001092
1093FX_TXTRUN::~FX_TXTRUN() {}
1094
1095FX_TXTRUN::FX_TXTRUN(const FX_TXTRUN& other) = default;