Tincture.Typography (Tincture v0.1.0)

Copy Markdown View Source

Paragraph layout: hyphenation, line breaking and justification.

This is the part Tincture inherits most directly from Joe Armstrong's erlguten, and the reason the library exists rather than wrapping a browser.

Line breaking

Two strategies, chosen with the :line_break option:

  • :greedy — fill each line as far as it goes, then break. Fast, and what most PDF libraries do.
  • :optimal — Knuth-Plass. Considers the paragraph as a whole and minimises total badness, so a tight line early on can be relaxed to avoid a much worse one later. This is what TeX does, and it is visibly better in justified text.

The optimal breaker models text as boxes, glue and penalties, and scores candidate breaks on fitness class, hyphenation, consecutive hyphens, and widows and orphans — all tunable per call.

Hyphenation

TeX hyphenation patterns, for :en_gb, :da_dk, :fi_fi, :nb_no and :sv_se. See Tincture.Typography.Hyphen.

Example

rich = RichText.from_plain(body, font: "Times-Roman", size: 11)

Typography.layout_paragraph(rich, 450,
  align: :justified,
  line_break: :optimal,
  widow_penalty: 150,
  orphan_penalty: 150
)

Returns positioned Line structs. Most callers reach this through Tincture.text_paragraph/6 rather than calling it directly.

Summary

Types

align()

@type align() :: :left | :center | :right | :justified

line_break_mode()

@type line_break_mode() :: :greedy | :optimal

optimal_cost_model()

@type optimal_cost_model() :: :quadratic | :box_glue

option()

@type option() ::
  {:align, align()}
  | {:line_height, number()}
  | {:line_break, line_break_mode()}
  | {:optimal_cost_model, optimal_cost_model()}
  | {:justify_max_space_multiplier, number()}
  | {:justify_min_space_multiplier, number()}
  | {:widow_penalty, number()}
  | {:orphan_penalty, number()}
  | {:hyphen_penalty, number()}
  | {:fitness_class_penalty, number()}
  | {:consecutive_hyphen_penalty, number()}

Functions

layout_paragraph(rich, max_width, opts \\ [])

@spec layout_paragraph(Tincture.Typography.RichText.t(), number(), [option()]) :: [
  Tincture.Typography.Line.t()
]

layout_paragraph_with_spill(rich, max_width, max_lines, opts \\ [])

@spec layout_paragraph_with_spill(
  Tincture.Typography.RichText.t(),
  number(),
  pos_integer(),
  [option()]
) ::
  Tincture.Typography.LayoutResult.t()