layout

package
v0.1.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 7, 2026 License: BSD-3-Clause Imports: 6 Imported by: 0

Documentation

Overview

Package layout is a block-and-inline flow engine. Block boxes stack vertically honouring margins, padding and width; inline content (text runs and inline elements) is broken into lines within the containing block at a given viewport width using measured word advances supplied through a Measurer. The geometry is deterministic and, given a fake Measurer, exactly testable without any font machinery.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func BuildIndex

func BuildIndex(root *Box) map[*dom.Node]Rect

BuildIndex walks a laid-out box tree and returns, for every element node, its used border-box rectangle in document coordinates. Block-level elements take their box rect directly (authoritative); inline-level elements — which produce InlineItems inside line boxes rather than their own Box — take the union of their fragments' rects (and of any inline descendants). This is the geometry the JS DOM binding reads back through getBoundingClientRect / offset* / getComputedStyle, so scripts that decide layout from measured metrics (responsive nav, MediaWiki's mw.loader sidebar collapse) see real numbers.

Types

type Box

type Box struct {
	Node       *dom.Node
	Style      *css.Style
	X, Y, W, H float64

	ContentX, ContentY, ContentW, ContentH float64

	Children  []*Box
	Lines     []*LineBox
	Anonymous bool

	// Float marks a box taken out of normal flow (float:left/right). Floated
	// boxes are painted like blocks but positioned by the float algorithm.
	Float css.Float

	// Position records the box's CSS position. Relative/sticky boxes remain in
	// flow but are shifted at the end of layout; absolute/fixed boxes are laid
	// out out of flow and appended to the root box (painted after in-flow
	// content) with their coordinates already resolved to document space.
	Position css.Position

	// Marker is the list-item marker box (bullet or ordinal), non-nil only on a
	// display:list-item box whose list-style-type is not `none`. Its coordinates
	// are in document space, positioned relative to this box's content box.
	Marker *Marker
}

Box is a laid-out block box. X,Y,W,H describe the border box (which, with no borders in Phase 0, equals the padding box that a background fills). Content* describe the content box. A box either has block Children or holds inline Lines (an anonymous box may hold Lines and carry no Node).

func LayoutDocument

func LayoutDocument(root *dom.Node, sm css.StyleMap, viewportW float64, m Measurer, imgSize map[*dom.Node][2]float64) (*Box, float64)

LayoutDocument lays out the element subtree at root within a viewport of width viewportW (CSS pixels), returning the root Box and the total content height. imgSize provides intrinsic image dimensions keyed by <img> node; it may be nil (images then fall back to width/height attributes).

type InlineItem

type InlineItem struct {
	Text  string
	Style *css.Style

	// Node is the element that directly produced this item — the immediate
	// parent element of a text run, or the <img> element of an image item. It
	// lets a consumer walk up the DOM (e.g. to the nearest <a href> ancestor)
	// without re-deriving document structure from geometry. It is nil only for
	// synthetic items with no originating element (a forced <br> carries its
	// own element; anonymous runs never occur here).
	Node *dom.Node

	Width       float64 // advance of the word / width of the image
	SpaceBefore float64 // width of a space in this item's font
	Ascent      float64
	LineHeight  float64

	Image      *dom.Node // non-nil when this item is an <img>
	ImgW, ImgH float64

	LineBreak bool // a <br>: forces the current line to end

	X, Y float64
}

InlineItem is one atom of inline content: a word, an image, or a forced line break. Positions (X,Y = top-left) are filled during line layout.

type LineBox

type LineBox struct {
	X, Y, W, H float64
	Items      []*InlineItem
}

LineBox is one line of inline content with its positioned items.

func WrapItems

func WrapItems(items []*InlineItem, maxW float64) []*LineBox

WrapItems greedily breaks a sequence of inline items into lines so that each line's used width does not exceed maxW, inserting a per-item SpaceBefore between adjacent items on the same line. A single item wider than maxW is placed alone on its own line (overflow). A LineBreak item ends the current line (and is not itself placed). This is the pure, exactly-testable core of inline layout; positioning and heights are applied by the caller.

type Marker

type Marker struct {
	Type       css.ListStyleType
	Style      *css.Style
	X, Y, W, H float64
	Ascent     float64
	Text       string
}

Marker is a laid-out list-item marker. For a bullet type (disc/circle/square) X,Y,W,H is the glyph's square bounding box. For the decimal type, Text is the ordinal string ("1.", "2.", …), X is its pen origin, Y the top of its line box and Ascent the baseline offset; W is the text advance (H unused). Style supplies the marker's colour and, for decimal, its font face.

type Measurer

type Measurer interface {
	// Measure returns the advance width in pixels of text in the given family,
	// size, weight and style (italic).
	Measure(text string, fam css.FontFamily, sizePx float64, weight int, italic bool) float64
	// Metrics returns the ascent (baseline offset from the top) and the line
	// height in pixels for a family/size/weight/style.
	Metrics(fam css.FontFamily, sizePx float64, weight int, italic bool) (ascent, lineHeight float64)
}

Measurer supplies text metrics to the layout engine. The real implementation lives in the paint package (backed by go-opentype); tests inject a fake.

type Rect

type Rect struct{ X, Y, W, H float64 }

Rect is a used-geometry rectangle in document (CSS pixel) coordinates: X,Y is the top-left of the border box, W,H its size.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL