Edit

kc3-lang/freetype/src/pfr/pfrobjs.c

Branch :

  • Show log

    Commit

  • Author : Alexei Podtelezhnikov
    Date : 2024-01-27 11:11:22
    Hash : 47574f7e
    Message : Update all copyright notices.

  • src/pfr/pfrobjs.c
  • /****************************************************************************
     *
     * pfrobjs.c
     *
     *   FreeType PFR object methods (body).
     *
     * Copyright (C) 2002-2024 by
     * David Turner, Robert Wilhelm, and Werner Lemberg.
     *
     * This file is part of the FreeType project, and may only be used,
     * modified, and distributed under the terms of the FreeType project
     * license, LICENSE.TXT.  By continuing to use, modify, or distribute
     * this file you indicate that you have read the license and
     * understand and accept it fully.
     *
     */
    
    
    #include "pfrobjs.h"
    #include "pfrload.h"
    #include "pfrgload.h"
    #include "pfrcmap.h"
    #include "pfrsbit.h"
    #include <freetype/ftoutln.h>
    #include <freetype/internal/ftdebug.h>
    #include <freetype/internal/ftcalc.h>
    #include <freetype/ttnameid.h>
    
    #include "pfrerror.h"
    
    #undef  FT_COMPONENT
    #define FT_COMPONENT  pfr
    
    
      /*************************************************************************/
      /*************************************************************************/
      /*****                                                               *****/
      /*****                     FACE OBJECT METHODS                       *****/
      /*****                                                               *****/
      /*************************************************************************/
      /*************************************************************************/
    
      FT_LOCAL_DEF( void )
      pfr_face_done( FT_Face  pfrface )     /* PFR_Face */
      {
        PFR_Face   face = (PFR_Face)pfrface;
        FT_Memory  memory;
    
    
        if ( !face )
          return;
    
        memory = pfrface->memory;
    
        /* we don't want dangling pointers */
        pfrface->family_name = NULL;
        pfrface->style_name  = NULL;
    
        /* finalize the physical font record */
        pfr_phy_font_done( &face->phy_font, memory );
    
        /* no need to finalize the logical font or the header */
        FT_FREE( pfrface->available_sizes );
      }
    
    
      FT_LOCAL_DEF( FT_Error )
      pfr_face_init( FT_Stream      stream,
                     FT_Face        pfrface,
                     FT_Int         face_index,
                     FT_Int         num_params,
                     FT_Parameter*  params )
      {
        PFR_Face  face = (PFR_Face)pfrface;
        FT_Error  error;
    
        FT_UNUSED( num_params );
        FT_UNUSED( params );
    
    
        FT_TRACE2(( "PFR driver\n" ));
    
        /* load the header and check it */
        error = pfr_header_load( &face->header, stream );
        if ( error )
        {
          FT_TRACE2(( "  not a PFR font\n" ));
          error = FT_THROW( Unknown_File_Format );
          goto Exit;
        }
    
        if ( !pfr_header_check( &face->header ) )
        {
          FT_TRACE2(( "  not a PFR font\n" ));
          error = FT_THROW( Unknown_File_Format );
          goto Exit;
        }
    
        /* check face index */
        {
          FT_Long  num_faces;
    
    
          error = pfr_log_font_count( stream,
                                      face->header.log_dir_offset,
                                      &num_faces );
          if ( error )
            goto Exit;
    
          pfrface->num_faces = num_faces;
        }
    
        if ( face_index < 0 )
          goto Exit;
    
        if ( ( face_index & 0xFFFF ) >= pfrface->num_faces )
        {
          FT_ERROR(( "pfr_face_init: invalid face index\n" ));
          error = FT_THROW( Invalid_Argument );
          goto Exit;
        }
    
        /* load the face */
        error = pfr_log_font_load(
                  &face->log_font,
                  stream,
                  (FT_UInt)( face_index & 0xFFFF ),
                  face->header.log_dir_offset,
                  FT_BOOL( face->header.phy_font_max_size_high ) );
        if ( error )
          goto Exit;
    
        /* load the physical font descriptor */
        error = pfr_phy_font_load( &face->phy_font, stream,
                                   face->log_font.phys_offset,
                                   face->log_font.phys_size );
        if ( error )
          goto Exit;
    
        /* set up all root face fields */
        {
          PFR_PhyFont  phy_font = &face->phy_font;
    
    
          pfrface->face_index = face_index & 0xFFFF;
          pfrface->num_glyphs = (FT_Long)phy_font->num_chars + 1;
    
          pfrface->face_flags |= FT_FACE_FLAG_SCALABLE;
    
          /* if gps_offset == 0 for all characters, we  */
          /* assume that the font only contains bitmaps */
          {
            FT_UInt  nn;
    
    
            for ( nn = 0; nn < phy_font->num_chars; nn++ )
              if ( phy_font->chars[nn].gps_offset != 0 )
                break;
    
            if ( nn == phy_font->num_chars )
            {
              if ( phy_font->num_strikes > 0 )
                pfrface->face_flags &= ~FT_FACE_FLAG_SCALABLE;
              else
              {
                FT_ERROR(( "pfr_face_init: font doesn't contain glyphs\n" ));
                error = FT_THROW( Invalid_File_Format );
                goto Exit;
              }
            }
          }
    
          if ( !( phy_font->flags & PFR_PHY_PROPORTIONAL ) )
            pfrface->face_flags |= FT_FACE_FLAG_FIXED_WIDTH;
    
          if ( phy_font->flags & PFR_PHY_VERTICAL )
            pfrface->face_flags |= FT_FACE_FLAG_VERTICAL;
          else
            pfrface->face_flags |= FT_FACE_FLAG_HORIZONTAL;
    
          if ( phy_font->num_strikes > 0 )
            pfrface->face_flags |= FT_FACE_FLAG_FIXED_SIZES;
    
          if ( phy_font->num_kern_pairs > 0 )
            pfrface->face_flags |= FT_FACE_FLAG_KERNING;
    
          /* If no family name was found in the `undocumented' auxiliary
           * data, use the font ID instead.  This sucks but is better than
           * nothing.
           */
          pfrface->family_name = phy_font->family_name;
          if ( !pfrface->family_name )
            pfrface->family_name = phy_font->font_id;
    
          /* note that the style name can be NULL in certain PFR fonts,
           * probably meaning `Regular'
           */
          pfrface->style_name = phy_font->style_name;
    
          pfrface->num_fixed_sizes = 0;
          pfrface->available_sizes = NULL;
    
          pfrface->bbox         = phy_font->bbox;
          pfrface->units_per_EM = (FT_UShort)phy_font->outline_resolution;
          pfrface->ascender     = (FT_Short) phy_font->bbox.yMax;
          pfrface->descender    = (FT_Short) phy_font->bbox.yMin;
    
          pfrface->height = (FT_Short)( ( pfrface->units_per_EM * 12 ) / 10 );
          if ( pfrface->height < pfrface->ascender - pfrface->descender )
            pfrface->height = (FT_Short)( pfrface->ascender - pfrface->descender );
    
          if ( phy_font->num_strikes > 0 )
          {
            FT_UInt          n, count = phy_font->num_strikes;
            FT_Bitmap_Size*  size;
            PFR_Strike       strike;
            FT_Memory        memory = pfrface->memory;
    
    
            if ( FT_QNEW_ARRAY( pfrface->available_sizes, count ) )
              goto Exit;
    
            size   = pfrface->available_sizes;
            strike = phy_font->strikes;
            for ( n = 0; n < count; n++, size++, strike++ )
            {
              size->height = (FT_Short)strike->y_ppm;
              size->width  = (FT_Short)strike->x_ppm;
              size->size   = (FT_Pos)( strike->y_ppm << 6 );
              size->x_ppem = (FT_Pos)( strike->x_ppm << 6 );
              size->y_ppem = (FT_Pos)( strike->y_ppm << 6 );
            }
            pfrface->num_fixed_sizes = (FT_Int)count;
          }
    
          /* now compute maximum advance width */
          if ( ( phy_font->flags & PFR_PHY_PROPORTIONAL ) == 0 )
            pfrface->max_advance_width = (FT_Short)phy_font->standard_advance;
          else
          {
            FT_Int    max = 0;
            FT_UInt   count = phy_font->num_chars;
            PFR_Char  gchar = phy_font->chars;
    
    
            for ( ; count > 0; count--, gchar++ )
            {
              if ( max < gchar->advance )
                max = gchar->advance;
            }
    
            pfrface->max_advance_width = (FT_Short)max;
          }
    
          pfrface->max_advance_height = pfrface->height;
    
          pfrface->underline_position  = (FT_Short)( -pfrface->units_per_EM / 10 );
          pfrface->underline_thickness = (FT_Short)(  pfrface->units_per_EM / 30 );
    
          /* create charmap */
          {
            FT_CharMapRec  charmap;
    
    
            charmap.face        = pfrface;
            charmap.platform_id = TT_PLATFORM_MICROSOFT;
            charmap.encoding_id = TT_MS_ID_UNICODE_CS;
            charmap.encoding    = FT_ENCODING_UNICODE;
    
            error = FT_CMap_New( &pfr_cmap_class_rec, NULL, &charmap, NULL );
          }
    
          /* check whether we have loaded any kerning pairs */
          if ( phy_font->num_kern_pairs )
            pfrface->face_flags |= FT_FACE_FLAG_KERNING;
        }
    
      Exit:
        return error;
      }
    
    
      /*************************************************************************/
      /*************************************************************************/
      /*****                                                               *****/
      /*****                    SLOT OBJECT METHOD                         *****/
      /*****                                                               *****/
      /*************************************************************************/
      /*************************************************************************/
    
      FT_LOCAL_DEF( FT_Error )
      pfr_slot_init( FT_GlyphSlot  pfrslot )        /* PFR_Slot */
      {
        PFR_Slot        slot   = (PFR_Slot)pfrslot;
        FT_GlyphLoader  loader = pfrslot->internal->loader;
    
    
        pfr_glyph_init( &slot->glyph, loader );
    
        return 0;
      }
    
    
      FT_LOCAL_DEF( void )
      pfr_slot_done( FT_GlyphSlot  pfrslot )        /* PFR_Slot */
      {
        PFR_Slot  slot = (PFR_Slot)pfrslot;
    
    
        pfr_glyph_done( &slot->glyph );
      }
    
    
      FT_LOCAL_DEF( FT_Error )
      pfr_slot_load( FT_GlyphSlot  pfrslot,         /* PFR_Slot */
                     FT_Size       pfrsize,         /* PFR_Size */
                     FT_UInt       gindex,
                     FT_Int32      load_flags )
      {
        PFR_Slot     slot    = (PFR_Slot)pfrslot;
        PFR_Size     size    = (PFR_Size)pfrsize;
        FT_Error     error;
        PFR_Face     face    = (PFR_Face)pfrslot->face;
        PFR_Char     gchar;
        FT_Outline*  outline = &pfrslot->outline;
        FT_ULong     gps_offset;
    
    
        FT_TRACE1(( "pfr_slot_load: glyph index %d\n", gindex ));
    
        if ( gindex > 0 )
          gindex--;
    
        if ( !face || gindex >= face->phy_font.num_chars )
        {
          error = FT_THROW( Invalid_Argument );
          goto Exit;
        }
    
        /* try to load an embedded bitmap */
        if ( !( load_flags & ( FT_LOAD_NO_SCALE | FT_LOAD_NO_BITMAP ) ) )
        {
          error = pfr_slot_load_bitmap(
                    slot,
                    size,
                    gindex,
                    ( load_flags & FT_LOAD_BITMAP_METRICS_ONLY ) != 0 );
          if ( !error )
            goto Exit;
        }
    
        if ( load_flags & FT_LOAD_SBITS_ONLY )
        {
          error = FT_THROW( Invalid_Argument );
          goto Exit;
        }
    
        gchar               = face->phy_font.chars + gindex;
        pfrslot->format     = FT_GLYPH_FORMAT_OUTLINE;
        outline->n_points   = 0;
        outline->n_contours = 0;
        gps_offset          = face->header.gps_section_offset;
    
        /* load the glyph outline (FT_LOAD_NO_RECURSE isn't supported) */
        error = pfr_glyph_load( &slot->glyph, face->root.stream,
                                gps_offset, gchar->gps_offset, gchar->gps_size );
    
        if ( !error )
        {
          FT_BBox            cbox;
          FT_Glyph_Metrics*  metrics = &pfrslot->metrics;
          FT_Pos             advance;
          FT_UInt            em_metrics, em_outline;
          FT_Bool            scaling;
    
    
          scaling = FT_BOOL( !( load_flags & FT_LOAD_NO_SCALE ) );
    
          /* copy outline data */
          *outline = slot->glyph.loader->base.outline;
    
          outline->flags &= ~FT_OUTLINE_OWNER;
          outline->flags |= FT_OUTLINE_REVERSE_FILL;
    
          if ( pfrsize->metrics.y_ppem < 24 )
            outline->flags |= FT_OUTLINE_HIGH_PRECISION;
    
          /* compute the advance vector */
          metrics->horiAdvance = 0;
          metrics->vertAdvance = 0;
    
          advance    = gchar->advance;
          em_metrics = face->phy_font.metrics_resolution;
          em_outline = face->phy_font.outline_resolution;
    
          if ( em_metrics != em_outline )
            advance = FT_MulDiv( advance,
                                 (FT_Long)em_outline,
                                 (FT_Long)em_metrics );
    
          if ( face->phy_font.flags & PFR_PHY_VERTICAL )
            metrics->vertAdvance = advance;
          else
            metrics->horiAdvance = advance;
    
          pfrslot->linearHoriAdvance = metrics->horiAdvance;
          pfrslot->linearVertAdvance = metrics->vertAdvance;
    
          /* make up vertical metrics(?) */
          metrics->vertBearingX = 0;
          metrics->vertBearingY = 0;
    
    #if 0 /* some fonts seem to be broken here! */
    
          /* Apply the font matrix, if any.                 */
          /* TODO: Test existing fonts with unusual matrix  */
          /* whether we have to adjust Units per EM.        */
          {
            FT_Matrix font_matrix;
    
    
            font_matrix.xx = face->log_font.matrix[0] << 8;
            font_matrix.yx = face->log_font.matrix[1] << 8;
            font_matrix.xy = face->log_font.matrix[2] << 8;
            font_matrix.yy = face->log_font.matrix[3] << 8;
    
            FT_Outline_Transform( outline, &font_matrix );
          }
    #endif
    
          /* scale when needed */
          if ( scaling )
          {
            FT_Int      n;
            FT_Fixed    x_scale = pfrsize->metrics.x_scale;
            FT_Fixed    y_scale = pfrsize->metrics.y_scale;
            FT_Vector*  vec     = outline->points;
    
    
            /* scale outline points */
            for ( n = 0; n < outline->n_points; n++, vec++ )
            {
              vec->x = FT_MulFix( vec->x, x_scale );
              vec->y = FT_MulFix( vec->y, y_scale );
            }
    
            /* scale the advance */
            metrics->horiAdvance = FT_MulFix( metrics->horiAdvance, x_scale );
            metrics->vertAdvance = FT_MulFix( metrics->vertAdvance, y_scale );
          }
    
          /* compute the rest of the metrics */
          FT_Outline_Get_CBox( outline, &cbox );
    
          metrics->width        = cbox.xMax - cbox.xMin;
          metrics->height       = cbox.yMax - cbox.yMin;
          metrics->horiBearingX = cbox.xMin;
          metrics->horiBearingY = cbox.yMax - metrics->height;
        }
    
      Exit:
        return error;
      }
    
    
      /*************************************************************************/
      /*************************************************************************/
      /*****                                                               *****/
      /*****                      KERNING METHOD                           *****/
      /*****                                                               *****/
      /*************************************************************************/
      /*************************************************************************/
    
      FT_LOCAL_DEF( FT_Error )
      pfr_face_get_kerning( FT_Face     pfrface,        /* PFR_Face */
                            FT_UInt     glyph1,
                            FT_UInt     glyph2,
                            FT_Vector*  kerning )
      {
        PFR_Face     face     = (PFR_Face)pfrface;
        FT_Error     error    = FT_Err_Ok;
        PFR_PhyFont  phy_font = &face->phy_font;
        FT_UInt32    code1, code2, pair;
    
    
        kerning->x = 0;
        kerning->y = 0;
    
        /* PFR indexing skips .notdef, which becomes UINT_MAX */
        glyph1--;
        glyph2--;
    
        /* check the array bounds, .notdef is automatically out */
        if ( glyph1 >= phy_font->num_chars ||
             glyph2 >= phy_font->num_chars )
          goto Exit;
    
        /* convert glyph indices to character codes */
        code1 = phy_font->chars[glyph1].char_code;
        code2 = phy_font->chars[glyph2].char_code;
        pair  = PFR_KERN_INDEX( code1, code2 );
    
        /* now search the list of kerning items */
        {
          PFR_KernItem  item   = phy_font->kern_items;
          FT_Stream     stream = pfrface->stream;
    
    
          for ( ; item; item = item->next )
          {
            if ( pair >= item->pair1 && pair <= item->pair2 )
              goto FoundPair;
          }
          goto Exit;
    
        FoundPair: /* we found an item, now parse it and find the value if any */
          if ( FT_STREAM_SEEK( item->offset )                       ||
               FT_FRAME_ENTER( item->pair_count * item->pair_size ) )
            goto Exit;
    
          {
            FT_UInt    count       = item->pair_count;
            FT_UInt    size        = item->pair_size;
            FT_UInt    power       = 1 << FT_MSB( count );
            FT_UInt    probe       = power * size;
            FT_UInt    extra       = count - power;
            FT_Byte*   base        = stream->cursor;
            FT_Bool    twobytes    = FT_BOOL( item->flags & PFR_KERN_2BYTE_CHAR );
            FT_Bool    twobyte_adj = FT_BOOL( item->flags & PFR_KERN_2BYTE_ADJ  );
            FT_Byte*   p;
            FT_UInt32  cpair;
    
    
            if ( extra > 0 )
            {
              p = base + extra * size;
    
              if ( twobytes )
                cpair = FT_NEXT_ULONG( p );
              else
                cpair = PFR_NEXT_KPAIR( p );
    
              if ( cpair == pair )
                goto Found;
    
              if ( cpair < pair )
              {
                if ( twobyte_adj )
                  p += 2;
                else
                  p++;
                base = p;
              }
            }
    
            while ( probe > size )
            {
              probe >>= 1;
              p       = base + probe;
    
              if ( twobytes )
                cpair = FT_NEXT_ULONG( p );
              else
                cpair = PFR_NEXT_KPAIR( p );
    
              if ( cpair == pair )
                goto Found;
    
              if ( cpair < pair )
                base += probe;
            }
    
            p = base;
    
            if ( twobytes )
              cpair = FT_NEXT_ULONG( p );
            else
              cpair = PFR_NEXT_KPAIR( p );
    
            if ( cpair == pair )
            {
              FT_Int  value;
    
    
            Found:
              if ( twobyte_adj )
                value = FT_PEEK_SHORT( p );
              else
                value = p[0];
    
              kerning->x = item->base_adj + value;
            }
          }
    
          FT_FRAME_EXIT();
        }
    
      Exit:
        return error;
      }
    
    
    /* END */