Commit bd66d9b
Generate swsh, salt, smcp and c2sc tables. This commit adds support for swashes, stylistic alternatives, small caps and conversion from uppercase to small caps
Changed files (12)
modifiedlibbirdfont/AlternateSets.valamodifiedlibbirdfont/ExportTool.valamodifiedlibbirdfont/OpenFontFormat/Alternate.valamodifiedlibbirdfont/OpenFontFormat/AlternateFeature.valamodifiedlibbirdfont/OpenFontFormat/CligFeature.valamodifiedlibbirdfont/OpenFontFormat/Feature.valamodifiedlibbirdfont/OpenFontFormat/FeatureList.valamodifiedlibbirdfont/OpenFontFormat/GsubTable.valamodifiedlibbirdfont/OpenFontFormat/Lookup.valamodifiedlibbirdfont/OpenFontFormat/Lookups.valamodifiedlibbirdfont/OverView.valamodifiedlibbirdfont/OverviewTools.vala
Diff
@@ -40,7 +40,7 @@ public class AlternateSets : GLib.Object { alt = new Gee.ArrayList<Alternate> (); foreach (Alternate a in alternates) {- if (a.tag == tag) {+ if (a.tag == tag && a.alternates.size > 0) { alt.add (a); } }@@ -51,6 +51,14 @@ public class AlternateSets : GLib.Object { public void add (Alternate alternate) { alternates.add (alternate); }+ + public AlternateSets copy () {+ AlternateSets n = new AlternateSets ();+ foreach (Alternate a in alternates) {+ n.alternates.add (a.copy ());+ }+ return n;+ } } }@@ -352,6 +352,14 @@ os.put_string ( -webkit-font-feature-settings: "smcp"; font-feature-settings: "smcp"; }++ span.capstosmallcaps {+ font-variant-caps: all-small-caps;+ -moz-font-feature-settings: "c2sc", "smcp";+ -ms-font-feature-settings: "c2sc", "smcp";+ -webkit-font-feature-settings: "c2sc", "smcp";+ font-feature-settings: "c2sc", "smcp";+ } </style> """); @@ -373,10 +381,11 @@ os.put_string ( <div> <h3 class="big"></h3> <p class="big">- OTF features, <span class="swashes">like swashes </span>+ <span class="capstosmallcaps">OTF</span> features, + <span class="swashes">like swashes </span> <span class="alternates">alternates & </span> <span class="smallcaps">small caps</span>, can be been added- to the font.+ to the font.</span> </p> </div> @@ -44,6 +44,15 @@ public class Alternate : GLib.Object { } } + public Alternate copy () {+ Alternate n = new Alternate (character, tag);++ foreach (string s in alternates) {+ n.add (s);+ }+ + return n;+ } } }@@ -47,14 +47,17 @@ public class AlternateFeature : GLib.Object { // offset to coverage int coverage_offset = 6; coverage_offset += 2 * alternates.size;- coverage_offset += 2 + 2 * get_number_of_alternates (); + + foreach (Alternate a in alternates) {+ coverage_offset += 2;+ coverage_offset += 2 * a.alternates.size;+ }+ fd.add_ushort ((uint16) coverage_offset); // number of alternate sets fd.add_ushort ((uint16) alternates.size); - print (@"alternates.size: $(alternates.size)\n");- int offset = 6 + 2 * alternates.size; for (int i = 0; i < alternates.size; i++) { // offset to each alternate set@@ -65,14 +68,23 @@ public class AlternateFeature : GLib.Object { // alternates foreach (Alternate alternate in alternates) {- print (@"alternate.alternates.size: $(alternate.alternates.size)\n"); fd.add_ushort ((uint16) alternate.alternates.size); + alternate.alternates.sort ((a, b) => {+ string alt1 = (string) a;+ string alt2 = (string) b;+ return strcmp (alt1, alt2);+ });+ foreach (string alt in alternate.alternates) { fd.add_ushort ((uint16) glyf_table.get_gid (alt)); } } + if (fd.length_with_padding () != coverage_offset) {+ warning (@"Bad coverage offset. $(fd.length_with_padding ()) != $coverage_offset");+ }+ // coverage fd.add_ushort (1); // format fd.add_ushort ((uint16) alternates.size); // coverage array length@@ -86,16 +98,6 @@ public class AlternateFeature : GLib.Object { return lookups; }- - int get_number_of_alternates () {- int n = 0;- - foreach (Alternate alternate in alternates) {- n += alternate.alternates.size;- }- - return n;- } } }@@ -59,14 +59,14 @@ public class CligFeature : GLib.Object { lookups.add_lookup(lookup); } - lookup = new Lookup (6, 0, Lookups.CHAINED_CONTEXT);+ lookup = new Lookup (6, 0, "chained"); foreach (FontData d in chain_data) { lookup.add_subtable (d); } lookups.add_lookup(lookup); } - lookup = new Lookup (4, 0, Lookups.LIGATURES);+ lookup = new Lookup (4, 0, "ligatures"); lookup.add_subtable (clig_subtable); lookups.add_lookup(lookup); }@@ -18,16 +18,14 @@ public class Feature : GLib.Object { public string tag; public Lookups lookups;- public Gee.ArrayList<int> public_lookups = new Gee.ArrayList<int> ();- - public int lookup_offset = 0; // FIXME:DELETE+ public Gee.ArrayList<string> public_lookups = new Gee.ArrayList<string> (); public Feature (string tag, Lookups lookups) { this.tag = tag; this.lookups = lookups; } - public void add_feature_lookup (int lookup_token) {+ public void add_feature_lookup (string lookup_token) { public_lookups.add (lookup_token); } @@ -28,14 +28,27 @@ public class FeatureList : GLib.Object { public FontData generate_feature_tags () throws GLib.Error { FontData fd = new FontData (); + features.sort ((fa, fb) => {+ Feature a = (Feature) fa;+ Feature b = (Feature) fb;+ return strcmp (a.tag, b.tag);+ });+ fd.add_ushort ((uint16) features.size); // number of features uint offset = 2 + 6 * features.size; foreach (Feature feature in features) {- fd.add_tag (feature.tag); // feature tag: aalt, clig etc.- fd.add_ushort ((uint16) offset); // offset to feature+ // feature tag: aalt, clig etc.+ fd.add_tag (feature.tag); + + // offset to feature from beginning of this table+ fd.add_ushort ((uint16) offset); offset += 4 + 2 * feature.get_public_lookups ();+ + if (feature.get_public_lookups () == 0) {+ warning (@"No lookups for $(feature.tag)");+ } } foreach (Feature feature in features) {@@ -45,7 +58,7 @@ public class FeatureList : GLib.Object { // number of lookups fd.add_ushort ((uint16) feature.public_lookups.size); - foreach (int p in feature.public_lookups) {+ foreach (string p in feature.public_lookups) { // reference to a lookup table (lookup index) fd.add_ushort (feature.lookups.find (p)); }@@ -32,19 +32,10 @@ public class GsubTable : OtfTable { fd = new FontData (); CligFeature clig_feature = new CligFeature (glyf_table);- AlternateFeature salt = new AlternateFeature (glyf_table, "salt"); Lookups lookups = new Lookups (); FeatureList features = new FeatureList (); - if (salt.has_alternates ()) { - Lookups salt_lookup = salt.get_lookups ();- Feature salt_feature_lookup = new Feature ("salt", lookups);- salt_feature_lookup.add_feature_lookup ("salt");- features.add (salt_feature_lookup); - lookups.append (salt_lookup);- }- bool has_clig = clig_feature.contextual.has_ligatures () || clig_feature.has_regular_ligatures (); @@ -53,24 +44,30 @@ public class GsubTable : OtfTable { Feature clig_feature_lookup = new Feature ("clig", lookups); if (clig_feature.contextual.has_ligatures ()) {- clig_feature_lookup.add_feature_lookup (Lookups.CHAINED_CONTEXT);+ clig_feature_lookup.add_feature_lookup ("chained"); } if (clig_feature.has_regular_ligatures ()) {- clig_feature_lookup.add_feature_lookup (Lookups.LIGATURES);+ clig_feature_lookup.add_feature_lookup ("ligatures"); } features.add (clig_feature_lookup); lookups.append (clig_lookups); }-+ + add_alternate_table (features, lookups, "swsh");+ add_alternate_table (features, lookups, "salt");+ add_alternate_table (features, lookups, "c2sc");+ add_alternate_table (features, lookups, "smcp");+ FontData feature_tags = features.generate_feature_tags (); - uint lookup_list_offset = 30 + feature_tags.length_with_padding ();+ uint feature_list_offset = 28 + 2 * features.features.size;+ uint lookup_list_offset = feature_list_offset + feature_tags.length_with_padding (); fd.add_ulong (0x00010000); // table version fd.add_ushort (10); // offset to script list- fd.add_ushort (30); // offset to feature list+ fd.add_ushort ((uint16) feature_list_offset); // offset to feature list fd.add_ushort ((uint16) lookup_list_offset); // offset to lookup list // script list@@ -86,7 +83,11 @@ public class GsubTable : OtfTable { fd.add_ushort (0); // reserved fd.add_ushort (0xFFFF); // required features (0xFFFF is none) fd.add_ushort ((uint16) features.features.size); // number of features- fd.add_ushort (0); // feature index++ // FIXME: double check this+ for (int i = 0; i < features.features.size; i++) {+ fd.add_ushort ((uint16) i); // feature index+ } // feature lookups with references to the lookup list fd.append (feature_tags);@@ -109,6 +110,20 @@ public class GsubTable : OtfTable { this.font_data = fd; }++ /** Add alterate substitutions to lookups and features. */+ public void add_alternate_table (FeatureList features, Lookups lookups, string tag) + throws GLib.Error {+ AlternateFeature alt = new AlternateFeature (glyf_table, tag);+ if (alt.has_alternates ()) { + Lookups alt_lookup = alt.get_lookups ();+ Feature alt_feature_lookup = new Feature (tag, lookups);+ alt_feature_lookup.add_feature_lookup (tag);+ features.add (alt_feature_lookup); + lookups.append (alt_lookup);+ }+ }+ } }@@ -19,9 +19,15 @@ public class Lookup : GLib.Object { public uint16 type; public uint16 flags; public Gee.ArrayList<FontData> subtables;- public int token;+ public string token; - public Lookup (uint16 type, uint16 flags, int token = Lookups.NONE) {+ // the token is used for obtaining index in lookup list, an empty+ // string ensures that the subtable can't be directly used by+ // a table, chaining context use that feature.+ //+ // Lookups.find is used to obtain index in the lookup list for+ // a token.+ public Lookup (uint16 type, uint16 flags, string token = "") { this.type = type; this.flags = flags; subtables = new Gee.ArrayList<FontData> ();@@ -20,11 +20,6 @@ namespace BirdFont { public class Lookups : GLib.Object { public Gee.ArrayList<Lookup> tables = new Gee.ArrayList<Lookup> ();-- public static const int NONE = 0;- public static const int CHAINED_CONTEXT = 1;- public static const int LIGATURES = 2;- public static const int ALTERNATES = 2; public Lookups () { }@@ -38,7 +33,7 @@ public class Lookups : GLib.Object { } /** Find the lookup index for a particular lookup. */- public uint16 find (int token) {+ public uint16 find (string token) { uint16 index = 0; foreach (Lookup lookup in tables) { if (lookup.token == token) {@@ -919,6 +919,8 @@ public class OverView : FontDisplay { Font font = BirdFont.get_current_font (); OverViewUndoItem undo_item = new OverViewUndoItem (); + undo_item.alternate_sets = font.alternates.copy ();+ foreach (GlyphCollection g in selected_items) { undo_item.glyphs.add (g.copy ()); }@@ -952,6 +954,9 @@ public class OverView : FontDisplay { } } + Font f = BirdFont.get_current_font ();+ f.alternates = previous_collection.alternate_sets.copy ();+ undo_items.remove_at (undo_items.size - 1); GlyphCanvas.redraw (); }@@ -973,6 +978,8 @@ public class OverView : FontDisplay { font.add_glyph_collection (g); } + font.alternates = previous_collection.alternate_sets.copy ();+ redo_items.remove_at (redo_items.size - 1); GlyphCanvas.redraw (); } @@ -982,6 +989,8 @@ public class OverView : FontDisplay { OverViewUndoItem ui = new OverViewUndoItem (); Font font = BirdFont.get_current_font (); + ui.alternate_sets = font.alternates.copy ();+ foreach (GlyphCollection g in previous_collection.glyphs) { gc = font.get_glyph_collection (g.get_name ()); @@ -997,6 +1006,8 @@ public class OverView : FontDisplay { public void store_undo_state (GlyphCollection gc) { OverViewUndoItem i = new OverViewUndoItem ();+ Font f = BirdFont.get_current_font ();+ i.alternate_sets = f.alternates.copy (); i.glyphs.add (gc); store_undo_items (i); }@@ -1414,7 +1425,7 @@ public class OverView : FontDisplay { } public void paste () {- GlyphCollection gc = new GlyphCollection ('\0', "");+ GlyphCollection gc; GlyphCollection? c; Glyph glyph; uint32 index;@@ -1422,10 +1433,14 @@ public class OverView : FontDisplay { int skip = 0; int s; string character_string;- Gee.ArrayList<GlyphCollection> glyps = new Gee.ArrayList<GlyphCollection> ();- Font f = BirdFont.get_current_font ();+ Gee.ArrayList<GlyphCollection> glyps;+ Font f; OverViewUndoItem undo_item; + f = BirdFont.get_current_font ();+ gc = new GlyphCollection ('\0', "");+ glyps = new Gee.ArrayList<GlyphCollection> ();+ copied_glyphs.sort ((a, b) => { return (int) ((GlyphCollection) a).get_unicode_character () - (int) ((GlyphCollection) b).get_unicode_character ();@@ -1480,6 +1495,7 @@ public class OverView : FontDisplay { } undo_item = new OverViewUndoItem ();+ undo_item.alternate_sets = f.alternates.copy (); foreach (GlyphCollection g in glyps) { undo_item.glyphs.add (g.copy ()); }@@ -1515,6 +1531,7 @@ public class OverView : FontDisplay { } public class OverViewUndoItem {+ public AlternateSets alternate_sets = new AlternateSets (); public Gee.ArrayList<GlyphCollection> glyphs = new Gee.ArrayList<GlyphCollection> (); } }@@ -162,6 +162,9 @@ public class OverviewTools : ToolCollection { o = get_overview (); ui = new OverView.OverViewUndoItem (); + Font f = BirdFont.get_current_font ();+ ui.alternate_sets = f.alternates.copy ();+ foreach (GlyphCollection gc in o.selected_items) { if (gc.length () > 0) { g = gc.get_current ();