Updated Files
birdfont/GtkWindow.vala |
birdfont/Main.vala |
configure |
dodo.py |
install.py |
libbirdfont/Argument.vala |
libbirdfont/BirdFont.vala |
libbirdfont/BirdFontFile.vala |
libbirdfont/BirdFontPart.vala |
libbirdfont/CharDatabase.vala |
libbirdfont/CharDatabaseParser.vala |
libbirdfont/FallbackFont.vala |
libbirdfont/GlyphCanvas.vala |
libbirdfont/OpenFontFormat/CodePageBits.vala |
libbirdfont/Path.vala |
libbirdfont/StrokeTool.vala |
libbirdfont/SvgParser.vala |
libbirdfont/TestCases.vala |
resources/codepages.sqlite |
resources/ucd.sqlite |
scripts/AndroidBirdFont.mk |
scripts/build.py |
scripts/version.py |
sqlite3.vapi |
--- a/birdfont/GtkWindow.vala
+++ b/birdfont/GtkWindow.vala
@@ -179,7 +179,7 @@
add (vbox);
try {
- set_icon_from_file ((!) Icons.find_icon ("birdfont_window_icon.png").get_path ());
+ set_icon_from_file ((!) SearchPaths.find_file (null, "birdfont_window_icon.png").get_path ());
} catch (GLib.Error e) {
warning (e.message);
}
--- a/birdfont/Main.vala
+++ b/birdfont/Main.vala
@@ -23,7 +23,6 @@
string file;
BirdFont.BirdFont birdfont;
- Icons.use_high_resolution (true);
birdfont = new BirdFont.BirdFont ();
birdfont.init (arg, null);
Gtk.init (ref arg);
@@ -36,51 +35,9 @@
birdfont.load_font_from_command_line ();
- load_ucd ();
Gtk.main ();
-
return 0;
- }
-
- /** Load descriptions from the unicode character database in a
- * background thread.
- */
- void load_ucd () {
- CharDatabaseParser db;
- unowned Thread<CharDatabaseParser> db_thread;
- Mutex database_mutex = new Mutex ();
- Cond main_loop_idle = new Cond ();
- bool in_idle = false;
-
- try {
- db = new CharDatabaseParser ();
- db_thread = Thread.create<CharDatabaseParser> (db.load, false);
-
- // wait until main loop is done
- db.sync.connect (() => {
- database_mutex.lock ();
- IdleSource idle = new IdleSource ();
- in_idle = false;
-
- idle.set_callback (() => {
- database_mutex.lock ();
- in_idle = true;
- main_loop_idle.broadcast ();
- database_mutex.unlock ();
- return false;
- });
- idle.attach (null);
-
- while (!in_idle) {
- main_loop_idle.wait (database_mutex);
- }
-
- database_mutex.unlock ();
- });
- } catch (GLib.Error e) {
- warning (e.message);
- }
}
--- a/configure
+++ b/configure
@@ -71,15 +71,16 @@
'gtk+-3.0',
'webkitgtk-3.0',
'libsoup-2.4',
- 'libnotify'
+ 'libnotify',
+ 'sqlite3'
]
else:
libs = [
'gdk-pixbuf-2.0',
'gio-2.0',
'glib-2.0',
+ 'sqlite'
]
-
for lib in libs:
if not test_library_version (lib):
--- a/dodo.py
+++ b/dodo.py
@@ -44,6 +44,7 @@
# external Vala libs
LIBS = [
+ 'sqlite3',
'glib-2.0',
'gio-2.0',
'cairo',
--- a/install.py
+++ b/install.py
@@ -105,6 +105,8 @@
install ('resources/roboto.bf', '/share/birdfont', 644)
install ('resources/linux/birdfont_window_icon.png', '/share/birdfont', 644)
install ('resources/linux/birdfont.desktop', '/share/applications', 644)
+ install ('resources/ucd.sqlite', '/share/birdfont', 644)
+ install ('resources/codepages.sqlite', '/share/birdfont', 644)
install ('resources/linux/256x256/birdfont.png', '/share/icons/hicolor/256x256/apps', 644)
install ('resources/linux/128x128/birdfont.png', '/share/icons/hicolor/128x128/apps', 644)
--- a/libbirdfont/Argument.vala
+++ b/libbirdfont/Argument.vala
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2012 Johan Mattsson
+ Copyright (C) 2012 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
@@ -16,18 +16,18 @@
public class Argument : GLib.Object {
- List<string> args;
+ Gee.ArrayList<string> args;
public Argument (string line) {
- args = new List<string> ();
+ args = new Gee.ArrayList<string> ();
set_argument (line);
}
public Argument.command_line (string[] arg) {
- args = new List<string> ();
+ args = new Gee.ArrayList<string> ();
foreach (string a in arg) {
- args.append (a);
+ args.add (a);
}
}
@@ -35,8 +35,9 @@
public int validate () {
string prev = "";
int i = 0;
- foreach (string a in args) {
-
+ string[] p;
+
+ foreach (string a in args) {
if (a == "") {
continue;
}
@@ -53,6 +54,11 @@
prev = a;
i++;
continue;
+ }
+
+ if (a.index_of ("=") > -1) {
+ p = a.split ("=");
+ a = p[0];
}
// a single character, like -t
@@ -71,8 +77,9 @@
a == "--mac" ||
a == "--android" ||
a == "--log" ||
- a == "--no-ucd" ||
- a == "--windows") {
+ a == "--windows" ||
+ a == "--parse-ucd" ||
+ a == "--codepages") {
prev = a;
i++;
continue;
@@ -96,8 +103,8 @@
public string get_file () {
string f = "";
- if (args.length () >= 2) {
- f = args.nth (1).data;
+ if (args.size >= 2) {
+ f = args.get (1);
}
if (f.has_prefix ("-")) {
@@ -108,7 +115,7 @@
}
public void print_all () {
- print (@"$(args.length ()) arguments:\n");
+ print (@"$(args.size) arguments:\n");
foreach (string p in args) {
print (@"$p\n");
@@ -124,18 +131,32 @@
int i = 0;
string? n;
string p;
-
+ string v = "";
+ string[] pm;
+
if (param.substring (0, 1) != "-") {
warning (@"parameters must begin with \"-\" got $param");
return null;
}
foreach (string s in args) {
+
+ if (s.index_of ("=") > -1) {
+ pm = s.split ("=");
+
+ if (pm.length > 1) {
+ v = pm[1];
+ }
+
+ s = pm[0];
+ }
// this is content not a parameter
- if (s.substring (0, 1) != "-") continue;
+ if (s.substring (0, 1) != "-") {
+ continue;
+ }
- // we might need to expand -t to test fo instance
+ // we might need to expand -t to test for instance
if (s.substring (0, 2) != "--") {
p = expand_param (s);
} else {
@@ -143,20 +164,24 @@
}
if (param == p) {
- if (i + 2 >= args.length ()) {
+ if (v != "") {
+ return v;
+ }
+
+ if (i + 2 >= args.size) {
return "";
}
- n = args.nth (i + 2).data;
+ n = args.get (i + 2);
if (n == null) {
return "";
}
- if (args.nth (i + 2).data.substring (0, 1) == "-") {
+ if (args.get (i + 2).substring (0, 1) == "-") {
return "";
}
- return args.nth (i + 2).data;
+ return args.get (i + 2);
}
i++;
@@ -184,10 +209,14 @@
private string expand_param (string? param) {
if (param == null) return "";
var p = (!) param;
+
+ if (p.get_char (0) != '-') {
+ return "";
+ }
- if (p.length == 0) return "";
- if (p.get_char (0) != '-') return "";
- if (p.char_count () != 2) return "";
+ if (p.char_count () != 2) {
+ return "";
+ }
switch (p.get_char (1)) {
case 'c':
@@ -235,17 +264,17 @@
n = arg.substring (i, a - i + 1);
}
- args.append (n);
+ args.add (n);
i += n.char_count () + 1;
} while (i < arg.char_count ());
}
public void print_help ()
- requires (args.length () > 0)
+ requires (args.size > 0)
{
stdout.printf (t_("Usage") + ": ");
- stdout.printf (args.nth (0).data);
+ stdout.printf (args.get (0));
stdout.printf (" [" + t_("FILE") + "] [" + t_("OPTION") + " ...]\n");
print_padded ("-a, --android", t_("enable Android customizations"));
--- a/libbirdfont/BirdFont.vala
+++ b/libbirdfont/BirdFont.vala
@@ -398,7 +398,9 @@
string theme;
int default_theme_version;
string theme_version;
-
+ CharDatabaseParser parser;
+ CodePageBits codepage_bits;
+
args = new Argument.command_line (arg);
#if ANDROID
@@ -523,6 +525,16 @@
if (TestBirdFont.get_singleton ().test_cases_to_run != "All") {
TestBirdFont.run_tests ();
+ }
+
+ if (has_argument ("--parse-ucd")) {
+ parser = new CharDatabaseParser ();
+ parser.regenerate_database ();
+ }
+
+ if (has_argument ("--codepages")) {
+ codepage_bits = new CodePageBits ();
+ codepage_bits.generate_codepage_database ();
}
}
--- a/libbirdfont/BirdFontFile.vala
+++ b/libbirdfont/BirdFontFile.vala
@@ -377,12 +377,12 @@
write_glyph_collection_start (gc, os);
write_selected (gc, os);
foreach (Glyph g in gc.get_version_list ().glyphs) {
- write_glyph (g, gc, os);
+ write_glyph (g, os);
}
write_glyph_collection_end (os);
}
- public void write_glyph (Glyph g, GlyphCollection gc, DataOutputStream os) throws GLib.Error {
+ public void write_glyph (Glyph g, DataOutputStream os) throws GLib.Error {
string data;
os.put_string (@"\t<glyph id=\"$(g.version_id)\" left=\"$(double_to_string (g.left_limit))\" right=\"$(double_to_string (g.right_limit))\">\n");
@@ -390,7 +390,10 @@
data = get_point_data (p);
if (data != "") {
os.put_string (@"\t\t<path ");
- os.put_string (@"stroke=\"$(double_to_string (p.stroke))\" ");
+
+ if (p.stroke != 0) {
+ os.put_string (@"stroke=\"$(double_to_string (p.stroke))\" ");
+ }
if (p.line_cap != LineCap.BUTT) {
if (p.line_cap == LineCap.ROUND) {
--- a/libbirdfont/BirdFontPart.vala
+++ b/libbirdfont/BirdFontPart.vala
@@ -265,7 +265,7 @@
os = create_file (@"$(file_name).bfp", "glyphs", dir_name);
bf.write_root_tag (os);
bf.write_glyph_collection_start (gc, os);
- bf.write_glyph (g, gc, os);
+ bf.write_glyph (g, os);
bf.write_glyph_collection_end (os);
bf.write_closing_root_tag (os);
os.close ();
--- a/libbirdfont/CharDatabase.vala
+++ b/libbirdfont/CharDatabase.vala
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2012 Johan Mattsson
+ Copyright (C) 2012 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
@@ -13,31 +13,46 @@
*/
using Gee;
+ using Sqlite;
namespace BirdFont {
public class CharDatabase {
-
- public static HashMap<string, string> entries;
- public static HashMultiMap<string, string> index;
-
public static GlyphRange full_unicode_range;
- public static bool database_is_loaded = false;
+
+ static unowned Database db;
+ static Database? database = null;
public CharDatabase () {
- entries = new HashMap<string, string> ();
- index = new HashMultiMap<string, string> ();
-
+ File f;
+
full_unicode_range = new GlyphRange ();
+ f = get_database_file ();
+ open_database () ;
+ }
+
+ public static void open_database () {
+ File f = get_database_file ();
+ int rc = Database.open ((!) f.get_path (), out database);
+
+ db = (!) database;
+
+ if (rc != Sqlite.OK) {
+ stderr.printf ("Can't open database: %d, %s\n", rc, db.errmsg ());
+ }
+ }
+
+ public static File get_database_file () {
+ return SearchPaths.find_file (null, "ucd.sqlite");
}
public static GlyphRange search (string s) {
GlyphRange result = new GlyphRange ();
GlyphRange ucd_result = new GlyphRange ();
+ int rc, cols;
+ Statement statement;
+ string select;
unichar c;
-
- return_val_if_fail (!is_null (index), result);
- return_val_if_fail (result.get_length () == 0, result);
if (s.has_prefix ("U+") || s.has_prefix ("u+")) {
c = Font.to_unichar (s.down ());
@@ -46,23 +61,49 @@
result.add_single (c);
}
}
-
+
if (s.char_count () == 1) {
- result.add_single (s.get_char ());
- }
-
- foreach (string i in index.get (s)) {
- c = Font.to_unichar ("U+" + i.down ());
- ucd_result.add_single (c);
+ result.add_single (s.get_char (0));
}
+
+ select = "SELECT unicode FROM Words "
+ + "WHERE word = '" + s.replace ("'", "''") + "';";
+
+ rc = db.prepare_v2 (select, select.length, out statement, null);
- try {
- if (ucd_result.get_length () > 0) {
- ucd_result.sort ();
- result.parse_ranges (ucd_result.get_all_ranges ());
+ if (rc == Sqlite.OK) {
+ cols = statement.column_count();
+
+ if (cols != 1) {
+ warning ("Expecting one column.");
+ return result;
}
- } catch (MarkupError e) {
- warning (e.message);
+
+ while (true) {
+ rc = statement.step ();
+
+ if (rc == Sqlite.DONE) {
+ break;
+ } else if (rc == Sqlite.ROW) {
+ c = (unichar) statement.column_int64 (0);
+ ucd_result.add_single (c);
+ } else {
+ warning ("Error: %d, %s\n", rc, db.errmsg ());
+ break;
+ }
+ }
+
+ try {
+ if (ucd_result.get_length () > 0) {
+ ucd_result.sort ();
+ result.parse_ranges (ucd_result.get_all_ranges ());
+ }
+ } catch (MarkupError e) {
+ warning (e.message);
+ }
+
+ } else {
+ warning ("SQL error: %d, %s\n", rc, db.errmsg ());
}
return result;
@@ -93,37 +134,47 @@
}
return false;
- }
-
- /** Convert from the U+xx form to the unicode database hex value. */
- static string to_database_hex (unichar c) {
- string hex_char = Font.to_hex (c).replace ("U+", "");
-
- if (hex_char.char_count () == 2) {
- hex_char = "00" + hex_char;
- }
-
- if (hex_char.char_count () == 6 && hex_char.has_prefix ("0")) {
- hex_char = hex_char.substring (1);
- }
-
- hex_char = hex_char.up ();
- return hex_char;
}
public static string get_unicode_database_entry (unichar c) {
- string description;
- string? d;
+ string description = "";
+ int rc, cols;
+ Statement statement;
+ string select = "SELECT description FROM Description "
+ + @"WHERE unicode = $((int64) c)";
- d = entries.get (to_database_hex (c));
+ rc = db.prepare_v2 (select, select.length, out statement, null);
- if (d == null) {
- description = Font.to_hex (c).replace ("U+", "") + "\tUNICODE CHARACTER";
+ if (rc == Sqlite.OK) {
+ cols = statement.column_count();
+
+ if (cols != 1) {
+ warning ("Expecting one column.");
+ return description;
+ }
+
+ while (true) {
+ rc = statement.step ();
+
+ if (rc == Sqlite.DONE) {
+ break;
+ } else if (rc == Sqlite.ROW) {
+ description = statement.column_text (0);
+ } else {
+ printerr ("Error: %d, %s\n", rc, db.errmsg ());
+ break;
+ }
+ }
+
} else {
- description = (!) d;
+ printerr ("SQL error: %d, %s\n", rc, db.errmsg ());
+ }
+
+ if (description == "") {
+ description = Font.to_hex (c).replace ("U+", "") + "\tUNICODE CHARACTER";
}
- return description;
+ return description;
}
public static void get_full_unicode (GlyphRange glyph_range) {
--- a/libbirdfont/CharDatabaseParser.vala
+++ b/libbirdfont/CharDatabaseParser.vala
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2013 Johan Mattsson
+ Copyright (C) 2013 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
@@ -13,16 +13,118 @@
*/
using Gee;
+ using Sqlite;
namespace BirdFont {
public class CharDatabaseParser : GLib.Object {
+ static unowned Database db;
+ static Database? database = null;
- public signal void sync ();
-
GlyphRange utf8 = new GlyphRange ();
public CharDatabaseParser () {
+ }
+
+ public File get_database_file () {
+ string? fn = BirdFont.get_argument ("--parse-ucd");
+
+ if (fn != null && ((!) fn) != "") {
+ return File.new_for_path ((!) fn);
+ }
+
+ return File.new_for_path ("ucd.sqlite");
+ }
+
+ public void regenerate_database () {
+ File f = get_database_file ();
+
+ stdout.printf ("Generating sqlite database in: %s\n", (!) f.get_path ());
+
+ try {
+ if (f.query_exists ()) {
+ f.delete ();
+ }
+
+ open_database ();
+ create_tables ();
+ parse_all_entries ();
+ } catch (GLib.Error e) {
+ warning (e.message);
+ }
+ }
+
+ public void open_database () {
+ File f = get_database_file ();
+ int rc = Database.open ((!) f.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 description_table = """
+ CREATE TABLE Description (
+ unicode INTEGER PRIMARY KEY NOT NULL,
+ description TEXT NOT NULL
+ );
+ """;
+
+ ec = db.exec (description_table, null, out errmsg);
+ if (ec != Sqlite.OK) {
+ warning ("Error: %s\n", (!) errmsg);
+ }
+
+ string index_table = """
+ CREATE TABLE Words (
+ unicode INTEGER NOT NULL,
+ word TEXT NOT NULL
+ );
+ """;
+
+ ec = db.exec (index_table, null, out errmsg);
+ if (ec != Sqlite.OK) {
+ warning ("Error: %s\n", (!) errmsg);
+ }
+
+ string create_index = "CREATE INDEX word_index ON Words (word);";
+
+ ec = db.exec (create_index, null, out errmsg);
+ if (ec != Sqlite.OK) {
+ warning ("Error: %s\n", (!) errmsg);
+ }
+ }
+
+ public void insert_lookup (int64 character, string word) {
+ string? errmsg;
+ string query = """
+ INSERT INTO Words (unicode, word)
+ VALUES (""" + @"$((int64) character)" + """, '""" + word.replace ("'", "''") + "');";
+ int ec = db.exec (query, null, out errmsg);
+ if (ec != Sqlite.OK) {
+ stderr.printf (query);
+ warning ("Error: %s\n", (!) errmsg);
+ }
+ }
+
+ public void insert_entry (int64 character, string description) {
+ string? errmsg;
+ string query = """
+ INSERT INTO Description (unicode, description)
+ VALUES (""" + @"$((int64) character)" + """, '""" + description.replace ("'", "''") + "');";
+
+ int ec = db.exec (query, null, out errmsg);
+
+ if (ec != Sqlite.OK) {
+ stderr.printf (query);
+ warning ("Error: %s\n", (!) errmsg);
+ warning (@"Can't insert description to: $(character)");
+ }
}
private void add_entry (string data) {
@@ -61,13 +163,8 @@
unicode_hex = e[0].up ();
ch = Font.to_unichar ("U+" + unicode_hex.down ());
-
- Idle.add (() => {
- CharDatabase.entries.set (unicode_hex, data);
- return false;
- });
- sync ();
-
+ stdout.printf ("Adding " + (!) ch.to_string () + "\n");
+ insert_entry ((int64) ch, data);
utf8.add_single (ch);
foreach (string s in e) {
@@ -76,11 +173,7 @@
d = t.split (" ");
foreach (string token in d) {
if (token != "") {
- Idle.add (() => {
- CharDatabase.index.set (token, unicode_hex);
- return false;
- });
- sync ();
+ insert_lookup ((int64)ch, token);
}
}
}
@@ -94,14 +187,17 @@
string data;
string description = "";
File file;
+ int ec;
+ string? errmsg;
+ uint64 transaction_number = 0;
+
+ file = get_unicode_database ();
- if (BirdFont.has_argument ("--no-ucd")) {
- warning ("Not loading UCD.");
- return;
+ ec = db.exec ("BEGIN TRANSACTION", null, out errmsg);
+ if (ec != Sqlite.OK) {
+ warning ("Error: %s\n", (!) errmsg);
}
-
- file = get_unicode_database ();
-
+
try {
fin = file.read ();
din = new DataInputStream (fin);
@@ -119,6 +215,23 @@
} else {
if (description.index_of ("<not a character>") == -1) {
add_entry (description);
+ transaction_number++;
+
+ if (transaction_number >= 1000) {
+ print ("Write to database\n");
+
+ ec = db.exec ("END TRANSACTION", null, out errmsg);
+ if (ec != Sqlite.OK) {
+ warning ("Error: %s\n", (!) errmsg);
+ }
+
+ ec = db.exec ("BEGIN TRANSACTION", null, out errmsg);
+ if (ec != Sqlite.OK) {
+ warning ("Error: %s\n", (!) errmsg);
+ }
+
+ transaction_number = 0;
+ }
}
break;
}
@@ -139,26 +252,19 @@
warning (e.message);
warning ("In %s", (!) get_unicode_database ().get_path ());
}
- }
-
- public CharDatabaseParser load () {
- parse_all_entries ();
- IdleSource idle = new IdleSource ();
- idle.set_callback (() => {
- CharDatabase.full_unicode_range = utf8;
- CharDatabase.database_is_loaded = true;
- return false;
- });
- idle.attach (null);
-
- return this;
+ ec = db.exec ("END TRANSACTION", null, out errmsg);
+ if (ec != Sqlite.OK) {
+ warning ("Error: %s\n", (!) errmsg);
+ }
+
+ stdout.printf ("Done");
}
- static File get_unicode_database () {
+ File get_unicode_database () {
return SearchPaths.get_char_database ();
}
}
}
--- /dev/null
+++ b/libbirdfont/FallbackFont.vala
@@ -1,1 +1,122 @@
+ /*
+ 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;
+
+ namespace BirdFont {
+
+ public class FallbackFont : GLib.Object {
+ static unowned Database db;
+ static Database? database = null;
+
+ public FallbackFont () {
+ }
+
+ 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);
+ }
+
+ }
+
+ 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);
+ }
+ }
+ }
+
+ }
--- a/libbirdfont/GlyphCanvas.vala
+++ b/libbirdfont/GlyphCanvas.vala
@@ -44,7 +44,7 @@
current_display.key_press (e);
}
- internal static void set_display (FontDisplay fd) {
+ public static void set_display (FontDisplay fd) {
current_display = fd;
}
--- a/libbirdfont/OpenFontFormat/CodePageBits.vala
+++ b/libbirdfont/OpenFontFormat/CodePageBits.vala
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2014 Johan Mattsson
+ Copyright (C) 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
@@ -11,6 +11,8 @@
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
*/
+
+ using Sqlite;
namespace BirdFont {
@@ -18,22 +20,24 @@
/** The first characters in all code pages. */
PageBit default_range;
-
- static bool has_codepages = false;
static Gee.ArrayList<PageBit> codepages;
-
- public CodePageBits () {
- default_range = new PageBit (-1, "null-");
+ static Gee.ArrayList<string> all_characters;
+
+ static unowned Database db;
+ static Database? database = null;
- if (!has_codepages) {
- codepages = new Gee.ArrayList<PageBit> ();
- create_codepage_list ();
- has_codepages = true;
+ public CodePageBits () {
+ if (database == null) {
+ open_database (get_database_file ());
}
+ }
+
+ public File get_database_file () {
+ return SearchPaths.find_file (null, "codepages.sqlite");
}
public void get_pages (Font font, out uint32 p0, out uint32 p1) {
- uint32 indice;
+ uint32 indice, a0, a1;
GlyphCollection? gl;
GlyphCollection g;
@@ -43,46 +47,52 @@
for (indice = 0; (gl = font.get_glyph_collection_indice (indice)) != null; indice++) {
g = (!) gl;
- if (default_range.has_char (g.get_unicode_character ())) {
- set_bit (0, ref p0, ref p1);
- } else {
- set_bits_for_glyph (g, ref p0, ref p1);
+ if (!g.is_unassigned ()) {
+ get_bits (g.get_unicode_character (), out a0, out a1);
+ p0 |= a0;
+ p1 |= a1;
}
}
}
-
- void set_bits_for_glyph (GlyphCollection g, ref uint32 p0, ref uint32 p1) {
- Gee.ArrayList<int> bits;
+
+ public void get_bits (unichar ch, out uint p0, out uint p1) {
+ int rc, cols;
+ Statement statement;
+ int64 c = (int64) ch;
+ string select = "SELECT codepages1, codepages2 FROM CodePages "
+ + "WHERE unicode = " + @"$c" + ";";
- if (!g.is_unassigned ()) {
- bits = get_bits (g.get_unicode_character ());
-
- foreach (int bit in bits) {
- set_bit (bit, ref p0, ref p1);
+ p0 = 0;
+ p1 = 0;
+
+ rc = db.prepare_v2 (select, select.length, out statement, null);
+
+ if (rc == Sqlite.OK) {
+ cols = statement.column_count();
+
+ if (cols != 2) {
+ warning ("Expecting two columns.");
+ return;
}
- }
- }
-
- public Gee.ArrayList<int> get_bits (unichar c) {
- Gee.ArrayList<int> bits = new Gee.ArrayList<int> ();
- foreach (PageBit pb in codepages) {
- if (pb.has_char (c)) {
- bits.add (pb.bit);
- }
- }
- return bits;
- }
- void set_bit (int bit, ref uint32 p0, ref uint32 p1) {
- const int length = 32;
-
- if (bit < length) {
- p0 |= 1 << bit;
+ while (true) {
+ rc = statement.step ();
+
+ if (rc == Sqlite.DONE) {
+ break;
+ } else if (rc == Sqlite.ROW) {
+ p0 = (uint) statement.column_int64 (0);
+ p1 = (uint) statement.column_int64 (1);
+ } else {
+ printerr ("Error: %d, %s\n", rc, db.errmsg ());
+ break;
+ }
+ }
} else {
- p1 |= 1 << (bit - length);
+ warning ("Database error: %s", db.errmsg ());
}
}
-
+
void create_codepage_list () {
// TODO: Add ASMO
// Windows-1252
@@ -149,11 +159,157 @@
create_codepage (63, "- ß-â ä-ï Ä-Ç É ö-÷ ñ-ô ù-ü ÿ Ö Ü -£ ¥ ₧ ƒ Ñ ¿ ⌐ ª-¬ º-½ ▐-▓ │ ┤ ┐ └ ┴ ┬ ├ ─ ┼ ═-╬ ┘ ┌ █ ▄ ▌ ▀ α Γ π Σ σ-τ µ Φ Θ Ω δ-ε ∞ φ ∩ ≡ °-² ≤-≥ ⌠-⌡ ≈ ∙-√ · ⁿ ■");
}
- void create_codepage (int bit, string ranges) {
- PageBit b = new PageBit (bit, ranges);
+ void create_codepage (int bit, string characters) {
+ string c;
+ PageBit b = new PageBit (bit, characters);
codepages.add (b);
+
+ for (int i = 0; i < b.ranges.length (); i++) {
+ c = b.ranges.get_char (i);
+ if (all_characters.index_of (c) == -1) {
+ all_characters.add (c);
+ }
+ }
}
+
+ File get_new_database_file () {
+ string? fn = BirdFont.get_argument ("--codepages");
+
+ if (fn != null && ((!) fn) != "") {
+ return File.new_for_path ((!) fn);
+ }
+
+ return File.new_for_path ("codepages.sqlite");
+ }
+
+ public void generate_codepage_database () {
+ File f = get_new_database_file ();
+ stdout.printf ("Generating codepage database: %s\n", (!) f.get_path ());
+
+ try {
+ if (f.query_exists ()) {
+ f.delete ();
+ }
+
+ open_database (f);
+ create_tables ();
+
+ default_range = new PageBit (-1, "null-");
+ codepages = new Gee.ArrayList<PageBit> ();
+ all_characters = new Gee.ArrayList<string> ();
+ create_codepage_list ();
+
+ write_database ();
+ } catch (GLib.Error e) {
+ warning (e.message);
+ }
+
+ stdout.printf ("Done\n");
+ }
+
+ void write_database () {
+ unichar ch;
+ uint32 pages1, pages2;
+ string? errmsg;
+
+ int ec = db.exec ("BEGIN TRANSACTION", null, out errmsg);
+ if (ec != Sqlite.OK) {
+ warning ("Error: %s\n", (!) errmsg);
+ }
+
+ foreach (string c in all_characters) {
+ ch = c.get_char (0);
+ get_pages_for_character (ch, out pages1, out pages2);
+ insert_codepage_for_character ((int64) ch, pages1, pages2);
+ }
+
+ ec = db.exec ("END TRANSACTION", null, out errmsg);
+ if (ec != Sqlite.OK) {
+ warning ("Error: %s\n", (!) errmsg);
+ }
+ }
+
+ void insert_codepage_for_character (int64 character, uint32 codepages1, uint32 codepages2) {
+ string? errmsg;
+ string query = """
+ INSERT INTO CodePages (unicode, codepages1, codepages2)
+ VALUES (""" + @"$((int64) character)" + ", " + @"$(codepages1), " + @"$(codepages2)" + ");";
+ int ec = db.exec (query, null, out errmsg);
+ if (ec != Sqlite.OK) {
+ stderr.printf (query);
+ warning ("Error: %s\n", (!) errmsg);
+ }
+ }
+
+ 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 ());
+ }
+ }
+
+ void create_tables () {
+ int ec;
+ string? errmsg;
+ string create_font_table = """
+ CREATE TABLE CodePages (
+ unicode INTEGER PRIMARY KEY NOT NULL,
+ codepages1 INTEGER NOT NULL,
+ codepages2 INTEGER NOT NULL
+ );
+ """;
+
+ ec = db.exec (create_font_table, null, out errmsg);
+ if (ec != Sqlite.OK) {
+ warning ("Error: %s\n", (!) errmsg);
+ }
+ }
+
+ void get_pages_for_character (unichar character, out uint32 p0, out uint32 p1) {
+ p0 = 0;
+ p1 = 0;
+
+ if (default_range.has_char (character)) {
+ set_bit (0, ref p0, ref p1);
+ } else {
+ set_bits_for_character (character, ref p0, ref p1);
+ }
+ }
+
+ void set_bits_for_character (unichar c, ref uint32 p0, ref uint32 p1) {
+ Gee.ArrayList<int> bits;
+
+ bits = get_code_page_bits (c);
+
+ foreach (int bit in bits) {
+ set_bit (bit, ref p0, ref p1);
+ }
+ }
+
+ Gee.ArrayList<int> get_code_page_bits (unichar c) {
+ Gee.ArrayList<int> bits = new Gee.ArrayList<int> ();
+ foreach (PageBit pb in codepages) {
+ if (pb.has_char (c)) {
+ bits.add (pb.bit);
+ }
+ }
+ return bits;
+ }
+
+ void set_bit (int bit, ref uint32 p0, ref uint32 p1) {
+ const int length = 32;
+
+ if (bit < length) {
+ p0 |= 1 << bit;
+ } else {
+ p1 |= 1 << (bit - length);
+ }
+ }
+
private class PageBit : GLib.Object {
public GlyphRange ranges;
public int bit;
--- a/libbirdfont/Path.vala
+++ b/libbirdfont/Path.vala
@@ -1290,7 +1290,7 @@
ep.get_left_handle ().set_point_type (PointType.LINE_DOUBLE_CURVE);
ep.type = PointType.DOUBLE_CURVE;
} else {
- warning ("Point types: $right and $left in insert_new_point_on_path");
+ warning (@"Point types: $right and $left in insert_new_point_on_path");
}
ep.get_left_handle ().parent = ep;
--- a/libbirdfont/StrokeTool.vala
+++ b/libbirdfont/StrokeTool.vala
@@ -69,20 +69,6 @@
PenTool.update_orientation ();
convert_stroke = false;
- }
-
- public PathList merge_selected_paths () {
- PathList n = new PathList ();
- Glyph g = MainWindow.get_current_glyph ();
-
- foreach (Path p in g.active_paths) {
- if (p.stroke == 0) {
- n.add (p);
- }
- }
-
- n = merge (n);
- return n;
}
public static PathList get_stroke_fast (Path path, double thickness) {
@@ -114,7 +100,21 @@
return m;
}
-
+
+ public PathList merge_selected_paths () {
+ PathList n = new PathList ();
+ Glyph g = MainWindow.get_current_glyph ();
+
+ foreach (Path p in g.active_paths) {
+ if (p.stroke == 0) {
+ n.add (p);
+ }
+ }
+
+ n = merge (n);
+ return n;
+ }
+
static Path simplify_stroke (Path p) {
Path simplified = new Path ();
Path segment, added_segment;
@@ -272,7 +272,7 @@
PathList r = new PathList ();
foreach (Path p in pl.paths) {
- if (p.points.size > 22) {
+ if (p.points.size > 7) {
r.add (p);
} else if (!has_new_corner (p)) {
r.add (p);
--- a/libbirdfont/SvgParser.vala
+++ b/libbirdfont/SvgParser.vala
@@ -444,17 +444,27 @@
Glyph glyph = MainWindow.get_current_glyph ();
PathList path_list = new PathList ();
SvgStyle style = new SvgStyle ();
+ bool hidden = false;
foreach (Attribute attr in tag.get_attributes ()) {
if (attr.get_name () == "d") {
path_list = parse_svg_data (attr.get_content (), glyph);
- pl.paths.append (path_list);
}
if (attr.get_name () == "style") {
style = SvgStyle.parse (attr.get_content ());
+ }
+
+ if (attr.get_name () == "display" && attr.get_content () == "none") {
+ hidden = true;
}
}
+
+ if (hidden) {
+ return;
+ }
+
+ pl.paths.append (path_list);
foreach (Path p in path_list.paths) {
p.stroke = style.get_stroke_width ();
@@ -1483,11 +1493,18 @@
path.close ();
path.create_list ();
- if (b[1].type == 'C' || b[1].type == 'S') {
+ int first_index = 1;
+ for (int j = i; j >= 1; j--) {
+ if (b[j].type == 'z') {
+ first_index = j + 2; // skipping M
+ }
+ }
+
+ if (b[first_index].type == 'C' || b[first_index].type == 'S') {
return_val_if_fail (path.points.size != 0, path_list);
ep = path.points.get (path.points.size - 1);
ep.get_right_handle ().set_point_type (PointType.CUBIC);
- ep.get_right_handle ().move_to_coordinate (b[1].x0, b[1].y0);
+ ep.get_right_handle ().move_to_coordinate (b[first_index].x0, b[first_index].y0);
}
path.recalculate_linear_handles ();
--- a/libbirdfont/TestCases.vala
+++ b/libbirdfont/TestCases.vala
@@ -84,20 +84,25 @@
public static void test_codepages () {
CodePageBits pages = new CodePageBits ();
+ uint32 p0, p1;
- if (pages.get_bits ('ó').size == 0) {
+ pages.get_bits ('ó', out p0, out p1);
+ if (p0 == 0 && p1 == 0) {
warning ("Codepage for Hungarian is not set.");
}
- if (pages.get_bits ('ö').size == 0) {
+ pages.get_bits ('ö', out p0, out p1);
+ if (p0 == 0 && p1 == 0) {
warning ("Codepage for Swedish is not set.");
}
- if (pages.get_bits ('ツ').size == 0) {
+ pages.get_bits ('ツ', out p0, out p1);
+ if (p0 == 0 && p1 == 0) {
warning ("Codepage for Japanese is not set.");
}
- if (pages.get_bits ('马').size == 0) {
+ pages.get_bits ('马', out p0, out p1);
+ if (p0 == 0 && p1 == 0) {
warning ("Codepage for Chinese is not set.");
}
}
--- /dev/null
+++ b/resources/codepages.sqlite
@@ -1,1 +1,348 @@
-
+ SQLite format 3 @ -
ctableCodePagesCodePagesCREATE TABLE CodePages (
+ unicode INTEGER PRIMARY KEY NOT NULL,
+ codepages1 INTEGER NOT NULL,
+ codepages2 INTEGER NOT NULL
+ ) \9 ꂻ: x w
p` `flrx~ &,28>DJPV\bhntz
+ "(.4:@FLRX^djpv|
+
! " # $ % & ' ( ) * + , - . / 0 1 2 3 4 5 6 7 8 9 : ; < = > ? @ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z [ \ ] ^ _ ` a b c d e f g h i j k l m n o p
<