Commit f1ca3d8
Load fallback font data from a list of TTF fonts
Changed files (14)
modifiedlibbirdfont/BackgroundSelectionTool.valamodifiedlibbirdfont/BirdFontFile.valadeletedlibbirdfont/FallbackFont.valamodifiedlibbirdfont/Font.valamodifiedlibbirdfont/Glyph.valamodifiedlibbirdfont/KerningDisplay.valamodifiedlibbirdfont/OpenFontFormat/OpenFontFormatReader.valamodifiedlibbirdfont/OpenFontFormat/load_font.cmodifiedlibbirdfont/OverView.valamodifiedlibbirdfont/OverViewItem.valaaddedlibbirdfont/Renderer/FallbackFont.valamodifiedlibbirdfont/Renderer/FontCache.valamodifiedlibbirdfont/Renderer/Text.valamodifiedlibbirdfont/Renderer/TextArea.vala
Diff
@@ -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 ();@@ -49,7 +49,7 @@ class BirdFontFile : GLib.Object { return ok; }-+ public bool load_part (string bfp_file) { string xml_data; XmlParser parser;deleted file mode 100644@@ -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);- }- }-}--}@@ -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) {@@ -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)) {@@ -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); }@@ -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 { @@ -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);@@ -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);@@ -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"); } new file mode 100644@@ -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);+ }+ }+}++}@@ -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 ();+ }+ } } }@@ -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) {@@ -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 (); }