1
2 /******************************************************************************
3 * MODULE : font_protrusion.cpp
4 * DESCRIPTION: font protrusion
5 * COPYRIGHT : (C) 2013 Joris van der Hoeven
6 *******************************************************************************
7 * This software falls under the GNU general public license version 3 or later.
8 * It comes WITHOUT ANY WARRANTY WHATSOEVER. For details, see the file LICENSE
9 * in the root directory or <http://www.gnu.org/licenses/gpl-3.0.html>.
10 ******************************************************************************/
11
12 #include "font.hpp"
13 #include "analyze.hpp"
14
15 /******************************************************************************
16 * Protrusion for western fonts
17 ******************************************************************************/
18
19 void
add_upright_left_protrusion(hashmap<string,double> & t)20 add_upright_left_protrusion (hashmap<string,double>& t) {
21 t ("`")= 0.7;
22 t ("\020")= 0.5; // ``
23 t ("(")= 0.05;
24 t ("A")= 0.05;
25 t ("J")= 0.05;
26 t ("T")= 0.05;
27 t ("V")= 0.05;
28 t ("W")= 0.05;
29 t ("X")= 0.05;
30 t ("Y")= 0.05;
31 t ("v")= 0.05;
32 t ("w")= 0.05;
33 t ("x")= 0.05;
34 t ("y")= 0.05;
35 }
36
37 void
add_upright_right_protrusion(hashmap<string,double> & t)38 add_upright_right_protrusion (hashmap<string,double>& t) {
39 t (".")= 0.7;
40 t ("-")= 0.7;
41 t (",")= 0.7;
42 t ("'")= 0.7;
43 t ("\021")= 0.5; // ''
44 t ("\022")= 0.5; // ,,
45 t (";")= 0.5;
46 t (":")= 0.5;
47 t ("\025")= 0.3; // --
48 t ("\026")= 0.2; // ---
49 t ("!")= 0.2;
50 t ("?")= 0.2;
51 t (")")= 0.05;
52 t ("A")= 0.05;
53 t ("F")= 0.05;
54 t ("K")= 0.05;
55 t ("L")= 0.05;
56 t ("T")= 0.05;
57 t ("V")= 0.05;
58 t ("W")= 0.05;
59 t ("X")= 0.05;
60 t ("Y")= 0.05;
61 t ("k")= 0.05;
62 t ("r")= 0.05;
63 t ("s")= 0.05;
64 t ("t")= 0.05;
65 t ("v")= 0.05;
66 t ("w")= 0.05;
67 t ("x")= 0.05;
68 t ("y")= 0.05;
69 }
70
71 void
add_accented_protrusion(hashmap<string,double> & t,string c,string s)72 add_accented_protrusion (hashmap<string,double>& t, string c, string s) {
73 if (t->contains (c)) {
74 int pos= 0;
75 while (pos < N(s)) {
76 int start= pos;
77 tm_char_forwards (s, pos);
78 t (s (start, pos))= t[c];
79 }
80 }
81 }
82
83 void
add_accented_protrusion(hashmap<string,double> & t)84 add_accented_protrusion (hashmap<string,double>& t) {
85 add_accented_protrusion (t, "A", "������\200\201");
86 add_accented_protrusion (t, "C", "�\202\203");
87 add_accented_protrusion (t, "E", "����\205\206");
88 add_accented_protrusion (t, "G", "\207");
89 add_accented_protrusion (t, "I", "����\235");
90 add_accented_protrusion (t, "L", "\210\212");
91 add_accented_protrusion (t, "N", "�\213\214");
92 add_accented_protrusion (t, "O", "�����\216");
93 add_accented_protrusion (t, "R", "\217\220");
94 add_accented_protrusion (t, "S", "\221\222\223");
95 add_accented_protrusion (t, "T", "\224\225");
96 add_accented_protrusion (t, "U", "����\226\227");
97 add_accented_protrusion (t, "Y", "�\230");
98 add_accented_protrusion (t, "Z", "\231\232\233");
99 add_accented_protrusion (t, "a", "������\240\241");
100 add_accented_protrusion (t, "c", "�\242\243");
101 add_accented_protrusion (t, "e", "����\245\246");
102 add_accented_protrusion (t, "g", "\247");
103 add_accented_protrusion (t, "i", "����");
104 add_accented_protrusion (t, "l", "\250\252");
105 add_accented_protrusion (t, "n", "�\253\254");
106 add_accented_protrusion (t, "o", "�����\256");
107 add_accented_protrusion (t, "r", "\257\260");
108 add_accented_protrusion (t, "s", "\261\262\263");
109 add_accented_protrusion (t, "t", "\265");
110 add_accented_protrusion (t, "u", "����\266\267");
111 add_accented_protrusion (t, "y", "�\270");
112 add_accented_protrusion (t, "z", "\271\272\273");
113 }
114
115 void
add_western(hashmap<string,double> & t,string font_name,bool right)116 add_western (hashmap<string,double>& t, string font_name, bool right) {
117 (void) font_name;
118 if (right) add_upright_right_protrusion (t);
119 else add_upright_left_protrusion (t);
120 add_accented_protrusion (t);
121 }
122
123 /******************************************************************************
124 * Protrusion for CJK fonts
125 ******************************************************************************/
126
127 void
add_cjk_left_protrusion(hashmap<string,double> & t)128 add_cjk_left_protrusion (hashmap<string,double>& t) {
129 t ("<#3008>")= 0.5;
130 t ("<#300A>")= 0.5;
131 t ("<#300C>")= 0.5;
132 t ("<#300E>")= 0.5;
133 t ("<#3016>")= 0.5;
134 t ("<#3018>")= 0.5;
135 t ("<#301A>")= 0.5;
136 t ("<#301D>")= 0.5;
137 }
138
139 void
add_cjk_right_protrusion(hashmap<string,double> & t)140 add_cjk_right_protrusion (hashmap<string,double>& t) {
141 t ("<#3001>")= 0.5;
142 t ("<#3002>")= 0.5;
143 t ("<#3009>")= 0.5;
144 t ("<#300B>")= 0.5;
145 t ("<#300D>")= 0.5;
146 t ("<#300F>")= 0.5;
147 t ("<#3017>")= 0.5;
148 t ("<#3019>")= 0.5;
149 t ("<#301B>")= 0.5;
150 t ("<#301E>")= 0.5;
151 t ("<#301F>")= 0.5;
152 t ("<#FF01>")= 0.5;
153 t ("<#FF0C>")= 0.5;
154 t ("<#FF0E>")= 0.5;
155 t ("<#FF1A>")= 0.5;
156 t ("<#FF1B>")= 0.5;
157 t ("<#FF1F>")= 0.5;
158 }
159
160 void
add_quanjiao(hashmap<string,double> & t,int mode,bool right)161 add_quanjiao (hashmap<string,double>& t, int mode, bool right) {
162 // FIXME: successions of several punctuation symbols
163 if (right) {
164 if ((mode & END_OF_LINE) != 0)
165 add_cjk_right_protrusion (t);
166 }
167 else {
168 if ((mode & START_OF_LINE) != 0)
169 add_cjk_left_protrusion (t);
170 }
171 }
172
173 void
add_banjiao(hashmap<string,double> & t,int mode,bool right)174 add_banjiao (hashmap<string,double>& t, int mode, bool right) {
175 if (right) add_cjk_right_protrusion (t);
176 else add_cjk_left_protrusion (t);
177 }
178
179 void
add_hangmobanjiao(hashmap<string,double> & t,int mode,bool right)180 add_hangmobanjiao (hashmap<string,double>& t, int mode, bool right) {
181 if (right) {
182 if ((mode & END_OF_LINE) != 0)
183 add_cjk_right_protrusion (t);
184 }
185 else {
186 if ((mode & START_OF_LINE) != 0)
187 add_cjk_left_protrusion (t);
188 }
189 }
190
191 void
add_kaiming(hashmap<string,double> & t,int mode,bool right)192 add_kaiming (hashmap<string,double>& t, int mode, bool right) {
193 if (right) {
194 add_cjk_right_protrusion (t);
195 if ((mode & END_OF_LINE) == 0) {
196 t->reset ("<#3002>");
197 }
198 }
199 else add_cjk_left_protrusion (t);
200 }
201
202 /******************************************************************************
203 * Setting up the global protrusion tables
204 ******************************************************************************/
205
206 static hashmap<string,int> protrusion_index_table (-1);
207 static array<hashmap<string,double> > protrusion_tables;
208
209 int
init_protrusion_table(string font_name,int mode,bool right)210 init_protrusion_table (string font_name, int mode, bool right) {
211 int index= (mode<<1) + (right?1:0);
212 string key= font_name * ":" * as_string (index);
213 if (!protrusion_index_table->contains (key)) {
214 int im= N(protrusion_tables);
215 protrusion_index_table (key)= im;
216 hashmap<string,double> t (0.0);
217 if ((mode & WESTERN_PROTRUSION) != 0)
218 add_western (t, font_name, right);
219 switch (mode & CJK_PROTRUSION_MASK) {
220 case QUANJIAO:
221 add_quanjiao (t, mode, right);
222 break;
223 case BANJIAO:
224 add_banjiao (t, mode, right);
225 break;
226 case HANGMOBANJIAO:
227 add_hangmobanjiao (t, mode, right);
228 break;
229 case KAIMING:
230 add_kaiming (t, mode, right);
231 break;
232 }
233 protrusion_tables << t;
234 }
235 return protrusion_index_table [key];
236 }
237
238 /******************************************************************************
239 * User interface
240 ******************************************************************************/
241
242 SI
get_left_protrusion(string s,int mode)243 font_rep::get_left_protrusion (string s, int mode) {
244 /*
245 static bool done= false;
246 if (!done) {
247 cout << "Font= " << res_name << "\n";
248 glyph o= get_glyph ("o");
249 for (int c=33; c<127; c++) {
250 string s ((char) c);
251 glyph g= get_glyph (s);
252 cout << s << " -> " << left_protrusion (g, o) << "\n";
253 }
254 done= true;
255 }
256 */
257
258 if (mode == 0 || N(s) == 0) return 0;
259 int index= (mode<<1);
260 if (!protrusion_maps->contains (index)) {
261 int code= init_protrusion_table (res_name, mode, false);
262 protrusion_maps (index)= code;
263 }
264 hashmap<string,double> t= protrusion_tables [protrusion_maps [index]];
265
266 int pos= 0;
267 tm_char_forwards (s, pos);
268 string first= s (0, pos);
269 if (t->contains (first)) {
270 metric ex;
271 get_extents (first, ex);
272 double factor= t[first];
273 return (SI) tm_round (factor * ex->x2);
274 }
275 return 0;
276 }
277
278 SI
get_right_protrusion(string s,int mode)279 font_rep::get_right_protrusion (string s, int mode) {
280 if (mode == 0 || N(s) == 0) return 0;
281 int index= (mode<<1) + 1;
282 if (!protrusion_maps->contains (index)) {
283 int code= init_protrusion_table (res_name, mode, true);
284 protrusion_maps (index)= code;
285 }
286 hashmap<string,double> t= protrusion_tables [protrusion_maps [index]];
287
288 int pos= N(s);
289 tm_char_backwards (s, pos);
290 string last= s (pos, N(s));
291 if (t->contains (last)) {
292 metric ex;
293 get_extents (last, ex);
294 double factor= t[last];
295 return (SI) tm_round (factor * ex->x2);
296 }
297 return 0;
298 }
299