Abstract type
Abstract type

Reputation: 1921

Cairo FreeType font - invalid matrix (not invertible)

I encounter the following cairo error when I try to use a FT font in cairo:

invalid matrix (not invertible)

Drawing is not involved because if I use the toy font API to do what is usually done with the serious font API then it works (cairo_scaled_font_text_to_glyphs and cairo_show_glyphs). So the problem certainly comes from the way the font is initialized.

This is how I set the font when my canvas gets a cairo_t context:

void fontToCairoData()
{
    _fontOptions = cairo_font_options_create;
    cairo_get_font_options (_cr, _fontOptions);

    /*
        - Toy API w/o matrix init: seconds assert fails: invalid matrix (not invertible)
        - Toy API + matrix init: OK
        - FreeType loader w/o matrix init: second assert fails: invalid matrix (not invertible)
        - FreeType loader + matrix init: the two assert OK but internal cairo assert failure.
    */

    cairo_matrix_init(&_fontMat, _font.size, 0, 0, _font.size, 0, 0);
    cairo_matrix_init(&_fontCtm, _font.size, 0, 0, _font.size, 0, 0);

    cairo_font_face_t* ff;
    version(none) // toy API
    {
        cairo_select_font_face(_cr, "Sans", CairoFontSlant.Normal, CairoFontWeight.Normal);
        ff = cairo_get_font_face(_cr);
    }
    else ff = getCairoFont(_font.name);

    assert(cairo_font_face_status(ff) == CairoStatus.Success,
        cairo_font_face_status(ff).cairo_status_to_string.fromStringz);

    cairo_ft_font_face_set_synthesize(ff, _font.getStyles.container & 3);
    _sf = cairo_scaled_font_create(ff, &_fontMat, &_fontCtm, _fontOptions);

    assert(cairo_scaled_font_status(_sf) == CairoStatus.Success,
        cairo_scaled_font_status(_sf).cairo_status_to_string.fromStringz);

    cairo_set_scaled_font(_cr, _sf);
}

getCairoFont is a call to the freetype loader, it returns something that comes from this function:

cairo_font_face_t* createFont(string name)
{
    import std.string: toStringz;

    FT_Face ftFace;
    FT_New_Face(ftHandle, cast(char*)name.toStringz, 0, &ftFace);
    return cairo_ft_font_face_create_for_ft_face(ftFace, 0);
}

When the code that initializes the matrices is not commented, I get in my console some cairo assertion failures such as

default_alignement: cairo-ft-font.c:657: _cairo_ft_unscaled_font_lock_face: Assertion `!unscaled->from_face' failed.

What's wrong in fontToCairoData ? How should the matrices be initialized ?

Upvotes: 1

Views: 1403

Answers (1)

Abstract type
Abstract type

Reputation: 1921

The problem was caused by a wrong usage of cairo_save() and cairo_restore() that caused settings to be lost (probably the default font matrix).

For each control, the previous translation was saved and restored like this:

void beginControl(CustomControl ctrl)
{
    cairo_save(_cr);
    cairo_translate(_cr, ctrl.left, ctrl.top);
    if (ctrl.clipChildren)
    {
        cairo_rectangle(_cr, -1, -1, ctrl.width+2, ctrl.height+2);
        cairo_clip(_cr);
    }
}

void endControl()
{
    cairo_restore(_cr);
}

Based on the wrong assumption that save/restore has only an effect on the plane geometry. But this was actually corrupting several settings.

When the plane is properly restored:

void endControl(CustomControl ctrl)
{
    cairo_translate(_cr, -ctrl.left, -ctrl.top);
    if (ctrl.clipChildren)
        cairo_reset_clip(_cr);
}

The messages related to the fonts disapear and the matrices are even not needed anymore (cairo_set_font_size does the job) because, as mentioned here, to create manually a scaled font is not necessary, it can be retrieved from the current font face.

Upvotes: 1

Related Questions