Clone in a terminal:
Commit 0b81ac4
Johan Mattsson - 2016-07-16T22:38:09+00:00
0b81ac485fe865bc3ca476d67fd68014b3bb3d8djohan.mattsson.m@gmail.com

Fallback fonts in SVG drawings

Changed files (5)

Diff

diff --git a/libbirdfont/TextRendering/FallbackFont.vala b/libbirdfont/TextRendering/FallbackFont.valaindex 93de45d..4539163 100644--- a/libbirdfont/TextRendering/FallbackFont.vala+++ b/libbirdfont/TextRendering/FallbackFont.vala@@ -14,32 +14,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); diff --git a/libbirdfont/TextRendering/fontconfig.c b/libbirdfont/TextRendering/fontconfig.cindex f02b747..b70f164 100644--- a/libbirdfont/TextRendering/fontconfig.c+++ b/libbirdfont/TextRendering/fontconfig.c@@ -130,8 +130,9 @@ gchar* find_font_file (FcConfig* font_config, const gchar* font_name) { 				path = g_strdup ((gchar*) file); 				break; 			}+			+			FcPatternDestroy (font); 		}-		FcPatternDestroy (font); 	}  	FcPatternDestroy (search_pattern);diff --git a/libsvgbird/SvgFile.vala b/libsvgbird/SvgFile.valaindex dbe4848..901ab9d 100644--- a/libsvgbird/SvgFile.vala+++ b/libsvgbird/SvgFile.vala@@ -614,11 +614,11 @@ public class SvgFile : GLib.Object { 			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") {diff --git a/libsvgbird/Text.vala b/libsvgbird/Text.valaindex 2888fe8..bc12878 100644--- 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 class Text : Object { 	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 (); 	} diff --git a/libsvgbird/text_helpers.c b/libsvgbird/text_helpers.cindex 5826e95..822ce61 100644--- 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 @@ typedef struct svg_bird_font_item_t { 	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 @@ void svg_bird_draw_text (cairo_t* cr, svg_bird_font_item* font, const char* text 		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,21 +161,92 @@ void svg_bird_draw_text (cairo_t* cr, svg_bird_font_item* font, const char* text 		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; }

Contact

Email: johan.mattsson.m@gmail.com
Mastodon: typo.social/@birdfont
GitHub: johanmattssonm
LinkedIn: johan-mattsson-2ab324112