Table of Contents

Class LineFlow

Namespace
Egami.Fonts.Layout
Assembly
Egami.Fonts.dll

Lays a paragraph out one line at a time, each at its own width, so text can flow across columns and pages or around images; Layout(float) is built on it. Not thread-safe; make one per flow.

public sealed class LineFlow
Inheritance
LineFlow
Inherited Members

Examples

// One line at a time, each at its own width: two columns of four lines, the second wrapping around an image.
LineFlow flow = paragraph.CreateFlow();
List<TextLine> first = [], second = [];
while (first.Count < 4 && flow.NextLine(150) is TextLine line)
{
    first.Add(line);
}

while (flow.NextLine(second.Count < 2 ? 90 : 150) is TextLine line)
{
    second.Add(line);                                     // narrower beside the image
}

Properties

IsComplete

Gets whether every line has been laid out. An empty paragraph has no lines, and a final hard break adds none, as CSS lays text out.

public bool IsComplete { get; }

Property Value

bool

Paragraph

Gets the paragraph being laid out.

public Paragraph Paragraph { get; }

Property Value

Paragraph

Position

Gets the UTF-16 index the next line starts at.

public int Position { get; }

Property Value

int

Methods

NextLine(float)

Lays out the next line in the available width.

public TextLine? NextLine(float availableWidth)

Parameters

availableWidth float

The line's width in canvas units; PositiveInfinity for no wrapping.

Returns

TextLine

The line, its top at 0, or null when the paragraph is done.

Exceptions

ArgumentOutOfRangeException

availableWidth is negative or not a number.

Reset()

Starts again from the paragraph's first line.

public void Reset()

Rewind(int)

Takes back the lines from position on, so the next NextLine(float) lays out from there again: a line that did not fit at the foot of a column goes back to start the next one (Start).

public void Rewind(int position)

Parameters

position int

A line's start, at most Position.

Examples

// One article flowed down two columns of a page: LineFlow hands out one line at a time at the width asked for, so the
// first column can be narrowed beside a picture and the rest carries on in the second. On Egap's PDF canvas the same
// calls write searchable text.
ParagraphStyle style = new() { DefaultStyle = new TextStyle { FontFamilies = [family], Size = 10 }, Align = TextAlign.Justify };
LineFlow flow = Paragraph.Create(article, style).CreateFlow();
(float X, float Top, float Bottom)[] columns = [(40, 60, 300), (310, 60, 300)];
foreach ((float x, float top, float bottom) in columns)
{
    float y = top;
    while (!flow.IsComplete)
    {
        float width = x == 40 && y < 160 ? 150 : 245;      // beside a picture at the top of column one
        TextLine line = flow.NextLine(width)!;
        if (y + line.Height > bottom)
        {
            flow.Rewind(line.Start);                        // that line goes to the next column
            break;
        }

        foreach (LayoutRun run in line.Runs)
        {
            if (run.Glyphs is { Count: > 0 } glyphs)
            {
                page.DrawGlyphRun(glyphs, new System.Numerics.Vector2(x, y), new SolidPaint(Rgba8.Black));
            }
        }

        y += line.Height;
    }
}

Exceptions

ArgumentOutOfRangeException

position is negative or past Position.