18 #include <freetype/ftmodapi.h> 19 #include "agg_font_freetype2.h" 20 #include "agg_bitset_iterator.h" 21 #include "agg_renderer_scanline.h" 40 static const unsigned crc32tab[256] =
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,
111 static unsigned calc_crc32(
const unsigned char* buf,
unsigned size)
113 unsigned crc = (unsigned)~0;
114 const unsigned char* p;
118 for (len += nr, p = buf; nr--; ++p)
120 crc = (crc >> 8) ^ crc32tab[(crc ^ *p) & 0xff];
126 static inline int dbl_to_plain_fx(
double d)
128 return int(d * 65536.0);
132 static inline double int26p6_to_dbl(
int p)
134 return double(p) / 64.0;
138 static inline int dbl_to_int26p6(
double p)
140 return int(p * 64.0 + 0.5);
145 template<
class PathStorage>
146 bool decompose_ft_outline(
const FT_Outline& outline,
148 const trans_affine& mtx,
151 typedef typename PathStorage::value_type value_type;
156 double x1, y1, x2, y2, x3, y3;
168 for(n = 0; n < outline.n_contours; n++)
172 last = outline.contours[n];
173 limit = outline.points + last;
175 v_start = outline.points[first];
176 v_last = outline.points[last];
180 point = outline.points + first;
181 tags = outline.tags + first;
182 tag = FT_CURVE_TAG(tags[0]);
185 if(tag == FT_CURVE_TAG_CUBIC)
return false;
188 if( tag == FT_CURVE_TAG_CONIC)
191 if(FT_CURVE_TAG(outline.tags[last]) == FT_CURVE_TAG_ON)
202 v_start.x = (v_start.x + v_last.x) / 2;
203 v_start.y = (v_start.y + v_last.y) / 2;
211 x1 = int26p6_to_dbl(v_start.x);
212 y1 = int26p6_to_dbl(v_start.y);
214 mtx.transform(&x1, &y1);
215 path.move_to(value_type(dbl_to_int26p6(x1)),
216 value_type(dbl_to_int26p6(y1)));
223 tag = FT_CURVE_TAG(tags[0]);
226 case FT_CURVE_TAG_ON:
228 x1 = int26p6_to_dbl(point->x);
229 y1 = int26p6_to_dbl(point->y);
231 mtx.transform(&x1, &y1);
232 path.line_to(value_type(dbl_to_int26p6(x1)),
233 value_type(dbl_to_int26p6(y1)));
238 case FT_CURVE_TAG_CONIC:
240 v_control.x = point->x;
241 v_control.y = point->y;
251 tag = FT_CURVE_TAG(tags[0]);
256 if(tag == FT_CURVE_TAG_ON)
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)));
272 if(tag != FT_CURVE_TAG_CONIC)
return false;
274 v_middle.x = (v_control.x + vec.x) / 2;
275 v_middle.y = (v_control.y + vec.y) / 2;
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)));
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)));
319 FT_Vector vec1, vec2;
321 if(point + 1 > limit || FT_CURVE_TAG(tags[1]) != FT_CURVE_TAG_CUBIC)
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)));
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)));
395 path.close_polygon();
407 template<
class Scanline,
class ScanlineStorage>
408 void decompose_ft_bitmap_mono(
const FT_Bitmap& bitmap,
412 ScanlineStorage& storage)
415 const int8u* buf = (
const int8u*)bitmap.buffer;
416 int pitch = bitmap.pitch;
417 sl.reset(x, x + bitmap.width);
421 buf += bitmap.pitch * (bitmap.rows - 1);
425 for(i = 0; i < bitmap.rows; i++)
428 bitset_iterator bits(buf, 0);
430 for(j = 0; j < bitmap.width; j++)
432 if(bits.bit()) sl.add_cell(x + j, cover_full);
438 sl.finalize(y - i - 1);
447 template<
class Rasterizer,
class Scanline,
class ScanlineStorage>
448 void decompose_ft_bitmap_gray8(
const FT_Bitmap& bitmap,
453 ScanlineStorage& storage)
456 const int8u* buf = (
const int8u*)bitmap.buffer;
457 int pitch = bitmap.pitch;
458 sl.reset(x, x + bitmap.width);
462 buf += bitmap.pitch * (bitmap.rows - 1);
466 for(i = 0; i < bitmap.rows; i++)
469 const int8u* p = buf;
470 for(j = 0; j < bitmap.width; j++)
472 if(*p) sl.add_cell(x + j, ras.apply_gamma(*p));
478 sl.finalize(y - i - 1);
492 bool font_engine_freetype_base::loaded_face::prepare_glyph(
unsigned glyph_code, prepared_glyph *prepared)
const 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);
502 prepared->glyph_code=glyph_code;
505 case glyph_ren_native_mono:
506 error = FT_Render_Glyph(m_ft_face->glyph, FT_RENDER_MODE_MONO);
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,
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);
529 case glyph_ren_native_gray8:
530 error = FT_Render_Glyph(m_ft_face->glyph, FT_RENDER_MODE_NORMAL);
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,
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 )
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;
555 prepared->bounds.x1 = 0;
556 prepared->bounds.y1 = 0;
557 prepared->bounds.x2 = prepared->advance_x;
558 prepared->bounds.y2 = 0;
565 case glyph_ren_outline:
568 if(m_engine.m_flag32)
570 m_engine.m_path32.remove_all();
571 if(decompose_ft_outline(m_ft_face->glyph->outline,
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);
591 m_engine.m_path16.remove_all();
592 if(decompose_ft_outline(m_ft_face->glyph->outline,
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);
613 case glyph_ren_agg_mono:
616 m_engine.m_rasterizer.reset();
617 if(m_engine.m_flag32)
619 m_engine.m_path32.remove_all();
620 decompose_ft_outline(m_ft_face->glyph->outline,
624 m_engine.m_rasterizer.add_path(m_engine.m_curves32);
628 m_engine.m_path16.remove_all();
629 decompose_ft_outline(m_ft_face->glyph->outline,
633 m_engine.m_rasterizer.add_path(m_engine.m_curves16);
635 m_engine.m_scanlines_bin.prepare();
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);
651 case glyph_ren_agg_gray8:
654 m_engine.m_rasterizer.reset();
655 if(m_engine.m_flag32)
657 m_engine.m_path32.remove_all();
658 decompose_ft_outline(m_ft_face->glyph->outline,
662 m_engine.m_rasterizer.add_path(m_engine.m_curves32);
666 m_engine.m_path16.remove_all();
667 decompose_ft_outline(m_ft_face->glyph->outline,
671 m_engine.m_rasterizer.add_path(m_engine.m_curves16);
673 m_engine.m_scanlines_aa.prepare();
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);
693 void font_engine_freetype_base::loaded_face::write_glyph_to(prepared_glyph *prepared, int8u* data)
const 695 if(data && prepared->data_size)
697 switch(prepared->data_type)
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)
705 m_engine.m_path32.serialize(data);
709 m_engine.m_path16.serialize(data);
712 case glyph_data_invalid:
break;
718 bool font_engine_freetype_base::loaded_face::add_kerning(
719 unsigned first,
unsigned second,
double* x,
double* y)
722 if(first && second && FT_HAS_KERNING(m_ft_face))
725 int error= FT_Get_Kerning(m_ft_face, first, second,
726 FT_KERNING_DEFAULT, &delta);
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)
735 m_affine.transform_2x2(&dx, &dy);
746 #define strcasecmp stricmp 750 void font_engine_freetype_base::loaded_face::set_face_name()
752 if( !strcasecmp(m_ft_face->style_name,
"Regular") )
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);
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 );
777 font_engine_freetype_base::~font_engine_freetype_base()
779 if(m_library_initialized) FT_Done_FreeType(m_library);
784 static FT_Error ft_init_freeType( FT_Library *alibrary, FT_Memory memory )
788 error = FT_New_Library( memory, alibrary );
792 FT_Add_Default_Modules( *alibrary );
797 font_engine_freetype_base::font_engine_freetype_base(
bool flag32,
void *ftMemory)
800 ,m_library_initialized(false)
803 ,m_curves16(m_path16)
804 ,m_curves32(m_path32)
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;
818 font_engine_freetype_base::loaded_face *font_engine_freetype_base::load_face(
819 const void* buffer, std::size_t bytes)
822 if(m_library_initialized)
825 int error = FT_New_Memory_Face(
827 (
const FT_Byte*)buffer,
833 face=create_loaded_face(ft_face);
839 font_engine_freetype_base::loaded_face *font_engine_freetype_base::load_face_file(
840 const char* file_name )
843 if(m_library_initialized)
846 int error = FT_New_Face(
853 face=create_loaded_face(ft_face);
860 font_engine_freetype_base::loaded_face *font_engine_freetype_base::create_loaded_face(FT_Face ft_face)
862 loaded_face *face=
new loaded_face( *
this, ft_face );