The Birdfont Source Code


All Repositories / birdfont.git / blob – RSS feed

Ligatures.vala in libbirdfont

This file is a part of the Birdfont project.

Contributing

Send patches or pull requests to johan.mattsson.m@gmail.com.
Clone this repository: git clone https://github.com/johanmattssonm/birdfont.git

Revisions

View the latest version of libbirdfont/Ligatures.vala.
Thread safety in text rendering
1 /* 2 Copyright (C) 2014 Johan Mattsson 3 4 This library is free software; you can redistribute it and/or modify 5 it under the terms of the GNU Lesser General Public License as 6 published by the Free Software Foundation; either version 3 of the 7 License, or (at your option) any later version. 8 9 This library is distributed in the hope that it will be useful, but 10 WITHOUT ANY WARRANTY; without even the implied warranty of 11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 Lesser General Public License for more details. 13 */ 14 15 using Cairo; 16 using Math; 17 18 namespace BirdFont { 19 20 public class Ligatures : GLib.Object { 21 22 Gee.ArrayList<Ligature> ligatures = new Gee.ArrayList<Ligature> (); 23 Gee.ArrayList<ContextualLigature> contextual_ligatures = new Gee.ArrayList<ContextualLigature> (); 24 25 public delegate void LigatureIterator (string substitution, string ligature); 26 public delegate void SingleLigatureIterator (GlyphSequence substitution, GlyphCollection ligature); 27 28 public delegate void ContextualLigatureIterator (ContextualLigature lig); 29 30 Font font; 31 32 public Ligatures (Font font) { 33 this.font = font; 34 } 35 36 public void get_ligatures (LigatureIterator iter) { 37 foreach (Ligature l in ligatures) { 38 iter (l.substitution, l.ligature); 39 } 40 } 41 42 public void get_contextual_ligatures (ContextualLigatureIterator iter) { 43 foreach (ContextualLigature l in contextual_ligatures) { 44 iter (l); 45 } 46 } 47 48 public void get_single_substitution_ligatures (SingleLigatureIterator iter) { 49 get_ligatures ((substitution, ligature) => { 50 GlyphCollection? gc; 51 GlyphCollection li; 52 GlyphSequence gs; 53 string[] subst_names = substitution.split (" "); 54 55 gc = font.get_glyph_collection_by_name (ligature); 56 57 if (gc == null) { 58 return; 59 } 60 61 li = (!) gc; 62 63 gs = new GlyphSequence (); 64 foreach (string s in subst_names) { 65 gc = font.get_glyph_collection_by_name (s); 66 67 if (gc == null) { 68 return; 69 } 70 71 gs.glyph.add (((!) gc).get_current ()); 72 } 73 74 iter (gs, li); 75 }); 76 } 77 78 public int count () { 79 return ligatures.size; 80 } 81 82 public int count_contextual_ligatures () { 83 return contextual_ligatures.size; 84 } 85 86 public void remove_at (int i) { 87 return_if_fail (0 <= i < ligatures.size); 88 ligatures.remove_at (i); 89 } 90 91 public void remove_contextual_ligatures_at (int i) { 92 return_if_fail (0 <= i < contextual_ligatures.size); 93 contextual_ligatures.remove_at (i); 94 } 95 96 /** Add ligaure for a chained substitution. */ 97 public void add_substitution_at (int index) { 98 return_if_fail (0 <= index < contextual_ligatures.size); 99 contextual_ligatures.get (index).add_ligature (); 100 } 101 102 public void set_beginning (int index) { 103 ContextualLigature lig; 104 TextListener listener; 105 106 return_if_fail (0 <= index < contextual_ligatures.size); 107 108 lig = contextual_ligatures.get (index); 109 listener = new TextListener (t_("Beginning"), lig.backtrack, t_("Set")); 110 111 listener.signal_text_input.connect ((text) => { 112 lig.backtrack = text; 113 }); 114 115 listener.signal_submit.connect (() => { 116 MainWindow.native_window.hide_text_input (); 117 MainWindow.get_ligature_display ().update_rows (); 118 }); 119 120 MainWindow.native_window.set_text_listener (listener); 121 } 122 123 public void set_middle (int index) { 124 ContextualLigature lig; 125 TextListener listener; 126 127 return_if_fail (0 <= index < contextual_ligatures.size); 128 129 lig = contextual_ligatures.get (index); 130 listener = new TextListener (t_("Middle"), lig.input, t_("Set")); 131 132 listener.signal_text_input.connect ((text) => { 133 lig.input = text; 134 }); 135 136 listener.signal_submit.connect (() => { 137 MainWindow.native_window.hide_text_input (); 138 MainWindow.get_ligature_display ().update_rows (); 139 }); 140 141 MainWindow.native_window.set_text_listener (listener); 142 } 143 144 public void set_end (int index) { 145 ContextualLigature lig; 146 TextListener listener; 147 148 return_if_fail (0 <= index < contextual_ligatures.size); 149 150 lig = contextual_ligatures.get (index); 151 listener = new TextListener (t_("End"), lig.lookahead, t_("Set")); 152 153 listener.signal_text_input.connect ((text) => { 154 lig.lookahead = text; 155 }); 156 157 listener.signal_submit.connect (() => { 158 MainWindow.native_window.hide_text_input (); 159 MainWindow.get_ligature_display ().update_rows (); 160 }); 161 162 MainWindow.native_window.set_text_listener (listener); 163 } 164 165 public void set_ligature (int index) { 166 Ligature lig; 167 168 return_if_fail (0 <= index < ligatures.size); 169 170 lig = ligatures.get (index); 171 lig.set_ligature (); 172 } 173 174 public void set_substitution (int index) { 175 Ligature lig; 176 177 return_if_fail (0 <= index < ligatures.size); 178 179 lig = ligatures.get (index); 180 lig.set_substitution (); 181 } 182 183 public void add_ligature (string subst, string liga) { 184 ligatures.insert (0, new Ligature (liga, subst)); 185 sort_ligatures (); 186 } 187 188 public void add_contextual_ligature (string backtrack, string input, string lookahead) { 189 ContextualLigature l = new ContextualLigature (backtrack, input, lookahead); 190 contextual_ligatures.insert (0, l); 191 sort_ligatures (); 192 } 193 194 public void sort_ligatures () { 195 ligatures.sort ((a, b) => { 196 Ligature first, next; 197 int chars_first, chars_next; 198 199 first = (Ligature) a; 200 next = (Ligature) b; 201 202 chars_first = first.substitution.split (" ").length; 203 chars_next = next.substitution.split (" ").length; 204 205 return chars_next - chars_first; 206 }); 207 208 contextual_ligatures.sort ((a, b) => { 209 ContextualLigature first, next; 210 int chars_first, chars_next; 211 212 first = (ContextualLigature) a; 213 next = (ContextualLigature) b; 214 215 chars_first = first.backtrack.split (" ").length; 216 chars_first += first.input.split (" ").length; 217 chars_first += first.lookahead.split (" ").length; 218 219 chars_next = next.backtrack.split (" ").length; 220 chars_next += next.input.split (" ").length; 221 chars_next += next.lookahead.split (" ").length; 222 223 return chars_next - chars_first; 224 }); 225 226 foreach (ContextualLigature c in contextual_ligatures) { 227 c.sort (); 228 } 229 } 230 } 231 232 } 233