The Birdfont Source Code


All Repositories / birdfont.git / blob – RSS feed

GlyphSequence.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/GlyphSequence.vala.
Fix translation
1 /* 2 Copyright (C) 2013 2015 2017 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 namespace BirdFont { 15 16 public class GlyphSequence : GLib.Object { 17 18 /** A list of all glyphs */ 19 public Gee.ArrayList<Glyph?> glyph; 20 21 /** A list of corresponding glyph ranges if applicable. */ 22 public Gee.ArrayList<GlyphRange?> ranges; 23 24 OtfTags otf_tags; 25 26 public GlyphSequence () { 27 glyph = new Gee.ArrayList<Glyph?> (); 28 ranges = new Gee.ArrayList<GlyphRange?> (); 29 otf_tags = new OtfTags (); 30 } 31 32 public void set_otf_tags (OtfTags tags) { 33 this.otf_tags = tags; 34 } 35 36 public int length () { 37 return glyph.size; 38 } 39 40 public void add (Glyph? g) { 41 glyph.add (g); 42 ranges.add (null); 43 } 44 45 public void append (GlyphSequence c) { 46 foreach (Glyph? g in c.glyph) { 47 glyph.add (g); 48 } 49 50 foreach (GlyphRange? r in c.ranges) { 51 ranges.add (r); 52 } 53 } 54 55 /** Perform glyph substitution. 56 * @param tags enable otf features 57 * @return a new sequence with ligatures 58 */ 59 public GlyphSequence process_ligatures (Font font) { 60 // FIXME add range to ligature 61 GlyphSequence ligature_sequence = new GlyphSequence (); 62 bool has_range = false; 63 Ligatures ligatures; 64 65 foreach (Glyph? g in glyph) { 66 ligature_sequence.glyph.add (g); 67 } 68 69 foreach (GlyphRange? r in ranges) { 70 ligature_sequence.ranges.add (r); 71 if (r != null) { 72 has_range = true; 73 } 74 } 75 76 // skip ligature substitution if this sequence contains ranges 77 if (has_range) { 78 return ligature_sequence; 79 } 80 81 ligatures = font.get_ligatures (); 82 83 for (int index = 0; index < glyph.size; index++) { 84 bool found = false; 85 foreach (ContextualLigature c in ligatures.contextual_ligatures) { 86 if (c.is_valid ()) { 87 found = ligature_sequence.replace_contextual (c.get_backtrack (), 88 c.get_input (), 89 c.get_lookahead (), 90 c.get_ligature_sequence (), 91 ref index); 92 93 if (found) { 94 index--; 95 break; 96 } 97 } 98 } 99 } 100 101 ligatures.get_single_substitution_ligatures ((substitute, ligature) => { 102 ligature_sequence.replace (substitute, ligature); 103 }); 104 105 // salt and similar tags 106 foreach (string tag in otf_tags.elements) { 107 Gee.ArrayList<Alternate> alternates; 108 alternates = font.alternates.get_alt (tag); 109 110 foreach (Alternate a in alternates) { 111 GlyphSequence old = new GlyphSequence (); 112 Glyph? g = font.get_glyph_by_name (a.glyph_name); 113 114 if (g != null) { 115 old.add (g); 116 117 if (a.alternates.size > 0) { 118 // FIXME: pick one of several alternates 119 string alt_name = a.alternates.get (0); 120 Glyph? alt = font.get_glyph_by_name (alt_name); 121 122 if (alt != null) { 123 GlyphSequence replacement = new GlyphSequence (); 124 replacement.add (alt); 125 ligature_sequence.replace (old, replacement); 126 } else { 127 warning (@"Alternate does not exist: $(alt_name)"); 128 } 129 } 130 } else { 131 warning (@"Alternative for a missing glyph: $(a.glyph_name)"); 132 } 133 } 134 } 135 136 ligature_sequence.ranges.clear (); 137 for (int i = 0; i < ligature_sequence.glyph.size; i++) { 138 ligature_sequence.ranges.add (null); 139 } 140 141 return ligature_sequence; 142 } 143 144 void replace (GlyphSequence old, GlyphSequence replacement) { 145 int i = 0; 146 while (i < glyph.size) { 147 if (starts_with (old, i)) { 148 glyph = substitute (i, old.glyph.size, replacement); 149 i += replacement.length (); 150 } else { 151 i++; 152 } 153 } 154 } 155 156 bool replace_contextual (GlyphSequence backtrack, GlyphSequence input, GlyphSequence lookahead, 157 GlyphSequence replacement, ref int index) { 158 159 bool start, middle, end; 160 int advance = 0; 161 162 start = starts_with (backtrack, index); 163 middle = starts_with (input, index + backtrack.length ()); 164 end = starts_with (lookahead, index + backtrack.length () + input.length ()); 165 166 if (start && middle && end) { 167 glyph = substitute (index + backtrack.length (), input.length (), replacement); 168 advance = backtrack.length () + replacement.length (); 169 index += advance; 170 171 if (advance <= 0) { 172 warning ("No advancement."); 173 return false; 174 } 175 176 return true; 177 } 178 179 return false; 180 } 181 182 bool starts_with (GlyphSequence old, uint index) { 183 Glyph? gl; 184 185 foreach (Glyph? g in old.glyph) { 186 if (index >= glyph.size) { 187 return false; 188 } 189 190 gl = glyph.get ((int) index); 191 192 if (g != gl) { 193 return false; 194 } 195 196 index++; 197 } 198 199 return true; 200 } 201 202 Gee.ArrayList<Glyph?> substitute (uint index, uint length, GlyphSequence substitute) { 203 Gee.ArrayList<Glyph?> new_list = new Gee.ArrayList<Glyph?> (); 204 int i = 0; 205 206 foreach (Glyph? g in glyph) { 207 if (i == index) { 208 foreach (Glyph? gn in substitute.glyph) { 209 new_list.add (gn); 210 } 211 } 212 213 if (!(i >= index && i < index + length)) { 214 new_list.add (g); 215 } 216 217 i++; 218 } 219 220 return new_list; 221 } 222 223 public string to_string () { 224 StringBuilder s = new StringBuilder(); 225 foreach (Glyph? g in glyph) { 226 227 if (g != null) { 228 Glyph gl = (!) g; 229 230 if (gl.unichar_code == '\0') { 231 s.append(@"[$(gl.name)]"); 232 } else { 233 string unichar_code = (!) gl.unichar_code.to_string (); 234 s.append(unichar_code); 235 } 236 } else { 237 s.append(@"[null]"); 238 } 239 } 240 241 return s.str; 242 } 243 } 244 245 }