Resources Numerical accuracy Calculation policy

Text width from built-in font metrics

The width of a text string, used to size and wrap text boxes in the markup.

How the precision is kept

Widths come from a table of whole-number advances in 1/1000 em, so the result is exact only as far as that table. The sum of advances is a whole number, divided once by 1000 and multiplied by the size.

Calculations under this policy

2 calculations in 1 source file. The code is read from the released app when this page loads. It is the calculation people run, not a copy kept for this page.

font.js MarkupCraft 0.8.1 64-bit 2 calculations Reviewed

Tests None found by the review

Character advance

64-bit

The advance width of one character in 1/1000 em.

Printable ASCII reads the table directly. Wider characters in bold use Math.round(w × 1.04). Unknown characters fall back to 556 or 1000.

  • font.js
  • lines 32 to 42
  • MarkupCraft 0.8.1
export function charAdvance(ch, bold = false) {
  ch = SUBST[ch] || ch;
  const table = bold ? HELV_BOLD : HELV;
  const code = ch.codePointAt(0);
  if (code >= 32 && code < 127) return table[code - 32];
  const w = CP1252[ch] !== undefined ? WIDE[CP1252[ch]] : WIDE[code];
  if (w) return bold ? Math.round(w * 1.04) : w;
  const b = ch.normalize('NFD')[0].codePointAt(0);
  if (b >= 32 && b < 127) return table[b - 32];
  return code >= 0x2e80 ? 1000 : 556;
}

String width

64-bit

The width of a string at a font size.

width = (Σ advance ÷ 1000) × size

The advances are integers, so their sum is exact; there is one division and one multiply.

  • font.js
  • lines 44 to 49
  • MarkupCraft 0.8.1
/** Width of a string at a font size (same units as size). */
export function textWidth(s, size, bold = false) {
  let w = 0;
  for (const ch of String(s)) w += charAdvance(ch, bold);
  return (w / 1000) * size;
}

In detail

Method
Sum of table advances ÷ 1000 × font size. Bold widths for characters outside printable ASCII are the regular width times 1.04, rounded.
Number types
64-bit numbers; advances are integers.
Tolerances
Wrapping fits a line when its width is less than or equal to the maximum width, with no tolerance.
Limits
Characters with no table entry get 556 (or 1000 for East Asian characters). The bold factor 1.04 is an estimate, not a table value.

Approach: 64-bit, stated limit

The arithmetic is 64-bit, but the method or the data sets the accuracy: a solver tolerance, a mesh, a step size, a datum shift, a table. The limit is stated where the result is shown.

Every policy that takes this approach