text/layout.go

Functions Structs

Functions

func DefaultLayoutOptions

DefaultLayoutOptions returns sensible default layout options.

func DefaultLayoutOptions() LayoutOptions {
	return LayoutOptions{
		MaxWidth:	0,	// No wrapping (no MaxWidth constraint)
		LineSpacing:	1.0,
		Alignment:	AlignLeft,
		Direction:	DirectionLTR,
		// WrapMode defaults to WrapWordChar (zero value)
	}
}

func Height

Height returns the total height of the line (ascent + descent).

func (l *Line) Height() float64 {
	return l.Ascent + l.Descent
}

func LayoutText

LayoutText performs text layout with the given options.

It segments text by direction/script, shapes each segment,

wraps lines if MaxWidth > 0, and positions lines with alignment.

The font size is obtained from face.Size().

 

For cancellable layout, use LayoutTextWithContext.

func LayoutText(text string, face Face, opts LayoutOptions) *Layout {
	layout, _ := LayoutTextWithContext(context.Background(), text, face, opts)
	return layout
}

func LayoutTextSimple

LayoutTextSimple is a convenience wrapper with default options.

The font size is obtained from face.Size().

func LayoutTextSimple(text string, face Face) *Layout {
	return LayoutText(text, face, DefaultLayoutOptions())
}

func LayoutTextWithContext

LayoutTextWithContext performs text layout with the given options and cancellation support.

It segments text by direction/script, shapes each segment,

wraps lines if MaxWidth > 0, and positions lines with alignment.

The font size is obtained from face.Size().

 

The context can be used to cancel long-running layout operations.

When canceled, returns nil and ctx.Err().

func LayoutTextWithContext(ctx context.Context, text string, face Face, opts LayoutOptions) (*Layout, error) {
	if text == "" {
		return &Layout{}, nil
	}
	if face == nil {
		return &Layout{}, nil
	}

	// Check for cancellation at start
	select {
	case <-ctx.Done():
		return nil, ctx.Err()
	default:
	}

	// Apply defaults for zero values
	if opts.LineSpacing <= 0 {
		opts.LineSpacing = 1.0
	}

	// Get font metrics for line height calculation
	metrics := face.Metrics()

	// Split by hard line breaks
	paragraphs := splitParagraphs(text)

	layout := &Layout{
		Lines: make([]Line, 0, len(paragraphs)),
	}

	var y float64

	for i, para := range paragraphs {
		// Check for cancellation periodically (every 8 paragraphs)
		if i%8 == 0 && i > 0 {
			select {
			case <-ctx.Done():
				return nil, ctx.Err()
			default:
			}
		}

		paraLines := layoutParagraph(para, face, opts, metrics)

		for j := range paraLines {
			line := ¶Lines[j]

			// Calculate baseline position: previous Y + line ascent
			if len(layout.Lines) == 0 && j == 0 {
				// Very first line of entire layout
				y = line.Ascent
			} else {
				// Get previous line: from current paragraph or from layout.Lines
				var prevLine *Line
				if j > 0 {
					prevLine = ¶Lines[j-1]
				} else {
					prevLine = &layout.Lines[len(layout.Lines)-1]
				}
				lineGap := metrics.LineGap * opts.LineSpacing
				y = prevLine.Y + prevLine.Descent + lineGap + line.Ascent
			}

			line.Y = y

			// Apply horizontal alignment
			applyAlignment(line, opts.Alignment, opts.MaxWidth)

			// Track layout bounds
			if line.Width > layout.Width {
				layout.Width = line.Width
			}
		}

		layout.Lines = append(layout.Lines, paraLines...)
	}

	// Calculate total height
	if len(layout.Lines) > 0 {
		lastLine := &layout.Lines[len(layout.Lines)-1]
		layout.Height = lastLine.Y + lastLine.Descent
	}

	return layout, nil
}

func String

String returns the string representation of the alignment.

func (a Alignment) String() string {
	switch a {
	case AlignLeft:
		return "Left"
	case AlignCenter:
		return "Center"
	case AlignRight:
		return "Right"
	case AlignJustify:
		return "Justify"
	default:
		return unknownStr
	}
}

Structs

type LayoutOptions struct

LayoutOptions configures text layout behavior.

type LayoutOptions struct {
	// MaxWidth is the maximum line width in pixels.
	// If 0, no line wrapping is performed (single-line paragraphs).
	MaxWidth	float64

	// LineSpacing is a multiplier for line height.
	// 1.0 uses the font's natural line height; 1.5 adds 50% extra space.
	LineSpacing	float64

	// Alignment specifies horizontal text alignment.
	Alignment	Alignment

	// Direction is the base text direction (LTR or RTL).
	// Used for paragraph-level direction when no strong directional text is present.
	Direction	Direction

	// WrapMode specifies how text is wrapped when it exceeds MaxWidth.
	// Default is WrapWordChar which breaks at word boundaries first,
	// then falls back to character boundaries for long words.
	WrapMode	WrapMode
}

type Line struct

Line represents a positioned line of text ready for rendering.

type Line struct {
	// Runs contains the shaped runs that make up this line.
	// Multiple runs occur with mixed scripts or directions.
	Runs	[]ShapedRun

	// Glyphs contains all glyphs from Runs, positioned for rendering.
	// Glyph X positions are absolute within the layout.
	Glyphs	[]ShapedGlyph

	// Width is the total advance width of all glyphs in this line.
	Width	float64

	// Ascent is the maximum ascent of all runs (distance above baseline).
	Ascent	float64

	// Descent is the maximum descent of all runs (distance below baseline).
	Descent	float64

	// Y is the baseline Y position of this line within the layout.
	Y	float64
}

type Layout struct

Layout represents the result of text layout.

type Layout struct {
	// Lines contains all lines of laid out text.
	Lines	[]Line

	// Width is the maximum width among all lines.
	Width	float64

	// Height is the total height of all lines.
	Height	float64
}