Clone in a terminal:
Commit f1ca3d8
Johan Mattsson - 2015-05-21T17:56:26+00:00
f1ca3d8090d8975b180e3da56f057b51a7c1cd45johan.mattsson.m@gmail.com

Load fallback font data from a list of TTF fonts

Changed files (14)

Diff

diff --git a/libbirdfont/BackgroundSelectionTool.vala b/libbirdfont/BackgroundSelectionTool.valaindex e3ddc67..bb7e971 100644--- a/libbirdfont/BackgroundSelectionTool.vala+++ b/libbirdfont/BackgroundSelectionTool.vala@@ -66,15 +66,13 @@ public class BackgroundSelectionTool : CutBackgroundTool { 				cr.fill (); 				 				if (bs.assigned_glyph != null) {-					if (label.has_character ((!) bs.assigned_glyph)) {-						font_height = 18;-						label.set_text ((!) bs.assigned_glyph);-						label.set_font_size (font_height);-						tx = x  + w - label.get_width () / 2.0;-						ty = y + h + label.get_acender () / 2.0 -  label.get_decender ();-						label.set_font_size (font_height);-						label.draw_at_baseline (cr, tx, ty);-					}+					font_height = 18;+					label.set_text ((!) bs.assigned_glyph);+					label.set_font_size (font_height);+					tx = x  + w - label.get_width () / 2.0;+					ty = y + h + label.get_acender () / 2.0 -  label.get_decender ();+					label.set_font_size (font_height);+					label.draw_at_baseline (cr, tx, ty); 				} 				 				cr.restore ();diff --git a/libbirdfont/BirdFontFile.vala b/libbirdfont/BirdFontFile.valaindex 5df1cef..5ad36b4 100644--- a/libbirdfont/BirdFontFile.vala+++ b/libbirdfont/BirdFontFile.vala@@ -49,7 +49,7 @@ class BirdFontFile : GLib.Object { 			 		return ok; 	}-+	 	public bool load_part (string bfp_file) { 		string xml_data; 		XmlParser parser;diff --git a/libbirdfont/FallbackFont.vala b/libbirdfont/FallbackFont.valadeleted file mode 100644index 11f634d..0000000--- a/libbirdfont/FallbackFont.vala+++ /dev/null@@ -1,255 +0,0 @@-/*-    Copyright (C) 2015 Johan Mattsson--    This library is free software; you can redistribute it and/or modify -    it under the terms of the GNU Lesser General Public License as -    published by the Free Software Foundation; either version 3 of the -    License, or (at your option) any later version.--    This library is distributed in the hope that it will be useful, but -    WITHOUT ANY WARRANTY; without even the implied warranty of -    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -    Lesser General Public License for more details.-*/--using Gee;-using Sqlite;-using Bird;--namespace BirdFont {--public class FallbackFont : GLib.Object {-	static unowned Database db;-	static Database? database = null;--	Gee.ArrayList<FontFace> fallback_fonts;-	Gee.ArrayList<File> font_directories;--	public FallbackFont () {	-		string home = Environment.get_home_dir ();-		-		fallback_fonts = new Gee.ArrayList<FontFace> ();-		font_directories = new Gee.ArrayList<File> ();-		-		add_font_folder ("/usr/share/fonts/");-		add_font_folder ("/usr/local/share/fonts/");-		add_font_folder (home + "/.local/share/fonts");-		add_font_folder ("C:\\Windows\\Fonts");-		-		open_fallback_fonts ();-	}--	~FallbackFont () {-		foreach (FontFace f in fallback_fonts) {-			close_font (f);-		}-	}-	-	void open_fallback_fonts () {-		add_font ("times.ttf");-		add_font ("verdana.ttf");-		add_font ("arial.ttf");-		add_font ("calibri.ttf");-		-		add_font ("Ubuntu-R.ttf");-		-		add_font ("DroidKufi.ttf");-		add_font ("DroidSansGeorgian.ttf");-		add_font ("DroidSansHebrew.ttf");-		add_font ("DroidNaskh.ttf");-		add_font ("DroidSansJapanese.ttf");-		add_font ("DroidSansArabic.ttf");-		add_font ("DroidSansArmenian.ttf");-		add_font ("DroidSans.ttf");-		add_font ("DroidSansEthiopic.ttf");-		add_font ("DroidSansFallbackFull.ttf");--		add_font ("Roboto-Regular.ttf");-	}--	void add_font (string font) {-		File f = find_font_file (font);-		-		if (f.query_exists ()) {-			add_font_file (f);-		}-	}--	void add_font_file (File font_file) {-		FontFace f = open_font ((!) font_file.get_path ());-		fallback_fonts.add (f);-	}--	File find_font_file (string font_file) {-		File d, f;-		-		for (int i = font_directories.size - 1; i >= 0; i--) {-			d = font_directories.get (i);-			f = get_child (d, font_file);-			-			if (f.query_exists ()) {-				return f;-			}-		}-		-		return File.new_for_path (font_file);-	}-		-	void add_font_folder (string f) {-		File folder = File.new_for_path (f);-		FileInfo? file_info;-		string fn;-		-		try {-			if (folder.query_exists ()) {-				font_directories.add (folder);-				-				var enumerator = folder.enumerate_children (FileAttribute.STANDARD_NAME + "," + FileAttribute.STANDARD_TYPE, 0);-				-				while ((file_info = enumerator.next_file ()) != null) {-					fn = ((!) file_info).get_name ();--					if (((!)file_info).get_file_type () == FileType.DIRECTORY) {-						add_font_folder ((!) get_child (folder, fn).get_path ());-					}-				}-			}-		} catch (GLib.Error e) {-			warning (e.message);-		}-	}-	-	public Glyph get_glyph (unichar c) {-		Glyph? g;-		FontFace f;-		-		for (int i = fallback_fonts.size - 1; i >= 0; i--) {-			f = fallback_fonts.get (i);-			g = get_glyph_in_font (f, c);-			-			if (g != null) {-				return (!) g;-			}-		}-		-		return new Glyph ("");-	}-	-	public Glyph? get_glyph_in_font (FontFace font, unichar c) {-		StringBuilder? glyph_data;-		GlyphCollection gc;-		XmlParser parser;-		BirdFontFile bf_parser;-		-		gc = new GlyphCollection (c, (!)c.to_string ());		-		glyph_data = load_glyph (font, (uint) c);-		-		if (glyph_data == null) {-			return null;-		}-		-		parser = new XmlParser (((!) glyph_data).str);	-		bf_parser = new BirdFontFile (new Font ());-		-		bf_parser.parse_glyph (parser.get_root_tag (),-			gc, gc.get_name (), gc.get_unicode_character (), 0, false);-		-		return gc.get_current ();-	}--	public File get_database_file () {-		return SearchPaths.find_file (null, "fallback-font.sqlite");-	}-	-	public File get_new_database_file () {-		string? fn = BirdFont.get_argument ("--fallback-font");-		-		if (fn != null && ((!) fn) != "") {-			return File.new_for_path ((!) fn);-		}-		-		return File.new_for_path ("fallback-font.sqlite");-	}-		-	public void generate_fallback_font () {-		File f = get_new_database_file ();-		string? fonts = BirdFont.get_argument ("--fonts");-		string fallback;-		-		if (fonts == null) {-			stderr.printf ("Add a list of fonts to use as fallback to the \"--fonts\" argument.\n");-			stderr.printf ("Separate each font file with \":\"\n");-			return;-		}-		-		fallback = (!) fonts;-		-		stdout.printf ("Generating fallback font: %s\n", (!) f.get_path ());-		-		try {-			if (f.query_exists ()) {-				f.delete ();-			}-			-			open_database (f);-			create_tables ();-			-			foreach (string font in fallback.split (":")) {-				add_font (font);-			}		-		} catch (GLib.Error e) {-			warning (e.message);-		}-		-	}--/* //FIXME:DELETE-	public void add_font (string font_file) {-		Font font;-		Glyph g;-		BirdFontFile bf;-		File single_glyph_font;-		-		font = new Font ();-		single_glyph_font = File.new_for_path ("/tmp/fallback_glyph.bf");-		-		font.set_file (font_file);-		if (!font.load ()) {-			stderr.printf ("Failed to load font: " + font_file);-			return;-		}-		-		for (int i = 0; i < font.length (); i++) {-			g = (!) font.get_glyph_indice (i);-			bf = new BirdFontFile (font);-		}-	} */--	public void open_database (File db_file) {-		int rc = Database.open ((!) db_file.get_path (), out database);--		db = (!) database;--		if (rc != Sqlite.OK) {-			stderr.printf ("Can't open database: %d, %s\n", rc, db.errmsg ());-		}-	}--	public void create_tables () {-		int ec;-		string? errmsg;-		string create_font_table = """-			CREATE TABLE FallbackFont (-				unicode        INTEGER     PRIMARY KEY    NOT NULL,-				font_data      TEXT                       NOT NULL-			);-		""";-		-		ec = db.exec (create_font_table, null, out errmsg);-		if (ec != Sqlite.OK) {-			warning ("Error: %s\n", (!) errmsg);-		}-	}-}--}diff --git a/libbirdfont/Font.vala b/libbirdfont/Font.valaindex 2716db9..3028fad 100644--- a/libbirdfont/Font.vala+++ b/libbirdfont/Font.vala@@ -451,7 +451,7 @@ public class Font : GLib.Object { 		} 	} 	-	public string get_name_for_character (unichar c) {+	public static string get_name_for_character (unichar c) { 		StringBuilder sb; 		 		if (c == 0) {diff --git a/libbirdfont/Glyph.vala b/libbirdfont/Glyph.valaindex 64dde7e..4804e95 100644--- a/libbirdfont/Glyph.vala+++ b/libbirdfont/Glyph.vala@@ -1962,7 +1962,7 @@ public class Glyph : FontDisplay { 		last_name = glyph.name; 		for (int i = pos + 1; i < glyph_sequence.char_count (); i++) { 			c = glyph_sequence.get_char (i);-			name = font.get_name_for_character (c);			+			name = (!) c.to_string ();			 			juxtaposed = (font.has_glyph (name)) ? (!) font.get_glyph (name) : font.get_space ().get_current (); 			 			if (font.has_glyph (last_name) && font.has_glyph (name)) {@@ -1995,7 +1995,7 @@ public class Glyph : FontDisplay { 		last_name = glyph.name; 		for (int i = pos - 1; i >= 0; i--) { 			c = glyph_sequence.get_char (i);-			name = font.get_name_for_character (c);			+			name = (!) c.to_string (); 			juxtaposed = (font.has_glyph (name)) ? (!) font.get_glyph (name) : font.get_space ().get_current (); 			 			if (font.has_glyph (last_name) && font.has_glyph (name)) {diff --git a/libbirdfont/KerningDisplay.vala b/libbirdfont/KerningDisplay.valaindex 9d15980..c6a3b78 100644--- a/libbirdfont/KerningDisplay.vala+++ b/libbirdfont/KerningDisplay.vala@@ -696,7 +696,7 @@ public class KerningDisplay : FontDisplay { 		f = current_font; 		 		if (!is_modifier_key (c) && c.validate ()) {-			name = f.get_name_for_character (c);+			name = (!) c.to_string (); 			g = f.get_glyph_by_name (name); 			inser_glyph (g); 		}diff --git a/libbirdfont/OpenFontFormat/OpenFontFormatReader.vala b/libbirdfont/OpenFontFormat/OpenFontFormatReader.valaindex c7e5480..47bdef7 100644--- a/libbirdfont/OpenFontFormat/OpenFontFormatReader.vala+++ b/libbirdfont/OpenFontFormat/OpenFontFormatReader.vala@@ -27,10 +27,10 @@ public extern static bool validate_freetype_font (string file); public extern static StringBuilder? load_glyph (FontFace font, uint unicode);  [CCode (cname = "open_font")]-public extern static FontFace open_font (string font_file);+public extern static FontFace* open_font (string font_file); -[CCode (cname = "close_font")]-public extern static FontFace close_font (FontFace font);+[CCode (cname = "close_ft_font")]+public extern static void close_font (FontFace* font);  namespace BirdFont { diff --git a/libbirdfont/OpenFontFormat/load_font.c b/libbirdfont/OpenFontFormat/load_font.cindex 86c19be..6d9c928 100644--- a/libbirdfont/OpenFontFormat/load_font.c+++ b/libbirdfont/OpenFontFormat/load_font.c@@ -524,7 +524,7 @@ GString* get_bf_contour_data (guint unicode, FT_Vector* points, char* flags, int 		} 		 		g_string_append (bf, contour->str);-		g_string_free (contour, 0);+		g_string_free (contour, TRUE); 	} 	 	free (new_points);@@ -541,7 +541,7 @@ GString* get_bf_path (guint unicode, FT_Face face, double units_per_em, int* err 	int i; 	int start; 	int end;-	+ 	if (face->glyph->outline.n_points == 0) { 		return bf;			 	}@@ -551,7 +551,7 @@ GString* get_bf_path (guint unicode, FT_Face face, double units_per_em, int* err 		end = face->glyph->outline.contours [i]; 		contour = get_bf_contour_data (unicode, face->glyph->outline.points + start, face->glyph->outline.tags + start, end - start, units_per_em, err); 		g_string_append_printf (bf, "\t\t<path data=\"%s\" />\n", contour->str);-		g_string_free (contour, 0);+		g_string_free (contour, TRUE); 		start = face->glyph->outline.contours [i] + 1; 	} @@ -559,38 +559,57 @@ GString* get_bf_path (guint unicode, FT_Face face, double units_per_em, int* err }  FontFace* open_font (const char* file) {-	FT_Library library;-	FT_Face face;+	FT_Library library = NULL;+	FT_Face face = NULL; 	int error; 	FontFace* font; 	 	error = FT_Init_FreeType (&library); 	if (error != OK) {-		g_warning ("Freetype init error %d.\n", error);+		printf ("Freetype init error %d.\n", error); 		return NULL; 	}  	error = FT_New_Face (library, file, 0, &face); 	if (error) {+		if (FT_Done_FreeType (library) != 0) {+			g_warning ("Can't close freetype.");+		}+		 		g_warning ("Freetype font face error %d\n", error); 		return NULL; 	}-+	+	font = malloc (sizeof (FontFace));+	font->face = face;+	font->library = library;+	 	error = FT_Select_Charmap (face , FT_ENCODING_UNICODE); 	if (error) { 		g_warning ("Freetype can not use Unicode, error: %d\n", error);+		close_ft_font (font); 		return NULL; 	} 	-	font = malloc (sizeof (FontFace));-	font->face = face;-	font->library = library;+	return font; } -void close_font (FontFace* font) {+void close_ft_font (FontFace* font) { 	if (font != NULL) {-		FT_Done_Face (font->face);-		FT_Done_FreeType (font->library);+		if (font->face != NULL) {+			if (FT_Done_Face (font->face) != 0) {+				g_warning ("Can't close font.");+			}+			font->face = NULL;+		}+		+		if (font->library != NULL) {+			if (FT_Done_FreeType (font->library) != 0) {+				g_warning ("Can't close freetype.");+			}+			font->library = NULL;+		}+		 		free (font); 	} }@@ -602,9 +621,12 @@ GString* load_glyph (FontFace* font, guint unicode) { 	int gid; 	FT_ULong charcode = (FT_ULong) unicode; 	double units;+	gchar line_position_buffer[80];+	gchar* line_position = (gchar*) &line_position_buffer;+	FT_Error error; 	-	if (font == NULL || font->face == NULL) {-		g_warning ("No font in load_glyph");+	if (font == NULL || font->face == NULL || font->library == NULL) {+		printf ("WARNING No font in load_glyph"); 		return NULL; 	} 	@@ -614,24 +636,49 @@ GString* load_glyph (FontFace* font, guint unicode) { 		return NULL; 	} 	-	glyph = g_string_new ("");-	FT_Load_Glyph(font->face, gid, FT_LOAD_DEFAULT | FT_LOAD_NO_SCALE);+	units = get_units (font->face->units_per_EM); 	-	paths = get_bf_path (unicode, font->face, font->face->units_per_EM, &err);-		-	if (err != OK) {-		g_warning ("WARNING Can't load glyph.");+	glyph = g_string_new ("<font>");++	g_string_append_printf (glyph, "<horizontal>\n");++	g_ascii_formatd (line_position, 80, "%f", font->face->ascender * units);+	g_string_append_printf (glyph, "\t<top_limit>%s</top_limit>\n", line_position);++	g_string_append_printf (glyph, "\t<base_line>0</base_line>\n");+	+	g_ascii_formatd (line_position, 80, "%f", font->face->descender * units);+	g_string_append_printf (glyph, "\t<bottom_limit>%s</bottom_limit>\n", line_position);		+	+	g_string_append_printf (glyph, "</horizontal>\n");++	error = FT_Load_Glyph(font->face, gid, FT_LOAD_DEFAULT | FT_LOAD_NO_SCALE);+	+	if (error != 0) {+		printf ("WARNING Failed to load glyph.");+		g_string_free (glyph, TRUE);+		return NULL; 	} 	-	units = get_units (font->face->units_per_EM);+	paths = get_bf_path (unicode, font->face, font->face->units_per_EM, &err); 	+	if (err != OK) {+		printf ("WARNING Can't load glyph.");+		g_string_free (glyph, TRUE);+		g_string_free (paths, TRUE);+		return NULL;+	}++	g_string_append_printf (glyph, "<collection unicode=\"U+%x\">\n", (guint)charcode); 	g_string_append_printf (glyph, "\t<glyph left=\"%f\" right=\"%f\" selected=\"true\">\n",  		0.0, font->face->glyph->metrics.horiAdvance * units); 		 	g_string_append_printf (glyph, "%s", paths->str); 	g_string_append_printf (glyph, "%s", "\t</glyph>");+	g_string_append_printf (glyph, "%s", "\t</collection>");+	g_string_append_printf (glyph, "%s", "</font>"); 	-	g_string_free (paths, 0);+	g_string_free (paths, TRUE); 	 	if (err != OK) { 		g_warning ("Can't load glyph data.");@@ -878,7 +925,7 @@ GString* get_bf_font (FT_Face face, char* file, int* err) { 		}  		g_string_append (bf, glyph->str);-		g_string_free (glyph, 0);+		g_string_free (glyph, TRUE); 	}  	bird_font_open_font_format_reader_append_kerning (bf, file);diff --git a/libbirdfont/OverView.vala b/libbirdfont/OverView.valaindex b6eaaf1..fed4af0 100644--- a/libbirdfont/OverView.vala+++ b/libbirdfont/OverView.vala@@ -52,16 +52,10 @@ public class OverView : FontDisplay { 	CharacterInfo? character_info = null; 	 	double scroll_size = 1;-	-	public static FallbackFont fallback_font;-	+ 	public OverView (GlyphRange? range = null, bool open_selected = true) { 		GlyphRange gr; -		if (is_null (fallback_font)) {-			fallback_font = new FallbackFont ();-		}- 		if (range == null) { 			gr = new GlyphRange (); 			set_glyph_range (gr);diff --git a/libbirdfont/OverViewItem.vala b/libbirdfont/OverViewItem.valaindex 8b71009..c18b86d 100644--- a/libbirdfont/OverViewItem.vala+++ b/libbirdfont/OverViewItem.vala@@ -164,8 +164,6 @@ public class OverViewItem : GLib.Object { 		double glyph_width, glyph_height; 		Surface s; 		Context c;-		Text fallback;-		double font_size; 		OverView o; 		Color color = Color.black (); @@ -182,7 +180,7 @@ public class OverViewItem : GLib.Object { 			g = ((!) gl).get_current (); 		} else { 			o = MainWindow.get_overview ();-			g = o.fallback_font.get_glyph (character);+			g = FontCache.fallback_font.get_glyph (character); 			color = Theme.get_color ("Overview Glyph"); 		} 		diff --git a/libbirdfont/Renderer/FallbackFont.vala b/libbirdfont/Renderer/FallbackFont.valanew file mode 100644index 0000000..5d25bea--- /dev/null+++ b/libbirdfont/Renderer/FallbackFont.vala@@ -0,0 +1,256 @@+/*+    Copyright (C) 2015 Johan Mattsson++    This library is free software; you can redistribute it and/or modify +    it under the terms of the GNU Lesser General Public License as +    published by the Free Software Foundation; either version 3 of the +    License, or (at your option) any later version.++    This library is distributed in the hope that it will be useful, but +    WITHOUT ANY WARRANTY; without even the implied warranty of +    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +    Lesser General Public License for more details.+*/++using Gee;+using Sqlite;+using Bird;++namespace BirdFont {++public class FallbackFont : GLib.Object {+	static unowned Database db;+	static Database? database = null;++	Gee.ArrayList<File> fallback_fonts;+	Gee.ArrayList<File> font_directories;++	public FallbackFont () {	+		string home = Environment.get_home_dir ();+		+		fallback_fonts = new Gee.ArrayList<File> ();+		font_directories = new Gee.ArrayList<File> ();+		+		add_font_folder ("/usr/share/fonts/");+		add_font_folder ("/usr/local/share/fonts/");+		add_font_folder (home + "/.local/share/fonts");+		add_font_folder ("C:\\Windows\\Fonts");+		+		//FIXME: MAC+		+		open_fallback_fonts ();+	}+	+	void open_fallback_fonts () {+		add_font ("times.ttf");+		add_font ("arial.ttf");+		add_font ("verdana.ttf");+		add_font ("calibri.ttf");+		+		add_font ("Ubuntu-R.ttf");+		+		add_font ("DroidKufi.ttf");+		add_font ("DroidSansGeorgian.ttf");+		add_font ("DroidSansHebrew.ttf");+		add_font ("DroidNaskh.ttf");+		add_font ("DroidSansJapanese.ttf");+		add_font ("DroidSansArabic.ttf");+		add_font ("DroidSansArmenian.ttf");+		add_font ("DroidSans.ttf");+		add_font ("DroidSansEthiopic.ttf");+		add_font ("DroidSansFallbackFull.ttf");++		add_font ("Roboto-Regular.ttf");+	}++	void add_font (string font) {+		File f = find_font_file (font);+		+		if (f.query_exists ()) {+			fallback_fonts.add (f);+		}+	}++	File find_font_file (string font_file) {+		File d, f;+		+		for (int i = font_directories.size - 1; i >= 0; i--) {+			d = font_directories.get (i);+			f = get_child (d, font_file);+			+			if (f.query_exists ()) {+				return f;+			}+		}+		+		return File.new_for_path (font_file);+	}+		+	void add_font_folder (string f) {+		File folder = File.new_for_path (f);+		FileInfo? file_info;+		string fn;+		+		try {+			if (folder.query_exists ()) {+				font_directories.add (folder);+				+				var enumerator = folder.enumerate_children (FileAttribute.STANDARD_NAME + "," + FileAttribute.STANDARD_TYPE, 0);+				+				while ((file_info = enumerator.next_file ()) != null) {+					fn = ((!) file_info).get_name ();++					if (((!)file_info).get_file_type () == FileType.DIRECTORY) {+						add_font_folder ((!) get_child (folder, fn).get_path ());+					}+				}+			}+		} catch (GLib.Error e) {+			warning (e.message);+		}+	}+	+	public Glyph get_glyph (unichar c) {+		return get_glyph_from_ttf (c);+	}+	+	public Glyph get_glyph_from_ttf (unichar c) {+		Glyph? g = null;+		File f;+		FontFace* font;+		+		for (int i = fallback_fonts.size - 1; i >= 0; i--) {+			f = fallback_fonts.get (i);+			+			font = open_font ((!) f.get_path ());+			+			if (font != null) {+				g = get_glyph_in_font ((!) font, c);+			}+			+			close_font (font);+			+			if (g != null) {+				return (!) g;+			}+		}+		+		return new Glyph ("");+	}+	+	public Glyph? get_glyph_in_font (FontFace font, unichar c) {+		StringBuilder? glyph_data = null;+		GlyphCollection gc;+		BirdFontFile bf_parser;+		Font bf_font;+		+		gc = new GlyphCollection (c, (!)c.to_string ());		+		glyph_data = load_glyph (font, (uint) c);+		+		if (glyph_data == null) {+			return null;+		}++		bf_font = new Font ();+		bf_parser = new BirdFontFile (bf_font);+		bf_parser.load_data (((!) glyph_data).str);+		+		return bf_font.get_glyph_by_name ((!) c.to_string ());+	}++	public File get_database_file () {+		return SearchPaths.find_file (null, "fallback-font.sqlite");+	}+	+	public File get_new_database_file () {+		string? fn = BirdFont.get_argument ("--fallback-font");+		+		if (fn != null && ((!) fn) != "") {+			return File.new_for_path ((!) fn);+		}+		+		return File.new_for_path ("fallback-font.sqlite");+	}+		+	public void generate_fallback_font () {+		File f = get_new_database_file ();+		string? fonts = BirdFont.get_argument ("--fonts");+		string fallback;+		+		if (fonts == null) {+			stderr.printf ("Add a list of fonts to use as fallback to the \"--fonts\" argument.\n");+			stderr.printf ("Separate each font file with \":\"\n");+			return;+		}+		+		fallback = (!) fonts;+		+		stdout.printf ("Generating fallback font: %s\n", (!) f.get_path ());+		+		try {+			if (f.query_exists ()) {+				f.delete ();+			}+			+			open_database (f);+			create_tables ();+			+			foreach (string font in fallback.split (":")) {+				add_font (font);+			}		+		} catch (GLib.Error e) {+			warning (e.message);+		}+		+	}++/* //FIXME:DELETE+	public void add_font (string font_file) {+		Font font;+		Glyph g;+		BirdFontFile bf;+		File single_glyph_font;+		+		font = new Font ();+		single_glyph_font = File.new_for_path ("/tmp/fallback_glyph.bf");+		+		font.set_file (font_file);+		if (!font.load ()) {+			stderr.printf ("Failed to load font: " + font_file);+			return;+		}+		+		for (int i = 0; i < font.length (); i++) {+			g = (!) font.get_glyph_indice (i);+			bf = new BirdFontFile (font);+		}+	} */++	public void open_database (File db_file) {+		int rc = Database.open ((!) db_file.get_path (), out database);++		db = (!) database;++		if (rc != Sqlite.OK) {+			stderr.printf ("Can't open database: %d, %s\n", rc, db.errmsg ());+		}+	}++	public void create_tables () {+		int ec;+		string? errmsg;+		string create_font_table = """+			CREATE TABLE FallbackFont (+				unicode        INTEGER     PRIMARY KEY    NOT NULL,+				font_data      TEXT                       NOT NULL+			);+		""";+		+		ec = db.exec (create_font_table, null, out errmsg);+		if (ec != Sqlite.OK) {+			warning ("Error: %s\n", (!) errmsg);+		}+	}+}++}diff --git a/libbirdfont/Renderer/FontCache.vala b/libbirdfont/Renderer/FontCache.valaindex 3c53407..1fe5582 100644--- a/libbirdfont/Renderer/FontCache.vala+++ b/libbirdfont/Renderer/FontCache.vala@@ -18,32 +18,38 @@ namespace BirdFont {  /** Thread specific font cache. */	 public class FontCache {	+	public static FallbackFont fallback_font;+	 	static FontCache? default_cache = null; 	Gee.HashMap<string, Font> fonts; 	 	public FontCache () { 		fonts = new Gee.HashMap<string, Font> ();+		+		if (is_null (fallback_font)) {+			fallback_font = new FallbackFont ();+		} 	} 	 	public void reload_font (string file_name) {-		Font? f = get_font (file_name);+		Font? f = get_font (file_name).font; 		 		if (f != null) { 			((!) f).load (); 		} 	} 	-	public Font? get_font (string file_name) {+	public CachedFont get_font (string file_name) { 		Font f; 		bool ok; 		 		if (file_name == "") { 			stderr.printf ("No file name.\n");-			return null;+			return new CachedFont (null); 		} 		 		if (fonts.has_key (file_name)) {-			return fonts.get (file_name);+			return new CachedFont (fonts.get (file_name)); 		} 		 		f = new Font ();@@ -51,12 +57,12 @@ public class FontCache { 		ok = f.load (); 		if (!ok) { 			stderr.printf ("Can't load %s\n", file_name);-			return null;+			return new CachedFont (null); 		} 		 		fonts.set (file_name, f); 		-		return f;+		return new CachedFont (f); 	} 	 	public static FontCache get_default_cache () {@@ -66,6 +72,49 @@ public class FontCache { 		 		return (!) default_cache; 	}+	+	public CachedFont get_fallback () {+		return new CachedFont (null);+	}+	+	public class CachedFont : GLib.Object {+		public Font? font;++		// FIXME: move fallback glyphs in to fond boundaries+		public double top_limit = 84;+		public double base_line = 0;+		public double bottom_limit = -27;+			+		public CachedFont (Font? font) {+			this.font = font;+		}+		+		public Glyph? get_glyph_by_name (string name) {+			Glyph? g = null;+			+			if (font != null) {+				g = ((!) font).get_glyph_by_name (name);+			}+			+			if (g == null && name.char_count () == 1) {+				g = fallback_font.get_glyph (name.get_char (0));+			}+			+			return g;+		}+		+		public GlyphCollection get_not_def_character () {+			Font f;+			+			if (font != null) {+				return ((!) font).get_not_def_character ();+			}+			+			f = new Font ();+			+			return f.get_not_def_character ();+		}+	} }  }diff --git a/libbirdfont/Renderer/Text.vala b/libbirdfont/Renderer/Text.valaindex 920ef1b..8545c4c 100644--- a/libbirdfont/Renderer/Text.vala+++ b/libbirdfont/Renderer/Text.vala@@ -15,30 +15,12 @@ using Cairo;  namespace BirdFont {-+	 /** Test implementation of a birdfont rendering engine. */ public class Text : Widget {--	public Font font {-		get {-			if (current_font == null) {-				current_font = get_default_font ();-				-				if (current_font == null) {-					current_font = new Font ();-				}-			}-			-			return (!) current_font;-		}-		-		set {-			current_font = value;-		}-	}-	 	FontCache font_cache;-	Font? current_font;+	public FontCache.CachedFont cached_font;+	 	public string text; 	 	GlyphSequence glyph_sequence {@@ -51,6 +33,7 @@ public class Text : Widget { 		} 	} 	+	Gee.ArrayList<string> glyph_names; 	GlyphSequence? gs = null; 	 	public delegate void Iterator (Glyph glyph, double kerning, bool last);@@ -66,9 +49,9 @@ public class Text : Widget { 	double truncated_width = -1; 	 	public Text (string text = "", double size = 17, double margin_bottom = 0) {-		current_font = null; 		this.margin_bottom = margin_bottom; 		font_cache = FontCache.get_default_cache ();+		cached_font = font_cache.get_fallback (); 		 		set_font_size (size); 		set_text (text);@@ -77,12 +60,6 @@ public class Text : Widget { 	public void use_cache (bool cache) { 		use_cached_glyphs = cache; 	}--	public static void load_default_font () {-		if (get_default_font () == null) {-			warning ("Default font not found.");-		}-	} 	 	/** Set font for this text area. 	 * @param font_absolute path to the font file or a file name for one of the font files in search paths.@@ -95,15 +72,11 @@ public class Text : Widget { 		f = File.new_for_path (font_file); 		path = (f.query_exists ()) ? f : SearchPaths.find_file (null, font_file); 		-		current_font = FontCache.get_default_cache ().get_font ((!) path.get_path ());-		return current_font != null;+		cached_font = FontCache.get_default_cache ().get_font ((!) path.get_path ());+		+		return cached_font.font != null; 	}--	public static Font? get_default_font () {-		File path = SearchPaths.find_file (null, "roboto.bf");-		return FontCache.get_default_cache ().get_font ((!) path.get_path ());-	}	-+	 	public void set_font_size (double height_in_pixels) { 		font_size = height_in_pixels; 		sidebearing_extent = 0;@@ -128,21 +101,18 @@ public class Text : Widget { 		 		gs = new GlyphSequence (); 		+		glyph_names = new Gee.ArrayList<string> (); 		index = 0; 		while (text.get_next_char (ref index, out c)) {-			name = font.get_name_for_character (c);-			g = font.get_glyph_by_name (name);+			name = (!) c.to_string ();+			g = cached_font.get_glyph_by_name (name); 			gs.glyph.add (g);+			glyph_names.add (name); 		} 		 		return gs; 	} -	/** @param character a string with a single glyph or the name of the glyph if it is a ligature. */-	public bool has_character (string character) {-		return font.has_glyph (character);-	}- 	public void iterate (Iterator iter) { 		Glyph glyph; 		double w, kern;@@ -162,13 +132,22 @@ public class Text : Widget { 		 		word = glyph_sequence; 		wi = 0;--		return_if_fail (current_font != null);-		word_with_ligatures = word.process_ligatures ((!) current_font);+		+		if (cached_font.font != null) {+			word_with_ligatures = word.process_ligatures ((!) cached_font.font);+		} else {+			word_with_ligatures = word.process_ligatures (new Font ());+		} 		 		gr_left = null; 		gr_right = null;-		kc = ((!) current_font).get_kerning_classes ();+		+		if (cached_font.font != null) {+			kc = ((!) cached_font.font).get_kerning_classes ();+		} else {+			kc = new KerningClasses (new Font ());+		}	+		 		for (int i = 0; i < word_with_ligatures.glyph.size; i++) {  			g = word_with_ligatures.glyph.get (i);@@ -186,7 +165,11 @@ public class Text : Widget { 			} 				 			// process glyph-			glyph = (g == null) ? font.get_not_def_character ().get_current () : (!) g;+			if (g == null) {+				g = cached_font.get_glyph_by_name (glyph_names.get (i));+			}+			+			glyph = (g == null) ? cached_font.get_not_def_character ().get_current () : (!) g; 			iter (glyph, kern, i + 1 == word_with_ligatures.glyph.size); 			 			prev = g;@@ -259,7 +242,7 @@ public class Text : Widget { 			} 		}); 		-		return max_height * ratio - font.base_line * ratio;+		return max_height * ratio - cached_font.base_line * ratio; 	}	  	public override double get_width () {@@ -303,18 +286,18 @@ public class Text : Widget { 			} 		}); 		-		decender = font.base_line * ratio - min_y * ratio;+		decender = cached_font.base_line * ratio - min_y * ratio; 		return decender > 0 ? decender : 0;  	}		 	 	public override void draw (Context cr) {-		double y = widget_y + get_height () + get_scale () * (font.bottom_limit + font.base_line);+		double y = widget_y + get_height () + get_scale () * (cached_font.bottom_limit + cached_font.base_line); 		draw_at_baseline (cr, widget_x, y); 	} 	 	public void draw_at_top (Context cr, double px, double py, string cacheid = "") { 		double s = get_scale ();-		double y = py + s * (font.top_limit - font.base_line);+		double y = py + s * (cached_font.top_limit - cached_font.base_line); 		draw_at_baseline (cr, px, y, cacheid); 	} 	@@ -346,7 +329,7 @@ public class Text : Widget { 		double cc_y;  		ratio = get_scale ();-		cc_y = (font.top_limit - font.base_line) * ratio;+		cc_y = (cached_font.top_limit - cached_font.base_line) * ratio;  		y = py; 		x = px;@@ -463,7 +446,7 @@ public class Text : Widget { 			ya = y - prev.y * scale; 			cr.move_to (xa, ya); 			-			by = (y - font.base_line * scale);+			by = (y - cached_font.base_line * scale); 			for (int i = 0; i < path.points.size; i++) { 				e = path.points.get (i).copy (); 				PenTool.convert_point_segment_type (prev, e, PointType.CUBIC);@@ -486,11 +469,11 @@ public class Text : Widget { 	}  	public double get_baseline_to_bottom () {-		return get_scale () * (-font.base_line - font.bottom_limit);+		return get_scale () * (-cached_font.base_line - cached_font.bottom_limit); 	}  	public double get_scale () {-		return font_size / (font.top_limit - font.bottom_limit);+		return font_size / (cached_font.top_limit - cached_font.bottom_limit); 	}  	public void truncate (double max_width) {diff --git a/libbirdfont/Renderer/TextArea.vala b/libbirdfont/Renderer/TextArea.valaindex c22cf2f..699af85 100644--- a/libbirdfont/Renderer/TextArea.vala+++ b/libbirdfont/Renderer/TextArea.vala@@ -1110,7 +1110,7 @@ public class TextArea : Widget { 						} 						 						if (paint_background && !(partial_start || partial_stop)) {	-							double selection_y = widget_y + next_word.widget_y + scale * -next_word.font.bottom_limit - font_size;+							double selection_y = widget_y + next_word.widget_y + scale * -next_word.cached_font.bottom_limit - font_size; 							cr.rectangle (widget_x + padding + next_word.widget_x - 1, selection_y, cw + 1, font_size); 							cr.fill (); 						}@@ -1129,7 +1129,7 @@ public class TextArea : Widget { 								cwi = (glyph.get_width ()) * next_word.get_scale () + kerning;  								if (draw) {-									double selection_y = widget_y + next_word.widget_y + scale * -next_word.font.bottom_limit - font_size;+									double selection_y = widget_y + next_word.widget_y + scale * -next_word.cached_font.bottom_limit - font_size; 									cr.rectangle (bx - 1, selection_y, cwi + 1, font_size); 									cr.fill (); 								}

Contact

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