• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /****************************************************************************
2  *
3  * t42objs.c
4  *
5  *   Type 42 objects manager (body).
6  *
7  * Copyright (C) 2002-2023 by
8  * Roberto Alameda.
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 "t42objs.h"
20 #include "t42parse.h"
21 #include "t42error.h"
22 #include <freetype/internal/ftdebug.h>
23 #include <freetype/ftlist.h>
24 #include <freetype/ttnameid.h>
25 
26 
27 #undef  FT_COMPONENT
28 #define FT_COMPONENT  t42
29 
30 
31   static FT_Error
T42_Open_Face(T42_Face face)32   T42_Open_Face( T42_Face  face )
33   {
34     T42_LoaderRec  loader;
35     T42_Parser     parser;
36     T1_Font        type1 = &face->type1;
37     FT_Memory      memory = face->root.memory;
38     FT_Error       error;
39 
40     PSAux_Service  psaux  = (PSAux_Service)face->psaux;
41 
42 
43     t42_loader_init( &loader, face );
44 
45     parser = &loader.parser;
46 
47     face->ttf_data = NULL;
48     face->ttf_size = 0;
49 
50     error = t42_parser_init( parser,
51                              face->root.stream,
52                              memory,
53                              psaux);
54     if ( error )
55       goto Exit;
56 
57     error = t42_parse_dict( face, &loader,
58                             parser->base_dict, parser->base_len );
59     if ( error )
60       goto Exit;
61 
62     if ( type1->font_type != 42 )
63     {
64       FT_ERROR(( "T42_Open_Face: cannot handle FontType %d\n",
65                  type1->font_type ));
66       error = FT_THROW( Unknown_File_Format );
67       goto Exit;
68     }
69 
70     /* now, propagate the charstrings and glyphnames tables */
71     /* to the Type1 data                                    */
72     type1->num_glyphs = loader.num_glyphs;
73 
74     if ( !loader.charstrings.init )
75     {
76       FT_ERROR(( "T42_Open_Face: no charstrings array in face\n" ));
77       error = FT_THROW( Invalid_File_Format );
78     }
79 
80     loader.charstrings.init  = 0;
81     type1->charstrings_block = loader.charstrings.block;
82     type1->charstrings       = loader.charstrings.elements;
83     type1->charstrings_len   = loader.charstrings.lengths;
84 
85     /* we copy the glyph names `block' and `elements' fields; */
86     /* the `lengths' field must be released later             */
87     type1->glyph_names_block    = loader.glyph_names.block;
88     type1->glyph_names          = (FT_String**)loader.glyph_names.elements;
89     loader.glyph_names.block    = NULL;
90     loader.glyph_names.elements = NULL;
91 
92     /* we must now build type1.encoding when we have a custom array */
93     if ( type1->encoding_type == T1_ENCODING_TYPE_ARRAY )
94     {
95       FT_Int  charcode, idx, min_char, max_char;
96 
97 
98       /* OK, we do the following: for each element in the encoding   */
99       /* table, look up the index of the glyph having the same name  */
100       /* as defined in the CharStrings array.                        */
101       /* The index is then stored in type1.encoding.char_index, and  */
102       /* the name in type1.encoding.char_name                        */
103 
104       min_char = 0;
105       max_char = 0;
106 
107       charcode = 0;
108       for ( ; charcode < loader.encoding_table.max_elems; charcode++ )
109       {
110         const FT_String*  char_name =
111               (const FT_String*)loader.encoding_table.elements[charcode];
112 
113 
114         type1->encoding.char_index[charcode] = 0;
115         type1->encoding.char_name [charcode] = ".notdef";
116 
117         if ( char_name )
118           for ( idx = 0; idx < type1->num_glyphs; idx++ )
119           {
120             const FT_String*  glyph_name = type1->glyph_names[idx];
121 
122 
123             if ( ft_strcmp( char_name, glyph_name ) == 0 )
124             {
125               type1->encoding.char_index[charcode] = (FT_UShort)idx;
126               type1->encoding.char_name [charcode] = glyph_name;
127 
128               /* Change min/max encoded char only if glyph name is */
129               /* not /.notdef                                      */
130               if ( ft_strcmp( ".notdef", glyph_name ) != 0 )
131               {
132                 if ( charcode < min_char )
133                   min_char = charcode;
134                 if ( charcode >= max_char )
135                   max_char = charcode + 1;
136               }
137               break;
138             }
139           }
140       }
141 
142       type1->encoding.code_first = min_char;
143       type1->encoding.code_last  = max_char;
144       type1->encoding.num_chars  = loader.num_chars;
145     }
146 
147   Exit:
148     t42_loader_done( &loader );
149     if ( error )
150     {
151       FT_FREE( face->ttf_data );
152       face->ttf_size = 0;
153     }
154     return error;
155   }
156 
157 
158   /***************** Driver Functions *************/
159 
160 
161   FT_LOCAL_DEF( FT_Error )
T42_Face_Init(FT_Stream stream,FT_Face t42face,FT_Int face_index,FT_Int num_params,FT_Parameter * params)162   T42_Face_Init( FT_Stream      stream,
163                  FT_Face        t42face,       /* T42_Face */
164                  FT_Int         face_index,
165                  FT_Int         num_params,
166                  FT_Parameter*  params )
167   {
168     T42_Face            face  = (T42_Face)t42face;
169     FT_Error            error;
170     FT_Service_PsCMaps  psnames;
171     PSAux_Service       psaux;
172     FT_Face             root  = (FT_Face)&face->root;
173     T1_Font             type1 = &face->type1;
174     PS_FontInfo         info  = &type1->font_info;
175 
176     FT_UNUSED( num_params );
177     FT_UNUSED( params );
178     FT_UNUSED( stream );
179 
180 
181     face->ttf_face       = NULL;
182     face->root.num_faces = 1;
183 
184     FT_FACE_FIND_GLOBAL_SERVICE( face, psnames, POSTSCRIPT_CMAPS );
185     face->psnames = psnames;
186 
187     face->psaux = FT_Get_Module_Interface( FT_FACE_LIBRARY( face ),
188                                            "psaux" );
189     psaux = (PSAux_Service)face->psaux;
190     if ( !psaux )
191     {
192       FT_ERROR(( "T42_Face_Init: cannot access `psaux' module\n" ));
193       error = FT_THROW( Missing_Module );
194       goto Exit;
195     }
196 
197     FT_TRACE2(( "Type 42 driver\n" ));
198 
199     /* open the tokenizer, this will also check the font format */
200     error = T42_Open_Face( face );
201     if ( error )
202       goto Exit;
203 
204     /* if we just wanted to check the format, leave successfully now */
205     if ( face_index < 0 )
206       goto Exit;
207 
208     /* check the face index */
209     if ( ( face_index & 0xFFFF ) > 0 )
210     {
211       FT_ERROR(( "T42_Face_Init: invalid face index\n" ));
212       error = FT_THROW( Invalid_Argument );
213       goto Exit;
214     }
215 
216     /* Now load the font program into the face object */
217 
218     /* Init the face object fields */
219     /* Now set up root face fields */
220 
221     root->num_glyphs   = type1->num_glyphs;
222     root->num_charmaps = 0;
223     root->face_index   = 0;
224 
225     root->face_flags |= FT_FACE_FLAG_SCALABLE    |
226                         FT_FACE_FLAG_HORIZONTAL  |
227                         FT_FACE_FLAG_GLYPH_NAMES;
228 
229     if ( info->is_fixed_pitch )
230       root->face_flags |= FT_FACE_FLAG_FIXED_WIDTH;
231 
232 #ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
233     root->face_flags |= FT_FACE_FLAG_HINTER;
234 #endif
235 
236     /* XXX: TODO -- add kerning with .afm support */
237 
238     /* get style name -- be careful, some broken fonts only */
239     /* have a `/FontName' dictionary entry!                 */
240     root->family_name = info->family_name;
241     /* assume "Regular" style if we don't know better */
242     root->style_name = (char *)"Regular";
243     if ( root->family_name )
244     {
245       char*  full   = info->full_name;
246       char*  family = root->family_name;
247 
248 
249       if ( full )
250       {
251         while ( *full )
252         {
253           if ( *full == *family )
254           {
255             family++;
256             full++;
257           }
258           else
259           {
260             if ( *full == ' ' || *full == '-' )
261               full++;
262             else if ( *family == ' ' || *family == '-' )
263               family++;
264             else
265             {
266               if ( !*family )
267                 root->style_name = full;
268               break;
269             }
270           }
271         }
272       }
273     }
274     else
275     {
276       /* do we have a `/FontName'? */
277       if ( type1->font_name )
278         root->family_name = type1->font_name;
279     }
280 
281     /* no embedded bitmap support */
282     root->num_fixed_sizes = 0;
283     root->available_sizes = NULL;
284 
285     /* Load the TTF font embedded in the T42 font */
286     {
287       FT_Open_Args  args;
288 
289 
290       args.flags       = FT_OPEN_MEMORY | FT_OPEN_DRIVER;
291       args.driver      = FT_Get_Module( FT_FACE_LIBRARY( face ),
292                                         "truetype" );
293       args.memory_base = face->ttf_data;
294       args.memory_size = face->ttf_size;
295 
296       if ( num_params )
297       {
298         args.flags     |= FT_OPEN_PARAMS;
299         args.num_params = num_params;
300         args.params     = params;
301       }
302 
303       error = FT_Open_Face( FT_FACE_LIBRARY( face ),
304                             &args, 0, &face->ttf_face );
305     }
306 
307     if ( error )
308       goto Exit;
309 
310     FT_Done_Size( face->ttf_face->size );
311 
312     /* Ignore info in FontInfo dictionary and use the info from the  */
313     /* loaded TTF font.  The PostScript interpreter also ignores it. */
314     root->bbox         = face->ttf_face->bbox;
315     root->units_per_EM = face->ttf_face->units_per_EM;
316 
317     root->ascender  = face->ttf_face->ascender;
318     root->descender = face->ttf_face->descender;
319     root->height    = face->ttf_face->height;
320 
321     root->max_advance_width  = face->ttf_face->max_advance_width;
322     root->max_advance_height = face->ttf_face->max_advance_height;
323 
324     root->underline_position  = (FT_Short)info->underline_position;
325     root->underline_thickness = (FT_Short)info->underline_thickness;
326 
327     /* compute style flags */
328     root->style_flags = 0;
329     if ( info->italic_angle )
330       root->style_flags |= FT_STYLE_FLAG_ITALIC;
331 
332     if ( face->ttf_face->style_flags & FT_STYLE_FLAG_BOLD )
333       root->style_flags |= FT_STYLE_FLAG_BOLD;
334 
335     if ( face->ttf_face->face_flags & FT_FACE_FLAG_VERTICAL )
336       root->face_flags |= FT_FACE_FLAG_VERTICAL;
337 
338     {
339       if ( psnames )
340       {
341         FT_CharMapRec    charmap;
342         T1_CMap_Classes  cmap_classes = psaux->t1_cmap_classes;
343         FT_CMap_Class    clazz;
344 
345 
346         charmap.face = root;
347 
348         /* first of all, try to synthesize a Unicode charmap */
349         charmap.platform_id = TT_PLATFORM_MICROSOFT;
350         charmap.encoding_id = TT_MS_ID_UNICODE_CS;
351         charmap.encoding    = FT_ENCODING_UNICODE;
352 
353         error = FT_CMap_New( cmap_classes->unicode, NULL, &charmap, NULL );
354         if ( error                                      &&
355              FT_ERR_NEQ( error, No_Unicode_Glyph_Name ) &&
356              FT_ERR_NEQ( error, Unimplemented_Feature ) )
357           goto Exit;
358         error = FT_Err_Ok;
359 
360         /* now, generate an Adobe Standard encoding when appropriate */
361         charmap.platform_id = TT_PLATFORM_ADOBE;
362         clazz               = NULL;
363 
364         switch ( type1->encoding_type )
365         {
366         case T1_ENCODING_TYPE_STANDARD:
367           charmap.encoding    = FT_ENCODING_ADOBE_STANDARD;
368           charmap.encoding_id = TT_ADOBE_ID_STANDARD;
369           clazz               = cmap_classes->standard;
370           break;
371 
372         case T1_ENCODING_TYPE_EXPERT:
373           charmap.encoding    = FT_ENCODING_ADOBE_EXPERT;
374           charmap.encoding_id = TT_ADOBE_ID_EXPERT;
375           clazz               = cmap_classes->expert;
376           break;
377 
378         case T1_ENCODING_TYPE_ARRAY:
379           charmap.encoding    = FT_ENCODING_ADOBE_CUSTOM;
380           charmap.encoding_id = TT_ADOBE_ID_CUSTOM;
381           clazz               = cmap_classes->custom;
382           break;
383 
384         case T1_ENCODING_TYPE_ISOLATIN1:
385           charmap.encoding    = FT_ENCODING_ADOBE_LATIN_1;
386           charmap.encoding_id = TT_ADOBE_ID_LATIN_1;
387           clazz               = cmap_classes->unicode;
388           break;
389 
390         default:
391           ;
392         }
393 
394         if ( clazz )
395           error = FT_CMap_New( clazz, NULL, &charmap, NULL );
396       }
397     }
398   Exit:
399     return error;
400   }
401 
402 
403   FT_LOCAL_DEF( void )
T42_Face_Done(FT_Face t42face)404   T42_Face_Done( FT_Face  t42face )
405   {
406     T42_Face     face = (T42_Face)t42face;
407     T1_Font      type1;
408     PS_FontInfo  info;
409     FT_Memory    memory;
410 
411 
412     if ( !face )
413       return;
414 
415     type1  = &face->type1;
416     info   = &type1->font_info;
417     memory = face->root.memory;
418 
419     /* delete internal ttf face prior to freeing face->ttf_data */
420     if ( face->ttf_face )
421       FT_Done_Face( face->ttf_face );
422 
423     /* release font info strings */
424     FT_FREE( info->version );
425     FT_FREE( info->notice );
426     FT_FREE( info->full_name );
427     FT_FREE( info->family_name );
428     FT_FREE( info->weight );
429 
430     /* release top dictionary */
431     FT_FREE( type1->charstrings_len );
432     FT_FREE( type1->charstrings );
433     FT_FREE( type1->glyph_names );
434 
435     FT_FREE( type1->charstrings_block );
436     FT_FREE( type1->glyph_names_block );
437 
438     FT_FREE( type1->encoding.char_index );
439     FT_FREE( type1->encoding.char_name );
440     FT_FREE( type1->font_name );
441 
442     FT_FREE( face->ttf_data );
443 
444 #if 0
445     /* release afm data if present */
446     if ( face->afm_data )
447       T1_Done_AFM( memory, (T1_AFM*)face->afm_data );
448 #endif
449 
450     /* release unicode map, if any */
451     FT_FREE( face->unicode_map.maps );
452     face->unicode_map.num_maps = 0;
453 
454     face->root.family_name = NULL;
455     face->root.style_name  = NULL;
456   }
457 
458 
459   /**************************************************************************
460    *
461    * @Function:
462    *   T42_Driver_Init
463    *
464    * @Description:
465    *   Initializes a given Type 42 driver object.
466    *
467    * @Input:
468    *   driver ::
469    *     A handle to the target driver object.
470    *
471    * @Return:
472    *   FreeType error code.  0 means success.
473    */
474   FT_LOCAL_DEF( FT_Error )
T42_Driver_Init(FT_Module module)475   T42_Driver_Init( FT_Module  module )        /* T42_Driver */
476   {
477     T42_Driver  driver = (T42_Driver)module;
478     FT_Module   ttmodule;
479 
480 
481     ttmodule = FT_Get_Module( module->library, "truetype" );
482     if ( !ttmodule )
483     {
484       FT_ERROR(( "T42_Driver_Init: cannot access `truetype' module\n" ));
485       return FT_THROW( Missing_Module );
486     }
487 
488     driver->ttclazz = (FT_Driver_Class)ttmodule->clazz;
489 
490     return FT_Err_Ok;
491   }
492 
493 
494   FT_LOCAL_DEF( void )
T42_Driver_Done(FT_Module module)495   T42_Driver_Done( FT_Module  module )
496   {
497     FT_UNUSED( module );
498   }
499 
500 
501   FT_LOCAL_DEF( FT_Error )
T42_Size_Init(FT_Size size)502   T42_Size_Init( FT_Size  size )         /* T42_Size */
503   {
504     T42_Size  t42size = (T42_Size)size;
505     FT_Face   face    = size->face;
506     T42_Face  t42face = (T42_Face)face;
507     FT_Size   ttsize;
508     FT_Error  error;
509 
510 
511     error = FT_New_Size( t42face->ttf_face, &ttsize );
512     if ( !error )
513       t42size->ttsize = ttsize;
514 
515     FT_Activate_Size( ttsize );
516 
517     return error;
518   }
519 
520 
521   FT_LOCAL_DEF( FT_Error )
T42_Size_Request(FT_Size t42size,FT_Size_Request req)522   T42_Size_Request( FT_Size          t42size,      /* T42_Size */
523                     FT_Size_Request  req )
524   {
525     T42_Size  size = (T42_Size)t42size;
526     T42_Face  face = (T42_Face)t42size->face;
527     FT_Error  error;
528 
529 
530     FT_Activate_Size( size->ttsize );
531 
532     error = FT_Request_Size( face->ttf_face, req );
533     if ( !error )
534       t42size->metrics = face->ttf_face->size->metrics;
535 
536     return error;
537   }
538 
539 
540   FT_LOCAL_DEF( FT_Error )
T42_Size_Select(FT_Size t42size,FT_ULong strike_index)541   T42_Size_Select( FT_Size   t42size,         /* T42_Size */
542                    FT_ULong  strike_index )
543   {
544     T42_Size  size = (T42_Size)t42size;
545     T42_Face  face = (T42_Face)t42size->face;
546     FT_Error  error;
547 
548 
549     FT_Activate_Size( size->ttsize );
550 
551     error = FT_Select_Size( face->ttf_face, (FT_Int)strike_index );
552     if ( !error )
553       t42size->metrics = face->ttf_face->size->metrics;
554 
555     return error;
556 
557   }
558 
559 
560   FT_LOCAL_DEF( void )
T42_Size_Done(FT_Size t42size)561   T42_Size_Done( FT_Size  t42size )             /* T42_Size */
562   {
563     T42_Size     size    = (T42_Size)t42size;
564     FT_Face      face    = t42size->face;
565     T42_Face     t42face = (T42_Face)face;
566     FT_ListNode  node;
567 
568 
569     node = FT_List_Find( &t42face->ttf_face->sizes_list, size->ttsize );
570     if ( node )
571     {
572       FT_Done_Size( size->ttsize );
573       size->ttsize = NULL;
574     }
575   }
576 
577 
578   FT_LOCAL_DEF( FT_Error )
T42_GlyphSlot_Init(FT_GlyphSlot t42slot)579   T42_GlyphSlot_Init( FT_GlyphSlot  t42slot )        /* T42_GlyphSlot */
580   {
581     T42_GlyphSlot  slot    = (T42_GlyphSlot)t42slot;
582     FT_Face        face    = t42slot->face;
583     T42_Face       t42face = (T42_Face)face;
584     FT_GlyphSlot   ttslot;
585     FT_Memory      memory  = face->memory;
586     FT_Error       error   = FT_Err_Ok;
587 
588 
589     if ( !face->glyph )
590     {
591       /* First glyph slot for this face */
592       slot->ttslot = t42face->ttf_face->glyph;
593     }
594     else
595     {
596       error = FT_New_GlyphSlot( t42face->ttf_face, &ttslot );
597       if ( !error )
598         slot->ttslot = ttslot;
599     }
600 
601     /* share the loader so that the autohinter can see it */
602     FT_GlyphLoader_Done( slot->ttslot->internal->loader );
603     FT_FREE( slot->ttslot->internal );
604     slot->ttslot->internal = t42slot->internal;
605 
606     return error;
607   }
608 
609 
610   FT_LOCAL_DEF( void )
T42_GlyphSlot_Done(FT_GlyphSlot t42slot)611   T42_GlyphSlot_Done( FT_GlyphSlot  t42slot )       /* T42_GlyphSlot */
612   {
613     T42_GlyphSlot  slot = (T42_GlyphSlot)t42slot;
614 
615 
616     /* do not destroy the inherited internal structure just yet */
617     slot->ttslot->internal = NULL;
618     FT_Done_GlyphSlot( slot->ttslot );
619   }
620 
621 
622   static void
t42_glyphslot_clear(FT_GlyphSlot slot)623   t42_glyphslot_clear( FT_GlyphSlot  slot )
624   {
625     /* free bitmap if needed */
626     ft_glyphslot_free_bitmap( slot );
627 
628     /* clear all public fields in the glyph slot */
629     FT_ZERO( &slot->metrics );
630     FT_ZERO( &slot->outline );
631     FT_ZERO( &slot->bitmap );
632 
633     slot->bitmap_left   = 0;
634     slot->bitmap_top    = 0;
635     slot->num_subglyphs = 0;
636     slot->subglyphs     = NULL;
637     slot->control_data  = NULL;
638     slot->control_len   = 0;
639     slot->other         = NULL;
640     slot->format        = FT_GLYPH_FORMAT_NONE;
641 
642     slot->linearHoriAdvance = 0;
643     slot->linearVertAdvance = 0;
644   }
645 
646 
647   FT_LOCAL_DEF( FT_Error )
T42_GlyphSlot_Load(FT_GlyphSlot glyph,FT_Size size,FT_UInt glyph_index,FT_Int32 load_flags)648   T42_GlyphSlot_Load( FT_GlyphSlot  glyph,
649                       FT_Size       size,
650                       FT_UInt       glyph_index,
651                       FT_Int32      load_flags )
652   {
653     FT_Error         error;
654     T42_GlyphSlot    t42slot = (T42_GlyphSlot)glyph;
655     T42_Size         t42size = (T42_Size)size;
656     T42_Face         t42face = (T42_Face)size->face;
657     FT_Driver_Class  ttclazz = ((T42_Driver)glyph->face->driver)->ttclazz;
658 
659 
660     FT_TRACE1(( "T42_GlyphSlot_Load: glyph index %d\n", glyph_index ));
661 
662     /* map T42 glyph index to embedded TTF's glyph index */
663     glyph_index = (FT_UInt)ft_strtol(
664                     (const char *)t42face->type1.charstrings[glyph_index],
665                     NULL, 10 );
666 
667     t42_glyphslot_clear( t42slot->ttslot );
668     error = ttclazz->load_glyph( t42slot->ttslot,
669                                  t42size->ttsize,
670                                  glyph_index,
671                                  load_flags | FT_LOAD_NO_BITMAP );
672 
673     if ( !error )
674     {
675       glyph->metrics = t42slot->ttslot->metrics;
676 
677       glyph->linearHoriAdvance = t42slot->ttslot->linearHoriAdvance;
678       glyph->linearVertAdvance = t42slot->ttslot->linearVertAdvance;
679 
680       glyph->format  = t42slot->ttslot->format;
681       glyph->outline = t42slot->ttslot->outline;
682 
683       glyph->bitmap      = t42slot->ttslot->bitmap;
684       glyph->bitmap_left = t42slot->ttslot->bitmap_left;
685       glyph->bitmap_top  = t42slot->ttslot->bitmap_top;
686 
687       glyph->num_subglyphs = t42slot->ttslot->num_subglyphs;
688       glyph->subglyphs     = t42slot->ttslot->subglyphs;
689 
690       glyph->control_data  = t42slot->ttslot->control_data;
691       glyph->control_len   = t42slot->ttslot->control_len;
692     }
693 
694     return error;
695   }
696 
697 
698 /* END */
699