Cairo FreeType 字体 - 无效矩阵(不可逆)

Cairo FreeType font - invalid matrix (not invertible)

我尝试在 cairo 中使用 FT 字体时遇到以下 cairo 错误:

invalid matrix (not invertible)

不涉及绘图,因为如果我使用玩具字体 API 来做通常使用严肃字体 API 所做的事情,那么它就可以工作 (cairo_scaled_font_text_to_glyphs cairo_show_glyphs)。 所以问题肯定出在字体的初始化方式上。

这就是我在 canvas 获得 cairo_t 上下文时设置字体的方式:

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 是对 freetype loader 的调用,它 returns 来自这个函数的东西:

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);
}

当初始化矩阵的代码未被注释时,我在控制台中遇到一些 cairo 断言失败,例如

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

fontToCairoData 有什么问题?应该如何初始化矩阵?

问题是由于 cairo_save()cairo_restore() 的错误使用引起的导致设置丢失(可能是默认字体矩阵)。

对于每个控件,以前的翻译是这样保存和恢复的:

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);
}

基于save/restore仅对平面几何有影响的错误假设。但这实际上破坏了几个设置。

飞机正常恢复时:

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

与字体相关的消息消失了,甚至不再需要矩阵(cairo_set_font_size 完成了工作)因为,如前所述 here,不需要手动创建缩放字体,可以从当前字体中检索。