tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

pfrobjs.c (17339B)


      1 /****************************************************************************
      2 *
      3 * pfrobjs.c
      4 *
      5 *   FreeType PFR object methods (body).
      6 *
      7 * Copyright (C) 2002-2025 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 %u\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    gps_offset = face->header.gps_section_offset;
    360 
    361    /* load the glyph outline (FT_LOAD_NO_RECURSE isn't supported) */
    362    error = pfr_glyph_load( &slot->glyph, face->root.stream,
    363                            gps_offset, gchar->gps_offset, gchar->gps_size );
    364 
    365    if ( !error )
    366    {
    367      FT_BBox            cbox;
    368      FT_Glyph_Metrics*  metrics = &pfrslot->metrics;
    369      FT_Pos             advance;
    370      FT_UInt            em_metrics, em_outline;
    371 
    372 
    373      pfrslot->format = FT_GLYPH_FORMAT_OUTLINE;
    374 
    375      /* copy outline data */
    376      *outline = slot->glyph.loader->base.outline;
    377 
    378      outline->flags &= ~FT_OUTLINE_OWNER;
    379      outline->flags |= FT_OUTLINE_REVERSE_FILL;
    380 
    381      if ( pfrsize->metrics.y_ppem < 24 )
    382        outline->flags |= FT_OUTLINE_HIGH_PRECISION;
    383 
    384      /* compute the advance vector */
    385      metrics->horiAdvance = 0;
    386      metrics->vertAdvance = 0;
    387 
    388      advance    = gchar->advance;
    389      em_metrics = face->phy_font.metrics_resolution;
    390      em_outline = face->phy_font.outline_resolution;
    391 
    392      if ( em_metrics != em_outline )
    393        advance = FT_MulDiv( advance,
    394                             (FT_Long)em_outline,
    395                             (FT_Long)em_metrics );
    396 
    397      if ( face->phy_font.flags & PFR_PHY_VERTICAL )
    398        metrics->vertAdvance = advance;
    399      else
    400        metrics->horiAdvance = advance;
    401 
    402      pfrslot->linearHoriAdvance = metrics->horiAdvance;
    403      pfrslot->linearVertAdvance = metrics->vertAdvance;
    404 
    405      /* make up vertical metrics(?) */
    406      metrics->vertBearingX = 0;
    407      metrics->vertBearingY = 0;
    408 
    409 #if 0 /* some fonts seem to be broken here! */
    410 
    411      /* Apply the font matrix, if any.                 */
    412      /* TODO: Test existing fonts with unusual matrix  */
    413      /* whether we have to adjust Units per EM.        */
    414      {
    415        FT_Matrix font_matrix;
    416 
    417 
    418        font_matrix.xx = face->log_font.matrix[0] << 8;
    419        font_matrix.yx = face->log_font.matrix[1] << 8;
    420        font_matrix.xy = face->log_font.matrix[2] << 8;
    421        font_matrix.yy = face->log_font.matrix[3] << 8;
    422 
    423        FT_Outline_Transform( outline, &font_matrix );
    424      }
    425 #endif
    426 
    427      /* scale when needed */
    428      if ( !( load_flags & FT_LOAD_NO_SCALE ) )
    429      {
    430        FT_Int      n;
    431        FT_Fixed    x_scale = pfrsize->metrics.x_scale;
    432        FT_Fixed    y_scale = pfrsize->metrics.y_scale;
    433        FT_Vector*  vec     = outline->points;
    434 
    435 
    436        /* scale outline points */
    437        for ( n = 0; n < outline->n_points; n++, vec++ )
    438        {
    439          vec->x = FT_MulFix( vec->x, x_scale );
    440          vec->y = FT_MulFix( vec->y, y_scale );
    441        }
    442 
    443        /* scale the advance */
    444        metrics->horiAdvance = FT_MulFix( metrics->horiAdvance, x_scale );
    445        metrics->vertAdvance = FT_MulFix( metrics->vertAdvance, y_scale );
    446      }
    447 
    448      /* compute the rest of the metrics */
    449      FT_Outline_Get_CBox( outline, &cbox );
    450 
    451      metrics->width        = cbox.xMax - cbox.xMin;
    452      metrics->height       = cbox.yMax - cbox.yMin;
    453      metrics->horiBearingX = cbox.xMin;
    454      metrics->horiBearingY = cbox.yMax - metrics->height;
    455    }
    456 
    457  Exit:
    458    return error;
    459  }
    460 
    461 
    462  /*************************************************************************/
    463  /*************************************************************************/
    464  /*****                                                               *****/
    465  /*****                      KERNING METHOD                           *****/
    466  /*****                                                               *****/
    467  /*************************************************************************/
    468  /*************************************************************************/
    469 
    470  FT_LOCAL_DEF( FT_Error )
    471  pfr_face_get_kerning( FT_Face     pfrface,        /* PFR_Face */
    472                        FT_UInt     glyph1,
    473                        FT_UInt     glyph2,
    474                        FT_Vector*  kerning )
    475  {
    476    PFR_Face     face     = (PFR_Face)pfrface;
    477    FT_Error     error    = FT_Err_Ok;
    478    PFR_PhyFont  phy_font = &face->phy_font;
    479    FT_UInt32    code1, code2, pair;
    480 
    481 
    482    kerning->x = 0;
    483    kerning->y = 0;
    484 
    485    /* PFR indexing skips .notdef, which becomes UINT_MAX */
    486    glyph1--;
    487    glyph2--;
    488 
    489    /* check the array bounds, .notdef is automatically out */
    490    if ( glyph1 >= phy_font->num_chars ||
    491         glyph2 >= phy_font->num_chars )
    492      goto Exit;
    493 
    494    /* convert glyph indices to character codes */
    495    code1 = phy_font->chars[glyph1].char_code;
    496    code2 = phy_font->chars[glyph2].char_code;
    497    pair  = PFR_KERN_INDEX( code1, code2 );
    498 
    499    /* now search the list of kerning items */
    500    {
    501      PFR_KernItem  item   = phy_font->kern_items;
    502      FT_Stream     stream = pfrface->stream;
    503 
    504 
    505      for ( ; item; item = item->next )
    506      {
    507        if ( pair >= item->pair1 && pair <= item->pair2 )
    508          goto FoundPair;
    509      }
    510      goto Exit;
    511 
    512    FoundPair: /* we found an item, now parse it and find the value if any */
    513      if ( FT_STREAM_SEEK( item->offset )                       ||
    514           FT_FRAME_ENTER( item->pair_count * item->pair_size ) )
    515        goto Exit;
    516 
    517      {
    518        FT_UInt    count       = item->pair_count;
    519        FT_UInt    size        = item->pair_size;
    520        FT_UInt    power       = 1 << FT_MSB( count );
    521        FT_UInt    probe       = power * size;
    522        FT_UInt    extra       = count - power;
    523        FT_Byte*   base        = stream->cursor;
    524        FT_Bool    twobytes    = FT_BOOL( item->flags & PFR_KERN_2BYTE_CHAR );
    525        FT_Bool    twobyte_adj = FT_BOOL( item->flags & PFR_KERN_2BYTE_ADJ  );
    526        FT_Byte*   p;
    527        FT_UInt32  cpair;
    528 
    529 
    530        if ( extra > 0 )
    531        {
    532          p = base + extra * size;
    533 
    534          if ( twobytes )
    535            cpair = FT_NEXT_ULONG( p );
    536          else
    537            cpair = PFR_NEXT_KPAIR( p );
    538 
    539          if ( cpair == pair )
    540            goto Found;
    541 
    542          if ( cpair < pair )
    543          {
    544            if ( twobyte_adj )
    545              p += 2;
    546            else
    547              p++;
    548            base = p;
    549          }
    550        }
    551 
    552        while ( probe > size )
    553        {
    554          probe >>= 1;
    555          p       = base + probe;
    556 
    557          if ( twobytes )
    558            cpair = FT_NEXT_ULONG( p );
    559          else
    560            cpair = PFR_NEXT_KPAIR( p );
    561 
    562          if ( cpair == pair )
    563            goto Found;
    564 
    565          if ( cpair < pair )
    566            base += probe;
    567        }
    568 
    569        p = base;
    570 
    571        if ( twobytes )
    572          cpair = FT_NEXT_ULONG( p );
    573        else
    574          cpair = PFR_NEXT_KPAIR( p );
    575 
    576        if ( cpair == pair )
    577        {
    578          FT_Int  value;
    579 
    580 
    581        Found:
    582          if ( twobyte_adj )
    583            value = FT_PEEK_SHORT( p );
    584          else
    585            value = p[0];
    586 
    587          kerning->x = item->base_adj + value;
    588        }
    589      }
    590 
    591      FT_FRAME_EXIT();
    592    }
    593 
    594  Exit:
    595    return error;
    596  }
    597 
    598 
    599 /* END */