freetype-commit
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Git][freetype/freetype][master] Add support for kerning from 'GPOS' tab


From: Werner Lemberg (@wl)
Subject: [Git][freetype/freetype][master] Add support for kerning from 'GPOS' tables.
Date: Sat, 27 Jan 2024 09:55:53 +0000

Werner Lemberg pushed to branch master at FreeType / FreeType

Commits:

  • 8f286c86
    by David Saltzman at 2024-01-27T10:55:04+01:00
    Add support for kerning from 'GPOS' tables.
    
    This commit adds support for kerning from 'GPOS' tables, while maintaining
    support for basic 'kern' tables.  `FT_HAS_KERNING` will be true for a font
    with either available and `FT_Get_Kerning` will still use the basic 'kern'
    table data if avilable, otherwise check the GPOS 'kern' feature.
    
    This feature is disabled by default; it can be enabled with the
    `TT_CONFIG_OPTION_GPOS_KERNING` flag.
    
    Only basic kerning (pair positioning with just an x advance) is supported
    from the GPOS layout features; support for that was added to make the
    existing `FT_Get_Kerning` API more consistently functional.  FreeType does
    not intend to extend itself to further GPOS functionality though; a
    higher-level library like HarfBuzz can be used instead for that.
    
    * include/freetype/config/ftoption.h, include/devel/ftoption.h
    (TT_CONFIG_OPTION_GPOS_KERNING): New configuration option.
    
    * include/freetype/internal/fttrace.h: Add `ttgpos` trace handler.
    
    * include/freetype/internal/sfnt.h (SFNT_Interface): Add `load_gpos` and
    `get_gpos_kerning` fields.
    (FT_DEFINE_SFNT_INTERFACE): Updated.
    
    * include/freetype/internal/tttypes.h: Include `fttypes.h`.
    (TT_FaceRec) [TT_CONFIG_OPTION_GPOS_KERNING]: Add `gpos_table` and
    `gpos_kerning_available` fields.
    
    * src/sfnt/ttgpos.c, src/sfnt/ttgpos.h: New files.
    
    * src/sfnt/sfdriver.c [TT_CONFIG_OPTION_GPOS_KERNING]: Include `ttgpos.h`.
    (sfnt_interface): Updated.
    
    * src/sfnt/sfnt.c: Include `ttgpos.c`.
    
    * src/sfnt/sfobjs.c [TT_CONFIG_OPTION_GPOS_KERNING]: Include `ttgpos.h`.
    (sfnt_load_face) [TT_CONFIG_OPTION_GPOS_KERNING]: Load and free GPOS kerning
    data; check GPOS kerning availability.
    
    * src/truetype/ttdriver.c (tt_get_kerning): Use GPOS kerning if there's no
    'kern' table.
    

13 changed files:

Changes:

  • devel/ftoption.h
    ... ... @@ -757,6 +757,22 @@ FT_BEGIN_HEADER
    757 757
     #endif
    
    758 758
     
    
    759 759
     
    
    760
    +  /**************************************************************************
    
    761
    +   *
    
    762
    +   * Option `TT_CONFIG_OPTION_GPOS_KERNING` enables a basic GPOS kerning
    
    763
    +   * implementation (for TrueType fonts only).  With this defined, FreeType
    
    764
    +   * is able to get kerning pair data from the GPOS 'kern' feature as well as
    
    765
    +   * legacy 'kern' tables; without this defined, FreeType will only be able
    
    766
    +   * to use legacy 'kern' tables.
    
    767
    +   *
    
    768
    +   * Note that FreeType does not support more advanced GPOS layout features;
    
    769
    +   * even the 'kern' feature implemented here doesn't handle more
    
    770
    +   * sophisticated kerning variants.  Use a higher-level library like
    
    771
    +   * HarfBuzz instead for that.
    
    772
    +   */
    
    773
    +#define TT_CONFIG_OPTION_GPOS_KERNING
    
    774
    +
    
    775
    +
    
    760 776
       /*************************************************************************/
    
    761 777
       /*************************************************************************/
    
    762 778
       /****                                                                 ****/
    

  • docs/CHANGES
    ... ... @@ -11,6 +11,16 @@ CHANGES BETWEEN 2.13.2 and 2.13.3 (202Y-Mmm-DD)
    11 11
         large performance improvement.  The rendering speed  has increased
    
    12 12
         and even doubled for very complex glyphs.
    
    13 13
     
    
    14
    +  - If the new configuration option `TT_CONFIG_OPTION_GPOS_KERNING` is
    
    15
    +    defined,  `FT_Get_Kerning`  understands rudimentary  GPOS  kerning
    
    16
    +    (for TrueType fonts  only).  This is not enabled  by default since
    
    17
    +    its usage  is very  limited, mainly  for legacy  applications that
    
    18
    +    have to support TrueType fonts automatically converted from 'kern'
    
    19
    +    tables to GPOS kerning.  If you need proper (GPOS) kerning support
    
    20
    +    please use a higher-level library like HarfBuzz.
    
    21
    +
    
    22
    +    Code contributed by David Saltzman <davidbsaltzman@gmail.com>.
    
    23
    +
    
    14 24
     
    
    15 25
     ======================================================================
    
    16 26
     
    

  • include/freetype/config/ftoption.h
    ... ... @@ -757,6 +757,22 @@ FT_BEGIN_HEADER
    757 757
     #endif
    
    758 758
     
    
    759 759
     
    
    760
    +  /**************************************************************************
    
    761
    +   *
    
    762
    +   * Option `TT_CONFIG_OPTION_GPOS_KERNING` enables a basic GPOS kerning
    
    763
    +   * implementation (for TrueType fonts only).  With this defined, FreeType
    
    764
    +   * is able to get kerning pair data from the GPOS 'kern' feature as well as
    
    765
    +   * legacy 'kern' tables; without this defined, FreeType will only be able
    
    766
    +   * to use legacy 'kern' tables.
    
    767
    +   *
    
    768
    +   * Note that FreeType does not support more advanced GPOS layout features;
    
    769
    +   * even the 'kern' feature implemented here doesn't handle more
    
    770
    +   * sophisticated kerning variants.  Use a higher-level library like
    
    771
    +   * HarfBuzz instead for that.
    
    772
    +   */
    
    773
    +/* #define TT_CONFIG_OPTION_GPOS_KERNING */
    
    774
    +
    
    775
    +
    
    760 776
       /*************************************************************************/
    
    761 777
       /*************************************************************************/
    
    762 778
       /****                                                                 ****/
    

  • include/freetype/freetype.h
    ... ... @@ -1322,9 +1322,13 @@ FT_BEGIN_HEADER
    1322 1322
        *   FT_FACE_FLAG_KERNING ::
    
    1323 1323
        *     The face contains kerning information.  If set, the kerning distance
    
    1324 1324
        *     can be retrieved using the function @FT_Get_Kerning.  Otherwise the
    
    1325
    -   *     function always returns the vector (0,0).  Note that FreeType
    
    1326
    -   *     doesn't handle kerning data from the SFNT 'GPOS' table (as present
    
    1327
    -   *     in many OpenType fonts).
    
    1325
    +   *     function always returns the vector (0,0).
    
    1326
    +   *
    
    1327
    +   *     Note that for TrueType fonts only, FreeType supports both the 'kern'
    
    1328
    +   *     table and the basic, pair-wise kerning feature from the 'GPOS' table
    
    1329
    +   *     (with `TT_CONFIG_OPTION_GPOS_KERNING` enabled), though FreeType does
    
    1330
    +   *     not support the more advanced GPOS layout features; use a library
    
    1331
    +   *     like HarfBuzz for those instead.
    
    1328 1332
        *
    
    1329 1333
        *   FT_FACE_FLAG_FAST_GLYPHS ::
    
    1330 1334
        *     THIS FLAG IS DEPRECATED.  DO NOT USE OR TEST IT.
    
    ... ... @@ -4058,9 +4062,26 @@ FT_BEGIN_HEADER
    4058 4062
        *   out of the scope of this API function -- they can be implemented
    
    4059 4063
        *   through format-specific interfaces.
    
    4060 4064
        *
    
    4061
    -   *   Kerning for OpenType fonts implemented in a 'GPOS' table is not
    
    4062
    -   *   supported; use @FT_HAS_KERNING to find out whether a font has data
    
    4063
    -   *   that can be extracted with `FT_Get_Kerning`.
    
    4065
    +   *   Note that, for TrueType fonts only, this can extract data from both
    
    4066
    +   *   the 'kern' table and the basic, pair-wise kerning feature from the
    
    4067
    +   *   GPOS table (with `TT_CONFIG_OPTION_GPOS_KERNING` enabled), though
    
    4068
    +   *   FreeType does not support the more advanced GPOS layout features; use
    
    4069
    +   *   a library like HarfBuzz for those instead.  If a font has both a
    
    4070
    +   *   'kern' table and kern features of a GPOS table, the 'kern' table will
    
    4071
    +   *   be used.
    
    4072
    +   *
    
    4073
    +   *   Also note for right-to-left scripts, the functionality may differ for
    
    4074
    +   *   fonts with GPOS tables vs. 'kern' tables.  For GPOS, right-to-left
    
    4075
    +   *   fonts typically use both a placement offset and an advance for pair
    
    4076
    +   *   positioning, which this API does not support, so it would output
    
    4077
    +   *   kerning values of zero; though if the right-to-left font used only
    
    4078
    +   *   advances in GPOS pair positioning, then this API could output kerning
    
    4079
    +   *   values for it, but it would use `left_glyph` to mean the first glyph
    
    4080
    +   *   for that case.  Whereas 'kern' tables are always advance-only and
    
    4081
    +   *   always store the left glyph first.
    
    4082
    +   *
    
    4083
    +   *   Use @FT_HAS_KERNING to find out whether a font has data that can be
    
    4084
    +   *   extracted with `FT_Get_Kerning`.
    
    4064 4085
        */
    
    4065 4086
       FT_EXPORT( FT_Error )
    
    4066 4087
       FT_Get_Kerning( FT_Face     face,
    

  • include/freetype/internal/fttrace.h
    ... ... @@ -64,6 +64,7 @@ FT_TRACE_DEF( ttbdf ) /* TrueType embedded BDF (ttbdf.c) */
    64 64
     FT_TRACE_DEF( ttcmap )    /* charmap handler         (ttcmap.c)   */
    
    65 65
     FT_TRACE_DEF( ttcolr )    /* glyph layer table       (ttcolr.c)   */
    
    66 66
     FT_TRACE_DEF( ttcpal )    /* color palette table     (ttcpal.c)   */
    
    67
    +FT_TRACE_DEF( ttgpos )    /* GPOS handler            (ttgpos.c)   */
    
    67 68
     FT_TRACE_DEF( ttsvg )     /* OpenType SVG table      (ttsvg.c)    */
    
    68 69
     FT_TRACE_DEF( ttkern )    /* kerning handler         (ttkern.c)   */
    
    69 70
     FT_TRACE_DEF( ttload )    /* basic TrueType tables   (ttload.c)   */
    

  • include/freetype/internal/sfnt.h
    ... ... @@ -924,6 +924,7 @@ FT_BEGIN_HEADER
    924 924
         /* this field was called `load_kerning' up to version 2.1.10 */
    
    925 925
         TT_Load_Table_Func  load_kern;
    
    926 926
     
    
    927
    +    TT_Load_Table_Func  load_gpos;
    
    927 928
         TT_Load_Table_Func  load_gasp;
    
    928 929
         TT_Load_Table_Func  load_pclt;
    
    929 930
     
    
    ... ... @@ -944,6 +945,8 @@ FT_BEGIN_HEADER
    944 945
     
    
    945 946
         /* new elements introduced after version 2.1.10 */
    
    946 947
     
    
    948
    +    TT_Face_GetKerningFunc  get_gpos_kerning;
    
    949
    +
    
    947 950
         /* load the font directory, i.e., the offset table and */
    
    948 951
         /* the table directory                                 */
    
    949 952
         TT_Load_Table_Func    load_font_dir;
    
    ... ... @@ -1002,6 +1005,7 @@ FT_BEGIN_HEADER
    1002 1005
               load_name_,                    \
    
    1003 1006
               free_name_,                    \
    
    1004 1007
               load_kern_,                    \
    
    1008
    +          load_gpos_,                    \
    
    1005 1009
               load_gasp_,                    \
    
    1006 1010
               load_pclt_,                    \
    
    1007 1011
               load_bhed_,                    \
    
    ... ... @@ -1009,6 +1013,7 @@ FT_BEGIN_HEADER
    1009 1013
               get_psname_,                   \
    
    1010 1014
               free_psnames_,                 \
    
    1011 1015
               get_kerning_,                  \
    
    1016
    +          get_gpos_kerning_,             \
    
    1012 1017
               load_font_dir_,                \
    
    1013 1018
               load_hmtx_,                    \
    
    1014 1019
               load_eblc_,                    \
    
    ... ... @@ -1050,6 +1055,7 @@ FT_BEGIN_HEADER
    1050 1055
         load_name_,                          \
    
    1051 1056
         free_name_,                          \
    
    1052 1057
         load_kern_,                          \
    
    1058
    +    load_gpos_,                          \
    
    1053 1059
         load_gasp_,                          \
    
    1054 1060
         load_pclt_,                          \
    
    1055 1061
         load_bhed_,                          \
    
    ... ... @@ -1057,6 +1063,7 @@ FT_BEGIN_HEADER
    1057 1063
         get_psname_,                         \
    
    1058 1064
         free_psnames_,                       \
    
    1059 1065
         get_kerning_,                        \
    
    1066
    +    get_gpos_kerning_,                   \
    
    1060 1067
         load_font_dir_,                      \
    
    1061 1068
         load_hmtx_,                          \
    
    1062 1069
         load_eblc_,                          \
    

  • include/freetype/internal/tttypes.h
    ... ... @@ -24,6 +24,7 @@
    24 24
     #include <freetype/tttables.h>
    
    25 25
     #include <freetype/internal/ftobjs.h>
    
    26 26
     #include <freetype/ftcolor.h>
    
    27
    +#include "freetype/fttypes.h"
    
    27 28
     
    
    28 29
     #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
    
    29 30
     #include <freetype/ftmm.h>
    
    ... ... @@ -1581,6 +1582,11 @@ FT_BEGIN_HEADER
    1581 1582
         FT_UInt32             kern_avail_bits;
    
    1582 1583
         FT_UInt32             kern_order_bits;
    
    1583 1584
     
    
    1585
    +#ifdef TT_CONFIG_OPTION_GPOS_KERNING
    
    1586
    +    FT_Byte*              gpos_table;
    
    1587
    +    FT_Bool               gpos_kerning_available;
    
    1588
    +#endif
    
    1589
    +
    
    1584 1590
     #ifdef TT_CONFIG_OPTION_BDF
    
    1585 1591
         TT_BDFRec             bdf;
    
    1586 1592
     #endif /* TT_CONFIG_OPTION_BDF */
    

  • src/sfnt/sfdriver.c
    ... ... @@ -49,6 +49,10 @@
    49 49
     #include <freetype/internal/services/svbdf.h>
    
    50 50
     #endif
    
    51 51
     
    
    52
    +#ifdef TT_CONFIG_OPTION_GPOS_KERNING
    
    53
    +#include "ttgpos.h"
    
    54
    +#endif
    
    55
    +
    
    52 56
     #include "ttcmap.h"
    
    53 57
     #include "ttkern.h"
    
    54 58
     #include "ttmtx.h"
    
    ... ... @@ -1249,6 +1253,12 @@
    1249 1253
     #define PUT_PS_NAMES( a )  a
    
    1250 1254
     #else
    
    1251 1255
     #define PUT_PS_NAMES( a )  NULL
    
    1256
    +#endif
    
    1257
    +
    
    1258
    +#ifdef TT_CONFIG_OPTION_GPOS_KERNING
    
    1259
    +#define PUT_GPOS_KERNING( a )  a
    
    1260
    +#else
    
    1261
    +#define PUT_GPOS_KERNING( a )  NULL
    
    1252 1262
     #endif
    
    1253 1263
     
    
    1254 1264
       FT_DEFINE_SFNT_INTERFACE(
    
    ... ... @@ -1274,6 +1284,8 @@
    1274 1284
         tt_face_free_name,      /* TT_Free_Table_Func      free_name       */
    
    1275 1285
     
    
    1276 1286
         tt_face_load_kern,      /* TT_Load_Table_Func      load_kern       */
    
    1287
    +    PUT_GPOS_KERNING( tt_face_load_gpos ),
    
    1288
    +                            /* TT_Load_Table_Func      load_gpos       */
    
    1277 1289
         tt_face_load_gasp,      /* TT_Load_Table_Func      load_gasp       */
    
    1278 1290
         tt_face_load_pclt,      /* TT_Load_Table_Func      load_init       */
    
    1279 1291
     
    
    ... ... @@ -1292,6 +1304,9 @@
    1292 1304
         /* since version 2.1.8 */
    
    1293 1305
         tt_face_get_kerning,    /* TT_Face_GetKerningFunc  get_kerning     */
    
    1294 1306
     
    
    1307
    +    PUT_GPOS_KERNING( tt_face_get_gpos_kerning ),
    
    1308
    +                           /* TT_Face_GetKerningFunc  get_gpos_kerning */
    
    1309
    +
    
    1295 1310
         /* since version 2.2 */
    
    1296 1311
         tt_face_load_font_dir,  /* TT_Load_Table_Func      load_font_dir   */
    
    1297 1312
         tt_face_load_hmtx,      /* TT_Load_Metrics_Func    load_hmtx       */
    

  • src/sfnt/sfnt.c
    ... ... @@ -29,6 +29,7 @@
    29 29
     #include "ttcpal.c"
    
    30 30
     #include "ttsvg.c"
    
    31 31
     
    
    32
    +#include "ttgpos.c"
    
    32 33
     #include "ttkern.c"
    
    33 34
     #include "ttload.c"
    
    34 35
     #include "ttmtx.c"
    

  • src/sfnt/sfobjs.c
    ... ... @@ -40,6 +40,10 @@
    40 40
     #include "ttbdf.h"
    
    41 41
     #endif
    
    42 42
     
    
    43
    +#ifdef TT_CONFIG_OPTION_GPOS_KERNING
    
    44
    +#include "ttgpos.h"
    
    45
    +#endif
    
    46
    +
    
    43 47
     
    
    44 48
       /**************************************************************************
    
    45 49
        *
    
    ... ... @@ -1026,6 +1030,10 @@
    1026 1030
         LOAD_( gasp );
    
    1027 1031
         LOAD_( kern );
    
    1028 1032
     
    
    1033
    +#ifdef TT_CONFIG_OPTION_GPOS_KERNING
    
    1034
    +    LOAD_( gpos );
    
    1035
    +#endif
    
    1036
    +
    
    1029 1037
         face->root.num_glyphs = face->max_profile.numGlyphs;
    
    1030 1038
     
    
    1031 1039
         /* Bit 8 of the `fsSelection' field in the `OS/2' table denotes  */
    
    ... ... @@ -1119,7 +1127,11 @@
    1119 1127
             flags |= FT_FACE_FLAG_VERTICAL;
    
    1120 1128
     
    
    1121 1129
           /* kerning available ? */
    
    1122
    -      if ( TT_FACE_HAS_KERNING( face ) )
    
    1130
    +      if ( TT_FACE_HAS_KERNING( face )
    
    1131
    +#ifdef TT_CONFIG_OPTION_GPOS_KERNING
    
    1132
    +           || face->gpos_kerning_available
    
    1133
    +#endif
    
    1134
    +         )
    
    1123 1135
             flags |= FT_FACE_FLAG_KERNING;
    
    1124 1136
     
    
    1125 1137
     #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
    
    ... ... @@ -1470,6 +1482,11 @@
    1470 1482
         /* freeing the kerning table */
    
    1471 1483
         tt_face_done_kern( face );
    
    1472 1484
     
    
    1485
    +#ifdef TT_CONFIG_OPTION_GPOS_KERNING
    
    1486
    +    /* freeing the GPOS table */
    
    1487
    +    tt_face_done_gpos( face );
    
    1488
    +#endif
    
    1489
    +
    
    1473 1490
         /* freeing the collection table */
    
    1474 1491
         FT_FREE( face->ttc_header.offsets );
    
    1475 1492
         face->ttc_header.count = 0;
    

  • src/sfnt/ttgpos.c
    1
    +/****************************************************************************
    
    2
    + *
    
    3
    + * ttgpos.c
    
    4
    + *
    
    5
    + *   Load the TrueType GPOS table.  The only GPOS layout feature this
    
    6
    + *   currently supports is kerning, from x advances in the pair adjustment
    
    7
    + *   layout feature.
    
    8
    + *
    
    9
    + *   Parts of the implementation were adapted from:
    
    10
    + *   https://github.com/nothings/stb/blob/master/stb_truetype.h
    
    11
    + *
    
    12
    + *   GPOS spec reference available at:
    
    13
    + *   https://learn.microsoft.com/en-us/typography/opentype/spec/gpos
    
    14
    + *
    
    15
    + * Copyright (C) 2024 by
    
    16
    + * David Saltzman
    
    17
    + *
    
    18
    + * This file is part of the FreeType project, and may only be used,
    
    19
    + * modified, and distributed under the terms of the FreeType project
    
    20
    + * license, LICENSE.TXT.  By continuing to use, modify, or distribute
    
    21
    + * this file you indicate that you have read the license and
    
    22
    + * understand and accept it fully.
    
    23
    + */
    
    24
    +
    
    25
    +#include <freetype/internal/ftdebug.h>
    
    26
    +#include <freetype/internal/ftstream.h>
    
    27
    +#include <freetype/tttags.h>
    
    28
    +#include "freetype/fttypes.h"
    
    29
    +#include "freetype/internal/ftobjs.h"
    
    30
    +#include "ttgpos.h"
    
    31
    +
    
    32
    +
    
    33
    +#ifdef TT_CONFIG_OPTION_GPOS_KERNING
    
    34
    +
    
    35
    +  /**************************************************************************
    
    36
    +   *
    
    37
    +   * The macro FT_COMPONENT is used in trace mode.  It is an implicit
    
    38
    +   * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log
    
    39
    +   * messages during execution.
    
    40
    +   */
    
    41
    +#undef  FT_COMPONENT
    
    42
    +#define FT_COMPONENT  ttgpos
    
    43
    +
    
    44
    +
    
    45
    +  typedef enum  coverage_table_format_type_
    
    46
    +  {
    
    47
    +    COVERAGE_TABLE_FORMAT_LIST  = 1,
    
    48
    +    COVERAGE_TABLE_FORMAT_RANGE = 2
    
    49
    +
    
    50
    +  } coverage_table_format_type;
    
    51
    +
    
    52
    +  typedef enum  class_def_table_format_type_
    
    53
    +  {
    
    54
    +    CLASS_DEF_TABLE_FORMAT_ARRAY        = 1,
    
    55
    +    CLASS_DEF_TABLE_FORMAT_RANGE_GROUPS = 2
    
    56
    +
    
    57
    +  } class_def_table_format_type;
    
    58
    +
    
    59
    +  typedef enum  gpos_lookup_type_
    
    60
    +  {
    
    61
    +    GPOS_LOOKUP_TYPE_SINGLE_ADJUSTMENT           = 1,
    
    62
    +    GPOS_LOOKUP_TYPE_PAIR_ADJUSTMENT             = 2,
    
    63
    +    GPOS_LOOKUP_TYPE_CURSIVE_ATTACHMENT          = 3,
    
    64
    +    GPOS_LOOKUP_TYPE_MARK_TO_BASE_ATTACHMENT     = 4,
    
    65
    +    GPOS_LOOKUP_TYPE_MARK_TO_LIGATURE_ATTACHMENT = 5,
    
    66
    +    GPOS_LOOKUP_TYPE_MARK_TO_MARK_ATTACHMENT     = 6,
    
    67
    +    GPOS_LOOKUP_TYPE_CONTEXT_POSITIONING         = 7,
    
    68
    +    GPOS_LOOKUP_TYPE_CHAINED_CONTEXT_POSITIONING = 8,
    
    69
    +    GPOS_LOOKUP_TYPE_EXTENSION_POSITIONING       = 9
    
    70
    +
    
    71
    +  } gpos_lookup_type;
    
    72
    +
    
    73
    +  typedef enum  gpos_pair_adjustment_format_
    
    74
    +  {
    
    75
    +    GPOS_PAIR_ADJUSTMENT_FORMAT_GLYPH_PAIR = 1,
    
    76
    +    GPOS_PAIR_ADJUSTMENT_FORMAT_CLASS_PAIR = 2
    
    77
    +
    
    78
    +  } gpos_pair_adjustment_format;
    
    79
    +
    
    80
    +  typedef enum  gpos_value_format_bitmask_
    
    81
    +  {
    
    82
    +    GPOS_VALUE_FORMAT_NONE               = 0x0000,
    
    83
    +    GPOS_VALUE_FORMAT_X_PLACEMENT        = 0x0001,
    
    84
    +    GPOS_VALUE_FORMAT_Y_PLACEMENT        = 0x0002,
    
    85
    +    GPOS_VALUE_FORMAT_X_ADVANCE          = 0x0004,
    
    86
    +    GPOS_VALUE_FORMAT_Y_ADVANCE          = 0x0008,
    
    87
    +    GPOS_VALUE_FORMAT_X_PLACEMENT_DEVICE = 0x0010,
    
    88
    +    GPOS_VALUE_FORMAT_Y_PLACEMENT_DEVICE = 0x0020,
    
    89
    +    GPOS_VALUE_FORMAT_X_ADVANCE_DEVICE   = 0x0040,
    
    90
    +    GPOS_VALUE_FORMAT_Y_ADVANCE_DEVICE   = 0x0080
    
    91
    +
    
    92
    +  } gpos_value_format_bitmask;
    
    93
    +
    
    94
    +
    
    95
    +  typedef struct TT_GPOS_Subtable_Iterator_Context_
    
    96
    +  {
    
    97
    +    /* Iteration state. */
    
    98
    +    FT_Byte*          current_lookup_table;
    
    99
    +    gpos_lookup_type  current_lookup_type;
    
    100
    +    FT_UShort         subtable_count;
    
    101
    +    FT_Byte*          subtable_offsets;
    
    102
    +    FT_UInt           subtable_idx;
    
    103
    +
    
    104
    +    /* Element for the current iteration. */
    
    105
    +    FT_Byte*          subtable;
    
    106
    +    gpos_lookup_type  subtable_type;
    
    107
    +
    
    108
    +  } TT_GPOS_Subtable_Iterator_Context;
    
    109
    +
    
    110
    +
    
    111
    +  /* Initialize a subtable iterator for a given lookup list index. */
    
    112
    +  static void
    
    113
    +  tt_gpos_subtable_iterator_init(
    
    114
    +    TT_GPOS_Subtable_Iterator_Context*  context,
    
    115
    +    FT_Byte*                            gpos_table,
    
    116
    +    FT_ULong                            lookup_list_idx )
    
    117
    +  {
    
    118
    +    FT_Byte*   lookup_list  = gpos_table + FT_PEEK_USHORT( gpos_table + 8 );
    
    119
    +    FT_UInt16  lookup_count = FT_PEEK_USHORT( lookup_list );
    
    120
    +
    
    121
    +
    
    122
    +    if ( lookup_list_idx < lookup_count )
    
    123
    +    {
    
    124
    +      context->current_lookup_table =
    
    125
    +        lookup_list + FT_PEEK_USHORT( lookup_list + 2 + 2 * lookup_list_idx );
    
    126
    +      context->current_lookup_type =
    
    127
    +        (gpos_lookup_type)FT_PEEK_USHORT( context->current_lookup_table );
    
    128
    +      context->subtable_count =
    
    129
    +        FT_PEEK_USHORT( context->current_lookup_table + 4 );
    
    130
    +      context->subtable_offsets = context->current_lookup_table + 6;
    
    131
    +    }
    
    132
    +    else
    
    133
    +    {
    
    134
    +      context->current_lookup_table = NULL;
    
    135
    +      context->current_lookup_type  = 0;
    
    136
    +      context->subtable_count       = 0;
    
    137
    +      context->subtable_offsets     = NULL;
    
    138
    +    }
    
    139
    +
    
    140
    +    context->subtable_idx  = 0;
    
    141
    +    context->subtable      = NULL;
    
    142
    +    context->subtable_type = 0;
    
    143
    +  }
    
    144
    +
    
    145
    +
    
    146
    +  /* Get the next subtable.  Return whether there was a next one. */
    
    147
    +  static FT_Bool
    
    148
    +  tt_gpos_subtable_iterator_next(
    
    149
    +    TT_GPOS_Subtable_Iterator_Context*  context )
    
    150
    +  {
    
    151
    +    if ( context->subtable_idx < context->subtable_count )
    
    152
    +    {
    
    153
    +      FT_UShort  subtable_offset =
    
    154
    +        FT_PEEK_USHORT( context->subtable_offsets +
    
    155
    +                        2 * context->subtable_idx );
    
    156
    +
    
    157
    +
    
    158
    +      context->subtable = context->current_lookup_table + subtable_offset;
    
    159
    +
    
    160
    +      if ( context->current_lookup_type ==
    
    161
    +           GPOS_LOOKUP_TYPE_EXTENSION_POSITIONING )
    
    162
    +      {
    
    163
    +        /* Update type and subtable based on extension positioning header. */
    
    164
    +        context->subtable_type =
    
    165
    +          (gpos_lookup_type)FT_PEEK_USHORT( context->subtable + 2 );
    
    166
    +        context->subtable += FT_PEEK_ULONG( context->subtable + 4 );
    
    167
    +      }
    
    168
    +      else
    
    169
    +        context->subtable_type = context->current_lookup_type;
    
    170
    +
    
    171
    +      context->subtable_idx++;
    
    172
    +      return TRUE;
    
    173
    +    }
    
    174
    +
    
    175
    +    return FALSE;
    
    176
    +  }
    
    177
    +
    
    178
    +
    
    179
    +  static FT_Int
    
    180
    +  tt_gpos_get_coverage_index( FT_Byte  *coverage_table,
    
    181
    +                              FT_UInt   glyph )
    
    182
    +  {
    
    183
    +    coverage_table_format_type  coverage_format =
    
    184
    +      (coverage_table_format_type)FT_PEEK_USHORT( coverage_table );
    
    185
    +
    
    186
    +
    
    187
    +    switch ( coverage_format )
    
    188
    +    {
    
    189
    +    case COVERAGE_TABLE_FORMAT_LIST:
    
    190
    +      {
    
    191
    +        FT_UShort  glyph_count = FT_PEEK_USHORT( coverage_table + 2 );
    
    192
    +
    
    193
    +        FT_Int  l = 0;
    
    194
    +        FT_Int  r = glyph_count - 1;
    
    195
    +        FT_Int  m;
    
    196
    +
    
    197
    +        FT_Int  straw;
    
    198
    +        FT_Int  needle = glyph;
    
    199
    +
    
    200
    +
    
    201
    +        /* Binary search. */
    
    202
    +        while ( l <= r )
    
    203
    +        {
    
    204
    +          FT_Byte   *glyph_array = coverage_table + 4;
    
    205
    +          FT_UShort  glyph_id;
    
    206
    +
    
    207
    +
    
    208
    +          m        = ( l + r ) >> 1;
    
    209
    +          glyph_id = FT_PEEK_USHORT( glyph_array + 2 * m );
    
    210
    +          straw    = glyph_id;
    
    211
    +
    
    212
    +          if ( needle < straw )
    
    213
    +            r = m - 1;
    
    214
    +          else if ( needle > straw )
    
    215
    +            l = m + 1;
    
    216
    +          else
    
    217
    +            return m;
    
    218
    +        }
    
    219
    +        break;
    
    220
    +      }
    
    221
    +
    
    222
    +    case COVERAGE_TABLE_FORMAT_RANGE:
    
    223
    +      {
    
    224
    +        FT_UShort  range_count = FT_PEEK_USHORT( coverage_table + 2 );
    
    225
    +        FT_Byte   *range_array = coverage_table + 4;
    
    226
    +
    
    227
    +        FT_Int  l = 0;
    
    228
    +        FT_Int  r = range_count - 1;
    
    229
    +        FT_Int  m;
    
    230
    +
    
    231
    +        FT_Int  straw_start;
    
    232
    +        FT_Int  straw_end;
    
    233
    +        FT_Int  needle = glyph;
    
    234
    +
    
    235
    +
    
    236
    +        /* Binary search. */
    
    237
    +        while ( l <= r )
    
    238
    +        {
    
    239
    +          FT_Byte  *range_record;
    
    240
    +
    
    241
    +
    
    242
    +          m            = ( l + r ) >> 1;
    
    243
    +          range_record = range_array + 6 * m;
    
    244
    +          straw_start  = FT_PEEK_USHORT( range_record );
    
    245
    +          straw_end    = FT_PEEK_USHORT( range_record + 2 );
    
    246
    +
    
    247
    +          if ( needle < straw_start )
    
    248
    +            r = m - 1;
    
    249
    +          else if ( needle > straw_end )
    
    250
    +            l = m + 1;
    
    251
    +          else
    
    252
    +          {
    
    253
    +            FT_UShort start_coverage_index =
    
    254
    +                        FT_PEEK_USHORT( range_record + 4 );
    
    255
    +
    
    256
    +
    
    257
    +            return start_coverage_index + glyph - straw_start;
    
    258
    +          }
    
    259
    +        }
    
    260
    +        break;
    
    261
    +      }
    
    262
    +
    
    263
    +    default:
    
    264
    +      return -1;  /* unsupported */
    
    265
    +    }
    
    266
    +
    
    267
    +    return -1;
    
    268
    +  }
    
    269
    +
    
    270
    +
    
    271
    +  static FT_Int
    
    272
    +  tt_gpos_get_glyph_class( FT_Byte  *class_def_table,
    
    273
    +                           FT_UInt   glyph )
    
    274
    +  {
    
    275
    +    class_def_table_format_type  class_def_format =
    
    276
    +      (class_def_table_format_type)FT_PEEK_USHORT( class_def_table );
    
    277
    +
    
    278
    +
    
    279
    +    switch ( class_def_format )
    
    280
    +    {
    
    281
    +    case CLASS_DEF_TABLE_FORMAT_ARRAY:
    
    282
    +      {
    
    283
    +        FT_UShort  start_glyph_id    = FT_PEEK_USHORT( class_def_table + 2 );
    
    284
    +        FT_UShort  glyph_count       = FT_PEEK_USHORT( class_def_table + 4 );
    
    285
    +        FT_Byte   *class_value_array = class_def_table + 6;
    
    286
    +
    
    287
    +
    
    288
    +        if ( glyph >= start_glyph_id              &&
    
    289
    +             glyph < start_glyph_id + glyph_count )
    
    290
    +          return (FT_Int)FT_PEEK_USHORT( class_value_array +
    
    291
    +                                         2 * ( glyph - start_glyph_id ) );
    
    292
    +        break;
    
    293
    +      }
    
    294
    +
    
    295
    +    case CLASS_DEF_TABLE_FORMAT_RANGE_GROUPS:
    
    296
    +      {
    
    297
    +        FT_UShort  class_range_count   = FT_PEEK_USHORT( class_def_table + 2 );
    
    298
    +        FT_Byte   *class_range_records = class_def_table + 4;
    
    299
    +
    
    300
    +        FT_Int  l = 0;
    
    301
    +        FT_Int  r = class_range_count - 1;
    
    302
    +        FT_Int  m;
    
    303
    +
    
    304
    +        FT_Int  straw_start;
    
    305
    +        FT_Int  straw_end;
    
    306
    +        FT_Int  needle = glyph;
    
    307
    +
    
    308
    +
    
    309
    +        while ( l <= r )
    
    310
    +        {
    
    311
    +          FT_Byte *class_range_record;
    
    312
    +
    
    313
    +
    
    314
    +          m                  = ( l + r ) >> 1;
    
    315
    +          class_range_record = class_range_records + 6 * m;
    
    316
    +          straw_start        = FT_PEEK_USHORT( class_range_record );
    
    317
    +          straw_end          = FT_PEEK_USHORT( class_range_record + 2 );
    
    318
    +
    
    319
    +          if ( needle < straw_start )
    
    320
    +            r = m - 1;
    
    321
    +          else if ( needle > straw_end )
    
    322
    +            l = m + 1;
    
    323
    +          else
    
    324
    +            return (FT_Int)FT_PEEK_USHORT( class_range_record + 4 );
    
    325
    +        }
    
    326
    +        break;
    
    327
    +      }
    
    328
    +
    
    329
    +    default:
    
    330
    +      return -1;  /* Unsupported definition type, return an error. */
    
    331
    +    }
    
    332
    +
    
    333
    +    /* "All glyphs not assigned to a class fall into class 0." */
    
    334
    +    /* (OpenType spec)                                         */
    
    335
    +    return 0;
    
    336
    +  }
    
    337
    +
    
    338
    +
    
    339
    +  FT_LOCAL_DEF( FT_Error )
    
    340
    +  tt_face_load_gpos( TT_Face    face,
    
    341
    +                     FT_Stream  stream )
    
    342
    +  {
    
    343
    +    FT_Error  error;
    
    344
    +    FT_ULong  table_size;
    
    345
    +
    
    346
    +
    
    347
    +    /* The GPOS table is optional; exit silently if it is missing. */
    
    348
    +    error = face->goto_table( face, TTAG_GPOS, stream, &table_size );
    
    349
    +    if ( error )
    
    350
    +      goto Exit;
    
    351
    +
    
    352
    +    if ( table_size < 4 )  /* the case of a malformed table */
    
    353
    +    {
    
    354
    +      FT_ERROR(( "tt_face_load_gpos:"
    
    355
    +                 " GPOS table is too small - ignored\n" ));
    
    356
    +      error = FT_THROW( Table_Missing );
    
    357
    +      goto Exit;
    
    358
    +    }
    
    359
    +
    
    360
    +    if ( FT_FRAME_EXTRACT( table_size, face->gpos_table ) )
    
    361
    +    {
    
    362
    +      FT_ERROR(( "tt_face_load_gpos:"
    
    363
    +                 " could not extract GPOS table\n" ));
    
    364
    +      goto Exit;
    
    365
    +    }
    
    366
    +
    
    367
    +    face->gpos_kerning_available = FALSE;
    
    368
    +
    
    369
    +    if ( face->gpos_table )
    
    370
    +    {
    
    371
    +      FT_Byte*   feature_list    = face->gpos_table +
    
    372
    +                                   FT_PEEK_USHORT( face->gpos_table + 6 );
    
    373
    +      FT_UInt16  feature_count   = FT_PEEK_USHORT( feature_list );
    
    374
    +      FT_Byte*   feature_records = feature_list + 2;
    
    375
    +
    
    376
    +      FT_UInt  idx;
    
    377
    +
    
    378
    +
    
    379
    +      for ( idx = 0; idx < feature_count; idx++, feature_records += 6 )
    
    380
    +      {
    
    381
    +        FT_ULong  feature_tag = FT_PEEK_ULONG( feature_records );
    
    382
    +
    
    383
    +
    
    384
    +        if ( feature_tag == TTAG_kern )
    
    385
    +        {
    
    386
    +          face->gpos_kerning_available = TRUE;
    
    387
    +          break;
    
    388
    +        }
    
    389
    +      }
    
    390
    +    }
    
    391
    +
    
    392
    +  Exit:
    
    393
    +    return error;
    
    394
    +  }
    
    395
    +
    
    396
    +
    
    397
    +  FT_LOCAL_DEF( void )
    
    398
    +  tt_face_done_gpos( TT_Face  face )
    
    399
    +  {
    
    400
    +    FT_Stream  stream = face->root.stream;
    
    401
    +
    
    402
    +
    
    403
    +    FT_FRAME_RELEASE( face->gpos_table );
    
    404
    +  }
    
    405
    +
    
    406
    +
    
    407
    +  FT_LOCAL_DEF( FT_Int )
    
    408
    +  tt_face_get_gpos_kerning( TT_Face  face,
    
    409
    +                            FT_UInt  left_glyph,
    
    410
    +                            FT_UInt  right_glyph )
    
    411
    +  {
    
    412
    +    FT_Byte*   feature_list;
    
    413
    +    FT_UInt16  feature_count;
    
    414
    +    FT_Byte*   feature_records;
    
    415
    +    FT_UInt    feature_idx;
    
    416
    +
    
    417
    +
    
    418
    +    if ( !face->gpos_kerning_available )
    
    419
    +      return 0;
    
    420
    +
    
    421
    +    feature_list    = face->gpos_table +
    
    422
    +                      FT_PEEK_USHORT( face->gpos_table + 6 );
    
    423
    +    feature_count   = FT_PEEK_USHORT( feature_list );
    
    424
    +    feature_records = feature_list + 2;
    
    425
    +
    
    426
    +    for ( feature_idx = 0;
    
    427
    +          feature_idx < feature_count;
    
    428
    +          feature_idx++, feature_records += 6 )
    
    429
    +    {
    
    430
    +      FT_ULong   feature_tag = FT_PEEK_ULONG( feature_records );
    
    431
    +      FT_Byte*   feature_table;
    
    432
    +      FT_UInt16  lookup_idx_count;
    
    433
    +      FT_UInt16  lookup_idx;
    
    434
    +
    
    435
    +
    
    436
    +      if ( feature_tag != TTAG_kern )
    
    437
    +        continue;
    
    438
    +
    
    439
    +      feature_table    = feature_list + FT_PEEK_USHORT( feature_records + 4 );
    
    440
    +      lookup_idx_count = FT_PEEK_USHORT( feature_table + 2 );
    
    441
    +
    
    442
    +      for ( lookup_idx = 0; lookup_idx < lookup_idx_count; lookup_idx++ )
    
    443
    +      {
    
    444
    +        FT_UInt16 lookup_list_idx =
    
    445
    +          FT_PEEK_USHORT( feature_table + 4 + 2 * lookup_idx );
    
    446
    +        TT_GPOS_Subtable_Iterator_Context  subtable_iter;
    
    447
    +
    
    448
    +
    
    449
    +        tt_gpos_subtable_iterator_init( &subtable_iter,
    
    450
    +                                        face->gpos_table,
    
    451
    +                                        lookup_list_idx );
    
    452
    +
    
    453
    +        while ( tt_gpos_subtable_iterator_next( &subtable_iter ) )
    
    454
    +        {
    
    455
    +          FT_Byte*  subtable;
    
    456
    +
    
    457
    +          gpos_value_format_bitmask    value_format_1;
    
    458
    +          gpos_value_format_bitmask    value_format_2;
    
    459
    +          gpos_pair_adjustment_format  format;
    
    460
    +
    
    461
    +          FT_UShort  coverage_offset;
    
    462
    +          FT_Int     coverage_index;
    
    463
    +
    
    464
    +
    
    465
    +          if ( subtable_iter.subtable_type !=
    
    466
    +               GPOS_LOOKUP_TYPE_PAIR_ADJUSTMENT )
    
    467
    +            continue;
    
    468
    +
    
    469
    +          subtable = subtable_iter.subtable;
    
    470
    +
    
    471
    +          value_format_1 =
    
    472
    +            (gpos_value_format_bitmask)FT_PEEK_USHORT( subtable + 4 );
    
    473
    +          value_format_2 =
    
    474
    +            (gpos_value_format_bitmask)FT_PEEK_USHORT( subtable + 6 );
    
    475
    +
    
    476
    +          if ( !( value_format_1 == GPOS_VALUE_FORMAT_X_ADVANCE &&
    
    477
    +                  value_format_2 == GPOS_VALUE_FORMAT_NONE      ) )
    
    478
    +            continue;
    
    479
    +
    
    480
    +          format = (gpos_pair_adjustment_format)FT_PEEK_USHORT( subtable );
    
    481
    +
    
    482
    +          coverage_offset = FT_PEEK_USHORT( subtable + 2 );
    
    483
    +          coverage_index  =
    
    484
    +            tt_gpos_get_coverage_index( subtable + coverage_offset,
    
    485
    +                                        left_glyph );
    
    486
    +
    
    487
    +          if ( coverage_index == -1 )
    
    488
    +            continue;
    
    489
    +
    
    490
    +          switch ( format )
    
    491
    +          {
    
    492
    +          case GPOS_PAIR_ADJUSTMENT_FORMAT_GLYPH_PAIR:
    
    493
    +            {
    
    494
    +              FT_Int  l, r, m;
    
    495
    +              FT_Int  straw, needle;
    
    496
    +
    
    497
    +              FT_Int  value_record_pair_size_in_bytes = 2;
    
    498
    +
    
    499
    +              FT_UShort  pair_set_count = FT_PEEK_USHORT( subtable + 8 );
    
    500
    +              FT_UShort  pair_pos_offset;
    
    501
    +
    
    502
    +              FT_Byte*   pair_value_table;
    
    503
    +              FT_UShort  pair_value_count;
    
    504
    +              FT_Byte*   pair_value_array;
    
    505
    +
    
    506
    +
    
    507
    +              if ( coverage_index >= pair_set_count )
    
    508
    +                return 0;
    
    509
    +
    
    510
    +              pair_pos_offset =
    
    511
    +                FT_PEEK_USHORT( subtable + 10 + 2 * coverage_index );
    
    512
    +
    
    513
    +              pair_value_table = subtable + pair_pos_offset;
    
    514
    +              pair_value_count = FT_PEEK_USHORT( pair_value_table );
    
    515
    +              pair_value_array = pair_value_table + 2;
    
    516
    +
    
    517
    +              needle = right_glyph;
    
    518
    +              r      = pair_value_count - 1;
    
    519
    +              l      = 0;
    
    520
    +
    
    521
    +              /* Binary search. */
    
    522
    +              while ( l <= r )
    
    523
    +              {
    
    524
    +                FT_UShort  second_glyph;
    
    525
    +                FT_Byte*   pair_value;
    
    526
    +
    
    527
    +
    
    528
    +                m            = ( l + r ) >> 1;
    
    529
    +                pair_value   = pair_value_array +
    
    530
    +                               ( 2 + value_record_pair_size_in_bytes ) * m;
    
    531
    +                second_glyph = FT_PEEK_USHORT( pair_value );
    
    532
    +                straw        = second_glyph;
    
    533
    +
    
    534
    +                if ( needle < straw )
    
    535
    +                  r = m - 1;
    
    536
    +                else if ( needle > straw )
    
    537
    +                  l = m + 1;
    
    538
    +                else
    
    539
    +                {
    
    540
    +                  FT_Short  x_advance = FT_PEEK_SHORT( pair_value + 2 );
    
    541
    +
    
    542
    +
    
    543
    +                  return x_advance;
    
    544
    +                }
    
    545
    +              }
    
    546
    +              break;
    
    547
    +            }
    
    548
    +
    
    549
    +          case GPOS_PAIR_ADJUSTMENT_FORMAT_CLASS_PAIR:
    
    550
    +            {
    
    551
    +              FT_UShort  class_def1_offset = FT_PEEK_USHORT( subtable + 8 );
    
    552
    +              FT_UShort  class_def2_offset = FT_PEEK_USHORT( subtable + 10 );
    
    553
    +
    
    554
    +              FT_Int  left_glyph_class =
    
    555
    +                tt_gpos_get_glyph_class( subtable + class_def1_offset,
    
    556
    +                                         left_glyph );
    
    557
    +              FT_Int  right_glyph_class =
    
    558
    +                tt_gpos_get_glyph_class( subtable + class_def2_offset,
    
    559
    +                                         right_glyph );
    
    560
    +
    
    561
    +              FT_UShort class1_count = FT_PEEK_USHORT( subtable + 12 );
    
    562
    +              FT_UShort class2_count = FT_PEEK_USHORT( subtable + 14 );
    
    563
    +
    
    564
    +              FT_Byte *class1_records, *class2_records;
    
    565
    +              FT_Short x_advance;
    
    566
    +
    
    567
    +
    
    568
    +              if ( left_glyph_class < 0             ||
    
    569
    +                   left_glyph_class >= class1_count )
    
    570
    +                return 0;  /* malformed */
    
    571
    +              if ( right_glyph_class < 0             ||
    
    572
    +                   right_glyph_class >= class2_count )
    
    573
    +                return 0;  /* malformed */
    
    574
    +
    
    575
    +              if ( right_glyph_class == 0 )
    
    576
    +                continue; /* right glyph not found in this table */
    
    577
    +
    
    578
    +              class1_records = subtable + 16;
    
    579
    +              class2_records =
    
    580
    +                class1_records + 2 * ( left_glyph_class * class2_count );
    
    581
    +
    
    582
    +              x_advance =
    
    583
    +                FT_PEEK_SHORT( class2_records + 2 * right_glyph_class );
    
    584
    +
    
    585
    +              return x_advance;
    
    586
    +            }
    
    587
    +
    
    588
    +          default:
    
    589
    +            return 0;
    
    590
    +          }
    
    591
    +        }
    
    592
    +      }
    
    593
    +    }
    
    594
    +
    
    595
    +    return 0;
    
    596
    +  }
    
    597
    +
    
    598
    +#else /* !TT_CONFIG_OPTION_GPOS_KERNING */
    
    599
    +
    
    600
    +  /* ANSI C doesn't like empty source files */
    
    601
    +  typedef int  tt_gpos_dummy_;
    
    602
    +
    
    603
    +#endif /* !TT_CONFIG_OPTION_GPOS_KERNING */
    
    604
    +
    
    605
    +
    
    606
    +/* END */

  • src/sfnt/ttgpos.h
    1
    +/****************************************************************************
    
    2
    + *
    
    3
    + * ttgpos.c
    
    4
    + *
    
    5
    + *   Load the TrueType GPOS table.  The only GPOS layout feature this
    
    6
    + *   currently supports is kerning, from x advances in the pair adjustment
    
    7
    + *   layout feature.
    
    8
    + *
    
    9
    + * Copyright (C) 2024 by
    
    10
    + * David Saltzman
    
    11
    + *
    
    12
    + * This file is part of the FreeType project, and may only be used,
    
    13
    + * modified, and distributed under the terms of the FreeType project
    
    14
    + * license, LICENSE.TXT.  By continuing to use, modify, or distribute
    
    15
    + * this file you indicate that you have read the license and
    
    16
    + * understand and accept it fully.
    
    17
    + */
    
    18
    +
    
    19
    +
    
    20
    +#ifndef TTGPOS_H_
    
    21
    +#define TTGPOS_H_
    
    22
    +
    
    23
    +
    
    24
    +#include <freetype/internal/ftstream.h>
    
    25
    +#include <freetype/internal/tttypes.h>
    
    26
    +
    
    27
    +
    
    28
    +FT_BEGIN_HEADER
    
    29
    +
    
    30
    +
    
    31
    +#ifdef TT_CONFIG_OPTION_GPOS_KERNING
    
    32
    +
    
    33
    +  FT_LOCAL( FT_Error  )
    
    34
    +  tt_face_load_gpos( TT_Face    face,
    
    35
    +                     FT_Stream  stream );
    
    36
    +
    
    37
    +  FT_LOCAL( void )
    
    38
    +  tt_face_done_gpos( TT_Face  face );
    
    39
    +
    
    40
    +  FT_LOCAL( FT_Int )
    
    41
    +  tt_face_get_gpos_kerning( TT_Face  face,
    
    42
    +                            FT_UInt  left_glyph,
    
    43
    +                            FT_UInt  right_glyph );
    
    44
    +
    
    45
    +#endif /* TT_CONFIG_OPTION_GPOS_KERNING */
    
    46
    +
    
    47
    +
    
    48
    +FT_END_HEADER
    
    49
    +
    
    50
    +#endif /* TTGPOS_H_ */
    
    51
    +
    
    52
    +
    
    53
    +/* END */

  • src/truetype/ttdriver.c
    ... ... @@ -217,7 +217,20 @@
    217 217
         kerning->y = 0;
    
    218 218
     
    
    219 219
         if ( sfnt )
    
    220
    -      kerning->x = sfnt->get_kerning( ttface, left_glyph, right_glyph );
    
    220
    +    {
    
    221
    +      /* Use 'kern' table if available since that can be faster; otherwise */
    
    222
    +      /* use GPOS kerning pairs if available.                              */
    
    223
    +      if ( ttface->kern_avail_bits != 0 )
    
    224
    +        kerning->x = sfnt->get_kerning( ttface,
    
    225
    +                                        left_glyph,
    
    226
    +                                        right_glyph );
    
    227
    +#ifdef TT_CONFIG_OPTION_GPOS_KERNING
    
    228
    +      else if ( ttface->gpos_kerning_available )
    
    229
    +        kerning->x = sfnt->get_gpos_kerning( ttface,
    
    230
    +                                             left_glyph,
    
    231
    +                                             right_glyph );
    
    232
    +#endif
    
    233
    +    }
    
    221 234
     
    
    222 235
         return 0;
    
    223 236
       }
    


  • reply via email to

    [Prev in Thread] Current Thread [Next in Thread]