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