@ -63,7 +63,7 @@ namespace Avalonia.Media.TextFormatting
MaxHeight = maxHeight ;
MaxHeight = maxHeight ;
MaxLines = maxLines ;
MaxLines = maxLines ;
TextLines = CreateTextLines ( ) ;
TextLines = CreateTextLines ( ) ;
}
}
@ -80,7 +80,7 @@ namespace Avalonia.Media.TextFormatting
/// <param name="maxLines">The maximum number of text lines.</param>
/// <param name="maxLines">The maximum number of text lines.</param>
public TextLayout (
public TextLayout (
ITextSource textSource ,
ITextSource textSource ,
TextParagraphProperties paragraphProperties ,
TextParagraphProperties paragraphProperties ,
TextTrimming ? textTrimming = null ,
TextTrimming ? textTrimming = null ,
double maxWidth = double . PositiveInfinity ,
double maxWidth = double . PositiveInfinity ,
double maxHeight = double . PositiveInfinity ,
double maxHeight = double . PositiveInfinity ,
@ -178,24 +178,18 @@ namespace Avalonia.Media.TextFormatting
return new Rect ( ) ;
return new Rect ( ) ;
}
}
if ( textPosition < 0 | | textPosition > = _ textSourceLength )
if ( textPosition < 0 )
{
{
var lastLine = TextLines [ TextLines . Count - 1 ] ;
textPosition = _ textSourceLength ;
var lineX = lastLine . Width ;
var lineY = Bounds . Bottom - lastLine . Height ;
return new Rect ( lineX , lineY , 0 , lastLine . Height ) ;
}
}
var currentY = 0.0 ;
var currentY = 0.0 ;
foreach ( var textLine in TextLines )
foreach ( var textLine in TextLines )
{
{
var end = textLine . FirstTextSourceIndex + textLine . Length - 1 ;
var end = textLine . FirstTextSourceIndex + textLine . Length ;
if ( end < textPosition )
if ( end < = textPosition & & end < _ textSourceLength )
{
{
currentY + = textLine . Height ;
currentY + = textLine . Height ;
@ -224,7 +218,7 @@ namespace Avalonia.Media.TextFormatting
}
}
var result = new List < Rect > ( TextLines . Count ) ;
var result = new List < Rect > ( TextLines . Count ) ;
var currentY = 0d ;
var currentY = 0d ;
foreach ( var textLine in TextLines )
foreach ( var textLine in TextLines )
@ -239,7 +233,7 @@ namespace Avalonia.Media.TextFormatting
var textBounds = textLine . GetTextBounds ( start , length ) ;
var textBounds = textLine . GetTextBounds ( start , length ) ;
if ( textBounds . Count > 0 )
if ( textBounds . Count > 0 )
{
{
foreach ( var bounds in textBounds )
foreach ( var bounds in textBounds )
{
{
@ -262,7 +256,7 @@ namespace Avalonia.Media.TextFormatting
}
}
}
}
if ( textLine . FirstTextSourceIndex + textLine . Length > = start + length )
if ( textLine . FirstTextSourceIndex + textLine . Length > = start + length )
{
{
break ;
break ;
}
}
@ -305,7 +299,7 @@ namespace Avalonia.Media.TextFormatting
return GetHitTestResult ( currentLine , characterHit , point ) ;
return GetHitTestResult ( currentLine , characterHit , point ) ;
}
}
public int GetLineIndexFromCharacterIndex ( int charIndex , bool trailingEdge )
public int GetLineIndexFromCharacterIndex ( int charIndex , bool trailingEdge )
{
{
if ( charIndex < 0 )
if ( charIndex < 0 )
@ -327,7 +321,7 @@ namespace Avalonia.Media.TextFormatting
continue ;
continue ;
}
}
if ( charIndex > = textLine . FirstTextSourceIndex & &
if ( charIndex > = textLine . FirstTextSourceIndex & &
charIndex < = textLine . FirstTextSourceIndex + textLine . Length - ( trailingEdge ? 0 : 1 ) )
charIndex < = textLine . FirstTextSourceIndex + textLine . Length - ( trailingEdge ? 0 : 1 ) )
{
{
return index ;
return index ;
@ -398,7 +392,7 @@ namespace Avalonia.Media.TextFormatting
/// <param name="left">The current left.</param>
/// <param name="left">The current left.</param>
/// <param name="width">The current width.</param>
/// <param name="width">The current width.</param>
/// <param name="height">The current height.</param>
/// <param name="height">The current height.</param>
private static void UpdateBounds ( TextLine textLine , ref double left , ref double width , ref double height )
private static void UpdateBounds ( TextLine textLine , ref double left , ref double width , ref double height )
{
{
var lineWidth = textLine . WidthIncludingTrailingWhitespace ;
var lineWidth = textLine . WidthIncludingTrailingWhitespace ;
@ -421,7 +415,7 @@ namespace Avalonia.Media.TextFormatting
{
{
var textLine = TextFormatterImpl . CreateEmptyTextLine ( 0 , double . PositiveInfinity , _ paragraphProperties ) ;
var textLine = TextFormatterImpl . CreateEmptyTextLine ( 0 , double . PositiveInfinity , _ paragraphProperties ) ;
Bounds = new Rect ( 0 , 0 , 0 , textLine . Height ) ;
Bounds = new Rect ( 0 , 0 , 0 , textLine . Height ) ;
return new List < TextLine > { textLine } ;
return new List < TextLine > { textLine } ;
}
}
@ -439,9 +433,9 @@ namespace Avalonia.Media.TextFormatting
var textLine = TextFormatter . Current . FormatLine ( _ textSource , _ textSourceLength , MaxWidth ,
var textLine = TextFormatter . Current . FormatLine ( _ textSource , _ textSourceLength , MaxWidth ,
_ paragraphProperties , previousLine ? . TextLineBreak ) ;
_ paragraphProperties , previousLine ? . TextLineBreak ) ;
if ( textLine = = null | | textLine . Length = = 0 | | textLine . TextRuns . Count = = 0 & & textLine . TextLineBreak ? . TextEndOfLine is TextEndOfParagraph )
if ( textLine = = null | | textLine . Length = = 0 | | textLine . TextRuns . Count = = 0 & & textLine . TextLineBreak ? . TextEndOfLine is TextEndOfParagraph )
{
{
if ( previousLine ! = null & & previousLine . NewLineLength > 0 )
if ( previousLine ! = null & & previousLine . NewLineLength > 0 )
{
{
var emptyTextLine = TextFormatterImpl . CreateEmptyTextLine ( _ textSourceLength , MaxWidth , _ paragraphProperties ) ;
var emptyTextLine = TextFormatterImpl . CreateEmptyTextLine ( _ textSourceLength , MaxWidth , _ paragraphProperties ) ;
@ -454,7 +448,7 @@ namespace Avalonia.Media.TextFormatting
}
}
_ textSourceLength + = textLine . Length ;
_ textSourceLength + = textLine . Length ;
//Fulfill max height constraint
//Fulfill max height constraint
if ( textLines . Count > 0 & & ! double . IsPositiveInfinity ( MaxHeight ) & & height + textLine . Height > MaxHeight )
if ( textLines . Count > 0 & & ! double . IsPositiveInfinity ( MaxHeight ) & & height + textLine . Height > MaxHeight )
{
{
@ -490,7 +484,7 @@ namespace Avalonia.Media.TextFormatting
}
}
//Make sure the TextLayout always contains at least on empty line
//Make sure the TextLayout always contains at least on empty line
if ( textLines . Count = = 0 )
if ( textLines . Count = = 0 )
{
{
var textLine = TextFormatterImpl . CreateEmptyTextLine ( 0 , MaxWidth , _ paragraphProperties ) ;
var textLine = TextFormatterImpl . CreateEmptyTextLine ( 0 , MaxWidth , _ paragraphProperties ) ;
@ -501,7 +495,7 @@ namespace Avalonia.Media.TextFormatting
Bounds = new Rect ( left , 0 , width , height ) ;
Bounds = new Rect ( left , 0 , width , height ) ;
if ( _ paragraphProperties . TextAlignment = = TextAlignment . Justify )
if ( _ paragraphProperties . TextAlignment = = TextAlignment . Justify )
{
{
var whitespaceWidth = 0d ;
var whitespaceWidth = 0d ;
@ -509,7 +503,7 @@ namespace Avalonia.Media.TextFormatting
{
{
var lineWhitespaceWidth = line . Width - line . WidthIncludingTrailingWhitespace ;
var lineWhitespaceWidth = line . Width - line . WidthIncludingTrailingWhitespace ;
if ( lineWhitespaceWidth > whitespaceWidth )
if ( lineWhitespaceWidth > whitespaceWidth )
{
{
whitespaceWidth = lineWhitespaceWidth ;
whitespaceWidth = lineWhitespaceWidth ;
}
}
@ -517,7 +511,7 @@ namespace Avalonia.Media.TextFormatting
var justificationWidth = width - whitespaceWidth ;
var justificationWidth = width - whitespaceWidth ;
if ( justificationWidth > 0 )
if ( justificationWidth > 0 )
{
{
var justificationProperties = new InterWordJustification ( justificationWidth ) ;
var justificationProperties = new InterWordJustification ( justificationWidth ) ;