@@ -32,10 +32,10 @@ public override string ToString() {
3232
3333 private class WordInfo
3434 {
35- public int Width ;
35+ public float Width ;
3636 public int CharCount ;
3737 public int [ ] GraphemeLengths ;
38- public int [ ] GraphemeWidths ;
38+ public float [ ] GraphemeWidths ;
3939 }
4040
4141 private class SubLineInfo
@@ -53,7 +53,7 @@ private class SubLineInfo
5353
5454 private int m_n_line_count_start_change = 0 ;
5555 private HashSet < TextLine > m_hs_changed_temp = new HashSet < TextLine > ( ) ;
56- private readonly Dictionary < char , int > m_dic_char_widths = new Dictionary < char , int > ( ) ;
56+ private readonly Dictionary < char , float > m_dic_char_widths = new Dictionary < char , float > ( ) ;
5757
5858 private readonly StringFormat m_sf = new StringFormat ( StringFormat . GenericTypographic ) {
5959 Alignment = StringAlignment . Far ,
@@ -154,22 +154,25 @@ public override void OnLineChanged(ISTTextBoxRender render, TextManagerLineEvent
154154 m_hs_changed_temp . Add ( e . Line ) ;
155155 }
156156
157- private int GetCharWidthFast ( STTextBox . Core c , TextLine line , int charIndexInLine , string strChar , int curX ) {
157+ private float GetCharWidthFastFloat ( STTextBox . Core c , TextLine line , int charIndexInLine , string strChar , float curX ) {
158+ if ( string . IsNullOrEmpty ( strChar ) ) return 0f ;
158159 if ( strChar . Length == 1 ) {
159160 char ch = strChar [ 0 ] ;
161+ if ( ch == '\r ' || ch == '\n ' ) return 0f ;
160162 if ( ch < 128 && c . ITextBoxRender . IsMonospaced ) {
161- return c . ITextBoxRender . GetSpaceWidth ( ) ;
163+ return c . ITextBoxRender . CharWidthFloat > 0f ? c . ITextBoxRender . CharWidthFloat : ( float ) c . ITextBoxRender . GetSpaceWidth ( ) ;
162164 }
163- if ( m_dic_char_widths . TryGetValue ( ch , out int cachedW ) ) {
165+ if ( m_dic_char_widths . TryGetValue ( ch , out float cachedW ) ) {
164166 return cachedW ;
165167 }
166168 var style = c . GetStyleFromCharIndex ( line . IndexOfFirstChar + charIndexInLine ) ;
167- int w = c . GetStringWidth ( strChar , style , curX ) ;
169+ float w = c . GetStringWidthFloat ( strChar , style , curX ) ;
168170 m_dic_char_widths [ ch ] = w ;
169171 return w ;
170172 } else {
173+ if ( strChar == "\r \n " ) return 0f ;
171174 var style = c . GetStyleFromCharIndex ( line . IndexOfFirstChar + charIndexInLine ) ;
172- return c . GetStringWidth ( strChar , style , curX ) ;
175+ return c . GetStringWidthFloat ( strChar , style , curX ) ;
173176 }
174177 }
175178
@@ -178,7 +181,7 @@ private List<SubLineInfo> GetCache(TextLine line, ISTTextBoxRender render) {
178181 List < SubLineInfo > lst = null ;
179182 if ( this . WrapMethod == Method . Char ) {
180183 lst = new List < SubLineInfo > ( ) ;
181- this . GetCacheByChar ( line , render , lst , 0 , 0 ) ;
184+ this . GetCacheByChar ( line , render , lst , 0 ) ;
182185 } else {
183186 lst = this . GetCacheByWord ( line , render ) ;
184187 }
@@ -187,79 +190,45 @@ private List<SubLineInfo> GetCache(TextLine line, ISTTextBoxRender render) {
187190 switch ( this . WrapAlignment ) {
188191 case Alignment . Center :
189192 sub . X = ( base . TextRectangle . Width - sub . Width ) >> 1 ;
190- if ( sub . Length > 0 ) {
191- switch ( line . RawString [ sub . Index + sub . Length - 1 ] ) {
192- case '\r ' :
193- case '\n ' :
194- sub . X += c . ITextBoxRender . GetSpaceWidth ( ) / 2 ;
195- break ;
196- }
197- }
198193 break ;
199194 case Alignment . Right :
200195 sub . X = base . TextRectangle . Width - sub . Width - c . ITextBoxRender . GetSpaceWidth ( ) ;
201- if ( sub . Length > 0 ) {
202- switch ( line . RawString [ sub . Index ] ) {
203- case '\r ' :
204- case '\n ' :
205- if ( i == 0 ) break ;
206- var temp = lst [ i - 1 ] ;
207- temp . Width += sub . Width ;
208- temp . Length += sub . Length ;
209- temp . CharCount += 1 ;
210- if ( temp . Offsets != null && sub . Offsets != null ) {
211- int [ ] mergedOffsets = new int [ temp . Length + 1 ] ;
212- Array . Copy ( temp . Offsets , 0 , mergedOffsets , 0 , temp . Offsets . Length ) ;
213- for ( int k = temp . Offsets . Length ; k < mergedOffsets . Length ; k ++ ) {
214- mergedOffsets [ k ] = temp . Width ;
215- }
216- temp . Offsets = mergedOffsets ;
217- }
218- lst [ i - 1 ] = temp ;
219- lst . RemoveAt ( i ) ;
220- return lst ;
221- }
222- switch ( line . RawString [ sub . Index + sub . Length - 1 ] ) {
223- case '\r ' :
224- case '\n ' :
225- sub . X += c . ITextBoxRender . GetSpaceWidth ( ) ;
226- break ;
227- }
228- break ;
229- }
230196 break ;
231197 }
232198 lst [ i ] = sub ;
233199 }
234200 return lst ;
235201 }
236202
237- private int GetCacheByChar ( TextLine line , ISTTextBoxRender render , List < SubLineInfo > lst , int nStartIndex , int nWidth ) {
203+ private void GetCacheByChar ( TextLine line , ISTTextBoxRender render , List < SubLineInfo > lst , int nStartIndex ) {
238204 var c = base . Core ;
239- int nLineWidth = nWidth , nCharWidth = 0 ;
240- int nSubStrLen = 0 ;
241- int nCharCount = 0 ;
242- int nTextViewLineWidth = Math . Max ( 10 , base . TextRectangle . Width ) ;
205+ float nTextViewLineWidth = ( float ) Math . Max ( 10 , base . TextRectangle . Width ) ;
243206 if ( this . WrapAlignment != Alignment . Left ) {
244- nTextViewLineWidth -= c . ITextBoxRender . GetSpaceWidth ( ) ;
207+ nTextViewLineWidth -= ( float ) c . ITextBoxRender . GetSpaceWidth ( ) ;
245208 }
246- nTextViewLineWidth = Math . Max ( 1 , nTextViewLineWidth ) ;
209+ nTextViewLineWidth = Math . Max ( 1f , nTextViewLineWidth ) ;
247210
211+ float nLineWidth = 0f ;
212+ int nSubStrLen = 0 ;
213+ int nCharCount = 0 ;
248214 List < int > curOffsets = new List < int > ( ) { 0 } ;
249215
250216 c . IGraphemeSplitter . Each ( line . RawString , nStartIndex , ( str , nStart , nLen ) => {
251217 string strChar = str . Substring ( nStart , nLen ) ;
252- if ( c . IsEmoji ( strChar ) ) {
253- nCharWidth = c . FontHeight ;
218+ float nCharWidth ;
219+ if ( strChar == "\r \n " || strChar == "\r " || strChar == "\n " ) {
220+ nCharWidth = 0f ;
221+ } else if ( c . IsEmoji ( strChar ) ) {
222+ nCharWidth = ( float ) c . FontHeight ;
254223 } else {
255- nCharWidth = GetCharWidthFast ( c , line , nStart , strChar , nLineWidth ) ;
224+ nCharWidth = GetCharWidthFastFloat ( c , line , nStart , strChar , nLineWidth ) ;
256225 }
257226 if ( nLineWidth + nCharWidth >= nTextViewLineWidth && nSubStrLen > 0 ) {
258227 lst . Add ( new SubLineInfo ( ) {
259228 Index = nStartIndex ,
260229 Length = nSubStrLen ,
261230 CharCount = nCharCount ,
262- Width = nLineWidth ,
231+ Width = ( int ) Math . Round ( nLineWidth ) ,
263232 Offsets = curOffsets . ToArray ( )
264233 } ) ;
265234 curOffsets . Clear ( ) ;
@@ -268,15 +237,17 @@ private int GetCacheByChar(TextLine line, ISTTextBoxRender render, List<SubLineI
268237 nStartIndex += nSubStrLen ;
269238 nSubStrLen = nLen ;
270239 nLineWidth = nCharWidth ;
240+ int off = ( int ) Math . Round ( nLineWidth ) ;
271241 for ( int k = 1 ; k <= nLen ; k ++ ) {
272- curOffsets . Add ( nLineWidth ) ;
242+ curOffsets . Add ( off ) ;
273243 }
274244 } else {
275245 nSubStrLen += nLen ;
276246 nLineWidth += nCharWidth ;
277247 nCharCount ++ ;
248+ int off = ( int ) Math . Round ( nLineWidth ) ;
278249 for ( int k = 1 ; k <= nLen ; k ++ ) {
279- curOffsets . Add ( nLineWidth ) ;
250+ curOffsets . Add ( off ) ;
280251 }
281252 }
282253 return true ;
@@ -285,24 +256,23 @@ private int GetCacheByChar(TextLine line, ISTTextBoxRender render, List<SubLineI
285256 Index = nStartIndex ,
286257 Length = nSubStrLen ,
287258 CharCount = nCharCount ,
288- Width = nLineWidth ,
259+ Width = ( int ) Math . Round ( nLineWidth ) ,
289260 Offsets = curOffsets . ToArray ( )
290261 } ) ;
291- return nLineWidth ;
292262 }
293263
294264 private List < SubLineInfo > GetCacheByWord ( TextLine line , ISTTextBoxRender render ) {
295265 var c = base . Core ;
296- int nTextViewLineWidth = Math . Max ( 10 , base . TextRectangle . Width ) ;
266+ float nTextViewLineWidth = ( float ) Math . Max ( 10 , base . TextRectangle . Width ) ;
297267 if ( this . WrapAlignment != Alignment . Left ) {
298- nTextViewLineWidth -= c . ITextBoxRender . GetSpaceWidth ( ) ;
268+ nTextViewLineWidth -= ( float ) c . ITextBoxRender . GetSpaceWidth ( ) ;
299269 }
300- nTextViewLineWidth = Math . Max ( 1 , nTextViewLineWidth ) ;
270+ nTextViewLineWidth = Math . Max ( 1f , nTextViewLineWidth ) ;
301271
302272 List < SubLineInfo > lst = new List < SubLineInfo > ( ) ;
303273 int curSubStart = 0 ;
304274 int curSubLen = 0 ;
305- int curSubWidth = 0 ;
275+ float curSubWidth = 0f ;
306276 int curCharCount = 0 ;
307277 List < int > curOffsets = new List < int > ( ) { 0 } ;
308278
@@ -314,27 +284,28 @@ private List<SubLineInfo> GetCacheByWord(TextLine line, ISTTextBoxRender render)
314284 // Single word is wider than the entire line -> split character by character
315285 for ( int g = 0 ; g < wi . GraphemeLengths . Length ; g ++ ) {
316286 int gLen = wi . GraphemeLengths [ g ] ;
317- int gWidth = wi . GraphemeWidths [ g ] ;
287+ float gWidth = wi . GraphemeWidths [ g ] ;
318288 if ( curSubWidth + gWidth >= nTextViewLineWidth && curSubLen > 0 ) {
319289 lst . Add ( new SubLineInfo ( ) {
320290 Index = curSubStart ,
321291 Length = curSubLen ,
322292 CharCount = curCharCount ,
323- Width = curSubWidth ,
293+ Width = ( int ) Math . Round ( curSubWidth ) ,
324294 Offsets = curOffsets . ToArray ( )
325295 } ) ;
326296 curSubStart += curSubLen ;
327297 curSubLen = 0 ;
328- curSubWidth = 0 ;
298+ curSubWidth = 0f ;
329299 curCharCount = 0 ;
330300 curOffsets . Clear ( ) ;
331301 curOffsets . Add ( 0 ) ;
332302 }
333303 curSubLen += gLen ;
334304 curSubWidth += gWidth ;
335305 curCharCount ++ ;
306+ int off = ( int ) Math . Round ( curSubWidth ) ;
336307 for ( int k = 1 ; k <= gLen ; k ++ ) {
337- curOffsets . Add ( curSubWidth ) ;
308+ curOffsets . Add ( off ) ;
338309 }
339310 }
340311 return true ;
@@ -346,12 +317,12 @@ private List<SubLineInfo> GetCacheByWord(TextLine line, ISTTextBoxRender render)
346317 Index = curSubStart ,
347318 Length = curSubLen ,
348319 CharCount = curCharCount ,
349- Width = curSubWidth ,
320+ Width = ( int ) Math . Round ( curSubWidth ) ,
350321 Offsets = curOffsets . ToArray ( )
351322 } ) ;
352323 curSubStart += curSubLen ;
353324 curSubLen = 0 ;
354- curSubWidth = 0 ;
325+ curSubWidth = 0f ;
355326 curCharCount = 0 ;
356327 curOffsets . Clear ( ) ;
357328 curOffsets . Add ( 0 ) ;
@@ -360,12 +331,13 @@ private List<SubLineInfo> GetCacheByWord(TextLine line, ISTTextBoxRender render)
360331 // Add the word to the current subline
361332 for ( int g = 0 ; g < wi . GraphemeLengths . Length ; g ++ ) {
362333 int gLen = wi . GraphemeLengths [ g ] ;
363- int gWidth = wi . GraphemeWidths [ g ] ;
334+ float gWidth = wi . GraphemeWidths [ g ] ;
364335 curSubLen += gLen ;
365336 curSubWidth += gWidth ;
366337 curCharCount ++ ;
338+ int off = ( int ) Math . Round ( curSubWidth ) ;
367339 for ( int k = 1 ; k <= gLen ; k ++ ) {
368- curOffsets . Add ( curSubWidth ) ;
340+ curOffsets . Add ( off ) ;
369341 }
370342 }
371343 return true ;
@@ -375,27 +347,37 @@ private List<SubLineInfo> GetCacheByWord(TextLine line, ISTTextBoxRender render)
375347 Index = curSubStart ,
376348 Length = curSubLen ,
377349 CharCount = curCharCount ,
378- Width = curSubWidth ,
350+ Width = ( int ) Math . Round ( curSubWidth ) ,
379351 Offsets = curOffsets . ToArray ( )
380352 } ) ;
381353
382354 return lst ;
383355 }
384356
385- private WordInfo GetWordInfo ( TextLine line , ISTTextBoxRender render , string strWord , int nIndex , int nLeftWidth ) {
357+ private WordInfo GetWordInfo ( TextLine line , ISTTextBoxRender render , string strWord , int nIndex , float nLeftWidth ) {
386358 var c = base . Core ;
387- int nWordWidth = 0 ;
359+ if ( strWord == "\r \n " || strWord == "\r " || strWord == "\n " ) {
360+ return new WordInfo ( ) {
361+ Width = 0f ,
362+ CharCount = 1 ,
363+ GraphemeLengths = new int [ ] { strWord . Length } ,
364+ GraphemeWidths = new float [ ] { 0f }
365+ } ;
366+ }
367+ float nWordWidth = 0f ;
388368 int nCharCount = 0 ;
389369 List < int > gLens = new List < int > ( ) ;
390- List < int > gWidths = new List < int > ( ) ;
370+ List < float > gWidths = new List < float > ( ) ;
391371
392372 c . IGraphemeSplitter . Each ( strWord , ( s , ns , nl ) => {
393373 string strChar = s . Substring ( ns , nl ) ;
394- int nCharWidth ;
395- if ( c . IsEmoji ( strChar ) ) {
396- nCharWidth = c . FontHeight ;
374+ float nCharWidth ;
375+ if ( strChar == "\r \n " || strChar == "\r " || strChar == "\n " ) {
376+ nCharWidth = 0f ;
377+ } else if ( c . IsEmoji ( strChar ) ) {
378+ nCharWidth = ( float ) c . FontHeight ;
397379 } else {
398- nCharWidth = GetCharWidthFast ( c , line , nIndex + ns , strChar , nLeftWidth + nWordWidth ) ;
380+ nCharWidth = GetCharWidthFastFloat ( c , line , nIndex + ns , strChar , nLeftWidth + nWordWidth ) ;
399381 }
400382 gLens . Add ( nl ) ;
401383 gWidths . Add ( nCharWidth ) ;
0 commit comments