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