/* wld: font.c * * Copyright (c) 2013, 2014 Michael Forney * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include "wld-private.h" #include EXPORT struct wld_font_context * wld_font_create_context() { struct wld_font_context * context; context = malloc(sizeof *context); if (!context) goto error0; if (FT_Init_FreeType(&context->library) != 0) { DEBUG("Failed to initialize FreeType library\n"); goto error1; } return context; error1: free(context); error0: return NULL; } EXPORT void wld_font_destroy_context(struct wld_font_context * context) { FT_Done_FreeType(context->library); free(context); } EXPORT struct wld_font * wld_font_open_name(struct wld_font_context * context, const char * name) { FcPattern * pattern, * match; FcResult result; DEBUG("Opening font with name: %s\n", name); pattern = FcNameParse((const FcChar8 *) name); FcConfigSubstitute(NULL, pattern, FcMatchPattern); FcDefaultSubstitute(pattern); match = FcFontMatch(NULL, pattern, &result); if (!match) return NULL; return wld_font_open_pattern(context, match); } EXPORT struct wld_font * wld_font_open_pattern(struct wld_font_context * context, FcPattern * match) { char * filename; struct font * font; FcResult result; double pixel_size, aspect; font = malloc(sizeof *font); if (!font) goto error0; font->context = context; result = FcPatternGetString(match, FC_FILE, 0, (FcChar8 **) &filename); if (result == FcResultMatch) { FT_Error error; DEBUG("Loading font file: %s\n", filename); error = FT_New_Face(context->library, filename, 0, &font->face); if (error == 0) goto load_face; } result = FcPatternGetFTFace(match, FC_FT_FACE, 0, &font->face); if (result != FcResultMatch) { DEBUG("Couldn't determine font filename or FreeType face\n"); goto error1; } load_face: result = FcPatternGetDouble(match, FC_PIXEL_SIZE, 0, &pixel_size); result = FcPatternGetDouble(match, FC_ASPECT, 0, &aspect); if (result == FcResultNoMatch) aspect = 1.0; if (font->face->face_flags & FT_FACE_FLAG_SCALABLE) { FT_F26Dot6 width, height; width = ((unsigned int) pixel_size) << 6; height = ((unsigned int) (pixel_size * aspect)) << 6; FT_Set_Char_Size(font->face, width, height, 0, 0); } else { FT_Set_Pixel_Sizes(font->face, (unsigned int) pixel_size, (unsigned int) (pixel_size * aspect)); } font->base.ascent = font->face->size->metrics.ascender >> 6; font->base.descent = -font->face->size->metrics.descender >> 6; font->base.height = font->base.ascent + font->base.descent; font->base.max_advance = font->face->size->metrics.max_advance >> 6; font->glyphs = calloc(font->face->num_glyphs, sizeof(struct glyph *)); return &font->base; error1: free(font); error0: return NULL; } EXPORT void wld_font_close(struct wld_font * font_base) { struct font * font = (void *) font_base; FT_Done_Face(font->face); free(font); } bool font_ensure_glyph(struct font * font, FT_UInt glyph_index) { if (glyph_index) { if (!font->glyphs[glyph_index]) { struct glyph * glyph; glyph = malloc(sizeof *glyph); if (!glyph) return false; FT_Load_Glyph(font->face, glyph_index, FT_LOAD_RENDER | FT_LOAD_MONOCHROME | FT_LOAD_TARGET_MONO); FT_Bitmap_New(&glyph->bitmap); FT_Bitmap_Copy(font->context->library, &font->face->glyph->bitmap, &glyph->bitmap); glyph->advance = font->face->glyph->metrics.horiAdvance >> 6; glyph->x = font->face->glyph->bitmap_left; glyph->y = -font->face->glyph->bitmap_top; font->glyphs[glyph_index] = glyph; } return true; } return false; } EXPORT bool wld_font_ensure_char(struct wld_font * font_base, uint32_t character) { struct font * font = (void *) font_base; FT_UInt glyph_index; glyph_index = FT_Get_Char_Index(font->face, character); return font_ensure_glyph(font, glyph_index); } EXPORT void wld_font_text_extents_n(struct wld_font * font_base, const char * text, int32_t length, struct wld_extents * extents) { struct font * font = (void *) font_base; int ret; uint32_t c; FT_UInt glyph_index; extents->advance = 0; while ((ret = FcUtf8ToUcs4((FcChar8 *) text, &c, length) > 0) && c != '\0') { length -= ret; text += ret; glyph_index = FT_Get_Char_Index(font->face, c); if (!font_ensure_glyph(font, glyph_index)) continue; extents->advance += font->glyphs[glyph_index]->advance; } }