The Birdfont Source Code
Fallback font
These changes was commited to the Birdfont repository Thu, 21 May 2015 09:48:41 +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 font
--- a/libbirdfont/BirdFontFile.vala
+++ b/libbirdfont/BirdFontFile.vala
@@ -1163,7 +1163,7 @@
return id;
}
- private void parse_glyph (Tag tag, GlyphCollection gc, string name,
+ public void parse_glyph (Tag tag, GlyphCollection gc, string name,
unichar unicode, int selected_id, bool unassigned) {
Glyph glyph = new Glyph (name, unicode);
Path path;
--- a/libbirdfont/FallbackFont.vala
+++ b/libbirdfont/FallbackFont.vala
@@ -14,14 +14,147 @@
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 () {
@@ -70,6 +203,7 @@
}
+ /* //FIXME:DELETE
public void add_font (string font_file) {
Font font;
Glyph g;
@@ -89,7 +223,7 @@
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);
--- a/libbirdfont/Glyph.vala
+++ b/libbirdfont/Glyph.vala
@@ -1497,17 +1497,18 @@
}
/** Draw filled paths. */
- public void draw_paths (Context cr) {
+ public void draw_paths (Context cr, Color? c = null) {
PathList stroke;
-
+ Color color = c == null ? Color.black () : (!) c;
+
cr.save ();
cr.new_path ();
foreach (Path p in path_list) {
if (p.stroke > 0) {
stroke = p.get_stroke_fast ();
- draw_path_list (stroke, cr, Color.black ());
+ draw_path_list (stroke, cr, color);
} else {
- p.draw_path (cr, this, Color.black ());
+ p.draw_path (cr, this, color);
}
}
cr.fill ();
--- a/libbirdfont/OpenFontFormat/OpenFontFormatReader.vala
+++ b/libbirdfont/OpenFontFormat/OpenFontFormatReader.vala
@@ -11,12 +11,26 @@
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
*/
+
+ [SimpleType]
+ [CCode (cname = "FontFace")]
+ public extern class FontFace {
+ }
[CCode (cname = "load_freetype_font")]
public extern static StringBuilder? load_freetype_font (string file, out int error);
[CCode (cname = "validate_freetype_font")]
public extern static bool validate_freetype_font (string file);
+
+ [CCode (cname = "load_glyph")]
+ public extern static StringBuilder? load_glyph (FontFace font, uint unicode);
+
+ [CCode (cname = "open_font")]
+ public extern static FontFace open_font (string font_file);
+
+ [CCode (cname = "close_font")]
+ public extern static FontFace close_font (FontFace font);
namespace BirdFont {
--- a/libbirdfont/OpenFontFormat/load_font.c
+++ b/libbirdfont/OpenFontFormat/load_font.c
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2013 2014 Johan Mattsson
+ Copyright (C) 2013 2014 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
@@ -33,6 +33,11 @@
#define CUBIC_CURVE 2
#define DOUBLE_CURVE 4
#define HIDDEN_CURVE 8
+
+ typedef struct FontFace {
+ FT_Face face;
+ FT_Library library;
+ } FontFace;
/** Convert units per em in font file format to the BirdFont format. */
double get_units (double units_per_em) {
@@ -513,7 +518,7 @@
i += 1;
} else {
contour = g_string_new ("");
- g_warning ("WARNING Can not parse outline.\n");
+ g_warning ("WARNING Can't parse outline.\n");
*err = 1;
i++;
}
@@ -551,6 +556,88 @@
}
return bf;
+ }
+
+ FontFace* open_font (const char* file) {
+ FT_Library library;
+ FT_Face face;
+ int error;
+ FontFace* font;
+
+ error = FT_Init_FreeType (&library);
+ if (error != OK) {
+ g_warning ("Freetype init error %d.\n", error);
+ return NULL;
+ }
+
+ error = FT_New_Face (library, file, 0, &face);
+ if (error) {
+ g_warning ("Freetype font face error %d\n", error);
+ return NULL;
+ }
+
+ error = FT_Select_Charmap (face , FT_ENCODING_UNICODE);
+ if (error) {
+ g_warning ("Freetype can not use Unicode, error: %d\n", error);
+ return NULL;
+ }
+
+ font = malloc (sizeof (FontFace));
+ font->face = face;
+ font->library = library;
+ }
+
+ void close_font (FontFace* font) {
+ if (font != NULL) {
+ FT_Done_Face (font->face);
+ FT_Done_FreeType (font->library);
+ free (font);
+ }
+ }
+
+ GString* load_glyph (FontFace* font, guint unicode) {
+ GString* glyph;
+ GString* paths;
+ int err = OK;
+ int gid;
+ FT_ULong charcode = (FT_ULong) unicode;
+ double units;
+
+ if (font == NULL || font->face == NULL) {
+ g_warning ("No font in load_glyph");
+ return NULL;
+ }
+
+ gid = FT_Get_Char_Index (font->face, charcode);
+
+ if (gid == 0) {
+ return NULL;
+ }
+
+ glyph = g_string_new ("");
+ FT_Load_Glyph(font->face, gid, FT_LOAD_DEFAULT | FT_LOAD_NO_SCALE);
+
+ paths = get_bf_path (unicode, font->face, font->face->units_per_EM, &err);
+
+ if (err != OK) {
+ g_warning ("WARNING Can't load glyph.");
+ }
+
+ units = get_units (font->face->units_per_EM);
+
+ 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_free (paths, 0);
+
+ if (err != OK) {
+ g_warning ("Can't load glyph data.");
+ }
+
+ return glyph;
}
/** Get char code for a glyph.
@@ -680,9 +767,6 @@
}
g_string_append (bf, "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"yes\"?>\n");
-
- // libxml2 fails on doctype declaration in windows.
-
g_string_append (bf, "<font>\n");
g_string_append_printf (bf, "<postscript_name>%s</postscript_name>\n", g_markup_escape_text (FT_Get_Postscript_Name(face), -1));
--- a/libbirdfont/OverView.vala
+++ b/libbirdfont/OverView.vala
@@ -52,9 +52,15 @@
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 ();
--- a/libbirdfont/OverViewItem.vala
+++ b/libbirdfont/OverViewItem.vala
@@ -166,6 +166,8 @@
Context c;
Text fallback;
double font_size;
+ OverView o;
+ Color color = Color.black ();
font = BirdFont.get_current_font ();
w = width;
@@ -178,37 +180,30 @@
if (gl != null) {
g = ((!) gl).get_current ();
- g.boundaries (out x1, out y1, out x2, out y2);
+ } else {
+ o = MainWindow.get_overview ();
+ g = o.fallback_font.get_glyph (character);
+ color = Theme.get_color ("Overview Glyph");
+ }
- glyph_width = x2 - x1;
- glyph_height = y2 - y1;
-
- gx = ((w / glyph_scale) - glyph_width) / 2;
- gy = (h / glyph_scale) - 25 / glyph_scale;
+ g.boundaries (out x1, out y1, out x2, out y2);
+
+ glyph_width = x2 - x1;
+ glyph_height = y2 - y1;
+
+ gx = ((w / glyph_scale) - glyph_width) / 2;
+ gy = (h / glyph_scale) - 25 / glyph_scale;
- c.save ();
- c.scale (glyph_scale, glyph_scale);
+ c.save ();
+ c.scale (glyph_scale, glyph_scale);
- g.add_help_lines ();
-
- c.translate (gx - g.get_lsb () - Glyph.xc (), g.get_baseline () + gy - Glyph.yc ());
-
- g.draw_paths (c);
- c.restore ();
- } else {
- c.save ();
- fallback = new Text ();
- Theme.text_color (fallback, "Overview Glyph");
- fallback.set_text ((!) character.to_string ());
- font_size = height * 0.8;
- fallback.set_font_size (font_size);
- gx = (width - fallback.get_extent ()) / 2.0;
- gy = height - 30;
- fallback.set_font_size (font_size);
- fallback.draw_at_baseline (c, gx, gy);
- c.restore ();
- }
-
+ g.add_help_lines ();
+
+ c.translate (gx - g.get_lsb () - Glyph.xc (), g.get_baseline () + gy - Glyph.yc ());
+
+ g.draw_paths (c, color);
+ c.restore ();
+
cr.save ();
cr.set_source_surface (s, x, y - h);
cr.paint ();