The Birdfont Source Code
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
Fallback fonts in SVG drawings
--- 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;
}