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.
Apply OTF substitution in kerning tab
1 /* 2 Copyright (C) 2013 2015 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 public GlyphSequence () { 25 glyph = new Gee.ArrayList<Glyph?> (); 26 ranges = new Gee.ArrayList<GlyphRange?> (); 27 } 28 29 public int length () { 30 return glyph.size; 31 } 32 33 public void add (Glyph? g) { 34 glyph.add (g); 35 ranges.add (null); 36 } 37 38 public void append (GlyphSequence c) { 39 foreach (Glyph? g in c.glyph) { 40 glyph.add (g); 41 } 42 43 foreach (GlyphRange? r in c.ranges) { 44 ranges.add (r); 45 } 46 } 47 48 /** Do ligature substitution. 49 * @return a new sequence with ligatures 50 */ 51 public GlyphSequence process_ligatures (Font font) { 52 // FIXME add range to ligature 53 GlyphSequence ligature_sequence = new GlyphSequence (); 54 bool has_range = false; 55 Ligatures ligatures; 56 57 foreach (Glyph? g in glyph) { 58 ligature_sequence.glyph.add (g); 59 } 60 61 foreach (GlyphRange? r in ranges) { 62 ligature_sequence.ranges.add (r); 63 if (r != null) { 64 has_range = true; 65 } 66 } 67 68 // skip ligature substitution if this sequence contains ranges 69 if (has_range) { 70 return ligature_sequence; 71 } 72 73 ligatures = font.get_ligatures (); 74 75 foreach (ContextualLigature c in ligatures.contextual_ligatures) { 76 ligature_sequence.replace_contextual (c.get_backtrack (), 77 c.get_input (), c.get_lookahead (), c.get_ligature_sequence ()); 78 } 79 80 ligatures.get_single_substitution_ligatures ((substitute, ligature) => { 81 ligature_sequence.replace (substitute, ligature); 82 }); 83 84 ligature_sequence.ranges.clear (); 85 for (int i = 0; i < ligature_sequence.glyph.size; i++) { 86 ligature_sequence.ranges.add (null); 87 } 88 89 return ligature_sequence; 90 } 91 92 void replace (GlyphSequence old, GlyphSequence replacement) { 93 int i = 0; 94 while (i < glyph.size) { 95 if (starts_with (old, i)) { 96 glyph = substitute (i, old.glyph.size, replacement); 97 i += replacement.length (); 98 } else { 99 i++; 100 } 101 } 102 } 103 104 void replace_contextual (GlyphSequence backtrack, GlyphSequence input, GlyphSequence lookahead, 105 GlyphSequence replacement) { 106 107 bool start, middle, end; 108 int i = 0; 109 int advance = 0; 110 111 while (i < glyph.size) { 112 start = starts_with (backtrack, i); 113 middle = starts_with (input, i + backtrack.length ()); 114 end = starts_with (lookahead, i + backtrack.length () + input.length ()); 115 116 if (start && middle && end) { 117 glyph = substitute (i + backtrack.length (), input.length (), replacement); 118 119 advance = backtrack.length () + replacement.length (); 120 i += advance; 121 122 if (advance <= 0) { 123 warning ("No advancement."); 124 return; 125 } 126 } else { 127 i++; 128 } 129 } 130 } 131 132 bool starts_with (GlyphSequence old, uint index) { 133 Glyph? gl; 134 135 foreach (Glyph? g in old.glyph) { 136 if (index >= glyph.size) { 137 return false; 138 } 139 140 gl = glyph.get ((int) index); 141 142 if (g != gl) { 143 return false; 144 } 145 146 index++; 147 } 148 149 return true; 150 } 151 152 Gee.ArrayList<Glyph?> substitute (uint index, uint length, GlyphSequence substitute) { 153 Gee.ArrayList<Glyph?> new_list = new Gee.ArrayList<Glyph?> (); 154 int i = 0; 155 156 foreach (Glyph? g in glyph) { 157 if (i == index) { 158 foreach (Glyph? gn in substitute.glyph) { 159 new_list.add (gn); 160 } 161 } 162 163 if (!(i >= index && i < index + length)) { 164 new_list.add (g); 165 } 166 167 i++; 168 } 169 170 return new_list; 171 } 172 } 173 174 } 175