FreeType の異体字セレクタ機能を使用

OpenType フォントのcmapテーブルに platform: 0, encoding: 5 のテーブルがあれば、異体字[1]のための別のグリフを利用できるかもしれない。文字のデータベースもある[4]。

1: http://www.unicode.org/reports/tr37/
4: http://www.unicode.org/ivd/

対応はフォントに依存する。

FreeType (2.3.6 以降)ではGSUBやGPOSテーブルをサポートしていないものの、cmap によるグリフ選択をサポートしている[2]。
2: http://www.freetype.org/freetype2/docs/reference/ft2-glyph_variants.html

今回は Mgen+ [3] フォントを使用する。

3: http://jikasei.me/font/mgenplus/

利用可能なセレクタを取得

FT_Face_GetVariantSelectors でフォント中で定義されている利用可能なセレクタの一覧を取得できる。

#include <iostream>
#include <freetype/ft2build.h>
#include FT_FREETYPE_H

int main()
{
    FT_Library ft;
    FT_Face face;
    
    FT_Init_FreeType(&ft);
    FT_New_Face(ft, "/home/asuka/.fonts/mgenplus-1m-regular.ttf", 0, &face);
    FT_Set_Char_Size(face, 0, 16 << 6, 96, 96);
    
    FT_UInt32* pSelectors = FT_Face_GetVariantSelectors(face);
    while (*pSelectors)
        std::cout << std::hex << "0x" << *pSelectors++ << std::endl;
/* Result: 
0xe0100
0xe0101
0xe0102
0xe0103
0xe0104
0xe0105
0xe0107 */
    FT_Done_Face(face);
    FT_Done_FreeType(ft);
}

このフォントでは7種類のセレクタが利用できる。

指定したコードポイントで利用可能なセレクタを取得

お嬢様で有名な芦屋[1]から、そのコードポイントに対して利用可能なセレクタを取得する。

    FT_ULong c = static_cast<FT_ULong>(L'芦');
    FT_UInt32* pSelectors = FT_Face_GetVariantsOfChar(face, c);
    while (*pSelectors)
        std::cout << std::hex << "0x" << *pSelectors++ << std::endl;
/* Result
0xe0100
0xe0101
0xe0102
0xe0103 */

セレクタごとに利用できるコードポイント一覧

指定したセレクタに対して定義されているコードポイントが取得できる。

    int length = 0;
    FT_UInt32* pSelectors = FT_Face_GetVariantSelectors(face);
    while (*pSelectors++)
        length++;
    
    FT_UInt32* p = new FT_UInt32[length+1];
    memcpy(p, pSelectors - length -1, sizeof(FT_UInt32) * length);
    p[length] = 0;
    
    while(*p)
    {
        std::cout << std::hex << "Selector: 0x" << *p << std::endl;
        std::cout << "----" << std::endl;
        FT_UInt32* pCodePoints = FT_Face_GetCharsOfVariant(face, *p++);
        while (*pCodePoints++)
            std::cout << std::hex << "0x" << *pCodePoints++ << std::endl;
        std::cout << "----" << std::endl;
    }

FT_Face_GetVariantSelectors 関数の呼び出し結果の配列は次の FreeType 関数の呼び出しで破壊される可能性があるため、コピーして利用する。

異体字のためのグリフインデックスを取得

    FT_ULong c = static_cast<FT_ULong>(L'芦');
    FT_UInt gindex = FT_Face_GetCharVariantIndex(face, c, 0xE0103);
    if (gindex == 0)
    {
        gindex = FT_Get_Char_Index(face, c);
    }
    FT_Load_Glyph(face, gindex, FT_LOAD_RENDER);

グリフインデックスが0の場合は普通の方法でグリフインデックスを取得し直す。