(root)/
freetype-2.13.2/
src/
pfr/
pfrobjs.c
       1  /****************************************************************************
       2   *
       3   * pfrobjs.c
       4   *
       5   *   FreeType PFR object methods (body).
       6   *
       7   * Copyright (C) 2002-2023 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 "pfrobjs.h"
      20  #include "pfrload.h"
      21  #include "pfrgload.h"
      22  #include "pfrcmap.h"
      23  #include "pfrsbit.h"
      24  #include <freetype/ftoutln.h>
      25  #include <freetype/internal/ftdebug.h>
      26  #include <freetype/internal/ftcalc.h>
      27  #include <freetype/ttnameid.h>
      28  
      29  #include "pfrerror.h"
      30  
      31  #undef  FT_COMPONENT
      32  #define FT_COMPONENT  pfr
      33  
      34  
      35    /*************************************************************************/
      36    /*************************************************************************/
      37    /*****                                                               *****/
      38    /*****                     FACE OBJECT METHODS                       *****/
      39    /*****                                                               *****/
      40    /*************************************************************************/
      41    /*************************************************************************/
      42  
      43    FT_LOCAL_DEF( void )
      44    pfr_face_done( FT_Face  pfrface )     /* PFR_Face */
      45    {
      46      PFR_Face   face = (PFR_Face)pfrface;
      47      FT_Memory  memory;
      48  
      49  
      50      if ( !face )
      51        return;
      52  
      53      memory = pfrface->memory;
      54  
      55      /* we don't want dangling pointers */
      56      pfrface->family_name = NULL;
      57      pfrface->style_name  = NULL;
      58  
      59      /* finalize the physical font record */
      60      pfr_phy_font_done( &face->phy_font, memory );
      61  
      62      /* no need to finalize the logical font or the header */
      63      FT_FREE( pfrface->available_sizes );
      64    }
      65  
      66  
      67    FT_LOCAL_DEF( FT_Error )
      68    pfr_face_init( FT_Stream      stream,
      69                   FT_Face        pfrface,
      70                   FT_Int         face_index,
      71                   FT_Int         num_params,
      72                   FT_Parameter*  params )
      73    {
      74      PFR_Face  face = (PFR_Face)pfrface;
      75      FT_Error  error;
      76  
      77      FT_UNUSED( num_params );
      78      FT_UNUSED( params );
      79  
      80  
      81      FT_TRACE2(( "PFR driver\n" ));
      82  
      83      /* load the header and check it */
      84      error = pfr_header_load( &face->header, stream );
      85      if ( error )
      86      {
      87        FT_TRACE2(( "  not a PFR font\n" ));
      88        error = FT_THROW( Unknown_File_Format );
      89        goto Exit;
      90      }
      91  
      92      if ( !pfr_header_check( &face->header ) )
      93      {
      94        FT_TRACE2(( "  not a PFR font\n" ));
      95        error = FT_THROW( Unknown_File_Format );
      96        goto Exit;
      97      }
      98  
      99      /* check face index */
     100      {
     101        FT_Long  num_faces;
     102  
     103  
     104        error = pfr_log_font_count( stream,
     105                                    face->header.log_dir_offset,
     106                                    &num_faces );
     107        if ( error )
     108          goto Exit;
     109  
     110        pfrface->num_faces = num_faces;
     111      }
     112  
     113      if ( face_index < 0 )
     114        goto Exit;
     115  
     116      if ( ( face_index & 0xFFFF ) >= pfrface->num_faces )
     117      {
     118        FT_ERROR(( "pfr_face_init: invalid face index\n" ));
     119        error = FT_THROW( Invalid_Argument );
     120        goto Exit;
     121      }
     122  
     123      /* load the face */
     124      error = pfr_log_font_load(
     125                &face->log_font,
     126                stream,
     127                (FT_UInt)( face_index & 0xFFFF ),
     128                face->header.log_dir_offset,
     129                FT_BOOL( face->header.phy_font_max_size_high ) );
     130      if ( error )
     131        goto Exit;
     132  
     133      /* load the physical font descriptor */
     134      error = pfr_phy_font_load( &face->phy_font, stream,
     135                                 face->log_font.phys_offset,
     136                                 face->log_font.phys_size );
     137      if ( error )
     138        goto Exit;
     139  
     140      /* set up all root face fields */
     141      {
     142        PFR_PhyFont  phy_font = &face->phy_font;
     143  
     144  
     145        pfrface->face_index = face_index & 0xFFFF;
     146        pfrface->num_glyphs = (FT_Long)phy_font->num_chars + 1;
     147  
     148        pfrface->face_flags |= FT_FACE_FLAG_SCALABLE;
     149  
     150        /* if gps_offset == 0 for all characters, we  */
     151        /* assume that the font only contains bitmaps */
     152        {
     153          FT_UInt  nn;
     154  
     155  
     156          for ( nn = 0; nn < phy_font->num_chars; nn++ )
     157            if ( phy_font->chars[nn].gps_offset != 0 )
     158              break;
     159  
     160          if ( nn == phy_font->num_chars )
     161          {
     162            if ( phy_font->num_strikes > 0 )
     163              pfrface->face_flags &= ~FT_FACE_FLAG_SCALABLE;
     164            else
     165            {
     166              FT_ERROR(( "pfr_face_init: font doesn't contain glyphs\n" ));
     167              error = FT_THROW( Invalid_File_Format );
     168              goto Exit;
     169            }
     170          }
     171        }
     172  
     173        if ( !( phy_font->flags & PFR_PHY_PROPORTIONAL ) )
     174          pfrface->face_flags |= FT_FACE_FLAG_FIXED_WIDTH;
     175  
     176        if ( phy_font->flags & PFR_PHY_VERTICAL )
     177          pfrface->face_flags |= FT_FACE_FLAG_VERTICAL;
     178        else
     179          pfrface->face_flags |= FT_FACE_FLAG_HORIZONTAL;
     180  
     181        if ( phy_font->num_strikes > 0 )
     182          pfrface->face_flags |= FT_FACE_FLAG_FIXED_SIZES;
     183  
     184        if ( phy_font->num_kern_pairs > 0 )
     185          pfrface->face_flags |= FT_FACE_FLAG_KERNING;
     186  
     187        /* If no family name was found in the `undocumented' auxiliary
     188         * data, use the font ID instead.  This sucks but is better than
     189         * nothing.
     190         */
     191        pfrface->family_name = phy_font->family_name;
     192        if ( !pfrface->family_name )
     193          pfrface->family_name = phy_font->font_id;
     194  
     195        /* note that the style name can be NULL in certain PFR fonts,
     196         * probably meaning `Regular'
     197         */
     198        pfrface->style_name = phy_font->style_name;
     199  
     200        pfrface->num_fixed_sizes = 0;
     201        pfrface->available_sizes = NULL;
     202  
     203        pfrface->bbox         = phy_font->bbox;
     204        pfrface->units_per_EM = (FT_UShort)phy_font->outline_resolution;
     205        pfrface->ascender     = (FT_Short) phy_font->bbox.yMax;
     206        pfrface->descender    = (FT_Short) phy_font->bbox.yMin;
     207  
     208        pfrface->height = (FT_Short)( ( pfrface->units_per_EM * 12 ) / 10 );
     209        if ( pfrface->height < pfrface->ascender - pfrface->descender )
     210          pfrface->height = (FT_Short)( pfrface->ascender - pfrface->descender );
     211  
     212        if ( phy_font->num_strikes > 0 )
     213        {
     214          FT_UInt          n, count = phy_font->num_strikes;
     215          FT_Bitmap_Size*  size;
     216          PFR_Strike       strike;
     217          FT_Memory        memory = pfrface->memory;
     218  
     219  
     220          if ( FT_QNEW_ARRAY( pfrface->available_sizes, count ) )
     221            goto Exit;
     222  
     223          size   = pfrface->available_sizes;
     224          strike = phy_font->strikes;
     225          for ( n = 0; n < count; n++, size++, strike++ )
     226          {
     227            size->height = (FT_Short)strike->y_ppm;
     228            size->width  = (FT_Short)strike->x_ppm;
     229            size->size   = (FT_Pos)( strike->y_ppm << 6 );
     230            size->x_ppem = (FT_Pos)( strike->x_ppm << 6 );
     231            size->y_ppem = (FT_Pos)( strike->y_ppm << 6 );
     232          }
     233          pfrface->num_fixed_sizes = (FT_Int)count;
     234        }
     235  
     236        /* now compute maximum advance width */
     237        if ( ( phy_font->flags & PFR_PHY_PROPORTIONAL ) == 0 )
     238          pfrface->max_advance_width = (FT_Short)phy_font->standard_advance;
     239        else
     240        {
     241          FT_Int    max = 0;
     242          FT_UInt   count = phy_font->num_chars;
     243          PFR_Char  gchar = phy_font->chars;
     244  
     245  
     246          for ( ; count > 0; count--, gchar++ )
     247          {
     248            if ( max < gchar->advance )
     249              max = gchar->advance;
     250          }
     251  
     252          pfrface->max_advance_width = (FT_Short)max;
     253        }
     254  
     255        pfrface->max_advance_height = pfrface->height;
     256  
     257        pfrface->underline_position  = (FT_Short)( -pfrface->units_per_EM / 10 );
     258        pfrface->underline_thickness = (FT_Short)(  pfrface->units_per_EM / 30 );
     259  
     260        /* create charmap */
     261        {
     262          FT_CharMapRec  charmap;
     263  
     264  
     265          charmap.face        = pfrface;
     266          charmap.platform_id = TT_PLATFORM_MICROSOFT;
     267          charmap.encoding_id = TT_MS_ID_UNICODE_CS;
     268          charmap.encoding    = FT_ENCODING_UNICODE;
     269  
     270          error = FT_CMap_New( &pfr_cmap_class_rec, NULL, &charmap, NULL );
     271        }
     272  
     273        /* check whether we have loaded any kerning pairs */
     274        if ( phy_font->num_kern_pairs )
     275          pfrface->face_flags |= FT_FACE_FLAG_KERNING;
     276      }
     277  
     278    Exit:
     279      return error;
     280    }
     281  
     282  
     283    /*************************************************************************/
     284    /*************************************************************************/
     285    /*****                                                               *****/
     286    /*****                    SLOT OBJECT METHOD                         *****/
     287    /*****                                                               *****/
     288    /*************************************************************************/
     289    /*************************************************************************/
     290  
     291    FT_LOCAL_DEF( FT_Error )
     292    pfr_slot_init( FT_GlyphSlot  pfrslot )        /* PFR_Slot */
     293    {
     294      PFR_Slot        slot   = (PFR_Slot)pfrslot;
     295      FT_GlyphLoader  loader = pfrslot->internal->loader;
     296  
     297  
     298      pfr_glyph_init( &slot->glyph, loader );
     299  
     300      return 0;
     301    }
     302  
     303  
     304    FT_LOCAL_DEF( void )
     305    pfr_slot_done( FT_GlyphSlot  pfrslot )        /* PFR_Slot */
     306    {
     307      PFR_Slot  slot = (PFR_Slot)pfrslot;
     308  
     309  
     310      pfr_glyph_done( &slot->glyph );
     311    }
     312  
     313  
     314    FT_LOCAL_DEF( FT_Error )
     315    pfr_slot_load( FT_GlyphSlot  pfrslot,         /* PFR_Slot */
     316                   FT_Size       pfrsize,         /* PFR_Size */
     317                   FT_UInt       gindex,
     318                   FT_Int32      load_flags )
     319    {
     320      PFR_Slot     slot    = (PFR_Slot)pfrslot;
     321      PFR_Size     size    = (PFR_Size)pfrsize;
     322      FT_Error     error;
     323      PFR_Face     face    = (PFR_Face)pfrslot->face;
     324      PFR_Char     gchar;
     325      FT_Outline*  outline = &pfrslot->outline;
     326      FT_ULong     gps_offset;
     327  
     328  
     329      FT_TRACE1(( "pfr_slot_load: glyph index %d\n", gindex ));
     330  
     331      if ( gindex > 0 )
     332        gindex--;
     333  
     334      if ( !face || gindex >= face->phy_font.num_chars )
     335      {
     336        error = FT_THROW( Invalid_Argument );
     337        goto Exit;
     338      }
     339  
     340      /* try to load an embedded bitmap */
     341      if ( !( load_flags & ( FT_LOAD_NO_SCALE | FT_LOAD_NO_BITMAP ) ) )
     342      {
     343        error = pfr_slot_load_bitmap(
     344                  slot,
     345                  size,
     346                  gindex,
     347                  ( load_flags & FT_LOAD_BITMAP_METRICS_ONLY ) != 0 );
     348        if ( !error )
     349          goto Exit;
     350      }
     351  
     352      if ( load_flags & FT_LOAD_SBITS_ONLY )
     353      {
     354        error = FT_THROW( Invalid_Argument );
     355        goto Exit;
     356      }
     357  
     358      gchar               = face->phy_font.chars + gindex;
     359      pfrslot->format     = FT_GLYPH_FORMAT_OUTLINE;
     360      outline->n_points   = 0;
     361      outline->n_contours = 0;
     362      gps_offset          = face->header.gps_section_offset;
     363  
     364      /* load the glyph outline (FT_LOAD_NO_RECURSE isn't supported) */
     365      error = pfr_glyph_load( &slot->glyph, face->root.stream,
     366                              gps_offset, gchar->gps_offset, gchar->gps_size );
     367  
     368      if ( !error )
     369      {
     370        FT_BBox            cbox;
     371        FT_Glyph_Metrics*  metrics = &pfrslot->metrics;
     372        FT_Pos             advance;
     373        FT_UInt            em_metrics, em_outline;
     374        FT_Bool            scaling;
     375  
     376  
     377        scaling = FT_BOOL( !( load_flags & FT_LOAD_NO_SCALE ) );
     378  
     379        /* copy outline data */
     380        *outline = slot->glyph.loader->base.outline;
     381  
     382        outline->flags &= ~FT_OUTLINE_OWNER;
     383        outline->flags |= FT_OUTLINE_REVERSE_FILL;
     384  
     385        if ( pfrsize->metrics.y_ppem < 24 )
     386          outline->flags |= FT_OUTLINE_HIGH_PRECISION;
     387  
     388        /* compute the advance vector */
     389        metrics->horiAdvance = 0;
     390        metrics->vertAdvance = 0;
     391  
     392        advance    = gchar->advance;
     393        em_metrics = face->phy_font.metrics_resolution;
     394        em_outline = face->phy_font.outline_resolution;
     395  
     396        if ( em_metrics != em_outline )
     397          advance = FT_MulDiv( advance,
     398                               (FT_Long)em_outline,
     399                               (FT_Long)em_metrics );
     400  
     401        if ( face->phy_font.flags & PFR_PHY_VERTICAL )
     402          metrics->vertAdvance = advance;
     403        else
     404          metrics->horiAdvance = advance;
     405  
     406        pfrslot->linearHoriAdvance = metrics->horiAdvance;
     407        pfrslot->linearVertAdvance = metrics->vertAdvance;
     408  
     409        /* make up vertical metrics(?) */
     410        metrics->vertBearingX = 0;
     411        metrics->vertBearingY = 0;
     412  
     413  #if 0 /* some fonts seem to be broken here! */
     414  
     415        /* Apply the font matrix, if any.                 */
     416        /* TODO: Test existing fonts with unusual matrix  */
     417        /* whether we have to adjust Units per EM.        */
     418        {
     419          FT_Matrix font_matrix;
     420  
     421  
     422          font_matrix.xx = face->log_font.matrix[0] << 8;
     423          font_matrix.yx = face->log_font.matrix[1] << 8;
     424          font_matrix.xy = face->log_font.matrix[2] << 8;
     425          font_matrix.yy = face->log_font.matrix[3] << 8;
     426  
     427          FT_Outline_Transform( outline, &font_matrix );
     428        }
     429  #endif
     430  
     431        /* scale when needed */
     432        if ( scaling )
     433        {
     434          FT_Int      n;
     435          FT_Fixed    x_scale = pfrsize->metrics.x_scale;
     436          FT_Fixed    y_scale = pfrsize->metrics.y_scale;
     437          FT_Vector*  vec     = outline->points;
     438  
     439  
     440          /* scale outline points */
     441          for ( n = 0; n < outline->n_points; n++, vec++ )
     442          {
     443            vec->x = FT_MulFix( vec->x, x_scale );
     444            vec->y = FT_MulFix( vec->y, y_scale );
     445          }
     446  
     447          /* scale the advance */
     448          metrics->horiAdvance = FT_MulFix( metrics->horiAdvance, x_scale );
     449          metrics->vertAdvance = FT_MulFix( metrics->vertAdvance, y_scale );
     450        }
     451  
     452        /* compute the rest of the metrics */
     453        FT_Outline_Get_CBox( outline, &cbox );
     454  
     455        metrics->width        = cbox.xMax - cbox.xMin;
     456        metrics->height       = cbox.yMax - cbox.yMin;
     457        metrics->horiBearingX = cbox.xMin;
     458        metrics->horiBearingY = cbox.yMax - metrics->height;
     459      }
     460  
     461    Exit:
     462      return error;
     463    }
     464  
     465  
     466    /*************************************************************************/
     467    /*************************************************************************/
     468    /*****                                                               *****/
     469    /*****                      KERNING METHOD                           *****/
     470    /*****                                                               *****/
     471    /*************************************************************************/
     472    /*************************************************************************/
     473  
     474    FT_LOCAL_DEF( FT_Error )
     475    pfr_face_get_kerning( FT_Face     pfrface,        /* PFR_Face */
     476                          FT_UInt     glyph1,
     477                          FT_UInt     glyph2,
     478                          FT_Vector*  kerning )
     479    {
     480      PFR_Face     face     = (PFR_Face)pfrface;
     481      FT_Error     error    = FT_Err_Ok;
     482      PFR_PhyFont  phy_font = &face->phy_font;
     483      FT_UInt32    code1, code2, pair;
     484  
     485  
     486      kerning->x = 0;
     487      kerning->y = 0;
     488  
     489      /* PFR indexing skips .notdef, which becomes UINT_MAX */
     490      glyph1--;
     491      glyph2--;
     492  
     493      /* check the array bounds, .notdef is automatically out */
     494      if ( glyph1 >= phy_font->num_chars ||
     495           glyph2 >= phy_font->num_chars )
     496        goto Exit;
     497  
     498      /* convert glyph indices to character codes */
     499      code1 = phy_font->chars[glyph1].char_code;
     500      code2 = phy_font->chars[glyph2].char_code;
     501      pair  = PFR_KERN_INDEX( code1, code2 );
     502  
     503      /* now search the list of kerning items */
     504      {
     505        PFR_KernItem  item   = phy_font->kern_items;
     506        FT_Stream     stream = pfrface->stream;
     507  
     508  
     509        for ( ; item; item = item->next )
     510        {
     511          if ( pair >= item->pair1 && pair <= item->pair2 )
     512            goto FoundPair;
     513        }
     514        goto Exit;
     515  
     516      FoundPair: /* we found an item, now parse it and find the value if any */
     517        if ( FT_STREAM_SEEK( item->offset )                       ||
     518             FT_FRAME_ENTER( item->pair_count * item->pair_size ) )
     519          goto Exit;
     520  
     521        {
     522          FT_UInt    count       = item->pair_count;
     523          FT_UInt    size        = item->pair_size;
     524          FT_UInt    power       = 1 << FT_MSB( count );
     525          FT_UInt    probe       = power * size;
     526          FT_UInt    extra       = count - power;
     527          FT_Byte*   base        = stream->cursor;
     528          FT_Bool    twobytes    = FT_BOOL( item->flags & PFR_KERN_2BYTE_CHAR );
     529          FT_Bool    twobyte_adj = FT_BOOL( item->flags & PFR_KERN_2BYTE_ADJ  );
     530          FT_Byte*   p;
     531          FT_UInt32  cpair;
     532  
     533  
     534          if ( extra > 0 )
     535          {
     536            p = base + extra * size;
     537  
     538            if ( twobytes )
     539              cpair = FT_NEXT_ULONG( p );
     540            else
     541              cpair = PFR_NEXT_KPAIR( p );
     542  
     543            if ( cpair == pair )
     544              goto Found;
     545  
     546            if ( cpair < pair )
     547            {
     548              if ( twobyte_adj )
     549                p += 2;
     550              else
     551                p++;
     552              base = p;
     553            }
     554          }
     555  
     556          while ( probe > size )
     557          {
     558            probe >>= 1;
     559            p       = base + probe;
     560  
     561            if ( twobytes )
     562              cpair = FT_NEXT_ULONG( p );
     563            else
     564              cpair = PFR_NEXT_KPAIR( p );
     565  
     566            if ( cpair == pair )
     567              goto Found;
     568  
     569            if ( cpair < pair )
     570              base += probe;
     571          }
     572  
     573          p = base;
     574  
     575          if ( twobytes )
     576            cpair = FT_NEXT_ULONG( p );
     577          else
     578            cpair = PFR_NEXT_KPAIR( p );
     579  
     580          if ( cpair == pair )
     581          {
     582            FT_Int  value;
     583  
     584  
     585          Found:
     586            if ( twobyte_adj )
     587              value = FT_PEEK_SHORT( p );
     588            else
     589              value = p[0];
     590  
     591            kerning->x = item->base_adj + value;
     592          }
     593        }
     594  
     595        FT_FRAME_EXIT();
     596      }
     597  
     598    Exit:
     599      return error;
     600    }
     601  
     602  
     603  /* END */