xref: /haiku/src/libs/agg/font_freetype/agg_font_freetype.cpp (revision ba62028d232c73fa6b1c2b2c0c253d245d2fce74)
1 //----------------------------------------------------------------------------
2 // Anti-Grain Geometry - Version 2.4
3 // Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
4 //
5 // Permission to copy, use, modify, sell and distribute this software
6 // is granted provided this copyright notice appears in all copies.
7 // This software is provided "as is" without express or implied
8 // warranty, and with no claim as to its suitability for any purpose.
9 //
10 //----------------------------------------------------------------------------
11 // Contact: mcseem@antigrain.com
12 //          mcseemagg@yahoo.com
13 //          http://www.antigrain.com
14 //----------------------------------------------------------------------------
15 
16 
17 #include <stdio.h>
18 #include "agg_font_freetype.h"
19 #include "agg_bitset_iterator.h"
20 #include "agg_renderer_scanline.h"
21 
22 
23 namespace agg
24 {
25 
26     //------------------------------------------------------------------------------
27     //
28     // This code implements the AUTODIN II polynomial
29     // The variable corresponding to the macro argument "crc" should
30     // be an unsigned long.
31     // Oroginal code  by Spencer Garrett <srg@quick.com>
32     //
33 
34     // generated using the AUTODIN II polynomial
35     //   x^32 + x^26 + x^23 + x^22 + x^16 +
36     //   x^12 + x^11 + x^10 + x^8 + x^7 + x^5 + x^4 + x^2 + x^1 + 1
37     //
38     //------------------------------------------------------------------------------
39 
40     static const unsigned crc32tab[256] =
41     {
42        0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
43        0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
44        0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
45        0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
46        0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
47        0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
48        0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
49        0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
50        0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
51        0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
52        0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
53        0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
54        0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
55        0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
56        0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
57        0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
58        0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
59        0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
60        0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
61        0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
62        0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
63        0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
64        0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
65        0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
66        0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
67        0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
68        0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
69        0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
70        0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
71        0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
72        0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
73        0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
74        0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
75        0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
76        0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
77        0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
78        0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
79        0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
80        0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
81        0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
82        0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
83        0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
84        0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
85        0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
86        0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
87        0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
88        0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
89        0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
90        0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
91        0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
92        0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
93        0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
94        0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
95        0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
96        0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
97        0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
98        0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
99        0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
100        0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
101        0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
102        0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
103        0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
104        0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
105        0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
106     };
107 
108 
109     //------------------------------------------------------------------------------
110 
calc_crc32(const unsigned char * buf,unsigned size)111     static unsigned calc_crc32(const unsigned char* buf, unsigned size)
112     {
113         unsigned crc = (unsigned)~0;
114         const unsigned char* p;
115         unsigned len = 0;
116         unsigned nr = size;
117 
118         for (len += nr, p = buf; nr--; ++p)
119         {
120             crc = (crc >> 8) ^ crc32tab[(crc ^ *p) & 0xff];
121         }
122         return ~crc;
123     }
124 
125     //------------------------------------------------------------------------
dbl_to_plain_fx(double d)126     static inline int dbl_to_plain_fx(double d)
127     {
128         return int(d * 65536.0);
129     }
130 
131     //------------------------------------------------------------------------
int26p6_to_dbl(int p)132     static inline double int26p6_to_dbl(int p)
133     {
134         return double(p) / 64.0;
135     }
136 
137     //------------------------------------------------------------------------
dbl_to_int26p6(double p)138     static inline int dbl_to_int26p6(double p)
139     {
140         return int(p * 64.0 + 0.5);
141     }
142 
143 
144     //------------------------------------------------------------------------
145     template<class PathStorage>
decompose_ft_outline(const FT_Outline & outline,bool flip_y,const trans_affine & mtx,PathStorage & path)146     bool decompose_ft_outline(const FT_Outline& outline,
147                               bool flip_y,
148                               const trans_affine& mtx,
149                               PathStorage& path)
150     {
151         typedef typename PathStorage::value_type value_type;
152 
153         FT_Vector   v_last;
154         FT_Vector   v_control;
155         FT_Vector   v_start;
156         double x1, y1, x2, y2, x3, y3;
157 
158         FT_Vector*  point;
159         FT_Vector*  limit;
160         char*       tags;
161 
162         int   n;         // index of contour in outline
163         int   first;     // index of first point in contour
164         char  tag;       // current point's state
165 
166         first = 0;
167 
168         for(n = 0; n < outline.n_contours; n++)
169         {
170             int  last;  // index of last point in contour
171 
172             last  = outline.contours[n];
173             limit = outline.points + last;
174 
175             v_start = outline.points[first];
176             v_last  = outline.points[last];
177 
178             v_control = v_start;
179 
180             point = outline.points + first;
181             tags  = outline.tags  + first;
182             tag   = FT_CURVE_TAG(tags[0]);
183 
184             // A contour cannot start with a cubic control point!
185             if(tag == FT_CURVE_TAG_CUBIC) return false;
186 
187             // check first point to determine origin
188             if( tag == FT_CURVE_TAG_CONIC)
189             {
190                 // first point is conic control.  Yes, this happens.
191                 if(FT_CURVE_TAG(outline.tags[last]) == FT_CURVE_TAG_ON)
192                 {
193                     // start at last point if it is on the curve
194                     v_start = v_last;
195                     limit--;
196                 }
197                 else
198                 {
199                     // if both first and last points are conic,
200                     // start at their middle and record its position
201                     // for closure
202                     v_start.x = (v_start.x + v_last.x) / 2;
203                     v_start.y = (v_start.y + v_last.y) / 2;
204 
205                     v_last = v_start;
206                 }
207                 point--;
208                 tags--;
209             }
210 
211             x1 = int26p6_to_dbl(v_start.x);
212             y1 = int26p6_to_dbl(v_start.y);
213             if(flip_y) y1 = -y1;
214             mtx.transform(&x1, &y1);
215             path.move_to(value_type(dbl_to_int26p6(x1)),
216                          value_type(dbl_to_int26p6(y1)));
217 
218             while(point < limit)
219             {
220                 point++;
221                 tags++;
222 
223                 tag = FT_CURVE_TAG(tags[0]);
224                 switch(tag)
225                 {
226                     case FT_CURVE_TAG_ON:  // emit a single line_to
227                     {
228                         x1 = int26p6_to_dbl(point->x);
229                         y1 = int26p6_to_dbl(point->y);
230                         if(flip_y) y1 = -y1;
231                         mtx.transform(&x1, &y1);
232                         path.line_to(value_type(dbl_to_int26p6(x1)),
233                                      value_type(dbl_to_int26p6(y1)));
234                         //path.line_to(conv(point->x), flip_y ? -conv(point->y) : conv(point->y));
235                         continue;
236                     }
237 
238                     case FT_CURVE_TAG_CONIC:  // consume conic arcs
239                     {
240                         v_control.x = point->x;
241                         v_control.y = point->y;
242 
243                     Do_Conic:
244                         if(point < limit)
245                         {
246                             FT_Vector vec;
247                             FT_Vector v_middle;
248 
249                             point++;
250                             tags++;
251                             tag = FT_CURVE_TAG(tags[0]);
252 
253                             vec.x = point->x;
254                             vec.y = point->y;
255 
256                             if(tag == FT_CURVE_TAG_ON)
257                             {
258                                 x1 = int26p6_to_dbl(v_control.x);
259                                 y1 = int26p6_to_dbl(v_control.y);
260                                 x2 = int26p6_to_dbl(vec.x);
261                                 y2 = int26p6_to_dbl(vec.y);
262                                 if(flip_y) { y1 = -y1; y2 = -y2; }
263                                 mtx.transform(&x1, &y1);
264                                 mtx.transform(&x2, &y2);
265                                 path.curve3(value_type(dbl_to_int26p6(x1)),
266                                             value_type(dbl_to_int26p6(y1)),
267                                             value_type(dbl_to_int26p6(x2)),
268                                             value_type(dbl_to_int26p6(y2)));
269                                 continue;
270                             }
271 
272                             if(tag != FT_CURVE_TAG_CONIC) return false;
273 
274                             v_middle.x = (v_control.x + vec.x) / 2;
275                             v_middle.y = (v_control.y + vec.y) / 2;
276 
277                             x1 = int26p6_to_dbl(v_control.x);
278                             y1 = int26p6_to_dbl(v_control.y);
279                             x2 = int26p6_to_dbl(v_middle.x);
280                             y2 = int26p6_to_dbl(v_middle.y);
281                             if(flip_y) { y1 = -y1; y2 = -y2; }
282                             mtx.transform(&x1, &y1);
283                             mtx.transform(&x2, &y2);
284                             path.curve3(value_type(dbl_to_int26p6(x1)),
285                                         value_type(dbl_to_int26p6(y1)),
286                                         value_type(dbl_to_int26p6(x2)),
287                                         value_type(dbl_to_int26p6(y2)));
288 
289                             //path.curve3(conv(v_control.x),
290                             //            flip_y ? -conv(v_control.y) : conv(v_control.y),
291                             //            conv(v_middle.x),
292                             //            flip_y ? -conv(v_middle.y) : conv(v_middle.y));
293 
294                             v_control = vec;
295                             goto Do_Conic;
296                         }
297 
298                         x1 = int26p6_to_dbl(v_control.x);
299                         y1 = int26p6_to_dbl(v_control.y);
300                         x2 = int26p6_to_dbl(v_start.x);
301                         y2 = int26p6_to_dbl(v_start.y);
302                         if(flip_y) { y1 = -y1; y2 = -y2; }
303                         mtx.transform(&x1, &y1);
304                         mtx.transform(&x2, &y2);
305                         path.curve3(value_type(dbl_to_int26p6(x1)),
306                                     value_type(dbl_to_int26p6(y1)),
307                                     value_type(dbl_to_int26p6(x2)),
308                                     value_type(dbl_to_int26p6(y2)));
309 
310                         //path.curve3(conv(v_control.x),
311                         //            flip_y ? -conv(v_control.y) : conv(v_control.y),
312                         //            conv(v_start.x),
313                         //            flip_y ? -conv(v_start.y) : conv(v_start.y));
314                         goto Close;
315                     }
316 
317                     default:  // FT_CURVE_TAG_CUBIC
318                     {
319                         FT_Vector vec1, vec2;
320 
321                         if(point + 1 > limit || FT_CURVE_TAG(tags[1]) != FT_CURVE_TAG_CUBIC)
322                         {
323                             return false;
324                         }
325 
326                         vec1.x = point[0].x;
327                         vec1.y = point[0].y;
328                         vec2.x = point[1].x;
329                         vec2.y = point[1].y;
330 
331                         point += 2;
332                         tags  += 2;
333 
334                         if(point <= limit)
335                         {
336                             FT_Vector vec;
337 
338                             vec.x = point->x;
339                             vec.y = point->y;
340 
341                             x1 = int26p6_to_dbl(vec1.x);
342                             y1 = int26p6_to_dbl(vec1.y);
343                             x2 = int26p6_to_dbl(vec2.x);
344                             y2 = int26p6_to_dbl(vec2.y);
345                             x3 = int26p6_to_dbl(vec.x);
346                             y3 = int26p6_to_dbl(vec.y);
347                             if(flip_y) { y1 = -y1; y2 = -y2; y3 = -y3; }
348                             mtx.transform(&x1, &y1);
349                             mtx.transform(&x2, &y2);
350                             mtx.transform(&x3, &y3);
351                             path.curve4(value_type(dbl_to_int26p6(x1)),
352                                         value_type(dbl_to_int26p6(y1)),
353                                         value_type(dbl_to_int26p6(x2)),
354                                         value_type(dbl_to_int26p6(y2)),
355                                         value_type(dbl_to_int26p6(x3)),
356                                         value_type(dbl_to_int26p6(y3)));
357 
358                             //path.curve4(conv(vec1.x),
359                             //            flip_y ? -conv(vec1.y) : conv(vec1.y),
360                             //            conv(vec2.x),
361                             //            flip_y ? -conv(vec2.y) : conv(vec2.y),
362                             //            conv(vec.x),
363                             //            flip_y ? -conv(vec.y) : conv(vec.y));
364                             continue;
365                         }
366 
367                         x1 = int26p6_to_dbl(vec1.x);
368                         y1 = int26p6_to_dbl(vec1.y);
369                         x2 = int26p6_to_dbl(vec2.x);
370                         y2 = int26p6_to_dbl(vec2.y);
371                         x3 = int26p6_to_dbl(v_start.x);
372                         y3 = int26p6_to_dbl(v_start.y);
373                         if(flip_y) { y1 = -y1; y2 = -y2; y3 = -y3; }
374                         mtx.transform(&x1, &y1);
375                         mtx.transform(&x2, &y2);
376                         mtx.transform(&x3, &y3);
377                         path.curve4(value_type(dbl_to_int26p6(x1)),
378                                     value_type(dbl_to_int26p6(y1)),
379                                     value_type(dbl_to_int26p6(x2)),
380                                     value_type(dbl_to_int26p6(y2)),
381                                     value_type(dbl_to_int26p6(x3)),
382                                     value_type(dbl_to_int26p6(y3)));
383 
384                         //path.curve4(conv(vec1.x),
385                         //            flip_y ? -conv(vec1.y) : conv(vec1.y),
386                         //            conv(vec2.x),
387                         //            flip_y ? -conv(vec2.y) : conv(vec2.y),
388                         //            conv(v_start.x),
389                         //            flip_y ? -conv(v_start.y) : conv(v_start.y));
390                         goto Close;
391                     }
392                 }
393             }
394 
395             path.close_polygon();
396 
397        Close:
398             first = last + 1;
399         }
400 
401         return true;
402     }
403 
404 
405 
406     //------------------------------------------------------------------------
407     template<class Scanline, class ScanlineStorage>
decompose_ft_bitmap_mono(const FT_Bitmap & bitmap,int x,int y,bool flip_y,Scanline & sl,ScanlineStorage & storage)408     void decompose_ft_bitmap_mono(const FT_Bitmap& bitmap,
409                                   int x, int y,
410                                   bool flip_y,
411                                   Scanline& sl,
412                                   ScanlineStorage& storage)
413     {
414         int i;
415         const int8u* buf = (const int8u*)bitmap.buffer;
416         int pitch = bitmap.pitch;
417         sl.reset(x, x + bitmap.width);
418         storage.prepare();
419         if(flip_y)
420         {
421             buf += bitmap.pitch * (bitmap.rows - 1);
422             y += bitmap.rows;
423             pitch = -pitch;
424         }
425         for(i = 0; i < bitmap.rows; i++)
426         {
427             sl.reset_spans();
428             bitset_iterator bits(buf, 0);
429             int j;
430             for(j = 0; j < bitmap.width; j++)
431             {
432                 if(bits.bit()) sl.add_cell(x + j, cover_full);
433                 ++bits;
434             }
435             buf += pitch;
436             if(sl.num_spans())
437             {
438                 sl.finalize(y - i - 1);
439                 storage.render(sl);
440             }
441         }
442     }
443 
444 
445 
446     //------------------------------------------------------------------------
447     template<class Rasterizer, class Scanline, class ScanlineStorage>
decompose_ft_bitmap_gray8(const FT_Bitmap & bitmap,int x,int y,bool flip_y,Rasterizer & ras,Scanline & sl,ScanlineStorage & storage)448     void decompose_ft_bitmap_gray8(const FT_Bitmap& bitmap,
449                                    int x, int y,
450                                    bool flip_y,
451                                    Rasterizer& ras,
452                                    Scanline& sl,
453                                    ScanlineStorage& storage)
454     {
455         int i, j;
456         const int8u* buf = (const int8u*)bitmap.buffer;
457         int pitch = bitmap.pitch;
458         sl.reset(x, x + bitmap.width);
459         storage.prepare();
460         if(flip_y)
461         {
462             buf += bitmap.pitch * (bitmap.rows - 1);
463             y += bitmap.rows;
464             pitch = -pitch;
465         }
466         for(i = 0; i < bitmap.rows; i++)
467         {
468             sl.reset_spans();
469             const int8u* p = buf;
470             for(j = 0; j < bitmap.width; j++)
471             {
472                 if(*p) sl.add_cell(x + j, ras.apply_gamma(*p));
473                 ++p;
474             }
475             buf += pitch;
476             if(sl.num_spans())
477             {
478                 sl.finalize(y - i - 1);
479                 storage.render(sl);
480             }
481         }
482     }
483 
484 
485 
486 
487 
488 
489 
490 
491 
492 
493 
494 
495 
496     //------------------------------------------------------------------------
~font_engine_freetype_base()497     font_engine_freetype_base::~font_engine_freetype_base()
498     {
499         unsigned i;
500         for(i = 0; i < m_num_faces; ++i)
501         {
502             delete [] m_face_names[i];
503             FT_Done_Face(m_faces[i]);
504         }
505         delete [] m_face_names;
506         delete [] m_faces;
507         delete [] m_signature;
508         if(m_library_initialized) FT_Done_FreeType(m_library);
509     }
510 
511 
512     //------------------------------------------------------------------------
font_engine_freetype_base(bool flag32,unsigned max_faces)513     font_engine_freetype_base::font_engine_freetype_base(bool flag32,
514                                                          unsigned max_faces) :
515         m_flag32(flag32),
516         m_change_stamp(0),
517         m_last_error(0),
518         m_name(0),
519         m_name_len(256-16-1),
520         m_face_index(0),
521         m_char_map(FT_ENCODING_NONE),
522         m_signature(new char [256+256-16]),
523         m_height(0),
524         m_width(0),
525         m_hinting(true),
526         m_flip_y(false),
527         m_library_initialized(false),
528         m_library(0),
529         m_faces(new FT_Face [max_faces]),
530         m_face_names(new char* [max_faces]),
531         m_num_faces(0),
532         m_max_faces(max_faces),
533         m_cur_face(0),
534         m_resolution(0),
535         m_glyph_rendering(glyph_ren_native_gray8),
536         m_glyph_index(0),
537         m_data_size(0),
538         m_data_type(glyph_data_invalid),
539         m_bounds(1,1,0,0),
540         m_advance_x(0.0),
541         m_advance_y(0.0),
542 
543         m_path16(),
544         m_path32(),
545         m_curves16(m_path16),
546         m_curves32(m_path32),
547         m_scanline_aa(),
548         m_scanline_bin(),
549         m_scanlines_aa(),
550         m_scanlines_bin(),
551         m_rasterizer()
552     {
553         m_curves16.approximation_scale(4.0);
554         m_curves32.approximation_scale(4.0);
555         m_last_error = FT_Init_FreeType(&m_library);
556         if(m_last_error == 0) m_library_initialized = true;
557     }
558 
559 
560 
561     //------------------------------------------------------------------------
resolution(unsigned dpi)562     void font_engine_freetype_base::resolution(unsigned dpi)
563     {
564         m_resolution = dpi;
565         update_char_size();
566     }
567 
568 
569     //------------------------------------------------------------------------
find_face(const char * face_name) const570     int font_engine_freetype_base::find_face(const char* face_name) const
571     {
572         unsigned i;
573         for(i = 0; i < m_num_faces; ++i)
574         {
575             if(strcmp(face_name, m_face_names[i]) == 0) return i;
576         }
577         return -1;
578     }
579 
580 
581     //------------------------------------------------------------------------
ascender() const582     double font_engine_freetype_base::ascender() const
583     {
584         if(m_cur_face)
585         {
586             return m_cur_face->ascender * height() / m_cur_face->height;
587         }
588         return 0.0;
589     }
590 
591     //------------------------------------------------------------------------
descender() const592     double font_engine_freetype_base::descender() const
593     {
594         if(m_cur_face)
595         {
596             return m_cur_face->descender * height() / m_cur_face->height;
597         }
598         return 0.0;
599     }
600 
601 
602     //------------------------------------------------------------------------
load_font(const char * font_name,unsigned face_index,glyph_rendering ren_type,const char * font_mem,const long font_mem_size)603     bool font_engine_freetype_base::load_font(const char* font_name,
604                                               unsigned face_index,
605                                               glyph_rendering ren_type,
606                                               const char* font_mem,
607                                               const long font_mem_size)
608     {
609         bool ret = false;
610 
611         if(m_library_initialized)
612         {
613             m_last_error = 0;
614 
615             int idx = find_face(font_name);
616             if(idx >= 0)
617             {
618                 m_cur_face = m_faces[idx];
619                 m_name     = m_face_names[idx];
620             }
621             else
622             {
623                 if(m_num_faces >= m_max_faces)
624                 {
625                     delete [] m_face_names[0];
626                     FT_Done_Face(m_faces[0]);
627                     memcpy(m_faces,
628                            m_faces + 1,
629                            (m_max_faces - 1) * sizeof(FT_Face));
630                     memcpy(m_face_names,
631                            m_face_names + 1,
632                            (m_max_faces - 1) * sizeof(char*));
633                     m_num_faces = m_max_faces - 1;
634                 }
635 
636                 if (font_mem && font_mem_size)
637                 {
638                     m_last_error = FT_New_Memory_Face(m_library,
639                                                       (const FT_Byte*)font_mem,
640                                                       font_mem_size,
641                                                       face_index,
642                                                       &m_faces[m_num_faces]);
643                 }
644                 else
645                 {
646                     m_last_error = FT_New_Face(m_library,
647                                                font_name,
648                                                face_index,
649                                                &m_faces[m_num_faces]);
650                 }
651 
652                 if(m_last_error == 0)
653                 {
654                     m_face_names[m_num_faces] = new char [strlen(font_name) + 1];
655                     strcpy(m_face_names[m_num_faces], font_name);
656                     m_cur_face = m_faces[m_num_faces];
657                     m_name     = m_face_names[m_num_faces];
658                     ++m_num_faces;
659                 }
660                 else
661                 {
662                     m_face_names[m_num_faces] = 0;
663                     m_cur_face = 0;
664                     m_name = 0;
665                 }
666             }
667 
668 
669             if(m_last_error == 0)
670             {
671                 ret = true;
672 
673                 switch(ren_type)
674                 {
675                 case glyph_ren_native_mono:
676                     m_glyph_rendering = glyph_ren_native_mono;
677                     break;
678 
679                 case glyph_ren_native_gray8:
680                     m_glyph_rendering = glyph_ren_native_gray8;
681                     break;
682 
683                 case glyph_ren_outline:
684                     if(FT_IS_SCALABLE(m_cur_face))
685                     {
686                         m_glyph_rendering = glyph_ren_outline;
687                     }
688                     else
689                     {
690                         m_glyph_rendering = glyph_ren_native_gray8;
691                     }
692                     break;
693 
694                 case glyph_ren_agg_mono:
695                     if(FT_IS_SCALABLE(m_cur_face))
696                     {
697                         m_glyph_rendering = glyph_ren_agg_mono;
698                     }
699                     else
700                     {
701                         m_glyph_rendering = glyph_ren_native_mono;
702                     }
703                     break;
704 
705                 case glyph_ren_agg_gray8:
706                     if(FT_IS_SCALABLE(m_cur_face))
707                     {
708                         m_glyph_rendering = glyph_ren_agg_gray8;
709                     }
710                     else
711                     {
712                         m_glyph_rendering = glyph_ren_native_gray8;
713                     }
714                     break;
715                 }
716                 update_signature();
717             }
718         }
719         return ret;
720     }
721 
722 
723     //------------------------------------------------------------------------
attach(const char * file_name)724     bool font_engine_freetype_base::attach(const char* file_name)
725     {
726         if(m_cur_face)
727         {
728             m_last_error = FT_Attach_File(m_cur_face, file_name);
729             return m_last_error == 0;
730         }
731         return false;
732     }
733 
734     //------------------------------------------------------------------------
num_faces() const735     unsigned font_engine_freetype_base::num_faces() const
736     {
737         if(m_cur_face)
738         {
739             return m_cur_face->num_faces;
740         }
741         return 0;
742     }
743 
744     //------------------------------------------------------------------------
char_map(FT_Encoding char_map)745     bool font_engine_freetype_base::char_map(FT_Encoding char_map)
746     {
747         if(m_cur_face)
748         {
749             m_last_error = FT_Select_Charmap(m_cur_face, char_map);
750             if(m_last_error == 0)
751             {
752                 m_char_map = char_map;
753                 update_signature();
754                 return true;
755             }
756         }
757         return false;
758     }
759 
760     //------------------------------------------------------------------------
height(double h)761     bool font_engine_freetype_base::height(double h)
762     {
763         m_height = int(h * 64.0);
764         if(m_cur_face)
765         {
766             update_char_size();
767             return true;
768         }
769         return false;
770     }
771 
772     //------------------------------------------------------------------------
width(double w)773     bool font_engine_freetype_base::width(double w)
774     {
775         m_width = int(w * 64.0);
776         if(m_cur_face)
777         {
778             update_char_size();
779             return true;
780         }
781         return false;
782     }
783 
784     //------------------------------------------------------------------------
hinting(bool h)785     void font_engine_freetype_base::hinting(bool h)
786     {
787         m_hinting = h;
788         if(m_cur_face)
789         {
790             update_signature();
791         }
792     }
793 
794     //------------------------------------------------------------------------
flip_y(bool f)795     void font_engine_freetype_base::flip_y(bool f)
796     {
797         m_flip_y = f;
798         if(m_cur_face)
799         {
800             update_signature();
801         }
802     }
803 
804     //------------------------------------------------------------------------
transform(const trans_affine & affine)805     void font_engine_freetype_base::transform(const trans_affine& affine)
806     {
807         m_affine = affine;
808         if(m_cur_face)
809         {
810             update_signature();
811         }
812     }
813 
814     //------------------------------------------------------------------------
update_signature()815     void font_engine_freetype_base::update_signature()
816     {
817         if(m_cur_face && m_name)
818         {
819             unsigned name_len = strlen(m_name);
820             if(name_len > m_name_len)
821             {
822                 delete [] m_signature;
823                 m_signature = new char [name_len + 32 + 256];
824                 m_name_len = name_len + 32 - 1;
825             }
826 
827             unsigned gamma_hash = 0;
828             if(m_glyph_rendering == glyph_ren_native_gray8 ||
829                m_glyph_rendering == glyph_ren_agg_mono ||
830                m_glyph_rendering == glyph_ren_agg_gray8)
831             {
832                 unsigned char gamma_table[rasterizer_scanline_aa<>::aa_scale];
833                 unsigned i;
834                 for(i = 0; i < rasterizer_scanline_aa<>::aa_scale; ++i)
835                 {
836                     gamma_table[i] = m_rasterizer.apply_gamma(i);
837                 }
838                 gamma_hash = calc_crc32(gamma_table, sizeof(gamma_table));
839             }
840 
841             sprintf(m_signature,
842                     "%s,%u,%d,%d,%d:%dx%d,%d,%d,%08X",
843                     m_name,
844                     m_char_map,
845                     m_face_index,
846                     int(m_glyph_rendering),
847                     m_resolution,
848                     m_height,
849                     m_width,
850                     int(m_hinting),
851                     int(m_flip_y),
852                     gamma_hash);
853             if(m_glyph_rendering == glyph_ren_outline ||
854                m_glyph_rendering == glyph_ren_agg_mono ||
855                m_glyph_rendering == glyph_ren_agg_gray8)
856             {
857                 double mtx[6];
858                 char buf[100];
859                 m_affine.store_to(mtx);
860                 sprintf(buf, ",%08X%08X%08X%08X%08X%08X",
861                     dbl_to_plain_fx(mtx[0]),
862                     dbl_to_plain_fx(mtx[1]),
863                     dbl_to_plain_fx(mtx[2]),
864                     dbl_to_plain_fx(mtx[3]),
865                     dbl_to_plain_fx(mtx[4]),
866                     dbl_to_plain_fx(mtx[5]));
867                 strcat(m_signature, buf);
868             }
869             ++m_change_stamp;
870         }
871     }
872 
873 
874     //------------------------------------------------------------------------
update_char_size()875     void font_engine_freetype_base::update_char_size()
876     {
877         if(m_cur_face)
878         {
879             if(m_resolution)
880             {
881                 FT_Set_Char_Size(m_cur_face,
882                                  m_width,       // char_width in 1/64th of points
883                                  m_height,      // char_height in 1/64th of points
884                                  m_resolution,  // horizontal device resolution
885                                  m_resolution); // vertical device resolution
886             }
887             else
888             {
889                 FT_Set_Pixel_Sizes(m_cur_face,
890                                    m_width >> 6,    // pixel_width
891                                    m_height >> 6);  // pixel_height
892             }
893             update_signature();
894         }
895     }
896 
897 
898 
899 
900 
901     //------------------------------------------------------------------------
prepare_glyph(unsigned glyph_code)902     bool font_engine_freetype_base::prepare_glyph(unsigned glyph_code)
903     {
904         m_glyph_index = FT_Get_Char_Index(m_cur_face, glyph_code);
905         m_last_error = FT_Load_Glyph(m_cur_face,
906                                      m_glyph_index,
907                                      m_hinting ? FT_LOAD_DEFAULT : FT_LOAD_NO_HINTING);
908 //                                     m_hinting ? FT_LOAD_FORCE_AUTOHINT : FT_LOAD_NO_HINTING);
909         if(m_last_error == 0)
910         {
911             switch(m_glyph_rendering)
912             {
913             case glyph_ren_native_mono:
914                 m_last_error = FT_Render_Glyph(m_cur_face->glyph, FT_RENDER_MODE_MONO);
915                 if(m_last_error == 0)
916                 {
917                     decompose_ft_bitmap_mono(m_cur_face->glyph->bitmap,
918                                              m_cur_face->glyph->bitmap_left,
919                                              m_flip_y ? -m_cur_face->glyph->bitmap_top :
920                                                          m_cur_face->glyph->bitmap_top,
921                                              m_flip_y,
922                                              m_scanline_bin,
923                                              m_scanlines_bin);
924                     m_bounds.x1 = m_scanlines_bin.min_x();
925                     m_bounds.y1 = m_scanlines_bin.min_y();
926                     m_bounds.x2 = m_scanlines_bin.max_x() + 1;
927                     m_bounds.y2 = m_scanlines_bin.max_y() + 1;
928                     m_data_size = m_scanlines_bin.byte_size();
929                     m_data_type = glyph_data_mono;
930                     m_advance_x = int26p6_to_dbl(m_cur_face->glyph->advance.x);
931                     m_advance_y = int26p6_to_dbl(m_cur_face->glyph->advance.y);
932                     return true;
933                 }
934                 break;
935 
936 
937             case glyph_ren_native_gray8:
938                 m_last_error = FT_Render_Glyph(m_cur_face->glyph, FT_RENDER_MODE_NORMAL);
939                 if(m_last_error == 0)
940                 {
941                     decompose_ft_bitmap_gray8(m_cur_face->glyph->bitmap,
942                                               m_cur_face->glyph->bitmap_left,
943                                               m_flip_y ? -m_cur_face->glyph->bitmap_top :
944                                                           m_cur_face->glyph->bitmap_top,
945                                               m_flip_y,
946                                               m_rasterizer,
947                                               m_scanline_aa,
948                                               m_scanlines_aa);
949                     m_bounds.x1 = m_scanlines_aa.min_x();
950                     m_bounds.y1 = m_scanlines_aa.min_y();
951                     m_bounds.x2 = m_scanlines_aa.max_x() + 1;
952                     m_bounds.y2 = m_scanlines_aa.max_y() + 1;
953                     m_data_size = m_scanlines_aa.byte_size();
954                     m_data_type = glyph_data_gray8;
955                     m_advance_x = int26p6_to_dbl(m_cur_face->glyph->advance.x);
956                     m_advance_y = int26p6_to_dbl(m_cur_face->glyph->advance.y);
957                     return true;
958                 }
959                 break;
960 
961 
962             case glyph_ren_outline:
963                 if(m_last_error == 0)
964                 {
965                     if(m_flag32)
966                     {
967                         m_path32.remove_all();
968                         if(decompose_ft_outline(m_cur_face->glyph->outline,
969                                                 m_flip_y,
970                                                 m_affine,
971                                                 m_path32))
972                         {
973                             rect_d bnd  = m_path32.bounding_rect();
974                             m_data_size = m_path32.byte_size();
975                             m_data_type = glyph_data_outline;
976                             m_bounds.x1 = int(floor(bnd.x1));
977                             m_bounds.y1 = int(floor(bnd.y1));
978                             m_bounds.x2 = int(ceil(bnd.x2));
979                             m_bounds.y2 = int(ceil(bnd.y2));
980                             m_advance_x = int26p6_to_dbl(m_cur_face->glyph->advance.x);
981                             m_advance_y = int26p6_to_dbl(m_cur_face->glyph->advance.y);
982                             m_affine.transform(&m_advance_x, &m_advance_y);
983                             return true;
984                         }
985                     }
986                     else
987                     {
988                         m_path16.remove_all();
989                         if(decompose_ft_outline(m_cur_face->glyph->outline,
990                                                 m_flip_y,
991                                                 m_affine,
992                                                 m_path16))
993                         {
994                             rect_d bnd  = m_path16.bounding_rect();
995                             m_data_size = m_path16.byte_size();
996                             m_data_type = glyph_data_outline;
997                             m_bounds.x1 = int(floor(bnd.x1));
998                             m_bounds.y1 = int(floor(bnd.y1));
999                             m_bounds.x2 = int(ceil(bnd.x2));
1000                             m_bounds.y2 = int(ceil(bnd.y2));
1001                             m_advance_x = int26p6_to_dbl(m_cur_face->glyph->advance.x);
1002                             m_advance_y = int26p6_to_dbl(m_cur_face->glyph->advance.y);
1003                             m_affine.transform(&m_advance_x, &m_advance_y);
1004                             return true;
1005                         }
1006                     }
1007                 }
1008                 return false;
1009 
1010             case glyph_ren_agg_mono:
1011                 if(m_last_error == 0)
1012                 {
1013                     m_rasterizer.reset();
1014                     if(m_flag32)
1015                     {
1016                         m_path32.remove_all();
1017                         decompose_ft_outline(m_cur_face->glyph->outline,
1018                                              m_flip_y,
1019                                              m_affine,
1020                                              m_path32);
1021                         m_rasterizer.add_path(m_curves32);
1022                     }
1023                     else
1024                     {
1025                         m_path16.remove_all();
1026                         decompose_ft_outline(m_cur_face->glyph->outline,
1027                                              m_flip_y,
1028                                              m_affine,
1029                                              m_path16);
1030                         m_rasterizer.add_path(m_curves16);
1031                     }
1032                     m_scanlines_bin.prepare(); // Remove all
1033                     render_scanlines(m_rasterizer, m_scanline_bin, m_scanlines_bin);
1034                     m_bounds.x1 = m_scanlines_bin.min_x();
1035                     m_bounds.y1 = m_scanlines_bin.min_y();
1036                     m_bounds.x2 = m_scanlines_bin.max_x() + 1;
1037                     m_bounds.y2 = m_scanlines_bin.max_y() + 1;
1038                     m_data_size = m_scanlines_bin.byte_size();
1039                     m_data_type = glyph_data_mono;
1040                     m_advance_x = int26p6_to_dbl(m_cur_face->glyph->advance.x);
1041                     m_advance_y = int26p6_to_dbl(m_cur_face->glyph->advance.y);
1042                     m_affine.transform(&m_advance_x, &m_advance_y);
1043                     return true;
1044                 }
1045                 return false;
1046 
1047 
1048             case glyph_ren_agg_gray8:
1049                 if(m_last_error == 0)
1050                 {
1051                     m_rasterizer.reset();
1052                     if(m_flag32)
1053                     {
1054                         m_path32.remove_all();
1055                         decompose_ft_outline(m_cur_face->glyph->outline,
1056                                              m_flip_y,
1057                                              m_affine,
1058                                              m_path32);
1059                         m_rasterizer.add_path(m_curves32);
1060                     }
1061                     else
1062                     {
1063                         m_path16.remove_all();
1064                         decompose_ft_outline(m_cur_face->glyph->outline,
1065                                              m_flip_y,
1066                                              m_affine,
1067                                              m_path16);
1068                         m_rasterizer.add_path(m_curves16);
1069                     }
1070                     m_scanlines_aa.prepare(); // Remove all
1071                     render_scanlines(m_rasterizer, m_scanline_aa, m_scanlines_aa);
1072                     m_bounds.x1 = m_scanlines_aa.min_x();
1073                     m_bounds.y1 = m_scanlines_aa.min_y();
1074                     m_bounds.x2 = m_scanlines_aa.max_x() + 1;
1075                     m_bounds.y2 = m_scanlines_aa.max_y() + 1;
1076                     m_data_size = m_scanlines_aa.byte_size();
1077                     m_data_type = glyph_data_gray8;
1078                     m_advance_x = int26p6_to_dbl(m_cur_face->glyph->advance.x);
1079                     m_advance_y = int26p6_to_dbl(m_cur_face->glyph->advance.y);
1080                     m_affine.transform(&m_advance_x, &m_advance_y);
1081                     return true;
1082                 }
1083                 return false;
1084             }
1085         }
1086         return false;
1087     }
1088 
1089 
1090 
1091 
1092     //------------------------------------------------------------------------
write_glyph_to(int8u * data) const1093     void font_engine_freetype_base::write_glyph_to(int8u* data) const
1094     {
1095         if(data && m_data_size)
1096         {
1097             switch(m_data_type)
1098             {
1099             default: return;
1100             case glyph_data_mono:    m_scanlines_bin.serialize(data); break;
1101             case glyph_data_gray8:   m_scanlines_aa.serialize(data);  break;
1102             case glyph_data_outline:
1103                 if(m_flag32)
1104                 {
1105                     m_path32.serialize(data);
1106                 }
1107                 else
1108                 {
1109                     m_path16.serialize(data);
1110                 }
1111                 break;
1112             case glyph_data_invalid: break;
1113             }
1114         }
1115     }
1116 
1117 
1118 
1119     //------------------------------------------------------------------------
add_kerning(unsigned first,unsigned second,double * x,double * y)1120     bool font_engine_freetype_base::add_kerning(unsigned first, unsigned second,
1121                                            double* x, double* y)
1122     {
1123         if(m_cur_face && first && second && FT_HAS_KERNING(m_cur_face))
1124         {
1125             FT_Vector delta;
1126             FT_Get_Kerning(m_cur_face, first, second,
1127                            FT_KERNING_DEFAULT, &delta);
1128             double dx = int26p6_to_dbl(delta.x);
1129             double dy = int26p6_to_dbl(delta.y);
1130             if(m_glyph_rendering == glyph_ren_outline ||
1131                m_glyph_rendering == glyph_ren_agg_mono ||
1132                m_glyph_rendering == glyph_ren_agg_gray8)
1133             {
1134                 m_affine.transform_2x2(&dx, &dy);
1135             }
1136             *x += dx;
1137             *y += dy;
1138 
1139             return true;
1140         }
1141         return false;
1142     }
1143 
1144 
1145 
1146 }
1147 
1148 
1149