1 /****************************************************************************
   2  *
   3  * cidobjs.c
   4  *
   5  *   CID objects manager (body).
   6  *
   7  * Copyright (C) 1996-2019 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_STREAM_H
  22 
  23 #include "cidgload.h"
  24 #include "cidload.h"
  25 
  26 #include FT_SERVICE_POSTSCRIPT_CMAPS_H
  27 #include FT_INTERNAL_POSTSCRIPT_AUX_H
  28 #include FT_INTERNAL_POSTSCRIPT_HINTS_H
  29 #include FT_DRIVER_H
  30 
  31 #include "ciderrs.h"
  32 
  33 
  34   /**************************************************************************
  35    *
  36    * The macro FT_COMPONENT is used in trace mode.  It is an implicit
  37    * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log
  38    * messages during execution.
  39    */
  40 #undef  FT_COMPONENT
  41 #define FT_COMPONENT  cidobjs
  42 
  43 
  44   /**************************************************************************
  45    *
  46    *                           SLOT  FUNCTIONS
  47    *
  48    */
  49 
  50   FT_LOCAL_DEF( void )
  51   cid_slot_done( FT_GlyphSlot  slot )
  52   {
  53     slot->internal->glyph_hints = NULL;
  54   }
  55 
  56 
  57   FT_LOCAL_DEF( FT_Error )
  58   cid_slot_init( FT_GlyphSlot  slot )
  59   {
  60     CID_Face          face;
  61     PSHinter_Service  pshinter;
  62 
  63 
  64     face     = (CID_Face)slot->face;
  65     pshinter = (PSHinter_Service)face->pshinter;
  66 
  67     if ( pshinter )
  68     {
  69       FT_Module  module;
  70 
  71 
  72       module = FT_Get_Module( slot->face->driver->root.library,
  73                               "pshinter" );
  74       if ( module )
  75       {
  76         T1_Hints_Funcs  funcs;
  77 
  78 
  79         funcs = pshinter->get_t1_funcs( module );
  80         slot->internal->glyph_hints = (void*)funcs;
  81       }
  82     }
  83 
  84     return 0;
  85   }
  86 
  87 
  88   /**************************************************************************
  89    *
  90    *                          SIZE  FUNCTIONS
  91    *
  92    */
  93 
  94 
  95   static PSH_Globals_Funcs
  96   cid_size_get_globals_funcs( CID_Size  size )
  97   {
  98     CID_Face          face     = (CID_Face)size->root.face;
  99     PSHinter_Service  pshinter = (PSHinter_Service)face->pshinter;
 100     FT_Module         module;
 101 
 102 
 103     module = FT_Get_Module( size->root.face->driver->root.library,
 104                             "pshinter" );
 105     return ( module && pshinter && pshinter->get_globals_funcs )
 106            ? pshinter->get_globals_funcs( module )
 107            : 0;
 108   }
 109 
 110 
 111   FT_LOCAL_DEF( void )
 112   cid_size_done( FT_Size  cidsize )         /* CID_Size */
 113   {
 114     CID_Size  size = (CID_Size)cidsize;
 115 
 116 
 117     if ( cidsize->internal->module_data )
 118     {
 119       PSH_Globals_Funcs  funcs;
 120 
 121 
 122       funcs = cid_size_get_globals_funcs( size );
 123       if ( funcs )
 124         funcs->destroy( (PSH_Globals)cidsize->internal->module_data );
 125 
 126       cidsize->internal->module_data = NULL;
 127     }
 128   }
 129 
 130 
 131   FT_LOCAL_DEF( FT_Error )
 132   cid_size_init( FT_Size  cidsize )     /* CID_Size */
 133   {
 134     CID_Size           size  = (CID_Size)cidsize;
 135     FT_Error           error = FT_Err_Ok;
 136     PSH_Globals_Funcs  funcs = cid_size_get_globals_funcs( size );
 137 
 138 
 139     if ( funcs )
 140     {
 141       PSH_Globals   globals;
 142       CID_Face      face = (CID_Face)cidsize->face;
 143       CID_FaceDict  dict = face->cid.font_dicts + face->root.face_index;
 144       PS_Private    priv = &dict->private_dict;
 145 
 146 
 147       error = funcs->create( cidsize->face->memory, priv, &globals );
 148       if ( !error )
 149         cidsize->internal->module_data = globals;
 150     }
 151 
 152     return error;
 153   }
 154 
 155 
 156   FT_LOCAL( FT_Error )
 157   cid_size_request( FT_Size          size,
 158                     FT_Size_Request  req )
 159   {
 160     PSH_Globals_Funcs  funcs;
 161 
 162 
 163     FT_Request_Metrics( size->face, req );
 164 
 165     funcs = cid_size_get_globals_funcs( (CID_Size)size );
 166 
 167     if ( funcs )
 168       funcs->set_scale( (PSH_Globals)size->internal->module_data,
 169                         size->metrics.x_scale,
 170                         size->metrics.y_scale,
 171                         0, 0 );
 172 
 173     return FT_Err_Ok;
 174   }
 175 
 176 
 177   /**************************************************************************
 178    *
 179    *                          FACE  FUNCTIONS
 180    *
 181    */
 182 
 183   /**************************************************************************
 184    *
 185    * @Function:
 186    *   cid_face_done
 187    *
 188    * @Description:
 189    *   Finalizes a given face object.
 190    *
 191    * @Input:
 192    *   face ::
 193    *     A pointer to the face object to destroy.
 194    */
 195   FT_LOCAL_DEF( void )
 196   cid_face_done( FT_Face  cidface )         /* CID_Face */
 197   {
 198     CID_Face      face = (CID_Face)cidface;
 199     FT_Memory     memory;
 200     CID_FaceInfo  cid;
 201     PS_FontInfo   info;
 202 
 203 
 204     if ( !face )
 205       return;
 206 
 207     cid    = &face->cid;
 208     info   = &cid->font_info;
 209     memory = cidface->memory;
 210 
 211     /* release subrs */
 212     if ( face->subrs )
 213     {
 214       FT_Int  n;
 215 
 216 
 217       for ( n = 0; n < cid->num_dicts; n++ )
 218       {
 219         CID_Subrs  subr = face->subrs + n;
 220 
 221 
 222         if ( subr->code )
 223         {
 224           FT_FREE( subr->code[0] );
 225           FT_FREE( subr->code );
 226         }
 227       }
 228 
 229       FT_FREE( face->subrs );
 230     }
 231 
 232     /* release FontInfo strings */
 233     FT_FREE( info->version );
 234     FT_FREE( info->notice );
 235     FT_FREE( info->full_name );
 236     FT_FREE( info->family_name );
 237     FT_FREE( info->weight );
 238 
 239     /* release font dictionaries */
 240     FT_FREE( cid->font_dicts );
 241     cid->num_dicts = 0;
 242 
 243     /* release other strings */
 244     FT_FREE( cid->cid_font_name );
 245     FT_FREE( cid->registry );
 246     FT_FREE( cid->ordering );
 247 
 248     cidface->family_name = NULL;
 249     cidface->style_name  = NULL;
 250 
 251     FT_FREE( face->binary_data );
 252     FT_FREE( face->cid_stream );
 253   }
 254 
 255 
 256   /**************************************************************************
 257    *
 258    * @Function:
 259    *   cid_face_init
 260    *
 261    * @Description:
 262    *   Initializes a given CID face object.
 263    *
 264    * @Input:
 265    *   stream ::
 266    *     The source font stream.
 267    *
 268    *   face_index ::
 269    *     The index of the font face in the resource.
 270    *
 271    *   num_params ::
 272    *     Number of additional generic parameters.  Ignored.
 273    *
 274    *   params ::
 275    *     Additional generic parameters.  Ignored.
 276    *
 277    * @InOut:
 278    *   face ::
 279    *     The newly built face object.
 280    *
 281    * @Return:
 282    *   FreeType error code.  0 means success.
 283    */
 284   FT_LOCAL_DEF( FT_Error )
 285   cid_face_init( FT_Stream      stream,
 286                  FT_Face        cidface,        /* CID_Face */
 287                  FT_Int         face_index,
 288                  FT_Int         num_params,
 289                  FT_Parameter*  params )
 290   {
 291     CID_Face          face = (CID_Face)cidface;
 292     FT_Error          error;
 293     PSAux_Service     psaux;
 294     PSHinter_Service  pshinter;
 295 
 296     FT_UNUSED( num_params );
 297     FT_UNUSED( params );
 298     FT_UNUSED( stream );
 299 
 300 
 301     cidface->num_faces = 1;
 302 
 303     psaux = (PSAux_Service)face->psaux;
 304     if ( !psaux )
 305     {
 306       psaux = (PSAux_Service)FT_Get_Module_Interface(
 307                 FT_FACE_LIBRARY( face ), "psaux" );
 308 
 309       if ( !psaux )
 310       {
 311         FT_ERROR(( "cid_face_init: cannot access `psaux' module\n" ));
 312         error = FT_THROW( Missing_Module );
 313         goto Exit;
 314       }
 315 
 316       face->psaux = psaux;
 317     }
 318 
 319     pshinter = (PSHinter_Service)face->pshinter;
 320     if ( !pshinter )
 321     {
 322       pshinter = (PSHinter_Service)FT_Get_Module_Interface(
 323                    FT_FACE_LIBRARY( face ), "pshinter" );
 324 
 325       face->pshinter = pshinter;
 326     }
 327 
 328     FT_TRACE2(( "CID driver\n" ));
 329 
 330     /* open the tokenizer; this will also check the font format */
 331     if ( FT_STREAM_SEEK( 0 ) )
 332       goto Exit;
 333 
 334     error = cid_face_open( face, face_index );
 335     if ( error )
 336       goto Exit;
 337 
 338     /* if we just wanted to check the format, leave successfully now */
 339     if ( face_index < 0 )
 340       goto Exit;
 341 
 342     /* check the face index */
 343     /* XXX: handle CID fonts with more than a single face */
 344     if ( ( face_index & 0xFFFF ) != 0 )
 345     {
 346       FT_ERROR(( "cid_face_init: invalid face index\n" ));
 347       error = FT_THROW( Invalid_Argument );
 348       goto Exit;
 349     }
 350 
 351     /* now load the font program into the face object */
 352 
 353     /* initialize the face object fields */
 354 
 355     /* set up root face fields */
 356     {
 357       CID_FaceInfo  cid  = &face->cid;
 358       PS_FontInfo   info = &cid->font_info;
 359 
 360 
 361       cidface->num_glyphs   = (FT_Long)cid->cid_count;
 362       cidface->num_charmaps = 0;
 363 
 364       cidface->face_index = face_index & 0xFFFF;
 365 
 366       cidface->face_flags |= FT_FACE_FLAG_SCALABLE   | /* scalable outlines */
 367                              FT_FACE_FLAG_HORIZONTAL | /* horizontal data   */
 368                              FT_FACE_FLAG_HINTER;      /* has native hinter */
 369 
 370       if ( info->is_fixed_pitch )
 371         cidface->face_flags |= FT_FACE_FLAG_FIXED_WIDTH;
 372 
 373       /* XXX: TODO: add kerning with .afm support */
 374 
 375       /* get style name -- be careful, some broken fonts only */
 376       /* have a /FontName dictionary entry!                   */
 377       cidface->family_name = info->family_name;
 378       /* assume "Regular" style if we don't know better */
 379       cidface->style_name = (char *)"Regular";
 380       if ( cidface->family_name )
 381       {
 382         char*  full   = info->full_name;
 383         char*  family = cidface->family_name;
 384 
 385 
 386         if ( full )
 387         {
 388           while ( *full )
 389           {
 390             if ( *full == *family )
 391             {
 392               family++;
 393               full++;
 394             }
 395             else
 396             {
 397               if ( *full == ' ' || *full == '-' )
 398                 full++;
 399               else if ( *family == ' ' || *family == '-' )
 400                 family++;
 401               else
 402               {
 403                 if ( !*family )
 404                   cidface->style_name = full;
 405                 break;
 406               }
 407             }
 408           }
 409         }
 410       }
 411       else
 412       {
 413         /* do we have a `/FontName'? */
 414         if ( cid->cid_font_name )
 415           cidface->family_name = cid->cid_font_name;
 416       }
 417 
 418       /* compute style flags */
 419       cidface->style_flags = 0;
 420       if ( info->italic_angle )
 421         cidface->style_flags |= FT_STYLE_FLAG_ITALIC;
 422       if ( info->weight )
 423       {
 424         if ( !ft_strcmp( info->weight, "Bold"  ) ||
 425              !ft_strcmp( info->weight, "Black" ) )
 426           cidface->style_flags |= FT_STYLE_FLAG_BOLD;
 427       }
 428 
 429       /* no embedded bitmap support */
 430       cidface->num_fixed_sizes = 0;
 431       cidface->available_sizes = NULL;
 432 
 433       cidface->bbox.xMin =   cid->font_bbox.xMin            >> 16;
 434       cidface->bbox.yMin =   cid->font_bbox.yMin            >> 16;
 435       /* no `U' suffix here to 0xFFFF! */
 436       cidface->bbox.xMax = ( cid->font_bbox.xMax + 0xFFFF ) >> 16;
 437       cidface->bbox.yMax = ( cid->font_bbox.yMax + 0xFFFF ) >> 16;
 438 
 439       if ( !cidface->units_per_EM )
 440         cidface->units_per_EM = 1000;
 441 
 442       cidface->ascender  = (FT_Short)( cidface->bbox.yMax );
 443       cidface->descender = (FT_Short)( cidface->bbox.yMin );
 444 
 445       cidface->height = (FT_Short)( ( cidface->units_per_EM * 12 ) / 10 );
 446       if ( cidface->height < cidface->ascender - cidface->descender )
 447         cidface->height = (FT_Short)( cidface->ascender - cidface->descender );
 448 
 449       cidface->underline_position  = (FT_Short)info->underline_position;
 450       cidface->underline_thickness = (FT_Short)info->underline_thickness;
 451     }
 452 
 453   Exit:
 454     return error;
 455   }
 456 
 457 
 458   /**************************************************************************
 459    *
 460    * @Function:
 461    *   cid_driver_init
 462    *
 463    * @Description:
 464    *   Initializes a given CID driver object.
 465    *
 466    * @Input:
 467    *   driver ::
 468    *     A handle to the target driver object.
 469    *
 470    * @Return:
 471    *   FreeType error code.  0 means success.
 472    */
 473   FT_LOCAL_DEF( FT_Error )
 474   cid_driver_init( FT_Module  module )
 475   {
 476     PS_Driver  driver = (PS_Driver)module;
 477 
 478     FT_UInt32  seed;
 479 
 480 
 481     /* set default property values, cf. `ftt1drv.h' */
 482 #ifdef T1_CONFIG_OPTION_OLD_ENGINE
 483     driver->hinting_engine = FT_HINTING_FREETYPE;
 484 #else
 485     driver->hinting_engine = FT_HINTING_ADOBE;
 486 #endif
 487 
 488     driver->no_stem_darkening = TRUE;
 489 
 490     driver->darken_params[0] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_X1;
 491     driver->darken_params[1] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y1;
 492     driver->darken_params[2] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_X2;
 493     driver->darken_params[3] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y2;
 494     driver->darken_params[4] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_X3;
 495     driver->darken_params[5] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y3;
 496     driver->darken_params[6] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_X4;
 497     driver->darken_params[7] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y4;
 498 
 499     /* compute random seed from some memory addresses */
 500     seed = (FT_UInt32)( (FT_Offset)(char*)&seed          ^
 501                         (FT_Offset)(char*)&module        ^
 502                         (FT_Offset)(char*)module->memory );
 503     seed = seed ^ ( seed >> 10 ) ^ ( seed >> 20 );
 504 
 505     driver->random_seed = (FT_Int32)seed;
 506     if ( driver->random_seed < 0 )
 507       driver->random_seed = -driver->random_seed;
 508     else if ( driver->random_seed == 0 )
 509       driver->random_seed = 123456789;
 510 
 511     return FT_Err_Ok;
 512   }
 513 
 514 
 515   /**************************************************************************
 516    *
 517    * @Function:
 518    *   cid_driver_done
 519    *
 520    * @Description:
 521    *   Finalizes a given CID driver.
 522    *
 523    * @Input:
 524    *   driver ::
 525    *     A handle to the target CID driver.
 526    */
 527   FT_LOCAL_DEF( void )
 528   cid_driver_done( FT_Module  driver )
 529   {
 530     FT_UNUSED( driver );
 531   }
 532 
 533 
 534 /* END */