glyphWidthAt method

double? glyphWidthAt(
  1. int index,
  2. int length
)

The width the PDF gives the glyph starting at index and spanning length code units, in em, with this run's spacing taken back off - the glyph's own advance rather than the pen's.

charOffsets are pen positions, so a step across one glyph carries the letterSpacing (and, after a space, the wordSpacing) that follows it. Spacing is not shape. A device substituting a system font sizes its glyphs by measuring them against the width the document gives them, and measuring against the pen step instead stretches the shapes to swallow the gap: ( 3)Tj under a 15.137 Tc - how a CAD export reaches the next table column - is a digit 0.556 em wide inside a 2.24 em step, and comes out four times too wide. Placement still uses the offsets themselves, so the spacing stays in the geometry where it belongs.

Returns null when there is no offset table to read, or when index and length fall outside it. Never negative: a Tc tight enough to walk the pen backwards clamps to 0. One character code can map to several characters through /ToUnicode, and the interpreter splits such a code's advance evenly across them; each piece is then charged the spacing once, which understates a spaced ligature's pieces.

Implementation

double? glyphWidthAt(int index, int length) {
  final offsets = charOffsets;
  if (offsets == null ||
      index < 0 ||
      length <= 0 ||
      index + length >= offsets.length) {
    return null;
  }
  var spacing = letterSpacing;
  if (length == 1 && index < text.length && text.codeUnitAt(index) == 0x20) {
    spacing += wordSpacing;
  }
  final step = offsets[index + length] - offsets[index];
  return step > spacing ? step - spacing : 0.0;
}