Documentation
¶
Index ¶
- func AppendBoundsOfTextRange(dst []image.Rectangle, p *TextLayoutParams, start, end int) []image.Rectangle
- func CachedVisualLineCount(width int, logicalLine string, wrapMode WrapMode, face font.Face, ...) int
- func CachedVisualLineMaxCaretX(width int, logicalLine string, wrapMode WrapMode, face font.Face, ...) float64
- func Draw(bounds image.Rectangle, dst *ebiten.Image, str string, options *DrawOptions)
- func FindWordBoundaries(text string, idx int) (start, end int)
- func FirstLineBreakPositionAndLen(str string) (pos, length int)
- func LastLineBreakPositionAndLen(str string) (pos, length int)
- func Measure(width int, str string, wrapMode WrapMode, face font.Face, faceRuns []FaceRun, ...) (float64, float64)
- func MeasureHeight(width int, str string, wrapMode WrapMode, face font.Face, faceRuns []FaceRun, ...) float64
- func MeasureLogicalLine(width int, logicalLine string, wrapMode WrapMode, face font.Face, ...) (float64, float64)
- func MeasureLogicalLineHeight(width int, logicalLine string, wrapMode WrapMode, face font.Face, ...) float64
- func NextPositionOnGraphemes(str string, position int) int
- func PrevPositionOnGraphemes(str string, position int) int
- func TextIndexFromPosition(p *TextLayoutParams, position image.Point) int
- func TextIndexFromPositionInLogicalLine(width int, position image.Point, logicalLine string, ...) int
- func TrimPartialUTF8Prefix(s string) string
- func TrimPartialUTF8Suffix(s string) string
- func VisualLineCountForLogicalLine(width int, logicalLine string, wrapMode WrapMode, face font.Face, ...) int
- type CompositionInfo
- type CompositionInfoParams
- type DrawOptions
- type FaceRun
- type HorizontalAlign
- type Insertion
- type LineByteOffsets
- func (l *LineByteOffsets) ByteOffsetByLineIndex(i int) int
- func (l *LineByteOffsets) LineCount() int
- func (l *LineByteOffsets) LineIndexForByteOffset(byteOffset int) int
- func (l *LineByteOffsets) Rebuild(scan func(io.Writer) error) error
- func (l *LineByteOffsets) Replace(newText string, start, end int, startCtx, endCtx string, atEOT bool)
- func (l *LineByteOffsets) Reset()
- type LineHeightMode
- type Style
- type StyleRun
- type TextLayoutParams
- type TextPosition
- func PositionWithinLogicalLine(p *TextLayoutParams, index int) (lineIdx int, position0, position1 TextPosition, count int)
- func TextPositionFromIndex(p *TextLayoutParams, index int) (position0, position1 TextPosition, count int)
- func TextPositionFromIndexInLogicalLine(width int, logicalLine string, logicalLineStartInBytes, index int, ...) (position0, position1 TextPosition, count int)
- type VerticalAlign
- type VisibleRange
- type VisibleRangeInViewportParams
- type WrapMode
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func AppendBoundsOfTextRange ¶
func AppendBoundsOfTextRange(dst []image.Rectangle, p *TextLayoutParams, start, end int) []image.Rectangle
AppendBoundsOfTextRange appends the bounding rectangles covering the byte range [start, end) of the rendering text to dst and returns the extended slice, one rectangle per crossed visual line, in order. A visual line holding an empty part of the range appends nothing. Coordinates are relative to the text layout origin, rounded outward to integers. Endpoints outside the text are clamped.
func CachedVisualLineCount ¶
func CachedVisualLineCount(width int, logicalLine string, wrapMode WrapMode, face font.Face, faceRuns []FaceRun, logicalLineStartInBytes int, tabWidth float64, keepTailingSpace bool) int
CachedVisualLineCount is VisualLineCountForLogicalLine backed by the content-keyed layout cache. For WrapModeNone (no packing) or a non-UTF-8 line it falls back to the uncached count. Use this for per-tick height measurement of a logical line whose wrap layout the other cached paths (draw, caret, hit-test) also touch, so they share one cache entry.
func CachedVisualLineMaxCaretX ¶
func CachedVisualLineMaxCaretX(width int, logicalLine string, wrapMode WrapMode, face font.Face, faceRuns []FaceRun, logicalLineStartInBytes int, tabWidth float64, keepTailingSpace bool) float64
CachedVisualLineMaxCaretX returns the furthest caret position rendered on the logical line's visual lines, using the same content-keyed layout cache as CachedVisualLineCount.
func FindWordBoundaries ¶
func LastLineBreakPositionAndLen ¶
LastLineBreakPositionAndLen returns the position and the byte length of the last line break in str. If no line break is found, it returns (-1, 0).
func MeasureHeight ¶
func MeasureHeight(width int, str string, wrapMode WrapMode, face font.Face, faceRuns []FaceRun, insertion Insertion, lineHeight float64, lineHeightMode LineHeightMode, tabWidth float64, keepTailingSpace bool) float64
MeasureHeight is like Measure but only returns height. When width does not need to be computed, this avoids per-visual-line shaping calls and is dramatically cheaper for very long text (e.g. a multi-megabyte editor buffer).
func MeasureLogicalLine ¶
func MeasureLogicalLine(width int, logicalLine string, wrapMode WrapMode, face font.Face, faceRuns []FaceRun, insertion Insertion, logicalLineStartInBytes int, lineHeight float64, lineHeightMode LineHeightMode, tabWidth float64, keepTailingSpace bool, ellipsisString string) (float64, float64)
MeasureLogicalLine returns the rendered width and height of one logical line at the given width. Per-logical-line counterpart of Measure.
func MeasureLogicalLineHeight ¶
func MeasureLogicalLineHeight(width int, logicalLine string, wrapMode WrapMode, face font.Face, faceRuns []FaceRun, insertion Insertion, logicalLineStartInBytes int, lineHeight float64, lineHeightMode LineHeightMode, tabWidth float64, keepTailingSpace bool) float64
MeasureLogicalLineHeight returns the rendered height of one logical line at the given width. This is the per-logical-line counterpart of MeasureHeight and is used by virtualized layout to size lines one at a time without scanning the whole document.
func NextPositionOnGraphemes ¶
func PrevPositionOnGraphemes ¶
func TextIndexFromPosition ¶
func TextIndexFromPosition(p *TextLayoutParams, position image.Point) int
TextIndexFromPosition returns the byte offset in the rendering text closest to position. When p.PrecomputedLineByteOffsets is supplied, the visual-line walk is localized: it starts from (p.LogicalLineIndexHint, p.VisualLineIndexHint) and steps forward (or backward) one logical line at a time until the line covering position.Y is found. With the hint placed inside the viewport this costs O(visible lines) of typesetting per query, instead of the O(documentLen) full scan performed when no precomputed logical-line offsets are supplied.
When an active IME composition splices into the rendering text, the precomputed committed-text logical-line offsets are reused: byte/visual-line shifts derived from ComputeCompositionInfo map between committed and rendering coordinates without rebuilding the offsets. Falls back to the unrestricted whole-document walk when the composition crosses a logical-line boundary, when no precomputed logical-line offsets are supplied, or when the document is empty. The fallback is observationally equivalent to the fast path.
func TextIndexFromPositionInLogicalLine ¶
func TextIndexFromPositionInLogicalLine(width int, position image.Point, logicalLine string, logicalLineStartInBytes int, style *Style) int
TextIndexFromPositionInLogicalLine returns the byte offset within one logical line closest to the given position. The position's Y is relative to the top of the logical line. style's face runs use whole-text byte offsets; logicalLineStartInBytes is logicalLine's start offset in that text. Counterpart of TextIndexFromPosition.
func TrimPartialUTF8Prefix ¶
TrimPartialUTF8Prefix drops any continuation bytes (10xxxxxx) at the start of s that would have belonged to a UTF-8 sequence sliced before s.
func TrimPartialUTF8Suffix ¶
TrimPartialUTF8Suffix drops a partial UTF-8 sequence at the end of s when the slice was cut before the sequence's continuation bytes were included.
func VisualLineCountForLogicalLine ¶
func VisualLineCountForLogicalLine(width int, logicalLine string, wrapMode WrapMode, face font.Face, faceRuns []FaceRun, logicalLineStartInBytes int, tabWidth float64, keepTailingSpace bool) int
VisualLineCountForLogicalLine returns the number of visual lines one logical line wraps into at the given width. With wrapMode set to WrapModeNone (or when the line fits) the result is always 1. faceRuns use whole-text byte offsets; logicalLineStartInBytes is logicalLine's start offset in that text.
Types ¶
type CompositionInfo ¶
type CompositionInfo struct {
// LineIndex is the logical-line index of the selection line.
// Lines with index > LineIndex are "past the splice" and have
// RenderingByteShift and RenderingYShift applied.
LineIndex int
// RenderingByteShift is added to a past-the-splice line's
// committed byte offset to get its rendering byte offset. Equals
// the composition's byte length minus the length of the committed
// range it replaces, so it can be negative for selection-
// replacement compositions.
RenderingByteShift int
// RenderingYShift is added to a past-the-splice line's committed
// visual-Y (in pixels, top-of-line) to get its rendering visual-Y.
// Non-zero only when WrapMode is not [WrapModeNone] and the composition
// causes the selection line to wrap into a different number of visual
// sub-lines.
RenderingYShift int
}
CompositionInfo describes how an active IME composition shifts the document layout for the visible-range slicer. The zero value is safe to pass when no composition is active: the shifts are zero, so any "past the splice" comparison the slicer makes is harmless.
func ComputeCompositionInfo ¶
func ComputeCompositionInfo(p *CompositionInfoParams) (CompositionInfo, bool)
ComputeCompositionInfo classifies an active composition and returns info that the textutil functions use to translate between committed and rendering byte/visual-line coordinates. ok is false when the splice changes the logical-line count - a hard line break inside the composition or a selection that straddles a logical line boundary - and the caller should fall back to drawing the unrestricted text.
type CompositionInfoParams ¶
type CompositionInfoParams struct {
// CompositionText is the active composition's bytes — the bytes
// inserted into the rendering text at SelectionStart, replacing
// committed[SelectionStart:SelectionEnd].
CompositionText string
// LineByteOffsets is the logical-line layout of the committed text.
LineByteOffsets *LineByteOffsets
// SelectionStart and SelectionEnd are byte offsets into the
// committed text describing the range the composition replaces.
// SelectionStart == SelectionEnd for a pure insertion.
SelectionStart int
SelectionEnd int
// WrapMode toggles the visual-Y delta measurement for the
// selection line. When [WrapModeNone], RenderingYShift in the result
// is always 0 and the fields below are ignored.
WrapMode WrapMode
// CommittedSelectionLine and RenderingSelectionLine are the bytes
// of the logical line containing the selection (SelectionStart ..
// SelectionEnd, which always lies within a single logical line —
// the function rejects multi-line selections), in committed and
// rendering coordinates respectively. Required when WrapMode is
// not [WrapModeNone]; ignored otherwise.
CommittedSelectionLine string
RenderingSelectionLine string
// Face, LineHeight, LineHeightMode, TabWidth, KeepTailingSpace are
// passed through to [MeasureLogicalLineHeight] when WrapMode is not
// [WrapModeNone].
Face font.Face
LineHeight float64
LineHeightMode LineHeightMode
TabWidth float64
KeepTailingSpace bool
// CommittedFaceRuns and RenderingFaceRuns override Face for byte
// ranges of the selection line, in committed-text and rendering-text
// whole-text byte offsets respectively. Consulted only when WrapMode
// is not [WrapModeNone]; nil means no overrides.
CommittedFaceRuns []FaceRun
RenderingFaceRuns []FaceRun
// SelectionLineStartInBytes is the selection line's whole-text start
// offset. The line start precedes the splice, so the offset is the
// same in the committed and rendering texts.
SelectionLineStartInBytes int
// WrapWidth is the pixel width at which logical lines wrap into
// visual sublines. Values <= 0 are treated as math.MaxInt (no
// wrapping).
WrapWidth int
}
CompositionInfoParams describes the inputs for ComputeCompositionInfo.
type DrawOptions ¶
type DrawOptions struct {
Style
// LayoutWidth is the width used to wrap and align text. When zero, the
// drawing bounds width is used.
LayoutWidth int
TextColor color.Color
DrawSelection bool
SelectionStart int
SelectionEnd int
SelectionColor color.Color
DrawComposition bool
CompositionStart int
CompositionEnd int
CompositionActiveStart int
CompositionActiveEnd int
InactiveCompositionColor color.Color
ActiveCompositionColor color.Color
CompositionBorderWidth float32
// VisibleBounds restricts drawing to lines and glyphs that intersect this
// rectangle. Lines fully above or below are skipped without shaping, and
// glyphs whose drawn rectangle falls entirely outside are not submitted to
// [(*ebiten.Image).DrawImage]. An empty rectangle draws nothing.
VisibleBounds image.Rectangle
// StyleRuns are paint-only style overrides applied to byte ranges of the
// drawn string, sorted by Start and disjoint. An empty slice draws the
// whole string uniformly.
StyleRuns []StyleRun
}
type FaceRun ¶
type FaceRun struct {
// Start is the inclusive start of the range in bytes.
Start int
// End is the exclusive end of the range in bytes.
End int
// Face measures and draws the range.
Face font.Face
}
FaceRun overrides the face used to measure and draw a byte range of the laid-out text.
type HorizontalAlign ¶
type HorizontalAlign int
const ( HorizontalAlignStart HorizontalAlign = iota HorizontalAlignCenter HorizontalAlignEnd HorizontalAlignLeft HorizontalAlignRight )
type Insertion ¶
type Insertion struct {
// Face is the face the inserted text uses. The zero value means there is
// no insertion.
Face font.Face
// IndexInBytes is the insertion's byte offset in the laid-out text.
IndexInBytes int
}
Insertion is a zero-width position in the laid-out text carrying the face of the text that will be inserted there. It takes part in the height of the visual line holding it, as a character with that face would. A face is all it carries: nothing is drawn at the position, so the colors and decorations of a StyleRun would have nothing to apply to.
type LineByteOffsets ¶
type LineByteOffsets struct {
// contains filtered or unexported fields
}
LineByteOffsets holds the byte offsets where each logical line (segment separated by hard line breaks) begins within a source string. It is a precomputed logical-line offset index that enables O(log n) line<->byte-offset lookups without rescanning the text.
After a rebuild the first entry is always 0 and the entries are strictly increasing. A trailing line break in the source string creates an extra empty line at the end (e.g. "abc\n" has two logical lines).
func (*LineByteOffsets) ByteOffsetByLineIndex ¶
func (l *LineByteOffsets) ByteOffsetByLineIndex(i int) int
ByteOffsetByLineIndex returns the byte offset of the start of the i-th logical line. Panics if i is out of range.
func (*LineByteOffsets) LineCount ¶
func (l *LineByteOffsets) LineCount() int
LineCount returns the number of logical lines.
The empty string has one logical line. A trailing line break creates an extra empty line, so "abc\n" has two logical lines.
func (*LineByteOffsets) LineIndexForByteOffset ¶
func (l *LineByteOffsets) LineIndexForByteOffset(byteOffset int) int
LineIndexForByteOffset returns the index of the logical line that contains byteOffset. byteOffset is clamped: negative values map to line 0 and values past the text map to the last line.
func (*LineByteOffsets) Rebuild ¶
func (l *LineByteOffsets) Rebuild(scan func(io.Writer) error) error
Rebuild discards any current contents and rescans the bytes written by scan for logical-line starts. The io.Writer passed to scan accepts bytes in any number of chunks; the recorded offsets are the same as if the concatenated bytes had been scanned in a single pass. Any error from scan is returned unchanged after the trailing partial-break state has been flushed.
func (*LineByteOffsets) Replace ¶
func (l *LineByteOffsets) Replace(newText string, start, end int, startCtx, endCtx string, atEOT bool)
Replace updates the offsets to reflect a splice that replaced the source text's [start, end) byte range with newText. The caller must invoke Replace immediately after applying the same splice to the underlying source.
startCtx is the up-to-2-byte slice of pre-splice text immediately before start (positions [max(0, start-2), start)); it is used to derive the scanner's entry state at start so a partial break ending at the splice boundary disambiguates correctly. endCtx is the up-to-3-byte slice of post-splice text immediately after newText (positions [start+len(newText), start+len(newText)+3)); it provides the lookahead the scanner needs for breaks formed at the splice's far boundary. atEOT must be true iff endCtx reaches end-of-text (i.e. start+len(newText)+3 ≥ post-splice length).
After Replace returns, the offsets describe the post-splice text.
func (*LineByteOffsets) Reset ¶
func (l *LineByteOffsets) Reset()
Reset clears the offsets. After Reset, LineCount returns 0; callers that expect at least one line must rebuild first.
type LineHeightMode ¶
type LineHeightMode int
LineHeightMode selects how a visual line's height responds to the font sizes on it. The basicwidget package mirrors this enum for its public API.
const ( // LineHeightModeFixed gives every visual line the same height. Text // larger than the line height overflows into the adjacent lines. LineHeightModeFixed LineHeightMode = iota // LineHeightModeFlexible scales a visual line's height and baseline by // the largest font size on it, relative to the base face's size. LineHeightModeFlexible )
type Style ¶
type Style struct {
WrapMode WrapMode
Face font.Face
// FaceRuns overrides Face for byte ranges of the laid-out text, sorted
// by Start and disjoint. An empty slice measures and draws the whole
// text with Face.
FaceRuns []FaceRun
// Insertion is the pending insertion point of the laid-out text. The
// zero value means there is none.
Insertion Insertion
LineHeight float64
// LineHeightMode selects how LineHeight responds to the font sizes on a
// visual line.
LineHeightMode LineHeightMode
HorizontalAlign HorizontalAlign
VerticalAlign VerticalAlign
TabWidth float64
KeepTailingSpace bool
EllipsisString string
}
type StyleRun ¶
type StyleRun struct {
// Start is the inclusive start of the range in bytes.
Start int
// End is the exclusive end of the range in bytes.
End int
// Color overrides the text and decoration color. Nil inherits
// [DrawOptions.TextColor].
Color color.Color
// BackgroundColor fills the range's background. Nil draws no background.
BackgroundColor color.Color
// Underline draws a line under the text.
Underline bool
// Strikethrough draws a line through the text.
Strikethrough bool
}
StyleRun is a paint-only style override applied to a byte range of the drawn string.
type TextLayoutParams ¶
type TextLayoutParams struct {
// RenderingTextRange returns rendering[start:end), where the
// rendering text is the committed text with any active composition
// spliced in. RenderingTextLength is the total byte length of the
// rendering text. Required: all reads of the rendering text — both
// the fast path and the slow-path fallback — go through this
// callback so the caller never has to materialize the full
// document.
RenderingTextRange func(start, end int) string
RenderingTextLength int
// Width is the rendering width.
Width int
// Style carries face, lineHeight, wrap mode, alignment, tab
// width, etc. Style.FaceRuns uses rendering-text byte offsets.
Style Style
// CommittedTextRange returns committed[start:end). Required when
// CompositionLen > 0; ignored otherwise.
CommittedTextRange func(start, end int) string
// CommittedFaceRuns carries the same face overrides as Style.FaceRuns
// in committed-text byte offsets. Consulted only when CompositionLen
// > 0; nil means no overrides.
CommittedFaceRuns []FaceRun
// PrecomputedLineByteOffsets is the logical-line layout of the committed text.
// Optional; when nil the query falls back to an O(documentLen) walk
// of every visual line.
PrecomputedLineByteOffsets *LineByteOffsets
// SelectionStart, SelectionEnd, CompositionLen describe an active
// IME composition: bytes [SelectionStart, SelectionEnd) in the
// committed text are replaced with bytes [SelectionStart,
// SelectionStart+CompositionLen) in the rendering text.
// CompositionLen == 0 means no active composition; the other
// fields are ignored in that case.
SelectionStart int
SelectionEnd int
CompositionLen int
// LogicalLineIndexHint / VisualLineIndexHint define the visual-line
// coordinate system the walk starts from: the logical line at
// LogicalLineIndexHint is treated as starting at visual-line index
// VisualLineIndexHint, and the walk steps forward (or backward)
// from there to the line the query resolves to. The result is
// therefore expressed in the caller's coordinate system — (0, 0)
// measures from line 0 (the document top); (firstLogicalLineInViewport, 0)
// measures from the first visible line's top, used by virtualized
// text.
//
// The walk is bounded by the logical-line distance between the
// hint and the resolved line, so a caller that pins the hint inside
// its viewport pays only O(visible) typesetting per query. The zero
// value walks from the document top. Used only when
// PrecomputedLineByteOffsets is set.
LogicalLineIndexHint int
VisualLineIndexHint int
}
TextLayoutParams carries the text-layout context shared by TextIndexFromPosition, TextPositionFromIndex, and PositionWithinLogicalLine. The first group of fields is always required; the second group is optional state that enables the fast path backed by the precomputed logical-line offsets.
type TextPosition ¶
func PositionWithinLogicalLine ¶
func PositionWithinLogicalLine(p *TextLayoutParams, index int) (lineIdx int, position0, position1 TextPosition, count int)
PositionWithinLogicalLine returns the caret's logical-line index and its visual position(s). pos.Top / pos.Bottom are measured from the start of the line at lineIdx, not the document top.
count==0 when the result is unavailable: index out of range, no precomputed logical-line offsets, empty document, or composition straddling a logical-line boundary. Callers needing the slow whole-document fallback in that case should call TextPositionFromIndex.
func TextPositionFromIndex ¶
func TextPositionFromIndex(p *TextLayoutParams, index int) (position0, position1 TextPosition, count int)
TextPositionFromIndex returns the visual position(s) for index in the rendering text. The Y origin is the visual line at (p.LogicalLineIndexHint, p.VisualLineIndexHint); count is 1, or 2 at line- break boundaries.
func TextPositionFromIndexInLogicalLine ¶
func TextPositionFromIndexInLogicalLine(width int, logicalLine string, logicalLineStartInBytes, index int, style *Style) (position0, position1 TextPosition, count int)
TextPositionFromIndexInLogicalLine returns the visual position(s) within one logical line corresponding to the given byte index inside that line. The Y values are relative to the top of the logical line (so the caller can offset them by the line's origin Y). Counterpart of TextPositionFromIndex.
index is a byte offset in [0, len(logicalLine)]. style's face runs use whole-text byte offsets; logicalLineStartInBytes is logicalLine's start offset in that text. Out-of-range values yield (TextPosition{}, TextPosition{}, 0).
type VerticalAlign ¶
type VerticalAlign int
const ( VerticalAlignTop VerticalAlign = iota VerticalAlignMiddle VerticalAlignBottom )
type VisibleRange ¶
type VisibleRange struct {
// FirstLine and LastLine are the inclusive range of logical-line
// indices the caller should draw.
FirstLine, LastLine int
// StartInBytes and EndInBytes are the byte range of the rendering
// text the caller should draw: rendering[StartInBytes:EndInBytes].
StartInBytes, EndInBytes int
// YShift is added to the drawing-origin Y so the first sliced line
// lands at its original screen Y. Already includes the alignment-
// specific portion of the original Y offset, so the caller forces
// [VerticalAlignTop] when calling [Draw].
YShift int
}
VisibleRange is the result of VisibleRangeInViewport when its ok return is true.
func VisibleRangeInViewport ¶
func VisibleRangeInViewport(p *VisibleRangeInViewportParams) (VisibleRange, bool)
VisibleRangeInViewport returns the byte range and logical-line indices that cover the visible region when the widget is positioned so FirstLogicalLineInViewport sits at widget-local Y=0. The walk steps forward from FirstLogicalLineInViewport, measuring each logical line's wrap count on the fly, so a caller pinned to the topmost visible line pays only O(visible) typesetting per query. Composition splices on lines past the splice are handled by reading rendering-text bytes for the composition's selection line.
ok is false when the document is empty.
VerticalAlign is intentionally not part of the input: when the caller pins the viewport at a non-zero logical line, the document is assumed to overflow the viewport (the case where alignment matters), so YShift is always 0 and the caller's bounds positioning carries any needed offset itself.
type VisibleRangeInViewportParams ¶
type VisibleRangeInViewportParams struct {
// FirstLogicalLineInViewport is the logical line whose top sits
// at the widget-local origin (Y=0). The caller's bounds-positioning
// places this line at the top of the rendered output, so the
// returned VisibleRange.FirstLine is always this index (clamped to
// the document) and YShift is always 0.
FirstLogicalLineInViewport int
// LineByteOffsets is the logical-line layout of the committed
// text. The number of logical lines comes from its LineCount.
LineByteOffsets *LineByteOffsets
// RenderingTextRange returns rendering[start:end). The walker
// reads each measured line through this callback so the caller
// never has to materialize the full rendering text. Required when
// WrapMode is not [WrapModeNone] (so the walker can shape per-line
// content); for [WrapModeNone] only RenderingTextLength is consulted.
RenderingTextRange func(start, end int) string
// RenderingTextLength is the total byte length of the rendering
// text.
RenderingTextLength int
// ViewportSize describes the rendering box the walker operates
// against: X is the wrap width passed through to
// [VisualLineCountForLogicalLine] when WrapMode is not
// [WrapModeNone], and Y is the distance below
// FirstLogicalLineInViewport's top that the visible region extends
// downward. The walk stops once cumulative line heights exceed Y,
// leaving one line of slack so the caller's inner Y clip can handle
// off-by-one rounding.
ViewportSize image.Point
// Face, LineHeight, LineHeightMode, TabWidth, KeepTailingSpace are
// passed through to [VisualLineCountForLogicalLine] when WrapMode is
// not [WrapModeNone].
Face font.Face
LineHeight float64
LineHeightMode LineHeightMode
TabWidth float64
KeepTailingSpace bool
// FaceRuns are the per-range face overrides of the rendering text,
// sorted by Start and disjoint.
FaceRuns []FaceRun
// Insertion is the pending insertion point of the rendering text. The
// zero value means there is none.
Insertion Insertion
// WrapMode toggles between a per-line shaping walk (any wrapping
// mode) and a flat LineHeight*idx arithmetic ([WrapModeNone]).
WrapMode WrapMode
// Composition is the splice info from [ComputeCompositionInfo].
// The zero value means "no active composition".
Composition CompositionInfo
}
VisibleRangeInViewportParams describes the inputs for VisibleRangeInViewport. The walk steps forward from FirstLogicalLineInViewport measuring per-line heights via VisualLineCountForLogicalLine until cumulative height covers Height, so the cost is O(visible logical lines) — the prefix [0, FirstLogicalLineInViewport) is never measured.