#include #include "fscalc.h" Font::Font(std::string s, int slant, int weight) { FcPattern *tmp1, *tmp2, *final; FcResult res; FcChar8 *filename; int fontindex; if(!(fc = FcInitLoadConfigAndFonts())) throw(std::runtime_error("failed to initialize fontconfig")); if(FT_Init_FreeType(&library)) throw(std::runtime_error("failed to initialize freetype")); aux = FcPatternCreate(); tmp1 = FcPatternBuild(NULL, FC_FAMILY, FcTypeString, s.c_str(), FC_SLANT, FcTypeInteger, slant, FC_WEIGHT, FcTypeInteger, weight ? 300 : 100, NULL); if(!tmp1) throw(std::runtime_error("failed to load font")); tmp2 = FcFontRenderPrepare(fc, tmp1, aux); FcPatternDestroy(tmp1); final = FcFontMatch(fc, tmp2, &res); FcPatternDestroy(tmp2); if(!final) throw(std::runtime_error("failed to load font")); if(FcPatternGetString(final, FC_FILE, 0, &filename) != FcResultMatch || FcPatternGetInteger(final, FC_INDEX, 0, &fontindex) != FcResultMatch) { FcPatternDestroy(final); throw(std::runtime_error("failed to locate font")); } if(FT_New_Face(library, (char*)filename, fontindex, &face)) { FcPatternDestroy(final); throw(std::runtime_error("failed to create new face")); } FcPatternDestroy(final); FcPatternDestroy(aux); // FcFini(); } Font::~Font() { FT_Done_Face(face); FT_Done_FreeType(library); } void Font::set_font_size(int size) { FT_Size_RequestRec req; TT_OS2 *os2; TT_HoriHeader *hori; float scale = 1.0; FT_Size_Metrics *m = &face->size->metrics; os2 = (TT_OS2*)FT_Get_Sfnt_Table(face, ft_sfnt_os2); hori = (TT_HoriHeader*)FT_Get_Sfnt_Table(face, ft_sfnt_hhea); if(os2 && hori) { int horisum = hori->Ascender - hori->Descender; unsigned int winsum = os2->usWinAscent + os2->usWinDescent; scale = (float)horisum / (float)winsum; } req.type = FT_SIZE_REQUEST_TYPE_REAL_DIM; req.width = 0; req.height = (FT_F26Dot6)(size * 64 * scale); req.horiResolution = 0; req.vertResolution = 0; FT_Request_Size(face, &req); } double Font::get_kerning(FT_UInt left, FT_UInt right) { if(FT_HAS_KERNING(face)) { FT_Vector d; FT_Get_Kerning(face, left, right, 0, &d); return (double)d.x / 64.0; } else return 0; } unsigned int Font::get_text_width(std::string s) { FT_UInt prev = 0; bool kerning = FT_HAS_KERNING(face); double width = 0; for(std::string::iterator c = s.begin(); c < s.end(); c++) { FT_UInt character; unsigned char first; first = character = *c; if(first & 0x80) { character += *(++c) << 8; if((first & 0xf0) == 0xe0) { character += *(++c) << 16; if((first & 0xf8) == 0xf0) character += *(++c) << 24; } } int i = FT_Get_Char_Index(face, character); if(kerning && prev && i) width += get_kerning(prev, i); if(FT_Load_Char(face, *c, 0)) throw(std::runtime_error("failed to load char")); width += (double)face->glyph->advance.x / 64.0; } return int(width); } unsigned int Font::get_line_height() { return (face->size->metrics.ascender - face->size->metrics.descender) / 64; }