Anti-Grain Geometry Tutorial
agg_font_freetype2.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 #include <cstdio>
17 #include <cstring>
18 #include <freetype/ftmodapi.h>
19 #include "agg_font_freetype2.h"
20 #include "agg_bitset_iterator.h"
21 #include "agg_renderer_scanline.h"
22 
23 namespace agg {
24 namespace fman {
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 
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  //------------------------------------------------------------------------
126  static inline int dbl_to_plain_fx(double d)
127  {
128  return int(d * 65536.0);
129  }
130 
131  //------------------------------------------------------------------------
132  static inline double int26p6_to_dbl(int p)
133  {
134  return double(p) / 64.0;
135  }
136 
137  //------------------------------------------------------------------------
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>
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>
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>
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  bool font_engine_freetype_base::loaded_face::prepare_glyph(unsigned glyph_code, prepared_glyph *prepared) const
493  {
494  bool success=false;
495  prepared->glyph_index = FT_Get_Char_Index(m_ft_face, glyph_code);
496  int error = FT_Load_Glyph(m_ft_face,
497  prepared->glyph_index,
498  m_hinting ? FT_LOAD_DEFAULT : FT_LOAD_NO_HINTING);
499  // m_hinting ? FT_LOAD_FORCE_AUTOHINT : FT_LOAD_NO_HINTING);
500  if(error == 0)
501  {
502  prepared->glyph_code=glyph_code;
503  switch(m_rendering)
504  {
505  case glyph_ren_native_mono:
506  error = FT_Render_Glyph(m_ft_face->glyph, FT_RENDER_MODE_MONO);
507  if(error == 0)
508  {
509  decompose_ft_bitmap_mono(m_ft_face->glyph->bitmap,
510  m_ft_face->glyph->bitmap_left,
511  m_flip_y ? -m_ft_face->glyph->bitmap_top :
512  m_ft_face->glyph->bitmap_top,
513  m_flip_y,
514  m_engine.m_scanline_bin,
515  m_engine.m_scanlines_bin);
516  prepared->bounds.x1 = m_engine.m_scanlines_bin.min_x();
517  prepared->bounds.y1 = m_engine.m_scanlines_bin.min_y();
518  prepared->bounds.x2 = m_engine.m_scanlines_bin.max_x() + 1;
519  prepared->bounds.y2 = m_engine.m_scanlines_bin.max_y() + 1;
520  prepared->data_size = m_engine.m_scanlines_bin.byte_size();
521  prepared->data_type = glyph_data_mono;
522  prepared->advance_x = int26p6_to_dbl(m_ft_face->glyph->advance.x);
523  prepared->advance_y = int26p6_to_dbl(m_ft_face->glyph->advance.y);
524  success=true;
525  }
526  break;
527 
528 
529  case glyph_ren_native_gray8:
530  error = FT_Render_Glyph(m_ft_face->glyph, FT_RENDER_MODE_NORMAL);
531  if(error == 0)
532  {
533  decompose_ft_bitmap_gray8(m_ft_face->glyph->bitmap,
534  m_ft_face->glyph->bitmap_left,
535  m_flip_y ? -m_ft_face->glyph->bitmap_top :
536  m_ft_face->glyph->bitmap_top,
537  m_flip_y,
538  m_engine.m_rasterizer,
539  m_engine.m_scanline_aa,
540  m_engine.m_scanlines_aa);
541  prepared->data_size = m_engine.m_scanlines_aa.byte_size();
542  prepared->data_type = glyph_data_gray8;
543  prepared->advance_x = int26p6_to_dbl(m_ft_face->glyph->advance.x);
544  prepared->advance_y = int26p6_to_dbl(m_ft_face->glyph->advance.y);
545  if( m_ft_face->glyph->bitmap.rows!=0 &&
546  m_ft_face->glyph->bitmap.width!=0 )
547  {
548  prepared->bounds.x1 = m_engine.m_scanlines_aa.min_x();
549  prepared->bounds.y1 = m_engine.m_scanlines_aa.min_y();
550  prepared->bounds.x2 = m_engine.m_scanlines_aa.max_x() + 1;
551  prepared->bounds.y2 = m_engine.m_scanlines_aa.max_y() + 1;
552  }
553  else
554  {
555  prepared->bounds.x1 = 0;
556  prepared->bounds.y1 = 0;
557  prepared->bounds.x2 = prepared->advance_x;
558  prepared->bounds.y2 = 0;
559  }
560  success=true;
561  }
562  break;
563 
564 
565  case glyph_ren_outline:
566  if(error == 0)
567  {
568  if(m_engine.m_flag32)
569  {
570  m_engine.m_path32.remove_all();
571  if(decompose_ft_outline(m_ft_face->glyph->outline,
572  m_flip_y,
573  m_affine,
574  m_engine.m_path32))
575  {
576  rect_d bnd = m_engine.m_path32.bounding_rect();
577  prepared->data_size = m_engine.m_path32.byte_size();
578  prepared->data_type = glyph_data_outline;
579  prepared->bounds.x1 = int(floor(bnd.x1));
580  prepared->bounds.y1 = int(floor(bnd.y1));
581  prepared->bounds.x2 = int(ceil(bnd.x2));
582  prepared->bounds.y2 = int(ceil(bnd.y2));
583  prepared->advance_x = int26p6_to_dbl(m_ft_face->glyph->advance.x);
584  prepared->advance_y = int26p6_to_dbl(m_ft_face->glyph->advance.y);
585  m_affine.transform(&prepared->advance_x, &prepared->advance_y);
586  success=true;
587  }
588  }
589  else
590  {
591  m_engine.m_path16.remove_all();
592  if(decompose_ft_outline(m_ft_face->glyph->outline,
593  m_flip_y,
594  m_affine,
595  m_engine.m_path16))
596  {
597  rect_d bnd = m_engine.m_path16.bounding_rect();
598  prepared->data_size = m_engine.m_path16.byte_size();
599  prepared->data_type = glyph_data_outline;
600  prepared->bounds.x1 = int(floor(bnd.x1));
601  prepared->bounds.y1 = int(floor(bnd.y1));
602  prepared->bounds.x2 = int(ceil(bnd.x2));
603  prepared->bounds.y2 = int(ceil(bnd.y2));
604  prepared->advance_x = int26p6_to_dbl(m_ft_face->glyph->advance.x);
605  prepared->advance_y = int26p6_to_dbl(m_ft_face->glyph->advance.y);
606  m_affine.transform(&prepared->advance_x, &prepared->advance_y);
607  success=true;
608  }
609  }
610  }
611  break;
612 
613  case glyph_ren_agg_mono:
614  if(error == 0)
615  {
616  m_engine.m_rasterizer.reset();
617  if(m_engine.m_flag32)
618  {
619  m_engine.m_path32.remove_all();
620  decompose_ft_outline(m_ft_face->glyph->outline,
621  m_flip_y,
622  m_affine,
623  m_engine.m_path32);
624  m_engine.m_rasterizer.add_path(m_engine.m_curves32);
625  }
626  else
627  {
628  m_engine.m_path16.remove_all();
629  decompose_ft_outline(m_ft_face->glyph->outline,
630  m_flip_y,
631  m_affine,
632  m_engine.m_path16);
633  m_engine.m_rasterizer.add_path(m_engine.m_curves16);
634  }
635  m_engine.m_scanlines_bin.prepare(); // Remove all
636  render_scanlines(m_engine.m_rasterizer, m_engine.m_scanline_bin, m_engine.m_scanlines_bin);
637  prepared->bounds.x1 = m_engine.m_scanlines_bin.min_x();
638  prepared->bounds.y1 = m_engine.m_scanlines_bin.min_y();
639  prepared->bounds.x2 = m_engine.m_scanlines_bin.max_x() + 1;
640  prepared->bounds.y2 = m_engine.m_scanlines_bin.max_y() + 1;
641  prepared->data_size = m_engine.m_scanlines_bin.byte_size();
642  prepared->data_type = glyph_data_mono;
643  prepared->advance_x = int26p6_to_dbl(m_ft_face->glyph->advance.x);
644  prepared->advance_y = int26p6_to_dbl(m_ft_face->glyph->advance.y);
645  m_affine.transform(&prepared->advance_x, &prepared->advance_y);
646  success=true;
647  }
648  break;
649 
650 
651  case glyph_ren_agg_gray8:
652  if(error == 0)
653  {
654  m_engine.m_rasterizer.reset();
655  if(m_engine.m_flag32)
656  {
657  m_engine.m_path32.remove_all();
658  decompose_ft_outline(m_ft_face->glyph->outline,
659  m_flip_y,
660  m_affine,
661  m_engine.m_path32);
662  m_engine.m_rasterizer.add_path(m_engine.m_curves32);
663  }
664  else
665  {
666  m_engine.m_path16.remove_all();
667  decompose_ft_outline(m_ft_face->glyph->outline,
668  m_flip_y,
669  m_affine,
670  m_engine.m_path16);
671  m_engine.m_rasterizer.add_path(m_engine.m_curves16);
672  }
673  m_engine.m_scanlines_aa.prepare(); // Remove all
674  render_scanlines(m_engine.m_rasterizer, m_engine.m_scanline_aa, m_engine.m_scanlines_aa);
675  prepared->bounds.x1 = m_engine.m_scanlines_aa.min_x();
676  prepared->bounds.y1 = m_engine.m_scanlines_aa.min_y();
677  prepared->bounds.x2 = m_engine.m_scanlines_aa.max_x() + 1;
678  prepared->bounds.y2 = m_engine.m_scanlines_aa.max_y() + 1;
679  prepared->data_size = m_engine.m_scanlines_aa.byte_size();
680  prepared->data_type = glyph_data_gray8;
681  prepared->advance_x = int26p6_to_dbl(m_ft_face->glyph->advance.x);
682  prepared->advance_y = int26p6_to_dbl(m_ft_face->glyph->advance.y);
683  m_affine.transform(&prepared->advance_x, &prepared->advance_y);
684  success=true;
685  }
686  break;
687  }
688  }
689  return success;
690  }
691 
692  //------------------------------------------------------------------------
693  void font_engine_freetype_base::loaded_face::write_glyph_to(prepared_glyph *prepared, int8u* data) const
694  {
695  if(data && prepared->data_size)
696  {
697  switch(prepared->data_type)
698  {
699  default: return;
700  case glyph_data_mono: m_engine.m_scanlines_bin.serialize(data); break;
701  case glyph_data_gray8: m_engine.m_scanlines_aa.serialize(data); break;
702  case glyph_data_outline:
703  if(m_engine.m_flag32)
704  {
705  m_engine.m_path32.serialize(data);
706  }
707  else
708  {
709  m_engine.m_path16.serialize(data);
710  }
711  break;
712  case glyph_data_invalid: break;
713  }
714  }
715  }
716 
717  //------------------------------------------------------------------------
718  bool font_engine_freetype_base::loaded_face::add_kerning(
719  unsigned first, unsigned second, double* x, double* y)
720  {
721  bool success=false;
722  if(first && second && FT_HAS_KERNING(m_ft_face))
723  {
724  FT_Vector delta;
725  int error= FT_Get_Kerning(m_ft_face, first, second,
726  FT_KERNING_DEFAULT, &delta);
727  if( error==0 )
728  {
729  double dx = int26p6_to_dbl(delta.x);
730  double dy = int26p6_to_dbl(delta.y);
731  if( m_rendering == glyph_ren_outline ||
732  m_rendering == glyph_ren_agg_mono ||
733  m_rendering == glyph_ren_agg_gray8)
734  {
735  m_affine.transform_2x2(&dx, &dy);
736  }
737  *x += dx;
738  *y += dy;
739  }
740  success=true;
741  }
742  return success;
743  }
744 
745 #ifdef _MSC_VER
746 #define strcasecmp stricmp
747 #endif
748 
749  //------------------------------------------------------------------------
750  void font_engine_freetype_base::loaded_face::set_face_name()
751  {
752  if( !strcasecmp(m_ft_face->style_name,"Regular") )
753  {
754  std::size_t len=std::strlen(m_ft_face->family_name)+1;
755  m_face_name=new char[len];
756  std::strcpy(m_face_name, m_ft_face->family_name);
757  }
758  else
759  {
760  std::size_t len=std::strlen(m_ft_face->family_name)+1+std::strlen(m_ft_face->style_name)+1;
761  m_face_name=new char[len];
762  std::sprintf( m_face_name, "%s %s", m_ft_face->family_name, m_ft_face->style_name );
763  }
764  }
765 
766 #ifdef _MSC_VER
767 #undef strcasecmp
768 #endif
769 
770 
771 
772 
773 
774 
775 
776  //------------------------------------------------------------------------
777  font_engine_freetype_base::~font_engine_freetype_base()
778  {
779  if(m_library_initialized) FT_Done_FreeType(m_library);
780  }
781 
782  //------------------------------------------------------------------------
783 
784  static FT_Error ft_init_freeType( FT_Library *alibrary, FT_Memory memory )
785  {
786  FT_Error error;
787 
788  error = FT_New_Library( memory, alibrary );
789  if ( error )
790  { }// FT_Done_Memory( memory );
791  else
792  FT_Add_Default_Modules( *alibrary );
793 
794  return error;
795  }
796 
797  font_engine_freetype_base::font_engine_freetype_base( bool flag32, void *ftMemory)
798  :m_flag32(flag32)
799  ,m_last_error(0)
800  ,m_library_initialized(false)
801  ,m_path16()
802  ,m_path32()
803  ,m_curves16(m_path16)
804  ,m_curves32(m_path32)
805  ,m_scanline_aa()
806  ,m_scanline_bin()
807  ,m_scanlines_aa()
808  ,m_scanlines_bin()
809  ,m_rasterizer()
810  {
811  m_curves16.approximation_scale(4.0);
812  m_curves32.approximation_scale(4.0);
813  m_last_error = ft_init_freeType(&m_library,FT_Memory(ftMemory));
814  if(m_last_error == 0) m_library_initialized = true;
815  }
816 
817  //------------------------------------------------------------------------
818  font_engine_freetype_base::loaded_face *font_engine_freetype_base::load_face(
819  const void* buffer, std::size_t bytes)
820  {
821  loaded_face *face=0;
822  if(m_library_initialized)
823  {
824  FT_Face ft_face;
825  int error = FT_New_Memory_Face(
826  m_library,
827  (const FT_Byte*)buffer,
828  bytes,
829  0,
830  &ft_face );
831  if( error==0 )
832  {
833  face=create_loaded_face(ft_face);
834  }
835  }
836  return face;
837  }
838  //------------------------------------------------------------------------
839  font_engine_freetype_base::loaded_face *font_engine_freetype_base::load_face_file(
840  const char* file_name )
841  {
842  loaded_face *face=0;
843  if(m_library_initialized)
844  {
845  FT_Face ft_face;
846  int error = FT_New_Face(
847  m_library,
848  file_name,
849  0,
850  &ft_face );
851  if( error==0 )
852  {
853  face=create_loaded_face(ft_face);
854  }
855  }
856  return face;
857  }
858 
859  //------------------------------------------------------------------------
860  font_engine_freetype_base::loaded_face *font_engine_freetype_base::create_loaded_face(FT_Face ft_face)
861  {
862  loaded_face *face=new loaded_face( *this, ft_face );
863 
864  return face;
865  }
866 
867  //------------------------------------------------------------------------
868  /*
869  bool font_engine_freetype_base::attach(const char* file_name)
870  {
871  if(m_cur_face)
872  {
873  m_last_error = FT_Attach_File(m_cur_face, file_name);
874  return m_last_error == 0;
875  }
876  return false;
877  }
878  */
879 }
880 }
881 
882 
Definition: agg_arc.cpp:24