.
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