Werner Lemberg pushed to branch master at FreeType / FreeType
Commits:
-
8f286c86
by David Saltzman at 2024-01-27T10:55:04+01:00
13 changed files:
- devel/ftoption.h
- docs/CHANGES
- include/freetype/config/ftoption.h
- include/freetype/freetype.h
- include/freetype/internal/fttrace.h
- include/freetype/internal/sfnt.h
- include/freetype/internal/tttypes.h
- src/sfnt/sfdriver.c
- src/sfnt/sfnt.c
- src/sfnt/sfobjs.c
- + src/sfnt/ttgpos.c
- + src/sfnt/ttgpos.h
- src/truetype/ttdriver.c
Changes:
| ... | ... | @@ -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 | /**** ****/
|
| ... | ... | @@ -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 |
| ... | ... | @@ -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 | /**** ****/
|
| ... | ... | @@ -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,
|
| ... | ... | @@ -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) */
|
| ... | ... | @@ -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_, \
|
| ... | ... | @@ -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 */
|
| ... | ... | @@ -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 */
|
| ... | ... | @@ -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"
|
| ... | ... | @@ -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;
|
| 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 */ |
| 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 */ |
| ... | ... | @@ -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 | }
|