Edit

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

Branch :

  • Show log

    Commit

  • Author : suzuki toshiya
    Date : 2010-07-09 12:26:33
    Hash : 840f208d
    Message : Use defined macros to set {platform,encoding}_id. * src/bdf/bdfdrivr.c: Include ttnameid.h and use macros to set charmap.{platfom,encoding}_id. * src/pcf/pcfdrivr.c: Ditto. * src/winfonts/winfnt.c: Ditto. * src/type1/t1objs.c: Ditto. * src/type42/t42objs.c: Ditto. * src/cff/cffobjs.c: Ditto. * src/pfr/pfrobjs.c: Ditto.

  • src/pfr/pfrobjs.c
  • /***************************************************************************/
    /*                                                                         */
    /*  pfrobjs.c                                                              */
    /*                                                                         */
    /*    FreeType PFR object methods (body).                                  */
    /*                                                                         */
    /*  Copyright 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2010 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 FT_OUTLINE_H
    #include FT_INTERNAL_DEBUG_H
    #include FT_TRUETYPE_IDS_H 
    
    #include "pfrerror.h"
    
    #undef  FT_COMPONENT
    #define FT_COMPONENT  trace_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->driver->root.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, FT_FACE_MEMORY( face ) );
    
        /* 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 );
    
    
        /* load the header and check it */
        error = pfr_header_load( &face->header, stream );
        if ( error )
          goto Exit;
    
        if ( !pfr_header_check( &face->header ) )
        {
          FT_TRACE4(( "pfr_face_init: not a valid PFR font\n" ));
          error = PFR_Err_Unknown_File_Format;
          goto Exit;
        }
    
        /* check face index */
        {
          FT_UInt  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 >= pfrface->num_faces )
        {
          FT_ERROR(( "pfr_face_init: invalid face index\n" ));
          error = PFR_Err_Invalid_Argument;
          goto Exit;
        }
    
        /* load the face */
        error = pfr_log_font_load(
                   &face->log_font, stream, face_index,
                   face->header.log_dir_offset,
                   FT_BOOL( face->header.phy_font_max_size_high != 0 ) );
        if ( error )
          goto Exit;
    
        /* now 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;
    
        /* now set up all root face fields */
        {
          PFR_PhyFont  phy_font = &face->phy_font;
    
    
          pfrface->face_index = face_index;
          pfrface->num_glyphs = phy_font->num_chars + 1;
          pfrface->face_flags = FT_FACE_FLAG_SCALABLE;
    
          /* if all characters point to the same gps_offset 0, 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 = 0;        /* not scalable */
              else
              {
                FT_ERROR(( "pfr_face_init: font doesn't contain glyphs\n" ));
                error = PFR_Err_Invalid_File_Format;
                goto Exit;
              }
            }
          }
    
          if ( (phy_font->flags & PFR_PHY_PROPORTIONAL) == 0 )
            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 == NULL )
            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 = 0;
    
          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->stream->memory;
    
    
            if ( FT_NEW_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_UShort)strike->y_ppm;
              size->width  = (FT_UShort)strike->x_ppm;
              size->size   = strike->y_ppm << 6;
              size->x_ppem = strike->x_ppm << 6;
              size->y_ppem = strike->y_ppm << 6;
            }
            pfrface->num_fixed_sizes = 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 );
    
    #if 0
            /* Select default charmap */
            if ( pfrface->num_charmaps )
              pfrface->charmap = pfrface->charmaps[0];
    #endif
          }
    
          /* check whether we've 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;
    
    
        if ( gindex > 0 )
          gindex--;
    
        if ( !face || gindex >= face->phy_font.num_chars )
        {
          error = PFR_Err_Invalid_Argument;
          goto Exit;
        }
    
        /* try to load an embedded bitmap */
        if ( ( load_flags & ( FT_LOAD_NO_SCALE | FT_LOAD_NO_BITMAP ) ) == 0 )
        {
          error = pfr_slot_load_bitmap( slot, size, gindex );
          if ( error == 0 )
            goto Exit;
        }
    
        if ( load_flags & FT_LOAD_SBITS_ONLY )
        {
          error = PFR_Err_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_Int             em_metrics, em_outline;
          FT_Bool            scaling;
    
    
          scaling = FT_BOOL( ( load_flags & FT_LOAD_NO_SCALE ) == 0 );
    
          /* copy outline data */
          *outline = slot->glyph.loader->base.outline;
    
          outline->flags &= ~FT_OUTLINE_OWNER;
          outline->flags |= FT_OUTLINE_REVERSE_FILL;
    
          if ( size && 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, em_outline, 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    = PFR_Err_Ok;
        PFR_PhyFont  phy_font = &face->phy_font;
        FT_UInt32    code1, code2, pair;
    
    
        kerning->x = 0;
        kerning->y = 0;
    
        if ( glyph1 > 0 )
          glyph1--;
    
        if ( glyph2 > 0 )
          glyph2--;
    
        /* convert glyph indices to character codes */
        if ( glyph1 > phy_font->num_chars ||
             glyph2 > phy_font->num_chars )
          goto Exit;
    
        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       = (FT_UInt)ft_highpow2( (FT_UInt32)count );
            FT_UInt    probe       = power * size;
            FT_UInt    extra       = count - power;
            FT_Byte*   base        = stream->cursor;
            FT_Bool    twobytes    = FT_BOOL( item->flags & 1 );
            FT_Bool    twobyte_adj = FT_BOOL( item->flags & 2 );
            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 */