- Merge from trunk up to r45543
[reactos.git] / lib / 3rdparty / freetype / src / cff / cffobjs.c
1 /***************************************************************************/
2 /* */
3 /* cffobjs.c */
4 /* */
5 /* OpenType objects manager (body). */
6 /* */
7 /* Copyright 1996-2001, 2002, 2003, 2004, 2005, 2006, 2007 by */
8 /* David Turner, Robert Wilhelm, and Werner Lemberg. */
9 /* */
10 /* This file is part of the FreeType project, and may only be used, */
11 /* modified, and distributed under the terms of the FreeType project */
12 /* license, LICENSE.TXT. By continuing to use, modify, or distribute */
13 /* this file you indicate that you have read the license and */
14 /* understand and accept it fully. */
15 /* */
16 /***************************************************************************/
17
18
19 #include <ft2build.h>
20 #include FT_INTERNAL_DEBUG_H
21 #include FT_INTERNAL_CALC_H
22 #include FT_INTERNAL_STREAM_H
23 #include FT_ERRORS_H
24 #include FT_TRUETYPE_IDS_H
25 #include FT_TRUETYPE_TAGS_H
26 #include FT_INTERNAL_SFNT_H
27 #include FT_SERVICE_POSTSCRIPT_CMAPS_H
28 #include FT_INTERNAL_POSTSCRIPT_HINTS_H
29 #include "cffobjs.h"
30 #include "cffload.h"
31 #include "cffcmap.h"
32 #include "cfferrs.h"
33
34
35 /*************************************************************************/
36 /* */
37 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
38 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
39 /* messages during execution. */
40 /* */
41 #undef FT_COMPONENT
42 #define FT_COMPONENT trace_cffobjs
43
44
45 /*************************************************************************/
46 /* */
47 /* SIZE FUNCTIONS */
48 /* */
49 /* Note that we store the global hints in the size's `internal' root */
50 /* field. */
51 /* */
52 /*************************************************************************/
53
54
55 static PSH_Globals_Funcs
56 cff_size_get_globals_funcs( CFF_Size size )
57 {
58 CFF_Face face = (CFF_Face)size->root.face;
59 CFF_Font font = (CFF_FontRec *)face->extra.data;
60 PSHinter_Service pshinter = (PSHinter_Service)font->pshinter;
61 FT_Module module;
62
63
64 module = FT_Get_Module( size->root.face->driver->root.library,
65 "pshinter" );
66 return ( module && pshinter && pshinter->get_globals_funcs )
67 ? pshinter->get_globals_funcs( module )
68 : 0;
69 }
70
71
72 FT_LOCAL_DEF( void )
73 cff_size_done( FT_Size cffsize ) /* CFF_Size */
74 {
75 CFF_Size size = (CFF_Size)cffsize;
76
77
78 if ( cffsize->internal )
79 {
80 PSH_Globals_Funcs funcs;
81
82
83 funcs = cff_size_get_globals_funcs( size );
84 if ( funcs )
85 funcs->destroy( (PSH_Globals)cffsize->internal );
86
87 cffsize->internal = 0;
88 }
89 }
90
91
92 FT_LOCAL_DEF( FT_Error )
93 cff_size_init( FT_Size cffsize ) /* CFF_Size */
94 {
95 CFF_Size size = (CFF_Size)cffsize;
96 FT_Error error = CFF_Err_Ok;
97 PSH_Globals_Funcs funcs = cff_size_get_globals_funcs( size );
98
99
100 if ( funcs )
101 {
102 PSH_Globals globals;
103 CFF_Face face = (CFF_Face)cffsize->face;
104 CFF_Font font = (CFF_FontRec *)face->extra.data;
105 CFF_SubFont subfont = &font->top_font;
106
107 CFF_Private cpriv = &subfont->private_dict;
108 PS_PrivateRec priv;
109
110
111 /* IMPORTANT: The CFF and Type1 private dictionaries have */
112 /* slightly different structures; we need to */
113 /* synthetize a type1 dictionary on the fly here. */
114
115 {
116 FT_UInt n, count;
117
118
119 FT_MEM_ZERO( &priv, sizeof ( priv ) );
120
121 count = priv.num_blue_values = cpriv->num_blue_values;
122 for ( n = 0; n < count; n++ )
123 priv.blue_values[n] = (FT_Short)cpriv->blue_values[n];
124
125 count = priv.num_other_blues = cpriv->num_other_blues;
126 for ( n = 0; n < count; n++ )
127 priv.other_blues[n] = (FT_Short)cpriv->other_blues[n];
128
129 count = priv.num_family_blues = cpriv->num_family_blues;
130 for ( n = 0; n < count; n++ )
131 priv.family_blues[n] = (FT_Short)cpriv->family_blues[n];
132
133 count = priv.num_family_other_blues = cpriv->num_family_other_blues;
134 for ( n = 0; n < count; n++ )
135 priv.family_other_blues[n] = (FT_Short)cpriv->family_other_blues[n];
136
137 priv.blue_scale = cpriv->blue_scale;
138 priv.blue_shift = (FT_Int)cpriv->blue_shift;
139 priv.blue_fuzz = (FT_Int)cpriv->blue_fuzz;
140
141 priv.standard_width[0] = (FT_UShort)cpriv->standard_width;
142 priv.standard_height[0] = (FT_UShort)cpriv->standard_height;
143
144 count = priv.num_snap_widths = cpriv->num_snap_widths;
145 for ( n = 0; n < count; n++ )
146 priv.snap_widths[n] = (FT_Short)cpriv->snap_widths[n];
147
148 count = priv.num_snap_heights = cpriv->num_snap_heights;
149 for ( n = 0; n < count; n++ )
150 priv.snap_heights[n] = (FT_Short)cpriv->snap_heights[n];
151
152 priv.force_bold = cpriv->force_bold;
153 priv.language_group = cpriv->language_group;
154 priv.lenIV = cpriv->lenIV;
155 }
156
157 error = funcs->create( cffsize->face->memory, &priv, &globals );
158 if ( !error )
159 cffsize->internal = (FT_Size_Internal)(void*)globals;
160 }
161
162 size->strike_index = 0xFFFFFFFFUL;
163
164 return error;
165 }
166
167
168 #ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS
169
170 FT_LOCAL_DEF( FT_Error )
171 cff_size_select( FT_Size size,
172 FT_ULong strike_index )
173 {
174 CFF_Size cffsize = (CFF_Size)size;
175 PSH_Globals_Funcs funcs;
176
177
178 cffsize->strike_index = strike_index;
179
180 FT_Select_Metrics( size->face, strike_index );
181
182 funcs = cff_size_get_globals_funcs( cffsize );
183
184 if ( funcs )
185 funcs->set_scale( (PSH_Globals)size->internal,
186 size->metrics.x_scale,
187 size->metrics.y_scale,
188 0, 0 );
189
190 return CFF_Err_Ok;
191 }
192
193 #endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */
194
195
196 FT_LOCAL_DEF( FT_Error )
197 cff_size_request( FT_Size size,
198 FT_Size_Request req )
199 {
200 CFF_Size cffsize = (CFF_Size)size;
201 PSH_Globals_Funcs funcs;
202
203
204 #ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS
205
206 if ( FT_HAS_FIXED_SIZES( size->face ) )
207 {
208 CFF_Face cffface = (CFF_Face)size->face;
209 SFNT_Service sfnt = (SFNT_Service)cffface->sfnt;
210 FT_ULong strike_index;
211
212
213 if ( sfnt->set_sbit_strike( cffface, req, &strike_index ) )
214 cffsize->strike_index = 0xFFFFFFFFUL;
215 else
216 return cff_size_select( size, strike_index );
217 }
218
219 #endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */
220
221 FT_Request_Metrics( size->face, req );
222
223 funcs = cff_size_get_globals_funcs( cffsize );
224
225 if ( funcs )
226 funcs->set_scale( (PSH_Globals)size->internal,
227 size->metrics.x_scale,
228 size->metrics.y_scale,
229 0, 0 );
230
231 return CFF_Err_Ok;
232 }
233
234
235 /*************************************************************************/
236 /* */
237 /* SLOT FUNCTIONS */
238 /* */
239 /*************************************************************************/
240
241 FT_LOCAL_DEF( void )
242 cff_slot_done( FT_GlyphSlot slot )
243 {
244 slot->internal->glyph_hints = 0;
245 }
246
247
248 FT_LOCAL_DEF( FT_Error )
249 cff_slot_init( FT_GlyphSlot slot )
250 {
251 CFF_Face face = (CFF_Face)slot->face;
252 CFF_Font font = (CFF_FontRec *)face->extra.data;
253 PSHinter_Service pshinter = (PSHinter_Service)font->pshinter;
254
255
256 if ( pshinter )
257 {
258 FT_Module module;
259
260
261 module = FT_Get_Module( slot->face->driver->root.library,
262 "pshinter" );
263 if ( module )
264 {
265 T2_Hints_Funcs funcs;
266
267
268 funcs = pshinter->get_t2_funcs( module );
269 slot->internal->glyph_hints = (void*)funcs;
270 }
271 }
272
273 return 0;
274 }
275
276
277 /*************************************************************************/
278 /* */
279 /* FACE FUNCTIONS */
280 /* */
281 /*************************************************************************/
282
283 static FT_String*
284 cff_strcpy( FT_Memory memory,
285 const FT_String* source )
286 {
287 FT_Error error;
288 FT_String* result;
289
290
291 result = ft_mem_strdup( memory, source, &error );
292
293 return result;
294 }
295
296
297 FT_LOCAL_DEF( FT_Error )
298 cff_face_init( FT_Stream stream,
299 FT_Face cffface, /* CFF_Face */
300 FT_Int face_index,
301 FT_Int num_params,
302 FT_Parameter* params )
303 {
304 CFF_Face face = (CFF_Face)cffface;
305 FT_Error error;
306 SFNT_Service sfnt;
307 FT_Service_PsCMaps psnames;
308 PSHinter_Service pshinter;
309 FT_Bool pure_cff = 1;
310 FT_Bool sfnt_format = 0;
311
312
313 #if 0
314 FT_FACE_FIND_GLOBAL_SERVICE( face, sfnt, SFNT );
315 FT_FACE_FIND_GLOBAL_SERVICE( face, psnames, POSTSCRIPT_NAMES );
316 FT_FACE_FIND_GLOBAL_SERVICE( face, pshinter, POSTSCRIPT_HINTER );
317
318 if ( !sfnt )
319 goto Bad_Format;
320 #else
321 sfnt = (SFNT_Service)FT_Get_Module_Interface(
322 cffface->driver->root.library, "sfnt" );
323 if ( !sfnt )
324 goto Bad_Format;
325
326 FT_FACE_FIND_GLOBAL_SERVICE( face, psnames, POSTSCRIPT_CMAPS );
327
328 pshinter = (PSHinter_Service)FT_Get_Module_Interface(
329 cffface->driver->root.library, "pshinter" );
330 #endif
331
332 /* create input stream from resource */
333 if ( FT_STREAM_SEEK( 0 ) )
334 goto Exit;
335
336 /* check whether we have a valid OpenType file */
337 error = sfnt->init_face( stream, face, face_index, num_params, params );
338 if ( !error )
339 {
340 if ( face->format_tag != 0x4F54544FL ) /* `OTTO'; OpenType/CFF font */
341 {
342 FT_TRACE2(( "[not a valid OpenType/CFF font]\n" ));
343 goto Bad_Format;
344 }
345
346 /* if we are performing a simple font format check, exit immediately */
347 if ( face_index < 0 )
348 return CFF_Err_Ok;
349
350 /* UNDOCUMENTED! A CFF in an SFNT can have only a single font. */
351 if ( face_index > 0 )
352 {
353 FT_ERROR(( "cff_face_init: invalid face index\n" ));
354 error = CFF_Err_Invalid_Argument;
355 goto Exit;
356 }
357
358 sfnt_format = 1;
359
360 /* now, the font can be either an OpenType/CFF font, or an SVG CEF */
361 /* font; in the latter case it doesn't have a `head' table */
362 error = face->goto_table( face, TTAG_head, stream, 0 );
363 if ( !error )
364 {
365 pure_cff = 0;
366
367 /* load font directory */
368 error = sfnt->load_face( stream, face,
369 face_index, num_params, params );
370 if ( error )
371 goto Exit;
372 }
373 else
374 {
375 /* load the `cmap' table explicitly */
376 error = sfnt->load_cmap( face, stream );
377 if ( error )
378 goto Exit;
379
380 /* XXX: we don't load the GPOS table, as OpenType Layout */
381 /* support will be added later to a layout library on top of */
382 /* FreeType 2 */
383 }
384
385 /* now load the CFF part of the file */
386 error = face->goto_table( face, TTAG_CFF, stream, 0 );
387 if ( error )
388 goto Exit;
389 }
390 else
391 {
392 /* rewind to start of file; we are going to load a pure-CFF font */
393 if ( FT_STREAM_SEEK( 0 ) )
394 goto Exit;
395 error = CFF_Err_Ok;
396 }
397
398 /* now load and parse the CFF table in the file */
399 {
400 CFF_Font cff;
401 CFF_FontRecDict dict;
402 FT_Memory memory = cffface->memory;
403 FT_Int32 flags;
404 FT_UInt i;
405
406
407 if ( FT_NEW( cff ) )
408 goto Exit;
409
410 face->extra.data = cff;
411 error = cff_font_load( stream, face_index, cff );
412 if ( error )
413 goto Exit;
414
415 cff->pshinter = pshinter;
416 cff->psnames = (void*)psnames;
417
418 /* Complement the root flags with some interesting information. */
419 /* Note that this is only necessary for pure CFF and CEF fonts; */
420 /* SFNT based fonts use the `name' table instead. */
421
422 cffface->num_glyphs = cff->num_glyphs;
423
424 dict = &cff->top_font.font_dict;
425
426 /* we need the `PSNames' module for CFF and CEF formats */
427 /* which aren't CID-keyed */
428 if ( dict->cid_registry == 0xFFFFU && !psnames )
429 {
430 FT_ERROR(( "cff_face_init:" ));
431 FT_ERROR(( " cannot open CFF & CEF fonts\n" ));
432 FT_ERROR(( " " ));
433 FT_ERROR(( " without the `PSNames' module\n" ));
434 goto Bad_Format;
435 }
436
437 if ( pure_cff )
438 {
439 char* style_name = NULL;
440
441
442 /* set up num_faces */
443 cffface->num_faces = cff->num_faces;
444
445 /* compute number of glyphs */
446 if ( dict->cid_registry != 0xFFFFU )
447 cffface->num_glyphs = dict->cid_count;
448 else
449 cffface->num_glyphs = cff->charstrings_index.count;
450
451 /* set global bbox, as well as EM size */
452 cffface->bbox.xMin = dict->font_bbox.xMin >> 16;
453 cffface->bbox.yMin = dict->font_bbox.yMin >> 16;
454 cffface->bbox.xMax = ( dict->font_bbox.xMax + 0xFFFFU ) >> 16;
455 cffface->bbox.yMax = ( dict->font_bbox.yMax + 0xFFFFU ) >> 16;
456
457 if ( !dict->units_per_em )
458 dict->units_per_em = 1000;
459
460 cffface->units_per_EM = dict->units_per_em;
461
462 cffface->ascender = (FT_Short)( cffface->bbox.yMax );
463 cffface->descender = (FT_Short)( cffface->bbox.yMin );
464
465 cffface->height = (FT_Short)( ( cffface->units_per_EM * 12 ) / 10 );
466 if ( cffface->height < cffface->ascender - cffface->descender )
467 cffface->height = (FT_Short)( cffface->ascender - cffface->descender );
468
469 cffface->underline_position =
470 (FT_Short)( dict->underline_position >> 16 );
471 cffface->underline_thickness =
472 (FT_Short)( dict->underline_thickness >> 16 );
473
474 /* retrieve font family & style name */
475 cffface->family_name = cff_index_get_name( &cff->name_index,
476 face_index );
477
478 if ( cffface->family_name )
479 {
480 char* full = cff_index_get_sid_string( &cff->string_index,
481 dict->full_name,
482 psnames );
483 char* fullp = full;
484 char* family = cffface->family_name;
485 char* family_name = 0;
486
487
488 if ( dict->family_name )
489 {
490 family_name = cff_index_get_sid_string( &cff->string_index,
491 dict->family_name,
492 psnames);
493 if ( family_name )
494 family = family_name;
495 }
496
497 /* We try to extract the style name from the full name. */
498 /* We need to ignore spaces and dashes during the search. */
499 if ( full && family )
500 {
501 while ( *fullp )
502 {
503 /* skip common characters at the start of both strings */
504 if ( *fullp == *family )
505 {
506 family++;
507 fullp++;
508 continue;
509 }
510
511 /* ignore spaces and dashes in full name during comparison */
512 if ( *fullp == ' ' || *fullp == '-' )
513 {
514 fullp++;
515 continue;
516 }
517
518 /* ignore spaces and dashes in family name during comparison */
519 if ( *family == ' ' || *family == '-' )
520 {
521 family++;
522 continue;
523 }
524
525 if ( !*family && *fullp )
526 {
527 /* The full name begins with the same characters as the */
528 /* family name, with spaces and dashes removed. In this */
529 /* case, the remaining string in `fullp' will be used as */
530 /* the style name. */
531 style_name = cff_strcpy( memory, fullp );
532 }
533 break;
534 }
535
536 if ( family_name )
537 FT_FREE( family_name );
538 FT_FREE( full );
539 }
540 }
541 else
542 {
543 char *cid_font_name =
544 cff_index_get_sid_string( &cff->string_index,
545 dict->cid_font_name,
546 psnames );
547
548
549 /* do we have a `/FontName' for a CID-keyed font? */
550 if ( cid_font_name )
551 cffface->family_name = cid_font_name;
552 }
553
554 if ( style_name )
555 cffface->style_name = style_name;
556 else
557 /* assume "Regular" style if we don't know better */
558 cffface->style_name = cff_strcpy( memory, (char *)"Regular" );
559
560 /*******************************************************************/
561 /* */
562 /* Compute face flags. */
563 /* */
564 flags = FT_FACE_FLAG_SCALABLE | /* scalable outlines */
565 FT_FACE_FLAG_HORIZONTAL | /* horizontal data */
566 FT_FACE_FLAG_HINTER; /* has native hinter */
567
568 if ( sfnt_format )
569 flags |= FT_FACE_FLAG_SFNT;
570
571 /* fixed width font? */
572 if ( dict->is_fixed_pitch )
573 flags |= FT_FACE_FLAG_FIXED_WIDTH;
574
575 /* XXX: WE DO NOT SUPPORT KERNING METRICS IN THE GPOS TABLE FOR NOW */
576 #if 0
577 /* kerning available? */
578 if ( face->kern_pairs )
579 flags |= FT_FACE_FLAG_KERNING;
580 #endif
581
582 cffface->face_flags = flags;
583
584 /*******************************************************************/
585 /* */
586 /* Compute style flags. */
587 /* */
588 flags = 0;
589
590 if ( dict->italic_angle )
591 flags |= FT_STYLE_FLAG_ITALIC;
592
593 {
594 char *weight = cff_index_get_sid_string( &cff->string_index,
595 dict->weight,
596 psnames );
597
598
599 if ( weight )
600 if ( !ft_strcmp( weight, "Bold" ) ||
601 !ft_strcmp( weight, "Black" ) )
602 flags |= FT_STYLE_FLAG_BOLD;
603 FT_FREE( weight );
604 }
605
606 /* double check */
607 if ( !(flags & FT_STYLE_FLAG_BOLD) && cffface->style_name )
608 if ( !ft_strncmp( cffface->style_name, "Bold", 4 ) ||
609 !ft_strncmp( cffface->style_name, "Black", 5 ) )
610 flags |= FT_STYLE_FLAG_BOLD;
611
612 cffface->style_flags = flags;
613 }
614 else
615 {
616 if ( !dict->units_per_em )
617 dict->units_per_em = face->root.units_per_EM;
618 }
619
620 /* handle font matrix settings in subfonts (if any) */
621 for ( i = cff->num_subfonts; i > 0; i-- )
622 {
623 CFF_FontRecDict sub = &cff->subfonts[i - 1]->font_dict;
624 CFF_FontRecDict top = &cff->top_font.font_dict;
625
626
627 if ( sub->units_per_em )
628 {
629 FT_Matrix scale;
630
631
632 scale.xx = scale.yy = (FT_Fixed)FT_DivFix( top->units_per_em,
633 sub->units_per_em );
634 scale.xy = scale.yx = 0;
635
636 FT_Matrix_Multiply( &scale, &sub->font_matrix );
637 FT_Vector_Transform( &sub->font_offset, &scale );
638 }
639 else
640 {
641 sub->font_matrix = top->font_matrix;
642 sub->font_offset = top->font_offset;
643 }
644 }
645
646 #ifndef FT_CONFIG_OPTION_NO_GLYPH_NAMES
647 /* CID-keyed CFF fonts don't have glyph names -- the SFNT loader */
648 /* has unset this flag because of the 3.0 `post' table */
649 if ( dict->cid_registry == 0xFFFFU )
650 cffface->face_flags |= FT_FACE_FLAG_GLYPH_NAMES;
651 #endif
652
653 /*******************************************************************/
654 /* */
655 /* Compute char maps. */
656 /* */
657
658 /* Try to synthetize a Unicode charmap if there is none available */
659 /* already. If an OpenType font contains a Unicode "cmap", we */
660 /* will use it, whatever be in the CFF part of the file. */
661 {
662 FT_CharMapRec cmaprec;
663 FT_CharMap cmap;
664 FT_UInt nn;
665 CFF_Encoding encoding = &cff->encoding;
666
667
668 for ( nn = 0; nn < (FT_UInt)cffface->num_charmaps; nn++ )
669 {
670 cmap = cffface->charmaps[nn];
671
672 /* Windows Unicode (3,1)? */
673 if ( cmap->platform_id == 3 && cmap->encoding_id == 1 )
674 goto Skip_Unicode;
675
676 /* Deprecated Unicode platform id? */
677 if ( cmap->platform_id == 0 )
678 goto Skip_Unicode; /* Standard Unicode (deprecated) */
679 }
680
681 /* since CID-keyed fonts don't contain glyph names, we can't */
682 /* construct a cmap */
683 if ( pure_cff && cff->top_font.font_dict.cid_registry != 0xFFFFU )
684 goto Exit;
685
686 /* we didn't find a Unicode charmap -- synthetize one */
687 cmaprec.face = cffface;
688 cmaprec.platform_id = 3;
689 cmaprec.encoding_id = 1;
690 cmaprec.encoding = FT_ENCODING_UNICODE;
691
692 nn = (FT_UInt)cffface->num_charmaps;
693
694 FT_CMap_New( &cff_cmap_unicode_class_rec, NULL, &cmaprec, NULL );
695
696 /* if no Unicode charmap was previously selected, select this one */
697 if ( cffface->charmap == NULL && nn != (FT_UInt)cffface->num_charmaps )
698 cffface->charmap = cffface->charmaps[nn];
699
700 Skip_Unicode:
701 if ( encoding->count > 0 )
702 {
703 FT_CMap_Class clazz;
704
705
706 cmaprec.face = cffface;
707 cmaprec.platform_id = 7; /* Adobe platform id */
708
709 if ( encoding->offset == 0 )
710 {
711 cmaprec.encoding_id = TT_ADOBE_ID_STANDARD;
712 cmaprec.encoding = FT_ENCODING_ADOBE_STANDARD;
713 clazz = &cff_cmap_encoding_class_rec;
714 }
715 else if ( encoding->offset == 1 )
716 {
717 cmaprec.encoding_id = TT_ADOBE_ID_EXPERT;
718 cmaprec.encoding = FT_ENCODING_ADOBE_EXPERT;
719 clazz = &cff_cmap_encoding_class_rec;
720 }
721 else
722 {
723 cmaprec.encoding_id = TT_ADOBE_ID_CUSTOM;
724 cmaprec.encoding = FT_ENCODING_ADOBE_CUSTOM;
725 clazz = &cff_cmap_encoding_class_rec;
726 }
727
728 FT_CMap_New( clazz, NULL, &cmaprec, NULL );
729 }
730 }
731 }
732
733 Exit:
734 return error;
735
736 Bad_Format:
737 error = CFF_Err_Unknown_File_Format;
738 goto Exit;
739 }
740
741
742 FT_LOCAL_DEF( void )
743 cff_face_done( FT_Face cffface ) /* CFF_Face */
744 {
745 CFF_Face face = (CFF_Face)cffface;
746 FT_Memory memory = cffface->memory;
747 SFNT_Service sfnt = (SFNT_Service)face->sfnt;
748
749
750 if ( sfnt )
751 sfnt->done_face( face );
752
753 {
754 CFF_Font cff = (CFF_Font)face->extra.data;
755
756
757 if ( cff )
758 {
759 cff_font_done( cff );
760 FT_FREE( face->extra.data );
761 }
762 }
763 }
764
765
766 FT_LOCAL_DEF( FT_Error )
767 cff_driver_init( FT_Module module )
768 {
769 FT_UNUSED( module );
770
771 return CFF_Err_Ok;
772 }
773
774
775 FT_LOCAL_DEF( void )
776 cff_driver_done( FT_Module module )
777 {
778 FT_UNUSED( module );
779 }
780
781
782 /* END */