The Birdfont Source Code


All Repositories / birdfont.git / commit – RSS feed

Fallback fonts in SVG drawings

These changes was commited to the Birdfont repository Sat, 16 Jul 2016 22:38:09 +0000.

Contributing

Send patches or pull requests to johan.mattsson.m@gmail.com.
Clone this repository: git clone https://github.com/johanmattssonm/birdfont.git
author Johan Mattsson <johan.mattsson.m@gmail.com>
Sat, 16 Jul 2016 22:38:09 +0000 (00:38 +0200)
committer Johan Mattsson <johan.mattsson.m@gmail.com>
Sat, 16 Jul 2016 22:38:09 +0000 (00:38 +0200)
commit 0b81ac485fe865bc3ca476d67fd68014b3bb3d8d
tree 51b930573093d05e9ee5f8bd271c94ec61001848
parent f17a0ce0a03cd87282ae994695bac5ad48d1e0df
Fallback fonts in SVG drawings

libbirdfont/TextRendering/FallbackFont.vala
libbirdfont/TextRendering/fontconfig.c
libsvgbird/SvgFile.vala
libsvgbird/Text.vala
libsvgbird/text_helpers.c
--- a/libbirdfont/TextRendering/FallbackFont.vala +++ b/libbirdfont/TextRendering/FallbackFont.vala @@ -13,32 +13,6 @@ */ using Gee; - - [SimpleType] - [CCode (has_type_id = false)] - public extern struct FcConfig { - } - - [CCode (cname = "FcInitLoadConfigAndFonts")] - public extern FcConfig* FcInitLoadConfigAndFonts (); - - [CCode (cname = "FcConfigAppFontAddDir")] - public extern string* FcConfigAppFontAddDir (FcConfig* config, string path); - - [CCode (cname = "FcConfigSetSysRoot")] - public extern void FcConfigSetSysRoot (FcConfig* config, string path); - - [CCode (cname = "FcConfigParseAndLoad")] - public extern bool FcConfigParseAndLoad (FcConfig* config, string path, bool complain); - - [CCode (cname = "FcConfigSetCurrent")] - public extern void FcConfigSetCurrent (FcConfig* config); - - [CCode (cname = "FcConfigCreate")] - public extern FcConfig* FcConfigCreate (); - - [CCode (cname = "FcConfigFilename")] - public extern string FcConfigFilename (string path); [CCode (cname = "find_font")] public extern string? find_font (FcConfig* font_config, string characters);
--- a/libbirdfont/TextRendering/fontconfig.c +++ b/libbirdfont/TextRendering/fontconfig.c @@ -130,8 +130,9 @@ path = g_strdup ((gchar*) file); break; } + + FcPatternDestroy (font); } - FcPatternDestroy (font); } FcPatternDestroy (search_pattern);
--- a/libsvgbird/SvgFile.vala +++ b/libsvgbird/SvgFile.vala @@ -614,11 +614,11 @@ string name = attr.get_name (); if (name == "font-size") { - text.font_size = (int) parse_number (attr.get_content ()); + text.set_font_size ((int) parse_number (attr.get_content ())); } if (name == "font-family") { - text.font_family = attr.get_content (); + text.set_font (attr.get_content ()); } if (name == "x") {
--- a/libsvgbird/Text.vala +++ b/libsvgbird/Text.vala @@ -15,31 +15,110 @@ using Cairo; using Math; - extern class svg_bird_font_item {} + [SimpleType] + [CCode (has_type_id = false)] + public extern struct FcConfig { + } + + [SimpleType] + [CCode (has_type_id = false)] + extern struct svg_bird_font_item { + } + extern void svg_bird_draw_text (Context cr, svg_bird_font_item* font, string text); extern void svg_bird_font_item_delete (svg_bird_font_item* item); - extern svg_bird_font_item svg_bird_font_item_create (string font_file, int font_size); + extern svg_bird_font_item* svg_bird_font_item_create (string font_file, int font_size); + + extern bool svg_bird_has_font_config (); + extern void svg_bird_set_font_config (FcConfig* f); + + [CCode (cname = "FcInitLoadConfigAndFonts")] + public extern FcConfig* FcInitLoadConfigAndFonts (); + + [CCode (cname = "FcConfigAppFontAddDir")] + public extern string* FcConfigAppFontAddDir (FcConfig* config, string path); + + [CCode (cname = "FcConfigSetSysRoot")] + public extern void FcConfigSetSysRoot (FcConfig* config, string path); + + [CCode (cname = "FcConfigParseAndLoad")] + public extern bool FcConfigParseAndLoad (FcConfig* config, string path, bool complain); + + [CCode (cname = "FcConfigSetCurrent")] + public extern void FcConfigSetCurrent (FcConfig* config); + + [CCode (cname = "FcConfigCreate")] + public extern FcConfig* FcConfigCreate (); + + [CCode (cname = "FcConfigFilename")] + public extern string FcConfigFilename (string path); + namespace SvgBird { public class Text : Object { - public string font_family = ""; - public int font_size = 12; + string font_family = ""; + int font_size = 12; + string content; + public double x = 0; public double y = 0; - public string content; - - svg_bird_font_item* font; + + svg_bird_font_item* font = null; public Text () { - font = svg_bird_font_item_create ("resources/Roboto-Regular.ttf", 34); + if (!svg_bird_has_font_config ()) { + init_font_config (); + } + + set_font ("Roboto"); } ~Text () { svg_bird_font_item_delete (font); } + public void set_font_size (int s) { + font_size = s; + set_font (font_family); + } + + public void set_font (string font_family) { + if (font != null) { + svg_bird_font_item_delete (font); + } + + font = svg_bird_font_item_create (font_family, font_size); + + if (font == null) { + font = svg_bird_font_item_create ("sans-serif", font_size); + } + } + + public void init_font_config () { + FcConfig* config; + + #if MAC + config = FcConfigCreate(); + + string bundle = (!) BirdFont.get_settings_directory ().get_path (); + FcConfigSetSysRoot(config, bundle); + + string path = FcConfigFilename((!) SearchPaths.search_file(null, "fontconfig.settings").get_path ()); + bool loaded = FcConfigParseAndLoad(config, path, true); + + if (!loaded) { + warning ("Fontconfig initialization failed."); + } + + FcConfigSetCurrent (config); + #else + config = FcInitLoadConfigAndFonts (); + #endif + svg_bird_set_font_config (config); + } + public void set_text (string t) { content = t.replace ("\n", " "); content = content.replace ("\t", " "); @@ -62,7 +141,13 @@ public override void draw_outline (Context cr) { cr.save (); cr.translate (x, y); - svg_bird_draw_text (cr, font, content); + + if (font != null) { + svg_bird_draw_text (cr, font, content); + } else { + warning ("No font."); + } + cr.restore (); }
--- a/libsvgbird/text_helpers.c +++ b/libsvgbird/text_helpers.c @@ -6,9 +6,9 @@ #include <harfbuzz/hb-ft.h> #include <cairo.h> #include <cairo-ft.h> - - #define FONT_SIZE 36 - #define MARGIN (FONT_SIZE * .5) + + static GMutex font_config_lock; + FcConfig* font_config = NULL; typedef struct svg_bird_font_item_t { int font_size; @@ -17,37 +17,81 @@ hb_font_t *hb_font; } svg_bird_font_item; - svg_bird_font_item* svg_bird_font_item_create (const char* font_file, int font_size) { - FT_Error ft_error; + gchar* svg_bird_find_font_file (const gchar* font_name); + void svg_bird_font_item_delete (svg_bird_font_item* item); + gboolean svg_bird_has_font_config () { + g_mutex_lock (&font_config_lock); + gboolean exists = font_config != NULL; + g_mutex_unlock (&font_config_lock); + return exists; + } + + void svg_bird_set_font_config (FcConfig* f) { + g_mutex_lock (&font_config_lock); + font_config = f; + g_mutex_unlock (&font_config_lock); + } + + svg_bird_font_item* svg_bird_font_item_create (const char* font_family, int font_size) { + FT_Error ft_error; svg_bird_font_item* font = malloc (sizeof (svg_bird_font_item)); + memset (font, 0, sizeof (svg_bird_font_item)); + + char* font_file = svg_bird_find_font_file (font_family); + FT_Library ft_library = 0; + FT_Face ft_face = 0; + font->font_size = font_size; - - if ((ft_error = FT_Init_FreeType (&font->ft_library))) { + if ((ft_error = FT_Init_FreeType (&ft_library))) { g_warning ("Can't init freetype"); + svg_bird_font_item_delete (font); return NULL; - } - - if ((ft_error = FT_New_Face (font->ft_library, font_file, 0, &font->ft_face))) { - g_warning ("Can't init freetype font."); + } + + font->ft_library = ft_library; + + if ((ft_error = FT_New_Face (font->ft_library, font_file, 0, &ft_face))) { + g_warning ("Can't find freetype font %s %s.", font_family, font_file); + svg_bird_font_item_delete (font); return NULL; - } - + } + + font->ft_face = ft_face; + if ((ft_error = FT_Set_Char_Size (font->ft_face, font_size * 64, font_size * 64, 0, 0))) { g_warning ("Can't set font size."); + svg_bird_font_item_delete (font); return NULL; } font->hb_font = hb_ft_font_create (font->ft_face, NULL); + if (font->hb_font == NULL) { + g_warning ("Can't create harfbuzz font for %s", font_file); + svg_bird_font_item_delete (font); + return NULL; + } + + free (font_file); + return font; } void svg_bird_font_item_delete (svg_bird_font_item* item) { - if (item != NULL) { - FT_Done_Face (item->ft_face); - FT_Done_FreeType (item->ft_library); - hb_font_destroy (item->hb_font); + if (item) { + if (item->ft_face) { + FT_Done_Face (item->ft_face); + } + + if (item->hb_font) { + hb_font_destroy (item->hb_font); + } + + if (item->ft_library) { + FT_Done_FreeType (item->ft_library); + } + free (item); } } @@ -74,7 +118,7 @@ unsigned int cluster = info[i].cluster; double x_position = current_x + pos[i].x_offset / 64.; double y_position = current_y + pos[i].y_offset / 64.; - + current_x += pos[i].x_advance / 64.; current_y += pos[i].y_advance / 64.; } @@ -117,22 +161,93 @@ cairo_glyphs[i].index = info[i].codepoint; cairo_glyphs[i].x = current_x + pos[i].x_offset / 64.; cairo_glyphs[i].y = -(current_y + pos[i].y_offset / 64.); - + double dx = pos[i].x_advance / 64.0; double dy = pos[i].y_advance / 64.0; - + cairo_matrix_transform_distance (&matrix, &dx, &dy); current_x += dx; current_y += dy; - } + } cairo_show_glyphs (cr, cairo_glyphs, len); cairo_glyph_free (cairo_glyphs); cairo_font_face_destroy (cairo_face); - + hb_buffer_destroy (hb_buffer); cairo_restore (cr); + } + + gchar* svg_bird_find_font_file (const gchar* font_name) { + const FcChar8* name; + FcPattern* search_pattern; + FcPattern* font; + FcChar8* file; + gchar* path; + FcObjectSet* font_properties; + FcFontSet* fonts; + int i; + + if (!svg_bird_has_font_config ()) { + g_warning("Font config not loaded."); + return NULL; + } + + g_mutex_lock (&font_config_lock); + + if (font_config == NULL) { + g_warning("Font config not loaded."); + return NULL; + } + + path = NULL; + name = font_name; + + // match any font as fallback + search_pattern = FcPatternCreate (); + font_properties = FcObjectSetBuild (FC_FILE, NULL); + + fonts = FcFontList (font_config, search_pattern, font_properties); + + if (fonts->nfont > 0) { + for (i = 0; i < fonts->nfont; i++) { + font = fonts->fonts[i]; + + if (FcPatternGetString(font, FC_FILE, 0, &file) == FcResultMatch) { + path = g_strdup ((gchar*) file); + break; + } + + FcPatternDestroy (font); + } + } + + FcPatternDestroy (search_pattern); + + // search for a family name + search_pattern = FcPatternCreate (); + FcPatternAddString (search_pattern, FC_FAMILY, name); + fonts = FcFontList (font_config, search_pattern, font_properties); + + if (fonts->nfont > 0) { + for (i = 0; i < fonts->nfont; i++) { + font = fonts->fonts[i]; + + if (FcPatternGetString(font, FC_FILE, 0, &file) == FcResultMatch) { + g_free (path); + path = g_strdup ((gchar*) file); + break; + } + + FcPatternDestroy (font); + } + } + + FcPatternDestroy (search_pattern); + + g_mutex_unlock (&font_config_lock); + return path; }