1
2 /******************************************************************************
3 * MODULE : unicode_font.cpp
4 * DESCRIPTION: True Type fonts (using FreeType II)
5 * COPYRIGHT : (C) 1999 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 "Freetype/free_type.hpp"
14 #include "Freetype/tt_file.hpp"
15 #include "Freetype/tt_face.hpp"
16 #include "analyze.hpp"
17 #include "converter.hpp"
18
19 #ifdef USE_FREETYPE
20
21 #define std_dpi 600
22 #define std_pixel (std_shrinkf*256)
23 #define ROUND(l) ((l*dpi+(std_dpi>>1))/std_dpi)
24 #define FLOOR(l) ((((l*dpi)/std_dpi)/std_pixel)*std_pixel)
25 #define CEIL(l) (((((l*dpi+(std_dpi-1))/std_dpi)+std_pixel-1)/std_pixel)*std_pixel)
26
27 #define LIGATURE_FF 1
28 #define LIGATURE_FI 2
29 #define LIGATURE_FL 4
30 #define LIGATURE_FT 8
31 #define LIGATURE_FFI 16
32 #define LIGATURE_FFL 32
33 #define LIGATURE_ST 64
34
35 /******************************************************************************
36 * True Type fonts
37 ******************************************************************************/
38
39 struct unicode_font_rep: font_rep {
40 string family;
41 int dpi;
42 font_metric fnm;
43 font_glyphs fng;
44 int ligs;
45
46 unicode_font_rep (string name, string family, int size, int dpi);
47
48 unsigned int ligature_replace (unsigned int c, string s, int& i);
49 bool supports (string c);
50 void get_extents (string s, metric& ex);
51 void get_xpositions (string s, SI* xpos, bool ligf);
52 void get_xpositions (string s, SI* xpos);
53 void draw_fixed (renderer ren, string s, SI x, SI y, bool ligf);
54 void draw_fixed (renderer ren, string s, SI x, SI y);
55 font magnify (double zoom);
56 glyph get_glyph (string s);
57 double get_left_slope (string s);
58 double get_right_slope (string s);
59 SI get_left_correction (string s);
60 SI get_right_correction (string s);
61 };
62
63 /******************************************************************************
64 * Initialization of main font parameters
65 ******************************************************************************/
66
unicode_font_rep(string name,string family2,int size2,int dpi2)67 unicode_font_rep::unicode_font_rep (string name,
68 string family2, int size2, int dpi2):
69 font_rep (name), family (family2), dpi (dpi2), ligs (0)
70 {
71 type= FONT_TYPE_UNICODE;
72 size= size2;
73 fnm = tt_font_metric (family, size, std_dpi);
74 fng = tt_font_glyphs (family, size, dpi);
75 if (fnm->bad_font_metric || fng->bad_font_glyphs) {
76 fnm= std_font_metric (res_name, NULL, 0, -1);
77 fng= std_font_glyphs (res_name, NULL, 0, -1);
78 if (DEBUG_AUTO)
79 debug_fonts << "TeXmacs] Font " << family << " " << size << "pt "
80 << "at " << dpi << " dpi could not be loaded\n";
81
82 }
83
84 // get main font parameters
85 metric ex;
86 get_extents ("f", ex);
87 y1= ex->y1;
88 y2= ex->y2;
89 get_extents ("p", ex);
90 y1= min (y1, ex->y1);
91 y2= max (y2, ex->y2);
92 get_extents ("d", ex);
93 y1= min (y1, ex->y1);
94 y2= max (y2, ex->y2);
95 display_size = y2-y1;
96 design_size = size << 8;
97
98 // get character dimensions
99 get_extents ("x", ex);
100 yx = ex->y2;
101 get_extents ("M", ex);
102 wquad = ex->x2;
103
104 // compute other heights
105 yfrac = yx >> 1;
106 ysub_lo_base = -yx/3;
107 ysub_hi_lim = (5*yx)/6;
108 ysup_lo_lim = yx/2;
109 ysup_lo_base = (5*yx)/6;
110 ysup_hi_lim = yx;
111 yshift = yx/6;
112
113 // compute other widths
114 wpt = (dpi*PIXEL)/72;
115 wfn = (wpt*design_size) >> 8;
116 wline = wfn/20;
117
118 // get fraction bar parameters
119 get_extents ("-", ex);
120 yfrac= (ex->y3 + ex->y4) >> 1;
121
122 // get space length
123 get_extents (" ", ex);
124 spc = space ((3*(ex->x2-ex->x1))>>2, ex->x2-ex->x1, (3*(ex->x2-ex->x1))>>1);
125 extra= spc/2;
126 sep = wfn/10;
127
128 // get_italic space
129 get_extents ("f", ex);
130 SI italic_spc= (ex->x4-ex->x3)-(ex->x2-ex->x1);
131 slope= ((double) italic_spc) / ((double) display_size) - 0.05;
132 if (slope<0.15) slope= 0.0;
133
134 // determine whether we are dealing with a monospaced font
135 get_extents ("m", ex);
136 SI em= ex->x2 - ex->x1;
137 get_extents ("i", ex);
138 SI ei= ex->x2 - ex->x1;
139 bool mono= (em == ei);
140
141 // available standard ligatures
142 if (!mono) {
143 if (fnm->exists (0xfb00)) ligs += LIGATURE_FF;
144 if (fnm->exists (0xfb01)) ligs += LIGATURE_FI;
145 if (fnm->exists (0xfb02)) ligs += LIGATURE_FL;
146 if (fnm->exists (0xfb03)) ligs += LIGATURE_FFI;
147 if (fnm->exists (0xfb04)) ligs += LIGATURE_FFL;
148 if (fnm->exists (0xfb05)) ligs += LIGATURE_FT;
149 if (fnm->exists (0xfb06)) ligs += LIGATURE_ST;
150 }
151 if (family == "Times New Roman")
152 ligs= LIGATURE_FI + LIGATURE_FL;
153 if (family == "Zapfino")
154 ligs= LIGATURE_FF + LIGATURE_FI + LIGATURE_FL + LIGATURE_FFI;
155 //cout << "ligs= " << ligs << ", " << family << ", " << size << "\n";
156 }
157
158 /******************************************************************************
159 * Routines for font
160 ******************************************************************************/
161
162 static unsigned int
read_unicode_char(string s,int & i)163 read_unicode_char (string s, int& i) {
164 if (s[i] == '<') {
165 i++;
166 int start= i;
167 while (s[i] != '>') i++;
168 if (s[start] == '#') {
169 start++;
170 return (unsigned int) from_hexadecimal (s (start, i++));
171 }
172 else {
173 string ss= s (start-1, ++i);
174 string uu= cork_to_utf8 (ss);
175 if (uu == ss) return 0;
176 int j= 0;
177 return decode_from_utf8 (uu, j);
178 }
179 }
180 else {
181 unsigned int c= (unsigned int) s[i++];
182 if (c >= 32 && c <= 127) return c;
183 string ss= s (i-1, i);
184 string uu= cork_to_utf8 (ss);
185 int j= 0;
186 return decode_from_utf8 (uu, j);
187 }
188 }
189
190 unsigned int
ligature_replace(unsigned int uc,string s,int & i)191 unicode_font_rep::ligature_replace (unsigned int uc, string s, int& i) {
192 int n= N(s);
193 if (((char) uc) == 'f') {
194 if (i<n && s[i] == 'i' && (ligs & LIGATURE_FI) != 0) {
195 i++; return 0xfb01; }
196 else if (i<n && s[i] == 'l' && (ligs & LIGATURE_FL) != 0) {
197 i++; return 0xfb02; }
198 else if (i<n && s[i] == 't' && (ligs & LIGATURE_FT) != 0) {
199 i++; return 0xfb05; }
200 else if ((i+1)<n && s[i] == 'f' && s[i+1] == 'i' &&
201 (ligs & LIGATURE_FFI) != 0) {
202 i+=2; return 0xfb03; }
203 else if ((i+1)<n && s[i] == 'f' && s[i+1] == 'l' &&
204 (ligs & LIGATURE_FFL) != 0) {
205 i+=2; return 0xfb04; }
206 else if (i<n && s[i] == 'f' && (ligs & LIGATURE_FF) != 0) {
207 i++; return 0xfb00; }
208 else return uc;
209 }
210 else if (((char) uc) == 's') {
211 if (i<n && s[i] == 't' && (ligs & LIGATURE_ST) != 0) {
212 i++; return 0xfb06; }
213 else return uc;
214 }
215 else return uc;
216 }
217
218 bool
supports(string c)219 unicode_font_rep::supports (string c) {
220 if (N(c) == 0) return false;
221 int i= 0;
222 unsigned int uc= read_unicode_char (c, i);
223 if (uc == 0 || !fnm->exists (uc)) return false;
224 if (uc >= 0x42 && uc <= 0x5a && !fnm->exists (0x41)) return false;
225 if (uc >= 0x62 && uc <= 0x7a && !fnm->exists (0x61)) return false;
226 metric_struct* m= fnm->get (uc);
227 return m->x1 < m->x2 && m->y1 < m->y2;
228 }
229
230 void
get_extents(string s,metric & ex)231 unicode_font_rep::get_extents (string s, metric& ex) {
232 if (N(s)==0) {
233 ex->x1= ex->x3= ex->x2= ex->x4=0;
234 ex->y3= ex->y1= 0; ex->y4= ex->y2= yx;
235 }
236 else {
237 int i= 0, n= N(s);
238 unsigned int uc= read_unicode_char (s, i);
239 if (ligs > 0 && (((char) uc) == 'f' || ((char) uc) == 's'))
240 uc= ligature_replace (uc, s, i);
241 metric_struct* first= fnm->get (uc);
242 ex->x1= ROUND (first->x1);
243 ex->y1= ROUND (first->y1);
244 ex->x2= ROUND (first->x2);
245 ex->y2= ROUND (first->y2);
246 ex->x3= FLOOR (first->x3);
247 ex->y3= FLOOR (first->y3);
248 ex->x4= CEIL (first->x4);
249 ex->y4= CEIL (first->y4);
250 SI x= ROUND (first->x2);
251
252 while (i<n) {
253 unsigned int pc= uc;
254 uc= read_unicode_char (s, i);
255 if (ligs > 0 && (((char) uc) == 'f' || ((char) uc) == 's'))
256 uc= ligature_replace (uc, s, i);
257 x += ROUND (fnm->kerning (pc, uc));
258 metric_struct* next= fnm->get (uc);
259 ex->x1= min (ex->x1, x+ ROUND (next->x1));
260 ex->y1= min (ex->y1, ROUND (next->y1));
261 ex->x2= max (ex->x2, x+ ROUND (next->x2));
262 ex->y2= max (ex->y2, ROUND (next->y2));
263 ex->x3= min (ex->x3, x+ FLOOR (next->x3));
264 ex->y3= min (ex->y3, FLOOR (next->y3));
265 ex->x4= max (ex->x4, x+ CEIL (next->x4));
266 ex->y4= max (ex->y4, CEIL (next->y4));
267 x += ROUND (next->x2);
268 //if (fnm->kerning (pc, uc) != 0)
269 //cout << "Kerning " << ((char) pc) << ((char) uc) << " " << ROUND (fnm->kerning (pc, uc)) << ", " << ROUND (next->x2) << "\n";
270 }
271 }
272 }
273
274 void
get_xpositions(string s,SI * xpos,bool ligf)275 unicode_font_rep::get_xpositions (string s, SI* xpos, bool ligf) {
276 int i= 0, n= N(s);
277 if (n == 0) return;
278
279 register SI x= 0;
280 unsigned int uc= 0xffffffff;
281 while (i<n) {
282 int start= i;
283 unsigned int pc= uc;
284 uc= read_unicode_char (s, i);
285 if (ligs > 0 && ligf && (((char) uc) == 'f' || ((char) uc) == 's'))
286 uc= ligature_replace (uc, s, i);
287 if (pc != 0xffffffff) x += ROUND (fnm->kerning (pc, uc));
288 metric_struct* next= fnm->get (uc);
289 for (int j= start; j<i; j++) xpos[j]= x;
290 x += ROUND (next->x2);
291 //if (fnm->kerning (pc, uc) != 0)
292 //cout << "Kerning " << ((char) pc) << ((char) uc) << " " << ROUND (fnm->kerning (pc, uc)) << ", " << ROUND (next->x2) << "\n";
293 }
294 xpos[n]= x;
295 }
296
297 void
get_xpositions(string s,SI * xpos)298 unicode_font_rep::get_xpositions (string s, SI* xpos) {
299 get_xpositions (s, xpos, true);
300 }
301
302 void
draw_fixed(renderer ren,string s,SI x,SI y,bool ligf)303 unicode_font_rep::draw_fixed (renderer ren, string s, SI x, SI y, bool ligf) {
304 int i= 0, n= N(s);
305 unsigned int uc= 0xffffffff;
306 while (i<n) {
307 unsigned int pc= uc;
308 uc= read_unicode_char (s, i);
309 if (ligs > 0 && ligf && (((char) uc) == 'f' || ((char) uc) == 's'))
310 uc= ligature_replace (uc, s, i);
311 if (pc != 0xffffffff) x += ROUND (fnm->kerning (pc, uc));
312 ren->draw (uc, fng, x, y);
313 metric_struct* ex= fnm->get (uc);
314 x += ROUND (ex->x2);
315 //if (fnm->kerning (pc, uc) != 0)
316 //cout << "Kerning " << ((char) pc) << ((char) uc) << " " << ROUND (fnm->kerning (pc, uc)) << ", " << ROUND (ex->x2) << "\n";
317 }
318 }
319
320 void
draw_fixed(renderer ren,string s,SI x,SI y)321 unicode_font_rep::draw_fixed (renderer ren, string s, SI x, SI y) {
322 draw_fixed (ren, s, x, y, true);
323 }
324
325
326 font
magnify(double zoom)327 unicode_font_rep::magnify (double zoom) {
328 return unicode_font (family, size, (int) tm_round (dpi * zoom));
329 }
330
331 glyph
get_glyph(string s)332 unicode_font_rep::get_glyph (string s) {
333 int i= 0, n= N(s);
334 unsigned int uc= read_unicode_char (s, i);
335 if (i != n) return font_rep::get_glyph (s);
336 glyph gl= fng->get (uc);
337 if (is_nil (gl)) return font_rep::get_glyph (s);
338 return gl;
339 }
340
341 double
get_left_slope(string s)342 unicode_font_rep::get_left_slope (string s) {
343 if (N(s) == 0) return slope;
344 int pos= 0;
345 tm_char_forwards (s, pos);
346 if (pos == 1) return slope;
347 metric ex;
348 get_extents (s (0, pos), ex);
349 if (ex->y3 >= 0) return slope;
350 double sl= ((double) (ex->x3 - ex->x1)) / ((double) ex->y3);
351 if (sl > slope + 0.05) return sl;
352 else return slope;
353 }
354
355 double
get_right_slope(string s)356 unicode_font_rep::get_right_slope (string s) {
357 if (N(s) == 0) return slope;
358 int pos= N(s);
359 tm_char_backwards (s, pos);
360 if (pos == N(s) - 1) return slope;
361 metric ex;
362 get_extents (s (pos, N(s)), ex);
363 if (ex->y4 <= 0) return slope;
364 double sl= ((double) (ex->x4 - ex->x2)) / ((double) ex->y4);
365 if (sl > slope + 0.05) return sl;
366 else return slope;
367 }
368
369 SI
get_left_correction(string s)370 unicode_font_rep::get_left_correction (string s) {
371 metric ex;
372 get_extents (s, ex);
373 if (ex->x3 < ex->x1) return ex->x1 - ex->x3;
374 return 0;
375 }
376
377 SI
get_right_correction(string s)378 unicode_font_rep::get_right_correction (string s) {
379 metric ex;
380 get_extents (s, ex);
381 if (ex->x4 > ex->x2) return ex->x4 - ex->x2;
382 return 0;
383 }
384
385 /******************************************************************************
386 * Interface
387 ******************************************************************************/
388
389 font
unicode_font(string family,int size,int dpi)390 unicode_font (string family, int size, int dpi) {
391 string name= "unicode:" * family * as_string (size) * "@" * as_string(dpi);
392 return make (font, name,
393 tm_new<unicode_font_rep> (name, family, size, dpi));
394 }
395
396 #else
397
398 font
unicode_font(string family,int size,int dpi)399 unicode_font (string family, int size, int dpi) {
400 string name= "unicode:" * family * as_string (size) * "@" * as_string(dpi);
401 failed_error << "Font name= " << name << "\n";
402 FAILED ("true type support was disabled");
403 return font ();
404 }
405
406 #endif
407