shapedjs

package
v0.3.20 Latest Latest
Warning

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

Go to latest
Published: Feb 20, 2026 License: BSD-3-Clause Imports: 12 Imported by: 0

README

html canvas (js) text shaping

The challenge faced by this package is to support text shaping using the html canvas measureText function, and the canvas fillText function to actually render the text, in a way that supports the necessary functionality.

The basic layout problem is tricky because:

  • In all platforms, formatted [rich.Text] must be rendered in spans where the same font styling parameters apply. Multiple spans can (and often do) appear on the same line of text.

  • The fillText and measureText functions only operate with a single active font style at a time (i.e., one span), and render requires an X, Y position to render at.

  • Layout and line wrapping requires assembling these spans and breaking them up at the right spots, which requires splitting spans and thus the ability to measure smaller chunks of text to figure out where to split. Doing this the right way in an internationalized text context requires knowledge of graphemes, and re-shaping spans after splitting them, etc. There is lots of complex logic in go-text for doing all of this.

  • Thus, it would be so much better to use go-text to manage all the layout, but that is not possible because there is no way to actually determine the font being used: stackoverflow nor is it possible to even get a list of fonts that might be used: stackoverflow

Fortunately, a simple strategy that works well in practice is to use go-text for first-pass layout and line wrapping, via the shapedgt package, and then go back through with html measureText on the actual chunks produced by that, and adjust the sizes accordingly. This is done in the AdjustOutput function.

Documentation

Rendered for js/wasm

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func NewShaper

func NewShaper() shaped.Shaper

NewShaper returns a new text shaper.

func SetFontStyle

func SetFontStyle(ctx js.Value, fnt *text.Font, tsty *text.Style, lineHeight float32)

SetFontStyle sets the html canvas font style from text.Font and text.Style, with optional lineHeight

Types

type Metrics

type Metrics struct {
	// Width is the actual width of the text span, which appears to be equivalent to the
	// Advance in go-text.
	Width float32

	// ActualBoundingBoxLeft is the distance parallel to the baseline from the
	// alignment point given by the CanvasRenderingContext2D.textAlign property
	// to the left side of the bounding rectangle of the given text, in CSS pixels.
	// Positive numbers indicating a distance going left from the given alignment point.
	ActualBoundingBoxLeft float32

	// ActualBoundingBoxRight is the distance from the alignment point given by the
	// CanvasRenderingContext2D.textAlign property to the right side of the bounding
	// rectangle of the given text, in CSS pixels.
	// The distance is measured parallel to the baseline.
	ActualBoundingBoxRight float32

	// FontBoundingBoxAscent is the distance from the horizontal line indicated
	// by the CanvasRenderingContext2D.textBaseline attribute to the top of the
	// highest bounding rectangle of all the fonts used to render the text, in CSS pixels.
	FontBoundingBoxAscent float32

	// FontBoundingBoxDescent is the distance from the horizontal line indicated
	// by the CanvasRenderingContext2D.textBaseline attribute to the bottom of the
	// bounding rectangle of all the fonts used to render the text, in CSS pixels.
	FontBoundingBoxDescent float32

	// ActualBoundingBoxAscent is the distance from the horizontal line indicated
	// by the CanvasRenderingContext2D.textBaseline attribute to the top of the
	// highest bounding rectangle of the actual text, in CSS pixels.
	ActualBoundingBoxAscent float32

	// ActualBoundingBoxDescent is the distance from the horizontal line indicated
	// by the CanvasRenderingContext2D.textBaseline attribute to the bottom of the
	// bounding rectangle of all the fonts used to render the text, in CSS pixels.
	ActualBoundingBoxDescent float32
}

Metrics are html canvas MeasureText metrics.

func MeasureText

func MeasureText(ctx js.Value, txt string) *Metrics

MeasureText calls html canvas MeasureText functon on given canvas context, using currently set font.

type Shaper

type Shaper struct {
	shapedgt.Shaper
}

Shaper is the html canvas version of text shaping, which bootstraps off of the go-text version and corrects the results using the results of measuring the text.

func (*Shaper) FontSize

func (sh *Shaper) FontSize(r rune, sty *rich.Style, tsty *text.Style) shaped.Run

FontSize returns the font shape sizing information for given font and text style, using given rune (often the letter 'm'). The GlyphBounds field of the [Run] result has the font ascent and descent information, and the BoundsBox() method returns a full bounding box for the given font, centered at the baseline. This is called under a mutex lock, so it is safe for parallel use.

func (*Shaper) LineHeight

func (sh *Shaper) LineHeight(sty *rich.Style, tsty *text.Style) float32

LineHeight returns the line height for given font and text style. For vertical text directions, this is actually the line width. It includes the text.Style LineHeight multiplier on the natural font-derived line height, which is not generally the same as the font size. This is called under a mutex lock, so it is safe for parallel use.

func (*Shaper) Shape

func (sh *Shaper) Shape(tx rich.Text, tsty *text.Style) []shaped.Run

Shape turns given input spans into [Runs] of rendered text, using given context needed for complete styling. The results are only valid until the next call to Shape or WrapParagraph: use slices.Clone if needed longer than that. This is called under a mutex lock, so it is safe for parallel use.

func (*Shaper) WrapLines

func (sh *Shaper) WrapLines(tx rich.Text, defSty *rich.Style, tsty *text.Style, size math32.Vector2) *shaped.Lines

WrapLines performs line wrapping and shaping on the given rich text source, using the given style information, where the rich.Style provides the default style information reflecting the contents of the source (e.g., the default family, weight, etc), for use in computing the default line height. Paragraphs are extracted first using standard newline markers, assumed to coincide with separate spans in the source text, and wrapped separately. For horizontal text, the Lines will render with a position offset at the upper left corner of the overall bounding box of the text. This is called under a mutex lock, so it is safe for parallel use.

Jump to

Keyboard shortcuts

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