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