8 Errors
dxtr edited this page 2026-10-19 01:12:07 +02:00

Errors

cl-textrender signals one condition, textrender-error, for every failure in it and in the libraries under it. You never need to handle a cl-harfbuzz, cl-icu, cl-ft2 or cl-sdf condition: their errors are reported in terms of the cl-textrender call that failed.

textrender-error

(handler-case (tr:layout-text "abc" font :spans '((2 9 :data :red)))
  (tr:textrender-error (e)
    (list (tr:textrender-error-message e)
          (tr:textrender-error-hint e))))
;; => ("The span (2 9 :DATA :RED) ends at 9, past the end of the text, which has 3 characters."
;;     "A span is (START END &key FONT FEATURES DATA), where START and END are
;;      character indexes with 0 <= START <= END <= the length of the text.")
  • textrender-error-message says what went wrong, in terms of the call.
  • textrender-error-hint says what to do about it, or is nil.
  • The report, as princ prints it, is the message, then the hint on a line of its own.

textrender-error is a subtype of error.

Type errors

Every exported function declares the types of its arguments, which SBCL checks as the function is entered, before it does anything:

  • An argument of the wrong type, a number out of range, such as a size of 0, a negative width or :max-lines 0, a keyword argument outside its documented choices, such as :align :middle or :hinting :full, and an empty font list given to layout-text signal a standard type-error that names the argument and the type it takes. SBCL may list a type's choices in another order:

    The value
      :MIDDLE
    is not of type
      (MEMBER :CENTER :LEFT :START :JUSTIFY :RIGHT :END)
    when binding :ALIGN
    
  • Written as a constant, such an argument is caught sooner: SBCL warns as it compiles the call, and ASDF stops loading the system with it.

    ; caught WARNING:
    ;   Constant
    ;     :MIDDLE conflicts with its asserted type
    ;     (MEMBER :JUSTIFY :CENTER :RIGHT :LEFT :END :START).
    
  • What a declared type cannot say is checked in the function. An element of a list that is of the wrong type, such as a tab stop that is not a positive real or a variation that is not a ("tag" . value) pair, is a type-error too. The rest, such as a span outside the text, an index past its end and a destroyed face or font, signals textrender-error, as below.

Every error

Fonts

When Message Hint
The font file does not exist or cannot be read Could not read the font file path: it does not exist or cannot be read. Check the path and the file's permissions.
The data is not a font path is not a font. (The font data is not a font, for an octet vector.) Pass a TrueType or OpenType font, or a font collection. WOFF and WOFF2 web fonts must be converted to one of those first.
:index is past the faces of a collection path has n faces, so face i does not exist. (The font data has …, for an octet vector.) Pass an :INDEX below n.
An axis in :variations is not the font's The font has no "wght" axis; its axes are "wdth", "opsz". Pass only the font's own axes in :VARIATIONS.
:variations given for a font that is not variable The font has no "wght" axis; it is not a variable font. Leave out :VARIATIONS for a font that is not variable.
A destroyed font is used The font has been destroyed with DESTROY-FONT. Make it again with MAKE-FONT or FACE-FONT, and destroy it only when nothing uses it any more.
A destroyed face is used The face has been destroyed with DESTROY-FACE. Make it again with MAKE-FACE, and destroy it only when nothing uses it any more.

A destroyed face or font is reported wherever it is used: layout-text, face-font, face-cache, font-cache, font-glyph-id, font-glyph-advance, glyph-outline, the cached outlines and the backends. Destroying a face destroys its fonts, so they report themselves destroyed.

Layout

When Message Hint
A span's :font is an empty list The font list is empty. Pass a FONT, or a list of FONTs: the primary first, then its fallbacks.
Something in a font list is not a font Element 2 of the font list is :BOLD, not a FONT. The same.
A span's :font is neither a font nor a list :BOLD is not a FONT. The same.
A span is not a list of start, end and options The span … is not of the form (START END &key FONT FEATURES DATA). A span is (START END &key FONT FEATURES DATA), where START and END are character indexes with 0 <= START <= END <= the length of the text.
A span has an unknown option The span (0 1 :COLOUR :RED) has the unknown option :COLOUR. The same.
A span's :features is not a list of strings The span … has :FEATURES "smcp", not a list of strings. Give :FEATURES as a list of strings such as ("smcp" "-liga").
A span ends past the text The span (2 9 :DATA :RED) ends at 9, past the end of the text, which has 3 characters. A span is (START END &key …).
A span starts after its end The span (2 1 :DATA :X) starts at 2, after its end. A span is (START END &key …).
The :tab-stops positions do not increase The tab stops (200 100) are not in increasing order: 100 comes after 200. Give :TAB-STOPS as positions along the line in increasing order, or as one interval.
HarfBuzz cannot parse a feature string "bad feature!" is not a valid feature. Write features in HarfBuzz's syntax: "liga" or "+liga" to turn one on, "-liga" to turn it off, "aalt=2" for a value, "smcp[3:5]" for a range.

Hit testing

When Message Hint
An index is past the end of the text Index 7 is past the end of the text, which has 3 characters. Text indexes are character positions, from 0 to the length of the text.

This applies to caret-position, caret-segment, move-caret, selection-rectangles, next-caret-index, previous-caret-index and line-at-index. A negative index is a type-error.

Outlines

When Message Hint
outline-quadratics of an outline with cubics, without :tolerance The outline has cubic segments, which a quadratic-only vector needs a tolerance to approximate. Pass :TOLERANCE, or make the outline with GLYPH-OUTLINE's :QUADRATIC T.

Optional systems

When Message Hint
FreeType cannot draw a glyph, as when its outline is damaged Glyph 36 of #<FONT DejaVu Sans 16.0 {…}> cannot be rasterized: Could not load glyph 36: the glyph's outline is damaged. The font's data for this glyph is damaged, or of a kind FreeType does not draw. Draw the text in another font.
A glyph's outline cannot be made into a distance field Glyph g of font cannot be made into a distance field: … The font's outline of this glyph is malformed. Draw it another way, such as rasterized.

What is not an error

  • A character no font has is drawn as the primary font's .notdef glyph (glyph 0), not reported.
  • A glyph ID a font does not have, given to any function that takes one, is answered for as the font's .notdef: its advance, outline, image and field. A malformed font's character map that points past its last glyph counts as no glyph, so the character falls back to the next font, or is drawn as .notdef.
  • An index inside a grapheme is moved back to the grapheme's start.
  • A point outside the text, given to hit-test, is clamped to the nearest line and character.
  • move-caret at either end of the text returns the index unchanged.
  • Destroying a face or font twice does nothing. Rasterizers and atlases are never destroyed: they hold nothing that needs it.