A cross-platform UI framework for .NET
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

121 lines
3.6 KiB

using System;
using System.Collections.Generic;
using Avalonia.Media.TextFormatting.Unicode;
namespace Avalonia.Media.TextFormatting
{
internal class InterWordJustification : JustificationProperties
{
public InterWordJustification(double width)
{
Width = width;
}
public override double Width { get; }
public override void Justify(TextLine textLine)
{
var lineImpl = textLine as TextLineImpl;
if(lineImpl is null)
{
return;
}
var paragraphWidth = Width;
if (double.IsInfinity(paragraphWidth))
{
return;
}
if (lineImpl.NewLineLength > 0)
{
return;
}
var textLineBreak = lineImpl.TextLineBreak;
if (textLineBreak is not null && textLineBreak.TextEndOfLine is not null)
{
if (textLineBreak.RemainingRuns is null || textLineBreak.RemainingRuns.Count == 0)
{
return;
}
}
var breakOportunities = new Queue<int>();
var currentPosition = textLine.FirstTextSourceIndex;
foreach (var textRun in lineImpl.TextRuns)
{
var text = new CharacterBufferRange(textRun);
if (text.IsEmpty)
{
continue;
}
var lineBreakEnumerator = new LineBreakEnumerator(text);
while (lineBreakEnumerator.MoveNext())
{
var currentBreak = lineBreakEnumerator.Current;
if (!currentBreak.Required && currentBreak.PositionWrap != textRun.Length)
{
breakOportunities.Enqueue(currentPosition + currentBreak.PositionMeasure);
}
}
currentPosition += textRun.Length;
}
if (breakOportunities.Count == 0)
{
return;
}
var remainingSpace = Math.Max(0, paragraphWidth - lineImpl.WidthIncludingTrailingWhitespace);
var spacing = remainingSpace / breakOportunities.Count;
currentPosition = textLine.FirstTextSourceIndex;
foreach (var textRun in lineImpl.TextRuns)
{
var text = textRun.CharacterBufferReference.CharacterBuffer;
if (text.IsEmpty)
{
continue;
}
if (textRun is ShapedTextRun shapedText)
{
var glyphRun = shapedText.GlyphRun;
var shapedBuffer = shapedText.ShapedBuffer;
while (breakOportunities.Count > 0)
{
var characterIndex = breakOportunities.Dequeue();
if (characterIndex < currentPosition)
{
continue;
}
var glyphIndex = glyphRun.FindGlyphIndex(characterIndex);
var glyphInfo = shapedBuffer.GlyphInfos[glyphIndex];
shapedBuffer.GlyphInfos[glyphIndex] = new GlyphInfo(glyphInfo.GlyphIndex, glyphInfo.GlyphCluster, glyphInfo.GlyphAdvance + spacing);
}
glyphRun.GlyphAdvances = shapedBuffer.GlyphAdvances;
}
currentPosition += textRun.Length;
}
}
}
}