freetype-commit
[Top][All Lists]
Advanced

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

[Git][freetype/freetype][adjust] 13 commits: * src/truetype/ttgxvar.c (f


From: Werner Lemberg (@wl)
Subject: [Git][freetype/freetype][adjust] 13 commits: * src/truetype/ttgxvar.c (ft_var_to_normalized): Integer overflow.
Date: Sun, 14 Apr 2024 14:04:22 +0000

Werner Lemberg pushed to branch adjust at FreeType / FreeType

Commits:

  • 546237e1
    by Werner Lemberg at 2024-02-23T11:55:53+01:00
    * src/truetype/ttgxvar.c (ft_var_to_normalized): Integer overflow.
    
    Reported as
    
      https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=66543
    
  • 2a790a9f
    by Ben Wanger at 2024-02-29T07:06:46+01:00
    [cff, truetype] Always set up default variable instance.
    
    For default variable instances `cff_face_init` did not set the blend.  This
    mostly worked as later use of the unset blend produced the default
    variation.  However, if a user called `TT_Get_MM_Var` the blend would be
    partially set up, but not fully.  In particular the number of axes, the axis
    definitions, and the instance locations would be set up, but not the current
    instance location (`coords` and `normalizedcoords`).  This could lead to the
    default instances of CFF2 fonts erroring on any use of `blend`.
    
    Ensure the default variable instance is fully set up by always calling
    `FT_Set_Named_Instance` on a variable face.
    
    * src/cff/cffobjs.c (cff_face_init): Call `FT_Set_Named_Instance` on
    default instances.
    * src/truetype/ttobjs.c (tt_face_init): Ditto.
    
    Fixes #1268.
    
  • 2cc58904
    by Jordan Williams at 2024-03-04T12:46:19-06:00
    meson: Use the standard dependency mechanism to find bzip2
    
    This follows standard conventions in Meson by using the pkg-config file.
    This change allows Conan to switch to the Meson build system.
    
  • 660a7017
    by Alexei Podtelezhnikov (Алексей Подтележников) at 2024-03-06T20:08:04+00:00
    * CMakeLists.txt: Bump required version to 3.5.
    
    Fixes #1267.
  • 17545d4b
    by Ben Wagner at 2024-03-08T17:47:43+01:00
    Avoid n^2 scanning for binary data.
    
    When creating a CID parser the location of the 'StartData' or '/sfnts'
    tokens needs to be known.  However, the token parser requires that the
    entire document be in memory and flattening the entire stream into memory is
    to be avoided.
    
    To avoid forcing the entire stream into memory, previously this code would
    scan through the stream looking for 'StartData' or '/sfnts' as strings.
    However, these strings could have been in a comment or string token, so the
    stream would be read into memory up to that point and the parser run to
    check that these strings were actually tokens.  This forced a parser restart
    from the beginning each time; as a result, data with many 'StartData'
    non-tokens would take n^2 time to check.
    
    * src/cid/cidparse.c (cid_parser_new): Change algorithm to make the initial
    scan look for the last possible 'StartData' or '/sfnts' string in the
    stream.  The stream is read forward instead of backward as a typical normal
    CID font will have one 'StartData' toward the beginning of the data and it
    it much faster to read the data from beginning to end instead of end to
    beginning.  For memory-based fonts the limit is set to the end of the stream
    since the stream is already in memory.  Then the parser is run once to look
    for 'StartData' or '/sfnts' tokens.  If they are found the parser is re-set
    to reflect this new information.
    
    Reported as
    
      https://issues.chromium.org/issues/40201695
    
  • f42ce255
    by Ben Wanger at 2024-03-08T14:55:12-05:00
    [colr] Ensure enough bytes for PaintColrLayers
    
    * src/sfnt/ttcolr.c (read_paint): check that there are five additional
    bytes to be read when reading PaintColrLayers.
    
    Reported as
    
      https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=66566
    
  • 813e081e
    by Craig White at 2024-04-14T14:00:00+02:00
    [base] Make `find_unicode_charmap` a base function.
    
    This is needed for forthcoming changes in the auto-hinter.
    
    * include/freetype/internal/ftobjs.h, src/base/ftobjs.c: Updated.
    
  • ab648b2d
    by Craig White at 2024-04-14T14:00:00+02:00
    [autofit] Add adjustment database.
    
    * src/autofit/afadjust.c, src/autofit/afadjust.h: New files.
    
    * include/freetype/internal/fttrace.h: Add 'afadjust' component.
    
    * src/autofit/autofit.c: Include `afadjust.c`.
    
    * src/autofit/rules.mk (AUTOF_DRV_SRC): Add `afadjust.c`.
    
  • 2d84675f
    by Craig White at 2024-04-14T14:00:00+02:00
    [autofit] Add code for reverse charmaps and adjustment database lookup.
    
    * src/autofit/aftypes.h (AF_ReverseMapEntry, AF_ReverseCharacterMap): New
    structures.
    
    * src/autofit/afadjust.c (af_adjustment_database_lookup,
    af_reverse_character_map_entry_compare, af_reverse_character_map_lookup,
    af_lookup_vertical_separation_type, af_lookup_tilde_correction_type,
    af_reverse_character_map_expand, af_reverse_character_map_new,
    af_reverse_character_map_done): New functions.
    
    * src/autofit/afadjust.c: Updated.
    
  • 34c1acfc
    by Craig White at 2024-04-14T14:00:00+02:00
    [autofit] Implement vertical separation adjustment.
    
    * src/autofit/aflatin.c: Include `afadjust.h`.
    (af_latin_metrics_init): Call `af_reverse_character_map_new`.
    (af_latin_metrics_done): New function.
    
    (af_move_contour_vertically, af_check_contour_horizontal_overlap,
    af_glyph_hints_apply_vertical_separation_adjustments): New functions.
    
    (af_latin_hints_apply): Call
    `af_glyph_hints_apply_vertical_separation_adjustments`.
    
    (af_latin_writing_system_class): Updated.
    
    * src/autofit/aftypes.h (AF_StyleMetricsRec): Add `reverse_charmap` field.
    
  • 48491c67
    by Craig White at 2024-04-14T14:55:53+02:00
    [autofit] Add tilde-unflattening algorithm.
    
    * src/autofit/aflatin.c (af_find_highest_contour,
    af_remove_segments_containing_point,
    af_latin_remove_tilde_points_from_edges, af_latin_stretch_tildes,
    af_latin_align_tildes): New functions.
    (af_latin_hints_apply): Call tilde-unflatting code if necessary.
    
  • 74d9a996
    by Craig White at 2024-04-14T14:55:57+02:00
    [autofit] Add GSUB table handling to reverse character map generation.
    
    If HarfBuzz is enabled, the reverse character map generation now considers
    GSUB entries when looking for glyphs that correspond to a code point.
    
    * src/autofit/afadjust.c (af_all_glyph_variants_helper,
    af_all_glyph_variants) [FT_CONFIG_OPTION_USE_HARFBUZZ]: New functions.
    
    (af_reverse_character_map_new) [FT_CONFIG_OPTION_USE_HARFBUZZ]: Call new
    code.
    
  • 7724a854
    by Werner Lemberg at 2024-04-14T14:55:58+02:00
    * docs/CHANGES: Mention Craig's GSoC 2023 project.
    

17 changed files:

Changes:

  • CMakeLists.txt
    ... ... @@ -110,7 +110,7 @@
    110 110
     
    
    111 111
     # To minimize the number of cmake_policy() workarounds,
    
    112 112
     # CMake >= 3 is requested.
    
    113
    -cmake_minimum_required(VERSION 3.0)
    
    113
    +cmake_minimum_required(VERSION 3.0...3.5)
    
    114 114
     
    
    115 115
     if (NOT CMAKE_VERSION VERSION_LESS 3.3)
    
    116 116
       # Allow symbol visibility settings also on static libraries. CMake < 3.3
    

  • docs/CHANGES
    ... ... @@ -5,7 +5,25 @@ CHANGES BETWEEN 2.13.2 and 2.13.3 (202Y-Mmm-DD)
    5 5
       - Excessive stack allocation in the autohinter has been fixed.
    
    6 6
     
    
    7 7
     
    
    8
    -  II. MISCELLANEOUS
    
    8
    +  II. IMPORTANT CHANGES
    
    9
    +
    
    10
    +  - The auto-hinter got new abilities.
    
    11
    +
    
    12
    +    . It can now better separate accents from base characters at small
    
    13
    +      sizes by artificially moving accents up if necessary.
    
    14
    +
    
    15
    +    . Tilde characters get vertically stretched at small sizes so that
    
    16
    +      they don't degenerate to horizontal lines.
    
    17
    +
    
    18
    +    Both  features use  a database,  which currently  has entries  for
    
    19
    +    Unicode characters lower than U+0180.  FreeType needs to access or
    
    20
    +    construct a proper Unicode character map from a given font to make
    
    21
    +    this work.
    
    22
    +
    
    23
    +    This was Craig White's GSoC 2023 project.
    
    24
    +
    
    25
    +
    
    26
    +  III. MISCELLANEOUS
    
    9 27
     
    
    10 28
       - The B/W rasterizer  has  received a major upkeep  that resulted in
    
    11 29
         large performance improvement.  The rendering speed  has increased
    

  • include/freetype/internal/ftobjs.h
    ... ... @@ -275,6 +275,28 @@ FT_BEGIN_HEADER
    275 275
                       FT_GlyphSlot    slot,
    
    276 276
                       FT_Render_Mode  mode );
    
    277 277
     
    
    278
    +
    
    279
    +  /**************************************************************************
    
    280
    +   *
    
    281
    +   * @Function:
    
    282
    +   *   find_unicode_charmap
    
    283
    +   *
    
    284
    +   * @Description:
    
    285
    +   *   This function finds a Unicode charmap, if there is one.  And if there
    
    286
    +   *   is more than one, it tries to favour the more extensive one, i.e., one
    
    287
    +   *   that supports UCS-4 against those which are limited to the BMP (UCS-2
    
    288
    +   *   encoding.)
    
    289
    +   *
    
    290
    +   *   If a unicode charmap is found, `face->charmap` is set to it.
    
    291
    +   *
    
    292
    +   *   This function is called from `open_face`, from `FT_Select_Charmap(...,
    
    293
    +   *   FT_ENCODING_UNICODE)`, and also from `afadjust.c` in the 'autofit'
    
    294
    +   *   module.
    
    295
    +   */
    
    296
    +  FT_BASE( FT_Error )
    
    297
    +  find_unicode_charmap( FT_Face  face );
    
    298
    +
    
    299
    +
    
    278 300
     #ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING
    
    279 301
     
    
    280 302
       typedef void  (*FT_Bitmap_LcdFilterFunc)( FT_Bitmap*      bitmap,
    

  • include/freetype/internal/fttrace.h
    ... ... @@ -159,6 +159,7 @@ FT_TRACE_DEF( gxvprop )
    159 159
     FT_TRACE_DEF( gxvtrak )
    
    160 160
     
    
    161 161
       /* autofit components */
    
    162
    +FT_TRACE_DEF( afadjust )
    
    162 163
     FT_TRACE_DEF( afcjk )
    
    163 164
     FT_TRACE_DEF( afglobal )
    
    164 165
     FT_TRACE_DEF( afhints )
    

  • meson.build
    ... ... @@ -316,8 +316,10 @@ else
    316 316
     endif
    
    317 317
     
    
    318 318
     # BZip2 support
    
    319
    -bzip2_dep = cc.find_library('bz2',
    
    320
    -  required: get_option('bzip2'))
    
    319
    +bzip2_dep = dependency('bzip2', required: false)
    
    320
    +if not bzip2_dep.found()
    
    321
    +  bzip2_dep = cc.find_library('bz2', has_headers: ['bzlib.h'], required: get_option('bzip2'))
    
    322
    +endif
    
    321 323
     
    
    322 324
     if bzip2_dep.found()
    
    323 325
       ftoption_command += ['--enable=FT_CONFIG_OPTION_USE_BZIP2']
    

  • src/autofit/afadjust.c
    1
    +/****************************************************************************
    
    2
    + *
    
    3
    + * afadjust.c
    
    4
    + *
    
    5
    + *   Auto-fitter routines to adjust components based on charcode (body).
    
    6
    + *
    
    7
    + * Copyright (C) 2023-2024 by
    
    8
    + * David Turner, Robert Wilhelm, and Werner Lemberg.
    
    9
    + *
    
    10
    + * Written by Craig White <gerzytet@gmail.com>.
    
    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
    +#include "afadjust.h"
    
    21
    +
    
    22
    +#include <freetype/freetype.h>
    
    23
    +#include <freetype/internal/ftobjs.h>
    
    24
    +#include <freetype/internal/ftmemory.h>
    
    25
    +#include <freetype/internal/ftdebug.h>
    
    26
    +
    
    27
    +#define AF_ADJUSTMENT_DATABASE_LENGTH           \
    
    28
    +          ( sizeof ( adjustment_database ) /    \
    
    29
    +            sizeof ( adjustment_database[0] ) )
    
    30
    +
    
    31
    +#undef  FT_COMPONENT
    
    32
    +#define FT_COMPONENT  afadjust
    
    33
    +
    
    34
    +
    
    35
    +  /*
    
    36
    +    All entries in this list must be sorted by ascending Unicode code
    
    37
    +    points.  The table entries are 3 numbers consisting of:
    
    38
    +
    
    39
    +    - Unicode code point.
    
    40
    +    - The vertical adjustment type.  This should be one of the enum
    
    41
    +      constants in `AF_VerticalSeparationAdjustmentType`.
    
    42
    +    - Value 1 if the topmost contour is a tilde and should be prevented from
    
    43
    +      flattening, and 0 otherwise.
    
    44
    +  */
    
    45
    +  FT_LOCAL_ARRAY_DEF( AF_AdjustmentDatabaseEntry )
    
    46
    +  adjustment_database[] =
    
    47
    +  {
    
    48
    +    { 0x21,  AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* ! */
    
    49
    +    { 0x69,  AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* i */
    
    50
    +    { 0x6A,  AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* j */
    
    51
    +
    
    52
    +    { 0xA1,  AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* ¡ */
    
    53
    +    { 0xBF,  AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* ¿ */
    
    54
    +
    
    55
    +    { 0xC0,  AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* À */
    
    56
    +    { 0xC1,  AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* Á */
    
    57
    +    { 0xC2,  AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* Â */
    
    58
    +    { 0xC3,  AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 1 }, /* Ã */
    
    59
    +    { 0xC8,  AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* È */
    
    60
    +    { 0xC9,  AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* É */
    
    61
    +    { 0xCA,  AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* Ê */
    
    62
    +    { 0xCC,  AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* Ì */
    
    63
    +    { 0xCD,  AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* Í */
    
    64
    +    { 0xCE,  AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* Î */
    
    65
    +
    
    66
    +    { 0xD1,  AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 1 }, /* Ñ */
    
    67
    +    { 0xD2,  AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* Ò */
    
    68
    +    { 0xD3,  AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* Ó */
    
    69
    +    { 0xD4,  AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* Ô */
    
    70
    +    { 0xD5,  AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 1 }, /* Õ */
    
    71
    +    { 0xD9,  AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* Ù */
    
    72
    +    { 0xDA,  AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* Ú */
    
    73
    +    { 0xDB,  AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* Û */
    
    74
    +    { 0xDD,  AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* Ý */
    
    75
    +
    
    76
    +    { 0xE0,  AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* à */
    
    77
    +    { 0xE1,  AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* á */
    
    78
    +    { 0xE2,  AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* â */
    
    79
    +    { 0xE3,  AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 1 }, /* ã */
    
    80
    +    { 0xE8,  AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* è */
    
    81
    +    { 0xE9,  AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* é */
    
    82
    +    { 0xEA,  AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* ê */
    
    83
    +    { 0xEC,  AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* ì */
    
    84
    +    { 0xED,  AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* í */
    
    85
    +    { 0xEE,  AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* î */
    
    86
    +
    
    87
    +    { 0xF1,  AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 1 }, /* ñ */
    
    88
    +    { 0xF2,  AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* ò */
    
    89
    +    { 0xF3,  AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* ó */
    
    90
    +    { 0xF4,  AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* ô */
    
    91
    +    { 0xF5,  AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 1 }, /* õ */
    
    92
    +    { 0xF9,  AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* ù */
    
    93
    +    { 0xFA,  AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* ú */
    
    94
    +    { 0xFB,  AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* û */
    
    95
    +    { 0xFD,  AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* ý */
    
    96
    +
    
    97
    +    { 0x100, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* Ā */
    
    98
    +    { 0x101, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* ā */
    
    99
    +    { 0x102, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* Ă */
    
    100
    +    { 0x103, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* ă */
    
    101
    +    { 0x106, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* Ć */
    
    102
    +    { 0x107, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* ć */
    
    103
    +    { 0x108, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* Ĉ */
    
    104
    +    { 0x109, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* ĉ */
    
    105
    +    { 0x10A, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* Ċ */
    
    106
    +    { 0x10B, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* ċ */
    
    107
    +    { 0x10C, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* Č */
    
    108
    +    { 0x10D, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* č */
    
    109
    +    { 0x10E, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* Ď */
    
    110
    +
    
    111
    +    { 0x112, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* Ē */
    
    112
    +    { 0x113, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* ē */
    
    113
    +    { 0x114, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* Ĕ */
    
    114
    +    { 0x115, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* ĕ */
    
    115
    +    { 0x116, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* Ė */
    
    116
    +    { 0x117, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* ė */
    
    117
    +    { 0x11A, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* Ě */
    
    118
    +    { 0x11B, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* ě */
    
    119
    +    { 0x11C, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* Ĝ */
    
    120
    +    { 0x11D, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* ĝ */
    
    121
    +    { 0x11E, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* Ğ */
    
    122
    +    { 0x11F, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* ğ */
    
    123
    +
    
    124
    +    { 0x120, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* Ġ */
    
    125
    +    { 0x121, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* ġ */
    
    126
    +    { 0x123, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* ģ */
    
    127
    +    { 0x124, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* Ĥ */
    
    128
    +    { 0x125, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* ĥ */
    
    129
    +    { 0x128, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 1 }, /* Ĩ */
    
    130
    +    { 0x129, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 1 }, /* ĩ */
    
    131
    +    { 0x12A, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* Ī */
    
    132
    +    { 0x12B, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* ī */
    
    133
    +    { 0x12C, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* Ĭ */
    
    134
    +    { 0x12D, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* ĭ */
    
    135
    +    { 0x12F, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* į */
    
    136
    +
    
    137
    +    { 0x130, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* İ */
    
    138
    +    { 0x133, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* ij */
    
    139
    +    { 0x134, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* Ĵ */
    
    140
    +    { 0x135, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* ĵ */
    
    141
    +    { 0x139, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* Ĺ */
    
    142
    +    { 0x13A, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* ĺ */
    
    143
    +
    
    144
    +    { 0x143, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* Ń */
    
    145
    +    { 0x144, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* ń */
    
    146
    +    { 0x147, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* Ň */
    
    147
    +    { 0x148, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* ň */
    
    148
    +    { 0x14C, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* Ō */
    
    149
    +    { 0x14D, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* ō */
    
    150
    +    { 0x14E, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* Ŏ */
    
    151
    +    { 0x14F, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* ŏ */
    
    152
    +
    
    153
    +    { 0x154, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* Ŕ */
    
    154
    +    { 0x155, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* ŕ */
    
    155
    +    { 0x158, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* Ř */
    
    156
    +    { 0x159, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* ř */
    
    157
    +    { 0x15A, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* Ś */
    
    158
    +    { 0x15B, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* ś */
    
    159
    +    { 0x15C, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* Ŝ */
    
    160
    +    { 0x15D, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* ŝ */
    
    161
    +
    
    162
    +    { 0x160, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* Š */
    
    163
    +    { 0x161, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* š */
    
    164
    +    { 0x164, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* Ť */
    
    165
    +    { 0x168, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 1 }, /* Ũ */
    
    166
    +    { 0x169, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 1 }, /* ũ */
    
    167
    +    { 0x16A, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* Ū */
    
    168
    +    { 0x16B, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* ū */
    
    169
    +    { 0x16C, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* Ŭ */
    
    170
    +    { 0x16D, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* ŭ */
    
    171
    +
    
    172
    +    { 0x174, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* Ŵ */
    
    173
    +    { 0x175, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* ŵ */
    
    174
    +    { 0x176, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* Ŷ */
    
    175
    +    { 0x177, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* ŷ */
    
    176
    +    { 0x179, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* Ź */
    
    177
    +    { 0x17A, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* ź */
    
    178
    +    { 0x17B, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* Ż */
    
    179
    +    { 0x17C, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* ż */
    
    180
    +    { 0x17D, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }, /* Ž */
    
    181
    +    { 0x17E, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0 }  /* ž */
    
    182
    +  };
    
    183
    +
    
    184
    +
    
    185
    +  /* Helper function: get the adjustment database entry for a codepoint. */
    
    186
    +  static const AF_AdjustmentDatabaseEntry*
    
    187
    +  af_adjustment_database_lookup( FT_UInt32  codepoint )
    
    188
    +  {
    
    189
    +    /* Binary search for database entry */
    
    190
    +    FT_Int  low  = 0;
    
    191
    +    FT_Int  high = AF_ADJUSTMENT_DATABASE_LENGTH - 1;
    
    192
    +
    
    193
    +
    
    194
    +    while ( high >= low )
    
    195
    +    {
    
    196
    +      FT_Int     mid           = ( low + high ) / 2;
    
    197
    +      FT_UInt32  mid_codepoint = adjustment_database[mid].codepoint;
    
    198
    +
    
    199
    +
    
    200
    +      if ( mid_codepoint < codepoint )
    
    201
    +        low = mid + 1;
    
    202
    +      else if ( mid_codepoint > codepoint )
    
    203
    +        high = mid - 1;
    
    204
    +      else
    
    205
    +        return &adjustment_database[mid];
    
    206
    +    }
    
    207
    +
    
    208
    +    return NULL;
    
    209
    +  }
    
    210
    +
    
    211
    +
    
    212
    +  /* `qsort` compare function for reverse character map. */
    
    213
    +  FT_COMPARE_DEF( FT_Int )
    
    214
    +  af_reverse_character_map_entry_compare( const void  *a,
    
    215
    +                                          const void  *b )
    
    216
    +  {
    
    217
    +    const AF_ReverseMapEntry  entry_a = *((const AF_ReverseMapEntry *)a);
    
    218
    +    const AF_ReverseMapEntry  entry_b = *((const AF_ReverseMapEntry *)b);
    
    219
    +
    
    220
    +
    
    221
    +    return entry_a.glyph_index < entry_b.glyph_index
    
    222
    +           ? -1
    
    223
    +           : entry_a.glyph_index > entry_b.glyph_index
    
    224
    +               ? 1
    
    225
    +               : 0;
    
    226
    +  }
    
    227
    +
    
    228
    +
    
    229
    +  static FT_UInt32
    
    230
    +  af_reverse_character_map_lookup( AF_ReverseCharacterMap  map,
    
    231
    +                                   FT_Int                  glyph_index )
    
    232
    +  {
    
    233
    +    FT_Int   low, high;
    
    234
    +    FT_Long  length;
    
    235
    +
    
    236
    +
    
    237
    +    if ( !map )
    
    238
    +      return 0;
    
    239
    +
    
    240
    +    length = map->length;
    
    241
    +
    
    242
    +    /* Binary search for reverse character map entry. */
    
    243
    +    low  = 0;
    
    244
    +    high = length - 1;
    
    245
    +
    
    246
    +    while ( high >= low )
    
    247
    +    {
    
    248
    +      FT_Int  mid             = ( high + low ) / 2;
    
    249
    +      FT_Int  mid_glyph_index = map->entries[mid].glyph_index;
    
    250
    +
    
    251
    +
    
    252
    +      if ( glyph_index < mid_glyph_index )
    
    253
    +        high = mid - 1;
    
    254
    +      else if ( glyph_index > mid_glyph_index )
    
    255
    +        low = mid + 1;
    
    256
    +      else
    
    257
    +        return map->entries[mid].codepoint;
    
    258
    +    }
    
    259
    +
    
    260
    +    return 0;
    
    261
    +  }
    
    262
    +
    
    263
    +
    
    264
    +  FT_LOCAL_DEF( AF_VerticalSeparationAdjustmentType )
    
    265
    +  af_lookup_vertical_separation_type( AF_ReverseCharacterMap  map,
    
    266
    +                                      FT_Int                  glyph_index )
    
    267
    +  {
    
    268
    +    FT_UInt32  codepoint = af_reverse_character_map_lookup( map,
    
    269
    +                                                            glyph_index );
    
    270
    +
    
    271
    +    const AF_AdjustmentDatabaseEntry  *entry =
    
    272
    +      af_adjustment_database_lookup( codepoint );
    
    273
    +
    
    274
    +
    
    275
    +    if ( !entry )
    
    276
    +      return AF_VERTICAL_ADJUSTMENT_NONE;
    
    277
    +
    
    278
    +    return entry->vertical_separation_adjustment_type;
    
    279
    +  }
    
    280
    +
    
    281
    +
    
    282
    +  /* Return 1 if tilde correction should be applied to the topmost */
    
    283
    +  /* contour, else 0.                                              */
    
    284
    +  FT_LOCAL_DEF( FT_Bool )
    
    285
    +  af_lookup_tilde_correction_type( AF_ReverseCharacterMap  map,
    
    286
    +                                   FT_Int                  glyph_index )
    
    287
    +  {
    
    288
    +    FT_UInt32  codepoint = af_reverse_character_map_lookup( map,
    
    289
    +                                                            glyph_index );
    
    290
    +
    
    291
    +    const AF_AdjustmentDatabaseEntry  *entry =
    
    292
    +      af_adjustment_database_lookup( codepoint );
    
    293
    +
    
    294
    +
    
    295
    +    if ( !entry )
    
    296
    +      return 0;
    
    297
    +
    
    298
    +    return entry->apply_tilde;
    
    299
    +  }
    
    300
    +
    
    301
    +
    
    302
    +  /* Prepare to add one more entry to the reverse character map.   */
    
    303
    +  /* This is a helper function for `af_reverse_character_map_new`. */
    
    304
    +  static FT_Error
    
    305
    +  af_reverse_character_map_expand( AF_ReverseCharacterMap  map,
    
    306
    +                                   FT_Long                *capacity,
    
    307
    +                                   FT_Memory               memory )
    
    308
    +  {
    
    309
    +    FT_Error  error;
    
    310
    +
    
    311
    +
    
    312
    +    if ( map->length < *capacity )
    
    313
    +      return FT_Err_Ok;
    
    314
    +
    
    315
    +    if ( map->length == *capacity )
    
    316
    +    {
    
    317
    +      FT_Long  new_capacity = *capacity + *capacity / 2;
    
    318
    +
    
    319
    +
    
    320
    +      if ( FT_RENEW_ARRAY( map->entries, map->length, new_capacity ) )
    
    321
    +        return error;
    
    322
    +
    
    323
    +      *capacity = new_capacity;
    
    324
    +    }
    
    325
    +
    
    326
    +    return FT_Err_Ok;
    
    327
    +  }
    
    328
    +
    
    329
    +
    
    330
    +#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ
    
    331
    +
    
    332
    +  /*
    
    333
    +    Recursive algorithm to find all glyphs that a code point could turn into
    
    334
    +    from the 'GSUB' table.
    
    335
    +
    
    336
    +    buffer:           a buffer containing only the input code point
    
    337
    +    feature_tag_pool: the current list of features under consideration
    
    338
    +    current_features: the current list of features being applied
    
    339
    +    num_features:     length of current_features
    
    340
    +    result:           the set of glyphs that the input code point can map to
    
    341
    +
    
    342
    +    The algorithm works by running the `hb_ot_shape_glyphs_closure` function
    
    343
    +    on different lists of features to check which features map the glyph onto
    
    344
    +    something different.  This function returns the result of transforming a
    
    345
    +    glyph using a list of features as well as all intermediate forms if the
    
    346
    +    glyph was transformed multiple times.
    
    347
    +
    
    348
    +    With no features enabled, `hb_ot_shape_glyphs_closure` only returns the
    
    349
    +    glyph given by the cmap.  This character is the first to be placed into
    
    350
    +    the result set.
    
    351
    +
    
    352
    +    Next, the algorithm tests the same lookup enabling one feature at a time
    
    353
    +    and check whether any of those features change the result.
    
    354
    +
    
    355
    +    If any new glyph variants are found this way, they are added to the
    
    356
    +    result set and the algorithm recurses, trying that feature in combination
    
    357
    +    with every other feature to look for further glyph variants.
    
    358
    +
    
    359
    +    Example:
    
    360
    +
    
    361
    +      suppose we have the following features in the GSUB table:
    
    362
    +
    
    363
    +        f1: a -> b
    
    364
    +        f2: b -> c
    
    365
    +        f3: d -> e
    
    366
    +
    
    367
    +      The algorithm takes the following steps to find all variants of 'a'.
    
    368
    +
    
    369
    +      - Add 'a' to the result.
    
    370
    +      - Look up with feature list {f1}, yielding {a, b}.
    
    371
    +        => Add 'b' to the result list, recurse.
    
    372
    +        - Look up with feature list {f1, f2}, yielding {a, b, c}.
    
    373
    +          => Add 'c' to the result list, recurse.
    
    374
    +          - Look up with feature list {f1, f2, f3}, yielding {a, b, c}.
    
    375
    +            => No new glyphs.
    
    376
    +        - Look up with feature list {f1, f3}, yielding {a, b}.
    
    377
    +          => No new glyphs.
    
    378
    +      - Look up with feature list {f2}, yielding {a}.
    
    379
    +        => No new glyphs.
    
    380
    +      - Look up with feature list {f3}, yielding {a}.
    
    381
    +        => No new glyphs.
    
    382
    +  */
    
    383
    +  static FT_Error
    
    384
    +  af_all_glyph_variants_helper( hb_font_t     *font,
    
    385
    +                                hb_buffer_t   *buffer,
    
    386
    +                                hb_set_t      *feature_tag_pool,
    
    387
    +                                hb_feature_t  *current_features,
    
    388
    +                                FT_UInt32      num_features,
    
    389
    +                                hb_set_t*      result )
    
    390
    +  {
    
    391
    +    FT_Error  error;
    
    392
    +
    
    393
    +    hb_set_t  *baseline_glyphs = NULL;
    
    394
    +    hb_set_t  *new_glyphs      = NULL;
    
    395
    +
    
    396
    +    hb_tag_t  feature_tag;
    
    397
    +
    
    398
    +
    
    399
    +    /* Get the list of glyphs that are created by only transforming, */
    
    400
    +    /* based on the features in `current_features`.                  */
    
    401
    +    baseline_glyphs = hb_set_create();
    
    402
    +    if ( !hb_set_allocation_successful( baseline_glyphs ) )
    
    403
    +    {
    
    404
    +      error = FT_Err_Out_Of_Memory;
    
    405
    +      goto Exit;
    
    406
    +    }
    
    407
    +
    
    408
    +    hb_ot_shape_glyphs_closure( font,
    
    409
    +                                buffer,
    
    410
    +                                current_features,
    
    411
    +                                num_features,
    
    412
    +                                baseline_glyphs );
    
    413
    +    if ( !hb_set_allocation_successful( baseline_glyphs ) )
    
    414
    +    {
    
    415
    +      error = FT_Err_Out_Of_Memory;
    
    416
    +      goto Exit;
    
    417
    +    }
    
    418
    +
    
    419
    +    /* Add these baseline glyphs to the result.  The baseline glyph set */
    
    420
    +    /* contains at least the glyph specified by the cmap.               */
    
    421
    +    hb_set_union( result, baseline_glyphs );
    
    422
    +    if ( !hb_set_allocation_successful( result ) )
    
    423
    +    {
    
    424
    +      error = FT_Err_Out_Of_Memory;
    
    425
    +      goto Exit;
    
    426
    +    }
    
    427
    +
    
    428
    +    if ( !hb_set_get_population( feature_tag_pool ) )
    
    429
    +    {
    
    430
    +      error = FT_Err_Out_Of_Memory;
    
    431
    +      goto Exit;
    
    432
    +    }
    
    433
    +
    
    434
    +    /* Prepare for adding different features to `current_features` to     */
    
    435
    +    /* check whether any of them have an effect of the glyphs we get from */
    
    436
    +    /* `hb_ot_shape_glyphs_closure`.                                      */
    
    437
    +    current_features[num_features].start = HB_FEATURE_GLOBAL_START;
    
    438
    +    current_features[num_features].end   = HB_FEATURE_GLOBAL_END;
    
    439
    +    current_features[num_features].value = 1; /* enable the feature */
    
    440
    +
    
    441
    +    /*
    
    442
    +      Quote from the HarfBuzz documentation about the `value` attribute:
    
    443
    +
    
    444
    +        0 disables the feature, non-zero (usually 1) enables the feature.
    
    445
    +        For features implemented as lookup type 3 (like 'salt') the value is
    
    446
    +        a one-based index into the alternates.  This algorithm does not
    
    447
    +        handle these lookup type 3 cases fully.
    
    448
    +    */
    
    449
    +
    
    450
    +    new_glyphs = hb_set_create();
    
    451
    +    if ( !hb_set_allocation_successful( new_glyphs ) )
    
    452
    +    {
    
    453
    +      error = FT_Err_Out_Of_Memory;
    
    454
    +      goto Exit;
    
    455
    +    }
    
    456
    +
    
    457
    +    feature_tag = HB_SET_VALUE_INVALID;
    
    458
    +
    
    459
    +    while ( hb_set_next( feature_tag_pool, &feature_tag ) )
    
    460
    +    {
    
    461
    +      hb_set_clear( new_glyphs );
    
    462
    +
    
    463
    +      current_features[num_features].tag = feature_tag;
    
    464
    +
    
    465
    +      hb_ot_shape_glyphs_closure ( font,
    
    466
    +                                   buffer,
    
    467
    +                                   current_features,
    
    468
    +                                   num_features + 1,
    
    469
    +                                   new_glyphs );
    
    470
    +      if ( !hb_set_allocation_successful( new_glyphs ) )
    
    471
    +      {
    
    472
    +        error = FT_Err_Out_Of_Memory;
    
    473
    +        goto Exit;
    
    474
    +      }
    
    475
    +
    
    476
    +      hb_set_subtract( new_glyphs, result );
    
    477
    +
    
    478
    +      /* `new_glyphs` now contains all glyphs that appeared in the result */
    
    479
    +      /* of `hb_ot_shape_glyphs_closure` that haven't already been        */
    
    480
    +      /* accounted for in the result.  If this contains any glyphs, we    */
    
    481
    +      /* also need to try this feature in combination with other features */
    
    482
    +      /* by recursing.                                                    */
    
    483
    +      if ( hb_set_get_population( new_glyphs ) != 0 )
    
    484
    +      {
    
    485
    +        /* Remove this feature from the feature pool temporarily so that */
    
    486
    +        /* a later recursion won't try it.                               */
    
    487
    +        hb_set_del( feature_tag_pool, feature_tag );
    
    488
    +
    
    489
    +        error = af_all_glyph_variants_helper( font,
    
    490
    +                                              buffer,
    
    491
    +                                              feature_tag_pool,
    
    492
    +                                              current_features,
    
    493
    +                                              num_features + 1,
    
    494
    +                                              result );
    
    495
    +        if ( error )
    
    496
    +          goto Exit;
    
    497
    +
    
    498
    +        /* Add back the feature we removed. */
    
    499
    +        hb_set_add( feature_tag_pool, feature_tag );
    
    500
    +        if ( !hb_set_allocation_successful( feature_tag_pool ) )
    
    501
    +          return FT_Err_Out_Of_Memory;
    
    502
    +      }
    
    503
    +    }
    
    504
    +
    
    505
    +  Exit:
    
    506
    +    hb_set_destroy( baseline_glyphs );
    
    507
    +    hb_set_destroy( new_glyphs );
    
    508
    +    return FT_Err_Ok;
    
    509
    +  }
    
    510
    +
    
    511
    +
    
    512
    +  static FT_Error
    
    513
    +  af_all_glyph_variants( FT_Face     face,
    
    514
    +                         hb_font_t  *hb_font,
    
    515
    +                         FT_UInt32   codepoint,
    
    516
    +                         hb_set_t*   result )
    
    517
    +  {
    
    518
    +    FT_Error  error;
    
    519
    +
    
    520
    +    FT_Memory   memory  = face->memory;
    
    521
    +    hb_face_t  *hb_face = hb_font_get_face( hb_font );
    
    522
    +
    
    523
    +    FT_Bool       feature_list_done;
    
    524
    +    unsigned int  start_offset;
    
    525
    +
    
    526
    +    /* The set of all feature tags in the font. */
    
    527
    +    hb_set_t        *feature_tags          = hb_set_create();
    
    528
    +    hb_set_t        *type_3_lookup_indices = hb_set_create();
    
    529
    +    hb_buffer_t     *codepoint_buffer      = hb_buffer_create();
    
    530
    +    hb_codepoint_t  *type_3_alternate_glyphs_buffer;
    
    531
    +
    
    532
    +    hb_feature_t  *feature_buffer;
    
    533
    +
    
    534
    +    /* List of features containing type 3 lookups. */
    
    535
    +    hb_tag_t  feature_list[] =
    
    536
    +    {
    
    537
    +      HB_TAG( 's', 'a', 'l', 't' ),
    
    538
    +      HB_TAG( 's', 'w', 's', 'h' ),
    
    539
    +      HB_TAG( 'n', 'a', 'l', 't' ),
    
    540
    +      HB_TAG_NONE
    
    541
    +    };
    
    542
    +
    
    543
    +    hb_codepoint_t  lookup_index;
    
    544
    +    FT_UInt         base_glyph_index;
    
    545
    +
    
    546
    +
    
    547
    +    if ( !hb_set_allocation_successful( feature_tags )           ||
    
    548
    +         !hb_buffer_allocation_successful( codepoint_buffer )    ||
    
    549
    +         !hb_set_allocation_successful ( type_3_lookup_indices ) )
    
    550
    +    {
    
    551
    +      error = FT_Err_Out_Of_Memory;
    
    552
    +      goto Exit;
    
    553
    +    }
    
    554
    +
    
    555
    +    /* Populate `feature_tags` using the output of */
    
    556
    +    /* `hb_ot_layout_table_get_feature_tags`.      */
    
    557
    +    feature_list_done = 0;
    
    558
    +    start_offset      = 0;
    
    559
    +
    
    560
    +    while ( !feature_list_done )
    
    561
    +    {
    
    562
    +      unsigned int  feature_count = 20;
    
    563
    +      hb_tag_t      tags[20];
    
    564
    +
    
    565
    +      unsigned int  i;
    
    566
    +
    
    567
    +
    
    568
    +      hb_ot_layout_table_get_feature_tags( hb_face,
    
    569
    +                                           HB_OT_TAG_GSUB,
    
    570
    +                                           start_offset,
    
    571
    +                                           &feature_count,
    
    572
    +                                           tags );
    
    573
    +      start_offset += 20;
    
    574
    +      if ( feature_count < 20 )
    
    575
    +        feature_list_done = 1;
    
    576
    +
    
    577
    +      for ( i = 0; i < feature_count; i++ )
    
    578
    +        hb_set_add( feature_tags, tags[i] );
    
    579
    +
    
    580
    +      if ( !hb_set_allocation_successful( feature_tags ) )
    
    581
    +      {
    
    582
    +        error = FT_Err_Out_Of_Memory;
    
    583
    +        goto Exit;
    
    584
    +      }
    
    585
    +    }
    
    586
    +
    
    587
    +    /* Make a buffer only consisting of the given code point. */
    
    588
    +    if ( !hb_buffer_pre_allocate( codepoint_buffer, 1 ) )
    
    589
    +    {
    
    590
    +      error = FT_Err_Out_Of_Memory;
    
    591
    +      goto Exit;
    
    592
    +    }
    
    593
    +    hb_buffer_set_direction( codepoint_buffer, HB_DIRECTION_LTR );
    
    594
    +    hb_buffer_add( codepoint_buffer, codepoint, 0 );
    
    595
    +
    
    596
    +    /* The array of features that is used by the recursive part has at */
    
    597
    +    /* most as many entries as there are features, so make the length  */
    
    598
    +    /* equal to the length of `feature_tags`.                          */
    
    599
    +    if ( ( error = FT_NEW_ARRAY( feature_buffer,
    
    600
    +                                 hb_set_get_population( feature_tags ) ) ) )
    
    601
    +      goto Exit;
    
    602
    +
    
    603
    +    error = af_all_glyph_variants_helper( hb_font,
    
    604
    +                                          codepoint_buffer,
    
    605
    +                                          feature_tags,
    
    606
    +                                          feature_buffer,
    
    607
    +                                          0,
    
    608
    +                                          result );
    
    609
    +    if ( error )
    
    610
    +      goto Exit;
    
    611
    +
    
    612
    +    /* Add the alternative glyph forms that come from features using
    
    613
    +       type 3 lookups.
    
    614
    +
    
    615
    +       This file from gtk was very useful in figuring out my approach:
    
    616
    +
    
    617
    +         https://gitlab.gnome.org/GNOME/gtk/-/blob/40f20fee3d8468749dfb233a6f95921c765c1163/gtk/gtkfontchooserwidget.c#L2100
    
    618
    +     */
    
    619
    +    hb_ot_layout_collect_lookups( hb_face,
    
    620
    +                                  HB_OT_TAG_GSUB,
    
    621
    +                                  NULL,
    
    622
    +                                  NULL,
    
    623
    +                                  feature_list,
    
    624
    +                                  type_3_lookup_indices );
    
    625
    +    if ( !hb_set_allocation_successful( type_3_lookup_indices ) )
    
    626
    +    {
    
    627
    +      error = FT_Err_Out_Of_Memory;
    
    628
    +      goto Exit;
    
    629
    +    }
    
    630
    +
    
    631
    +#define MAX_ALTERNATES  100  /* ad-hoc value */
    
    632
    +
    
    633
    +    if ( ( error = FT_NEW_ARRAY( type_3_alternate_glyphs_buffer,
    
    634
    +                                 MAX_ALTERNATES ) ) )
    
    635
    +      goto Exit;
    
    636
    +
    
    637
    +    lookup_index     = HB_SET_VALUE_INVALID;
    
    638
    +    base_glyph_index = FT_Get_Char_Index( face, codepoint );
    
    639
    +
    
    640
    +    if ( base_glyph_index )
    
    641
    +    {
    
    642
    +      while ( hb_set_next( type_3_lookup_indices, &lookup_index ) )
    
    643
    +      {
    
    644
    +        unsigned  alternate_count = MAX_ALTERNATES;
    
    645
    +        unsigned  i;
    
    646
    +
    
    647
    +
    
    648
    +        hb_ot_layout_lookup_get_glyph_alternates(
    
    649
    +          hb_face,
    
    650
    +          lookup_index,
    
    651
    +          base_glyph_index,
    
    652
    +          0,
    
    653
    +          &alternate_count,
    
    654
    +          type_3_alternate_glyphs_buffer );
    
    655
    +
    
    656
    +        for ( i = 0; i < alternate_count; i++ )
    
    657
    +          hb_set_add( result, type_3_alternate_glyphs_buffer[i] );
    
    658
    +      }
    
    659
    +    }
    
    660
    +
    
    661
    +  Exit:
    
    662
    +    hb_set_destroy( feature_tags );
    
    663
    +    hb_buffer_destroy( codepoint_buffer );
    
    664
    +    FT_FREE( feature_buffer );
    
    665
    +    FT_FREE( type_3_alternate_glyphs_buffer );
    
    666
    +
    
    667
    +    return error;
    
    668
    +  }
    
    669
    +
    
    670
    +#endif /*FT_CONFIG_OPTION_USE_HARFBUZZ*/
    
    671
    +
    
    672
    +
    
    673
    +  FT_LOCAL_DEF( FT_Error )
    
    674
    +  af_reverse_character_map_new( AF_ReverseCharacterMap  *map,
    
    675
    +                                AF_FaceGlobals           globals )
    
    676
    +  {
    
    677
    +    FT_Error  error;
    
    678
    +
    
    679
    +    FT_Face    face   = globals->face;
    
    680
    +    FT_Memory  memory = face->memory;
    
    681
    +
    
    682
    +    FT_CharMap  old_charmap;
    
    683
    +
    
    684
    +    FT_Long  capacity;
    
    685
    +
    
    686
    +
    
    687
    +    /* Search for a unicode charmap.           */
    
    688
    +    /* If there isn't one, create a blank map. */
    
    689
    +
    
    690
    +    FT_TRACE4(( "af_reverse_character_map_new:"
    
    691
    +                " building reverse character map\n" ));
    
    692
    +
    
    693
    +    /* Back up `face->charmap` because `find_unicode_charmap` sets it. */
    
    694
    +    old_charmap = face->charmap;
    
    695
    +
    
    696
    +    if ( ( error = find_unicode_charmap( face ) ) )
    
    697
    +      goto Exit;
    
    698
    +
    
    699
    +    *map = NULL;
    
    700
    +    if ( FT_NEW( *map ) )
    
    701
    +      goto Exit;
    
    702
    +
    
    703
    +    /* Start with a capacity of 10 entries. */
    
    704
    +    capacity         = 10;
    
    705
    +    ( *map )->length = 0;
    
    706
    +
    
    707
    +    if ( FT_NEW_ARRAY( ( *map )->entries, capacity ) )
    
    708
    +      goto Exit;
    
    709
    +
    
    710
    +#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ
    
    711
    +
    
    712
    +    {
    
    713
    +      hb_font_t  *hb_font    = globals->hb_font;
    
    714
    +      hb_set_t   *result_set = hb_set_create();
    
    715
    +
    
    716
    +      FT_ULong  i;
    
    717
    +
    
    718
    +
    
    719
    +      if ( !hb_set_allocation_successful( result_set ) )
    
    720
    +      {
    
    721
    +        error = FT_Err_Out_Of_Memory;
    
    722
    +        goto harfbuzz_path_Exit;
    
    723
    +      }
    
    724
    +
    
    725
    +      /* Find all glyph variants of the code points, then make an entry */
    
    726
    +      /* from the glyph to the code point for each one.                 */
    
    727
    +      for ( i = 0; i < AF_ADJUSTMENT_DATABASE_LENGTH; i++ )
    
    728
    +      {
    
    729
    +        FT_UInt32  codepoint = adjustment_database[i].codepoint;
    
    730
    +
    
    731
    +        hb_codepoint_t  glyph;
    
    732
    +
    
    733
    +
    
    734
    +        error = af_all_glyph_variants( face,
    
    735
    +                                       hb_font,
    
    736
    +                                       codepoint,
    
    737
    +                                       result_set );
    
    738
    +        if ( error )
    
    739
    +          goto harfbuzz_path_Exit;
    
    740
    +
    
    741
    +        glyph = HB_SET_VALUE_INVALID;
    
    742
    +
    
    743
    +        while ( hb_set_next( result_set, &glyph ) )
    
    744
    +        {
    
    745
    +          FT_Long  insert_point;
    
    746
    +
    
    747
    +
    
    748
    +          error = af_reverse_character_map_expand( *map, &capacity, memory );
    
    749
    +          if ( error )
    
    750
    +            goto harfbuzz_path_Exit;
    
    751
    +
    
    752
    +          insert_point = ( *map )->length;
    
    753
    +
    
    754
    +          ( *map )->length++;
    
    755
    +          ( *map )->entries[insert_point].glyph_index = glyph;
    
    756
    +          ( *map )->entries[insert_point].codepoint   = codepoint;
    
    757
    +        }
    
    758
    +
    
    759
    +        hb_set_clear( result_set );
    
    760
    +      }
    
    761
    +
    
    762
    +    harfbuzz_path_Exit:
    
    763
    +      hb_set_destroy( result_set );
    
    764
    +      if ( error )
    
    765
    +        goto Exit;
    
    766
    +    }
    
    767
    +
    
    768
    +#else /* !FT_CONFIG_OPTION_USE_HARFBUZZ */
    
    769
    +
    
    770
    +    {
    
    771
    +      FT_UInt  i;
    
    772
    +#ifdef FT_DEBUG_LEVEL_TRACE
    
    773
    +      int  failed_lookups = 0;
    
    774
    +#endif
    
    775
    +
    
    776
    +
    
    777
    +      for ( i = 0; i < AF_ADJUSTMENT_DATABASE_LENGTH; i++ )
    
    778
    +      {
    
    779
    +        FT_UInt32  codepoint = adjustment_database[i].codepoint;
    
    780
    +        FT_Int     glyph     = FT_Get_Char_Index( face, codepoint );
    
    781
    +
    
    782
    +
    
    783
    +        if ( glyph == 0 )
    
    784
    +        {
    
    785
    +#ifdef FT_DEBUG_LEVEL_TRACE
    
    786
    +          failed_lookups++;
    
    787
    +#endif
    
    788
    +          continue;
    
    789
    +        }
    
    790
    +
    
    791
    +        error = af_reverse_character_map_expand( *map, &capacity, memory );
    
    792
    +        if ( error )
    
    793
    +          goto Exit;
    
    794
    +
    
    795
    +        ( *map )->length++;
    
    796
    +        ( *map )->entries[i].glyph_index = glyph;
    
    797
    +        ( *map )->entries[i].codepoint   = codepoint;
    
    798
    +      }
    
    799
    +    }
    
    800
    +
    
    801
    +#endif /* !FT_CONFIG_OPTION_USE_HARFBUZZ */
    
    802
    +
    
    803
    +    ft_qsort( ( *map )->entries,
    
    804
    +              ( *map )->length,
    
    805
    +              sizeof ( AF_ReverseMapEntry ),
    
    806
    +              af_reverse_character_map_entry_compare );
    
    807
    +
    
    808
    +    FT_TRACE4(( "    reverse character map built successfully"
    
    809
    +                " with %ld entries\n", (*map)->length ));
    
    810
    +
    
    811
    +  Exit:
    
    812
    +    face->charmap = old_charmap;
    
    813
    +
    
    814
    +    if ( error )
    
    815
    +    {
    
    816
    +      FT_TRACE4(( "    error while building reverse character map."
    
    817
    +                  " Using blank map.\n" ));
    
    818
    +
    
    819
    +      if ( *map )
    
    820
    +        FT_FREE( ( *map )->entries );
    
    821
    +
    
    822
    +      FT_FREE( *map );
    
    823
    +      *map = NULL;
    
    824
    +      return error;
    
    825
    +    }
    
    826
    +
    
    827
    +    return FT_Err_Ok;
    
    828
    +  }
    
    829
    +
    
    830
    +
    
    831
    +  FT_LOCAL_DEF( FT_Error )
    
    832
    +  af_reverse_character_map_done( AF_ReverseCharacterMap  map,
    
    833
    +                                 FT_Memory               memory )
    
    834
    +  {
    
    835
    +    if ( map )
    
    836
    +      FT_FREE( map->entries );
    
    837
    +    FT_FREE( map );
    
    838
    +
    
    839
    +    return FT_Err_Ok;
    
    840
    +  }
    
    841
    +
    
    842
    +
    
    843
    +/* END */

  • src/autofit/afadjust.h
    1
    +/****************************************************************************
    
    2
    + *
    
    3
    + * afadjust.h
    
    4
    + *
    
    5
    + *   Auto-fitter routines to adjust components based on charcode (header).
    
    6
    + *
    
    7
    + * Copyright (C) 2023-2024 by
    
    8
    + * David Turner, Robert Wilhelm, and Werner Lemberg.
    
    9
    + *
    
    10
    + * Written by Craig White <gerzytet@gmail.com>.
    
    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
    +
    
    21
    +#ifndef AFADJUST_H_
    
    22
    +#define AFADJUST_H_
    
    23
    +
    
    24
    +#include <freetype/fttypes.h>
    
    25
    +
    
    26
    +#include "afglobal.h"
    
    27
    +#include "aftypes.h"
    
    28
    +
    
    29
    +
    
    30
    +FT_BEGIN_HEADER
    
    31
    +
    
    32
    +
    
    33
    +  /* The type of adjustment that should be done to prevent cases where   */
    
    34
    +  /* two parts of a character stacked vertically merge, even though they */
    
    35
    +  /* should be separate.                                                 */
    
    36
    +  typedef enum  AF_VerticalSeparationAdjustmentType_
    
    37
    +  {
    
    38
    +    /* This means that the hinter should find the topmost contour and push */
    
    39
    +    /* it up until its lowest point is one pixel above the highest point   */
    
    40
    +    /* not part of that contour.                                           */
    
    41
    +    AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP,
    
    42
    +
    
    43
    +    /* This is the opposite direction.  The hinter should find the         */
    
    44
    +    /* bottommost contour and push it down until there is a one-pixel gap. */
    
    45
    +    AF_VERTICAL_ADJUSTMENT_BOTTOM_CONTOUR_DOWN,
    
    46
    +
    
    47
    +    AF_VERTICAL_ADJUSTMENT_NONE
    
    48
    +
    
    49
    +  } AF_VerticalSeparationAdjustmentType;
    
    50
    +
    
    51
    +
    
    52
    +  typedef struct  AF_AdjustmentDatabaseEntry_
    
    53
    +  {
    
    54
    +    FT_UInt32                            codepoint;
    
    55
    +    AF_VerticalSeparationAdjustmentType  vertical_separation_adjustment_type;
    
    56
    +    FT_Bool                              apply_tilde;
    
    57
    +
    
    58
    +  } AF_AdjustmentDatabaseEntry;
    
    59
    +
    
    60
    +
    
    61
    +  FT_LOCAL( AF_VerticalSeparationAdjustmentType )
    
    62
    +  af_lookup_vertical_separation_type( AF_ReverseCharacterMap  map,
    
    63
    +                                      FT_Int                  glyph_index );
    
    64
    +
    
    65
    +  FT_LOCAL( FT_Bool )
    
    66
    +  af_lookup_tilde_correction_type( AF_ReverseCharacterMap  map,
    
    67
    +                                   FT_Int                  glyph_index );
    
    68
    +
    
    69
    +  /* Allocate and populate the reverse character map, */
    
    70
    +  /* using the character map within the face.         */
    
    71
    +  FT_LOCAL( FT_Error )
    
    72
    +  af_reverse_character_map_new( AF_ReverseCharacterMap  *map,
    
    73
    +                                AF_FaceGlobals           globals );
    
    74
    +
    
    75
    +  /* Free the reverse character map. */
    
    76
    +  FT_LOCAL( FT_Error )
    
    77
    +  af_reverse_character_map_done( AF_ReverseCharacterMap  map,
    
    78
    +                                 FT_Memory               memory );
    
    79
    +
    
    80
    +
    
    81
    +FT_END_HEADER
    
    82
    +
    
    83
    +#endif /* AFADJUST_H_ */
    
    84
    +
    
    85
    +
    
    86
    +/* END */

  • src/autofit/aflatin.c
    ... ... @@ -22,6 +22,7 @@
    22 22
     #include "afglobal.h"
    
    23 23
     #include "aflatin.h"
    
    24 24
     #include "aferrors.h"
    
    25
    +#include "afadjust.h"
    
    25 26
     
    
    26 27
     
    
    27 28
       /**************************************************************************
    
    ... ... @@ -1155,6 +1156,9 @@
    1155 1156
           af_latin_metrics_check_digits( metrics, face );
    
    1156 1157
         }
    
    1157 1158
     
    
    1159
    +    af_reverse_character_map_new( &metrics->root.reverse_charmap,
    
    1160
    +                                  metrics->root.globals );
    
    1161
    +
    
    1158 1162
       Exit:
    
    1159 1163
         face->charmap = oldmap;
    
    1160 1164
         return error;
    
    ... ... @@ -1485,6 +1489,17 @@
    1485 1489
       }
    
    1486 1490
     
    
    1487 1491
     
    
    1492
    +  FT_CALLBACK_DEF( void )
    
    1493
    +  af_latin_metrics_done( AF_StyleMetrics  metrics_ )
    
    1494
    +  {
    
    1495
    +    AF_LatinMetrics  metrics = (AF_LatinMetrics)metrics_;
    
    1496
    +
    
    1497
    +
    
    1498
    +    af_reverse_character_map_done( metrics->root.reverse_charmap,
    
    1499
    +                                   metrics->root.globals->face->memory );
    
    1500
    +  }
    
    1501
    +
    
    1502
    +
    
    1488 1503
       /* Scale global values in both directions. */
    
    1489 1504
     
    
    1490 1505
       FT_LOCAL_DEF( void )
    
    ... ... @@ -2738,6 +2753,601 @@
    2738 2753
       }
    
    2739 2754
     
    
    2740 2755
     
    
    2756
    +#undef  FT_COMPONENT
    
    2757
    +#define FT_COMPONENT  afadjust
    
    2758
    +
    
    2759
    +
    
    2760
    +  static void
    
    2761
    +  af_move_contour_vertically( AF_Point  contour,
    
    2762
    +                              FT_Int    movement )
    
    2763
    +  {
    
    2764
    +    AF_Point  point       = contour;
    
    2765
    +    AF_Point  first_point = point;
    
    2766
    +
    
    2767
    +
    
    2768
    +    if ( point )
    
    2769
    +    {
    
    2770
    +      do
    
    2771
    +      {
    
    2772
    +        point->y += movement;
    
    2773
    +        point     = point->next;
    
    2774
    +
    
    2775
    +      } while ( point != first_point );
    
    2776
    +    }
    
    2777
    +  }
    
    2778
    +
    
    2779
    +
    
    2780
    +  static FT_Int
    
    2781
    +  af_find_highest_contour( AF_GlyphHints  hints )
    
    2782
    +  {
    
    2783
    +    FT_Int  highest_contour = -1;
    
    2784
    +
    
    2785
    +    FT_Pos  highest_min_y = 0;
    
    2786
    +    FT_Pos  current_min_y = 0;
    
    2787
    +
    
    2788
    +    FT_Int  contour;
    
    2789
    +
    
    2790
    +
    
    2791
    +    for ( contour = 0; contour < hints->num_contours; contour++ )
    
    2792
    +    {
    
    2793
    +      AF_Point  point       = hints->contours[contour];
    
    2794
    +      AF_Point  first_point = point;
    
    2795
    +
    
    2796
    +
    
    2797
    +      if ( !point )
    
    2798
    +        continue;
    
    2799
    +
    
    2800
    +      current_min_y = point->y;
    
    2801
    +
    
    2802
    +      do
    
    2803
    +      {
    
    2804
    +        if ( point->y < current_min_y )
    
    2805
    +          current_min_y = point->y;
    
    2806
    +        point = point->next;
    
    2807
    +
    
    2808
    +      } while ( point != first_point );
    
    2809
    +
    
    2810
    +      if ( highest_contour == -1 || current_min_y > highest_min_y )
    
    2811
    +      {
    
    2812
    +        highest_min_y   = current_min_y;
    
    2813
    +        highest_contour = contour;
    
    2814
    +      }
    
    2815
    +    }
    
    2816
    +
    
    2817
    +    return highest_contour;
    
    2818
    +  }
    
    2819
    +
    
    2820
    +
    
    2821
    +  static void
    
    2822
    +  af_remove_segments_containing_point( AF_GlyphHints  hints,
    
    2823
    +                                       AF_Point       point )
    
    2824
    +  {
    
    2825
    +    AF_AxisHints  axis     = &hints->axis[AF_DIMENSION_VERT];
    
    2826
    +    AF_Segment    segments = axis->segments;
    
    2827
    +
    
    2828
    +    FT_UInt  i;
    
    2829
    +
    
    2830
    +
    
    2831
    +    for ( i = 0; i < axis->num_segments; i++ )
    
    2832
    +    {
    
    2833
    +      AF_Segment  seg = &segments[i];
    
    2834
    +      AF_Point    p   = seg->first;
    
    2835
    +
    
    2836
    +      FT_Bool  remove = 0;
    
    2837
    +
    
    2838
    +
    
    2839
    +      while ( 1 )
    
    2840
    +      {
    
    2841
    +        if ( p == point )
    
    2842
    +        {
    
    2843
    +          remove = 1;
    
    2844
    +          break;
    
    2845
    +        }
    
    2846
    +
    
    2847
    +        if ( p == seg->last )
    
    2848
    +          break;
    
    2849
    +
    
    2850
    +        p = p->next;
    
    2851
    +      }
    
    2852
    +
    
    2853
    +      if ( remove )
    
    2854
    +      {
    
    2855
    +        /* First, check the first and last segment of the edge. */
    
    2856
    +        AF_Edge  edge = seg->edge;
    
    2857
    +
    
    2858
    +
    
    2859
    +        if ( edge->first == seg && edge->last == seg )
    
    2860
    +        {
    
    2861
    +          /* The edge only consists of the segment to be removed. */
    
    2862
    +          /* Remove the edge.                                     */
    
    2863
    +          *edge = axis->edges[--axis->num_edges];
    
    2864
    +        }
    
    2865
    +        else
    
    2866
    +        {
    
    2867
    +          if ( edge->first == seg )
    
    2868
    +            edge->first = seg->edge_next;
    
    2869
    +
    
    2870
    +          if ( edge->last == seg )
    
    2871
    +          {
    
    2872
    +            edge->last = edge->first;
    
    2873
    +
    
    2874
    +            while ( edge->last->edge_next != seg )
    
    2875
    +              edge->last = edge->last->edge_next;
    
    2876
    +          }
    
    2877
    +        }
    
    2878
    +
    
    2879
    +        /* Now, delete the segment. */
    
    2880
    +        *seg = axis->segments[--axis->num_segments];
    
    2881
    +
    
    2882
    +        i--; /* We have to check the new segment at this position. */
    
    2883
    +      }
    
    2884
    +    }
    
    2885
    +  }
    
    2886
    +
    
    2887
    +
    
    2888
    +  /* Remove all segments containing points on the tilde contour. */
    
    2889
    +  static void
    
    2890
    +  af_latin_remove_tilde_points_from_edges( AF_GlyphHints  hints )
    
    2891
    +  {
    
    2892
    +    FT_Int    highest_contour = af_find_highest_contour( hints );
    
    2893
    +    AF_Point  first_point     = hints->contours[highest_contour];
    
    2894
    +
    
    2895
    +    AF_Point  p = first_point;
    
    2896
    +
    
    2897
    +
    
    2898
    +    do
    
    2899
    +    {
    
    2900
    +      p = p->next;
    
    2901
    +      af_remove_segments_containing_point( hints, p );
    
    2902
    +
    
    2903
    +    } while ( p != first_point );
    
    2904
    +  }
    
    2905
    +
    
    2906
    +
    
    2907
    +  /*
    
    2908
    +    The tilde-unflattening algorithm sometimes goes too far and makes an
    
    2909
    +    unusually high tilde, where decreasing the ppem will increase the height
    
    2910
    +    instead of a steady decrease in height as less pixels are used.
    
    2911
    +
    
    2912
    +    For example, the 'n tilde' glyph from 'Times New Roman', with forced
    
    2913
    +    autofitting on, exhibits this behaviour in the font size range 16.5 to
    
    2914
    +    18 ppem.
    
    2915
    +  */
    
    2916
    +  static void
    
    2917
    +  af_latin_stretch_tildes( AF_GlyphHints  hints )
    
    2918
    +  {
    
    2919
    +    FT_Int    highest_contour = af_find_highest_contour( hints );
    
    2920
    +    AF_Point  p               = hints->contours[highest_contour];
    
    2921
    +
    
    2922
    +    AF_Point  first_point = p;
    
    2923
    +
    
    2924
    +    FT_Pos    min_y, max_y;
    
    2925
    +    FT_Short  min_fy, max_fy;
    
    2926
    +
    
    2927
    +    FT_Pos  min_measurement;
    
    2928
    +
    
    2929
    +    FT_Pos  height;
    
    2930
    +    FT_Pos  target_height;
    
    2931
    +
    
    2932
    +
    
    2933
    +    min_y  = max_y  = p->y;
    
    2934
    +    min_fy = max_fy = p->fy;
    
    2935
    +
    
    2936
    +    do
    
    2937
    +    {
    
    2938
    +      p = p->next;
    
    2939
    +
    
    2940
    +      if ( p->y < min_y )
    
    2941
    +        min_y = p->y;
    
    2942
    +      if ( p->y > max_y )
    
    2943
    +        max_y = p->y;
    
    2944
    +
    
    2945
    +      if ( p->fy < min_fy )
    
    2946
    +        min_fy = p->fy;
    
    2947
    +      if ( p->fy > max_fy )
    
    2948
    +        max_fy = p->fy;
    
    2949
    +
    
    2950
    +    } while ( p != first_point );
    
    2951
    +
    
    2952
    +    min_measurement = 32000;
    
    2953
    +    do
    
    2954
    +    {
    
    2955
    +      p = p->next;
    
    2956
    +
    
    2957
    +      if ( !( p->flags & AF_FLAG_CONTROL )          &&
    
    2958
    +           p->prev->y == p->y && p->next->y == p->y &&
    
    2959
    +           p->y != min_y && p->y != max_y           &&
    
    2960
    +           p->prev->flags & AF_FLAG_CONTROL         &&
    
    2961
    +           p->next->flags & AF_FLAG_CONTROL         )
    
    2962
    +      {
    
    2963
    +        /* This point could be a candidate.  Find the next and previous */
    
    2964
    +        /* on-curve points, and make sure they are both either above or */
    
    2965
    +        /* below the point, then make the measurement.                  */
    
    2966
    +        AF_Point  prevOn = p->prev;
    
    2967
    +        AF_Point  nextOn = p->next;
    
    2968
    +
    
    2969
    +        FT_Pos  measurement;
    
    2970
    +
    
    2971
    +
    
    2972
    +        while ( prevOn->flags & AF_FLAG_CONTROL )
    
    2973
    +          prevOn = prevOn->prev;
    
    2974
    +        while ( nextOn->flags & AF_FLAG_CONTROL )
    
    2975
    +          nextOn = nextOn->next;
    
    2976
    +
    
    2977
    +        if ( nextOn->y > p->y && prevOn->y > p->y )
    
    2978
    +          measurement = p->y - min_y;
    
    2979
    +        else if ( nextOn->y < p->y && prevOn->y < p->y )
    
    2980
    +          measurement = max_y - p->y;
    
    2981
    +        else
    
    2982
    +          continue;
    
    2983
    +
    
    2984
    +        if ( measurement < min_measurement )
    
    2985
    +          min_measurement = measurement;
    
    2986
    +      }
    
    2987
    +    } while ( p != first_point );
    
    2988
    +
    
    2989
    +    /* touch all points */
    
    2990
    +    p = first_point;
    
    2991
    +    do
    
    2992
    +    {
    
    2993
    +      p = p->next;
    
    2994
    +      if ( !( p->flags & AF_FLAG_CONTROL ) )
    
    2995
    +        p->flags |= AF_FLAG_TOUCH_Y;
    
    2996
    +
    
    2997
    +    } while ( p != first_point );
    
    2998
    +
    
    2999
    +    height        = max_y - min_y;
    
    3000
    +    target_height = min_measurement + 64;
    
    3001
    +
    
    3002
    +    if ( height >= target_height )
    
    3003
    +      return;
    
    3004
    +
    
    3005
    +    p = first_point;
    
    3006
    +    do
    
    3007
    +    {
    
    3008
    +      p     = p->next;
    
    3009
    +      p->y  = ( ( p->y - min_y ) * target_height / height ) + min_y;
    
    3010
    +      p->fy = ( ( p->fy - min_fy ) * target_height / height ) + min_fy;
    
    3011
    +      p->oy = p->y;
    
    3012
    +
    
    3013
    +    } while ( p != first_point );
    
    3014
    +  }
    
    3015
    +
    
    3016
    +
    
    3017
    +  /*
    
    3018
    +    As part of `af_latin_stretch_tildes`, all points in the tilde are marked
    
    3019
    +    as touched, so the existing grid fitting will leave the tilde misaligned
    
    3020
    +    with the grid.
    
    3021
    +
    
    3022
    +    This function moves the tilde contour down to be grid-fitted.  We assume
    
    3023
    +    that if moving the tilde down would cause it to touch or overlap another
    
    3024
    +    countour, the vertical adjustment step will fix it.
    
    3025
    +
    
    3026
    +    Because the vertical adjustment step comes after all other grid-fitting
    
    3027
    +    steps, the top edge of the contour under the tilde is usually aligned
    
    3028
    +    with a horizontal grid line.  The vertical gap enforced by the vertical
    
    3029
    +    adjustment is exactly one pixel, so if the top edge of the contour below
    
    3030
    +    the tilde is on a grid line, the resulting tilde contour will also be
    
    3031
    +    grid-aligned.
    
    3032
    +
    
    3033
    +    But in cases where the gap is already big enough so that the vertical
    
    3034
    +    adjustment does nothing, this function ensures that even without the
    
    3035
    +    intervention of the vertical adjustment step, the tilde will be
    
    3036
    +    grid-aligned.
    
    3037
    +  */
    
    3038
    +  static void
    
    3039
    +  af_latin_align_tildes( AF_GlyphHints  hints )
    
    3040
    +  {
    
    3041
    +    FT_Int  highest_contour = af_find_highest_contour( hints );
    
    3042
    +
    
    3043
    +    AF_Point  p           = hints->contours[highest_contour];
    
    3044
    +    AF_Point  first_point = p;
    
    3045
    +
    
    3046
    +    FT_Pos  min_y, max_y;
    
    3047
    +    FT_Pos  min_y_rounded;
    
    3048
    +    FT_Pos  delta;
    
    3049
    +
    
    3050
    +
    
    3051
    +    do
    
    3052
    +    {
    
    3053
    +      p = p->next;
    
    3054
    +      if ( p->y < min_y )
    
    3055
    +        min_y = p->y;
    
    3056
    +      if ( p->y > max_y )
    
    3057
    +        max_y = p->y;
    
    3058
    +
    
    3059
    +    } while ( p != first_point );
    
    3060
    +
    
    3061
    +    // mid_y = ( min_y + max_y ) / 2;
    
    3062
    +    min_y_rounded = FT_PIX_ROUND( min_y );
    
    3063
    +    delta         = min_y_rounded - min_y;
    
    3064
    +
    
    3065
    +    do
    
    3066
    +    {
    
    3067
    +      p     = p->next;
    
    3068
    +      p->y += delta;
    
    3069
    +
    
    3070
    +    } while ( p != first_point );
    
    3071
    +  }
    
    3072
    +
    
    3073
    +
    
    3074
    +  /* Return 1 if the given contour overlaps horizontally with the bounding */
    
    3075
    +  /* box of all other contours combined.  This is a helper for function    */
    
    3076
    +  /* `af_glyph_hints_apply_vertical_separation_adjustments`.               */
    
    3077
    +  static FT_Bool
    
    3078
    +  af_check_contour_horizontal_overlap( AF_GlyphHints  hints,
    
    3079
    +                                       FT_Int         contour_index )
    
    3080
    +  {
    
    3081
    +    FT_Pos  contour_max_x = -32000;
    
    3082
    +    FT_Pos  contour_min_x =  32000;
    
    3083
    +    FT_Pos  others_max_x  = -32000;
    
    3084
    +    FT_Pos  others_min_x  =  32000;
    
    3085
    +
    
    3086
    +    FT_Int  contour;
    
    3087
    +
    
    3088
    +    FT_Bool  horizontal_overlap;
    
    3089
    +
    
    3090
    +
    
    3091
    +    for ( contour = 0; contour < hints->num_contours; contour++ )
    
    3092
    +    {
    
    3093
    +      AF_Point  first_point = hints->contours[contour];
    
    3094
    +      AF_Point  p           = first_point;
    
    3095
    +
    
    3096
    +
    
    3097
    +      do
    
    3098
    +      {
    
    3099
    +        p = p->next;
    
    3100
    +
    
    3101
    +        if ( contour == contour_index )
    
    3102
    +        {
    
    3103
    +          if ( p->x < contour_min_x )
    
    3104
    +            contour_min_x = p->x;
    
    3105
    +          if ( p->x > contour_max_x )
    
    3106
    +            contour_max_x = p->x;
    
    3107
    +        }
    
    3108
    +        else
    
    3109
    +        {
    
    3110
    +          if ( p->x < others_min_x )
    
    3111
    +            others_min_x = p->x;
    
    3112
    +          if ( p->x > others_max_x )
    
    3113
    +            others_max_x = p->x;
    
    3114
    +        }
    
    3115
    +      } while ( p != first_point );
    
    3116
    +    }
    
    3117
    +
    
    3118
    +    horizontal_overlap =
    
    3119
    +      ( others_min_x <= contour_max_x && contour_max_x <= others_max_x ) ||
    
    3120
    +      ( others_min_x <= contour_min_x && contour_min_x <= others_max_x ) ||
    
    3121
    +      ( contour_max_x >= others_max_x && contour_min_x <= others_min_x );
    
    3122
    +
    
    3123
    +    return horizontal_overlap;
    
    3124
    +  }
    
    3125
    +
    
    3126
    +
    
    3127
    +  static void
    
    3128
    +  af_glyph_hints_apply_vertical_separation_adjustments(
    
    3129
    +    AF_GlyphHints           hints,
    
    3130
    +    AF_Dimension            dim,
    
    3131
    +    FT_Int                  glyph_index,
    
    3132
    +    AF_ReverseCharacterMap  reverse_charmap )
    
    3133
    +  {
    
    3134
    +    FT_TRACE4(( "Entering"
    
    3135
    +                " af_glyph_hints_apply_vertical_separation_adjustments\n" ));
    
    3136
    +
    
    3137
    +    if ( dim != AF_DIMENSION_VERT )
    
    3138
    +      return;
    
    3139
    +
    
    3140
    +    if ( af_lookup_vertical_separation_type( reverse_charmap,
    
    3141
    +                                             glyph_index ) ==
    
    3142
    +           AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP              &&
    
    3143
    +         hints->num_contours >= 2                             )
    
    3144
    +    {
    
    3145
    +      FT_Int  highest_contour = -1;
    
    3146
    +      FT_Pos  highest_min_y   = 0;
    
    3147
    +      FT_Pos  current_min_y   = 0;
    
    3148
    +
    
    3149
    +      FT_Int   contour;
    
    3150
    +      FT_Bool  horizontal_overlap;
    
    3151
    +      FT_Int   adjustment_amount;
    
    3152
    +
    
    3153
    +      FT_TRACE4(( "af_glyph_hints_apply_vertical_separation_adjustments:\n"
    
    3154
    +                  "  Applying vertical adjustment:"
    
    3155
    +                  " AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP\n" ));
    
    3156
    +
    
    3157
    +      /* Figure out which contour is the higher one by finding the one */
    
    3158
    +      /* with the highest minimum y value.                             */
    
    3159
    +      for ( contour = 0; contour < hints->num_contours; contour++ )
    
    3160
    +      {
    
    3161
    +        AF_Point  point       = hints->contours[contour];
    
    3162
    +        AF_Point  first_point = point;
    
    3163
    +
    
    3164
    +
    
    3165
    +        if ( !point )
    
    3166
    +          continue;
    
    3167
    +
    
    3168
    +        current_min_y = point->y;
    
    3169
    +
    
    3170
    +        do
    
    3171
    +        {
    
    3172
    +          if ( point->y < current_min_y )
    
    3173
    +            current_min_y = point->y;
    
    3174
    +          point = point->next;
    
    3175
    +
    
    3176
    +        } while ( point != first_point );
    
    3177
    +
    
    3178
    +        if ( highest_contour == -1 || current_min_y > highest_min_y )
    
    3179
    +        {
    
    3180
    +          highest_min_y   = current_min_y;
    
    3181
    +          highest_contour = contour;
    
    3182
    +        }
    
    3183
    +      }
    
    3184
    +
    
    3185
    +      /* Check for a horizontal overlap between the top contour and the */
    
    3186
    +      /* rest.  If there is no overlap, do not adjust.                  */
    
    3187
    +      horizontal_overlap =
    
    3188
    +        af_check_contour_horizontal_overlap( hints, highest_contour );
    
    3189
    +      if ( !horizontal_overlap )
    
    3190
    +      {
    
    3191
    +        FT_TRACE4(( "    Top contour does not horizontally overlap"
    
    3192
    +                    " with other contours.\n"
    
    3193
    +                    "    Skipping adjustment.\n" ));
    
    3194
    +        return;
    
    3195
    +      }
    
    3196
    +
    
    3197
    +      /* If there are any contours that have a maximum y coordinate       */
    
    3198
    +      /* greater than or equal to the minimum y coordinate of the         */
    
    3199
    +      /* previously found highest contour, bump the high contour up until */
    
    3200
    +      /* the distance is one pixel.                                       */
    
    3201
    +      adjustment_amount = 0;
    
    3202
    +
    
    3203
    +      for ( contour = 0; contour < hints->num_contours; contour++ )
    
    3204
    +      {
    
    3205
    +        AF_Point  point;
    
    3206
    +        AF_Point  first_point;
    
    3207
    +
    
    3208
    +        FT_Pos max_y;
    
    3209
    +
    
    3210
    +
    
    3211
    +        if ( contour == highest_contour )
    
    3212
    +          continue;
    
    3213
    +
    
    3214
    +        point       = hints->contours[contour];
    
    3215
    +        first_point = point;
    
    3216
    +        if ( !point )
    
    3217
    +          continue;
    
    3218
    +
    
    3219
    +        max_y = point->y;
    
    3220
    +        do
    
    3221
    +        {
    
    3222
    +          if ( point->y > max_y )
    
    3223
    +            max_y = point->y;
    
    3224
    +          point = point->next;
    
    3225
    +
    
    3226
    +        } while ( point != first_point );
    
    3227
    +
    
    3228
    +        if ( max_y >= highest_min_y - 64 )
    
    3229
    +          adjustment_amount = 64 - ( highest_min_y - max_y );
    
    3230
    +      }
    
    3231
    +
    
    3232
    +      FT_TRACE4(( "    Calculated adjustment amount: %d\n",
    
    3233
    +                  adjustment_amount ));
    
    3234
    +
    
    3235
    +      if ( adjustment_amount > 64 )
    
    3236
    +        FT_TRACE4(( "    Calculated adjustment amount %d"
    
    3237
    +                    " was more than threshold of 64.  Not adjusting\n",
    
    3238
    +                    adjustment_amount ));
    
    3239
    +      else if ( adjustment_amount > 0 )
    
    3240
    +      {
    
    3241
    +        FT_TRACE4(( "    Pushing top contour %d units up\n",
    
    3242
    +                    adjustment_amount ));
    
    3243
    +
    
    3244
    +        af_move_contour_vertically( hints->contours[highest_contour],
    
    3245
    +                                    adjustment_amount );
    
    3246
    +      }
    
    3247
    +    }
    
    3248
    +
    
    3249
    +    else if ( af_lookup_vertical_separation_type( reverse_charmap,
    
    3250
    +                                                  glyph_index ) ==
    
    3251
    +                AF_VERTICAL_ADJUSTMENT_BOTTOM_CONTOUR_DOWN         &&
    
    3252
    +              hints->num_contours >= 2                             )
    
    3253
    +    {
    
    3254
    +      FT_Int  lowest_contour = -1;
    
    3255
    +      FT_Pos  lowest_max_y   = 0;
    
    3256
    +      FT_Pos  current_max_y  = 0;
    
    3257
    +
    
    3258
    +      FT_Int  contour;
    
    3259
    +      FT_Int  adjustment_amount;
    
    3260
    +
    
    3261
    +
    
    3262
    +      FT_TRACE4(( "af_glyph_hints_apply_vertical_separation_adjustments:\n"
    
    3263
    +                  "  Applying vertical adjustment:"
    
    3264
    +                  " AF_VERTICAL_ADJUSTMENT_BOTTOM_CONTOUR_DOWN\n" ));
    
    3265
    +
    
    3266
    +      /* Find lowest contour. */
    
    3267
    +      for ( contour = 0; contour < hints->num_contours; contour++ )
    
    3268
    +      {
    
    3269
    +        AF_Point  point       = hints->contours[contour];
    
    3270
    +        AF_Point  first_point = point;
    
    3271
    +
    
    3272
    +
    
    3273
    +        if ( !point )
    
    3274
    +          continue;
    
    3275
    +
    
    3276
    +        current_max_y = point->y;
    
    3277
    +
    
    3278
    +        do
    
    3279
    +        {
    
    3280
    +          if ( point->y > current_max_y )
    
    3281
    +            current_max_y = point->y;
    
    3282
    +          point = point->next;
    
    3283
    +
    
    3284
    +        } while ( point != first_point );
    
    3285
    +
    
    3286
    +        if ( lowest_contour == -1 || current_max_y < lowest_max_y )
    
    3287
    +        {
    
    3288
    +          lowest_max_y   = current_max_y;
    
    3289
    +          lowest_contour = contour;
    
    3290
    +        }
    
    3291
    +      }
    
    3292
    +
    
    3293
    +      adjustment_amount = 0;
    
    3294
    +
    
    3295
    +      for ( contour = 0; contour < hints->num_contours; contour++ )
    
    3296
    +      {
    
    3297
    +        AF_Point  point;
    
    3298
    +        AF_Point  first_point;
    
    3299
    +
    
    3300
    +        FT_Pos  min_y;
    
    3301
    +
    
    3302
    +
    
    3303
    +        if ( contour == lowest_contour )
    
    3304
    +          continue;
    
    3305
    +
    
    3306
    +        point       = hints->contours[contour];
    
    3307
    +        first_point = point;
    
    3308
    +        if ( !point )
    
    3309
    +          continue;
    
    3310
    +
    
    3311
    +        min_y = point->y;
    
    3312
    +        do
    
    3313
    +        {
    
    3314
    +          if ( point->y < min_y )
    
    3315
    +            min_y = point->y;
    
    3316
    +          point = point->next;
    
    3317
    +
    
    3318
    +        } while ( point != first_point );
    
    3319
    +
    
    3320
    +        if ( min_y <= lowest_max_y - 64 )
    
    3321
    +          adjustment_amount = 64 - ( min_y - lowest_max_y );
    
    3322
    +      }
    
    3323
    +
    
    3324
    +      if ( adjustment_amount > 64 )
    
    3325
    +        FT_TRACE4(( "    Calculated adjustment amount %d"
    
    3326
    +                    " was more than threshold of 64.  Not adjusting\n",
    
    3327
    +                    adjustment_amount ));
    
    3328
    +      else if ( adjustment_amount > 0 )
    
    3329
    +      {
    
    3330
    +        FT_TRACE4(( "    Pushing bottom contour %d units down\n",
    
    3331
    +                    adjustment_amount ));
    
    3332
    +
    
    3333
    +        af_move_contour_vertically( hints->contours[lowest_contour],
    
    3334
    +                                    -adjustment_amount );
    
    3335
    +      }
    
    3336
    +    }
    
    3337
    +
    
    3338
    +    else
    
    3339
    +      FT_TRACE4(( "af_glyph_hints_apply_vertical_separation_adjustments:\n"
    
    3340
    +                  "  No vertical adjustment needed\n" ));
    
    3341
    +
    
    3342
    +    FT_TRACE4(( "Exiting"
    
    3343
    +                " af_glyph_hints_apply_vertical_separation_adjustments\n" ));
    
    3344
    +  }
    
    3345
    +
    
    3346
    +
    
    3347
    +#undef  FT_COMPONENT
    
    3348
    +#define FT_COMPONENT  aflatin
    
    3349
    +
    
    3350
    +
    
    2741 3351
       /* Compute the snapped width of a given stem, ignoring very thin ones. */
    
    2742 3352
       /* There is a lot of voodoo in this function; changing the hard-coded  */
    
    2743 3353
       /* parameters influence the whole hinting process.                     */
    
    ... ... @@ -3548,6 +4158,47 @@
    3548 4158
       }
    
    3549 4159
     
    
    3550 4160
     
    
    4161
    +#ifdef FT_DEBUG_LEVEL_TRACE
    
    4162
    +  /* Print the height of the topmost contour for debugging purposes. */
    
    4163
    +  /* TODO: remove this once the tilde unflattening works.            */
    
    4164
    +  static void
    
    4165
    +  af_latin_trace_height( FT_UInt        num,
    
    4166
    +                         AF_GlyphHints  hints )
    
    4167
    +  {
    
    4168
    +    AF_Point  p           = hints->contours[af_find_highest_contour(hints)];
    
    4169
    +    AF_Point  first_point = p;
    
    4170
    +
    
    4171
    +    FT_Pos  min_y, max_y;
    
    4172
    +
    
    4173
    +
    
    4174
    +    min_y = max_y = p->y;
    
    4175
    +
    
    4176
    +    do
    
    4177
    +    {
    
    4178
    +      p = p->next;
    
    4179
    +      if ( !(p->flags & AF_FLAG_CONTROL) )
    
    4180
    +      {
    
    4181
    +        if ( p->y < min_y )
    
    4182
    +          min_y = p->y;
    
    4183
    +        if ( p->y > max_y )
    
    4184
    +          max_y = p->y;
    
    4185
    +      }
    
    4186
    +
    
    4187
    +    } while ( p != first_point );
    
    4188
    +
    
    4189
    +    FT_TRACE4(( "height %d: %ld\n", num, max_y - min_y ));
    
    4190
    +  }
    
    4191
    +#else
    
    4192
    +  static void
    
    4193
    +  af_latin_trace_height( FT_UInt        num,
    
    4194
    +                         AF_GlyphHints  hints )
    
    4195
    +  {
    
    4196
    +    FT_UNUSED( num );
    
    4197
    +    FT_UNUSED( hints );
    
    4198
    +  }
    
    4199
    +#endif
    
    4200
    +
    
    4201
    +
    
    3551 4202
       /* Apply the complete hinting algorithm to a latin glyph. */
    
    3552 4203
     
    
    3553 4204
       static FT_Error
    
    ... ... @@ -3582,11 +4233,26 @@
    3582 4233
     
    
    3583 4234
         if ( AF_HINTS_DO_VERTICAL( hints ) )
    
    3584 4235
         {
    
    4236
    +      FT_Bool  is_tilde = af_lookup_tilde_correction_type(
    
    4237
    +                            metrics->root.reverse_charmap, glyph_index );
    
    4238
    +
    
    4239
    +
    
    4240
    +      if ( is_tilde )
    
    4241
    +      {
    
    4242
    +        af_latin_trace_height(0, hints );
    
    4243
    +        af_latin_stretch_tildes( hints );
    
    4244
    +        af_latin_align_tildes( hints );
    
    4245
    +        af_latin_trace_height(1, hints );
    
    4246
    +      }
    
    4247
    +
    
    3585 4248
           axis  = &metrics->axis[AF_DIMENSION_VERT];
    
    3586 4249
           error = af_latin_hints_detect_features( hints,
    
    3587 4250
                                                   axis->width_count,
    
    3588 4251
                                                   axis->widths,
    
    3589 4252
                                                   AF_DIMENSION_VERT );
    
    4253
    +      if ( is_tilde )
    
    4254
    +        af_latin_remove_tilde_points_from_edges( hints );
    
    4255
    +
    
    3590 4256
           if ( error )
    
    3591 4257
             goto Exit;
    
    3592 4258
     
    
    ... ... @@ -3602,9 +4268,19 @@
    3602 4268
                ( dim == AF_DIMENSION_VERT && AF_HINTS_DO_VERTICAL( hints ) )   )
    
    3603 4269
           {
    
    3604 4270
             af_latin_hint_edges( hints, (AF_Dimension)dim );
    
    4271
    +        af_latin_trace_height(2, hints );
    
    3605 4272
             af_glyph_hints_align_edge_points( hints, (AF_Dimension)dim );
    
    4273
    +        af_latin_trace_height(3, hints );
    
    3606 4274
             af_glyph_hints_align_strong_points( hints, (AF_Dimension)dim );
    
    4275
    +        af_latin_trace_height(4, hints );
    
    3607 4276
             af_glyph_hints_align_weak_points( hints, (AF_Dimension)dim );
    
    4277
    +        af_latin_trace_height(5, hints );
    
    4278
    +        af_glyph_hints_apply_vertical_separation_adjustments(
    
    4279
    +          hints,
    
    4280
    +          (AF_Dimension)dim,
    
    4281
    +          glyph_index,
    
    4282
    +          metrics->root.reverse_charmap );
    
    4283
    +        af_latin_trace_height(6, hints );
    
    3608 4284
           }
    
    3609 4285
         }
    
    3610 4286
     
    
    ... ... @@ -3633,7 +4309,7 @@
    3633 4309
     
    
    3634 4310
         (AF_WritingSystem_InitMetricsFunc) af_latin_metrics_init,        /* style_metrics_init    */
    
    3635 4311
         (AF_WritingSystem_ScaleMetricsFunc)af_latin_metrics_scale,       /* style_metrics_scale   */
    
    3636
    -    (AF_WritingSystem_DoneMetricsFunc) NULL,                         /* style_metrics_done    */
    
    4312
    +    (AF_WritingSystem_DoneMetricsFunc) af_latin_metrics_done,        /* style_metrics_done    */
    
    3637 4313
         (AF_WritingSystem_GetStdWidthsFunc)af_latin_get_standard_widths, /* style_metrics_getstdw */
    
    3638 4314
     
    
    3639 4315
         (AF_WritingSystem_InitHintsFunc)   af_latin_hints_init,          /* style_hints_init      */
    

  • src/autofit/aftypes.h
    ... ... @@ -406,6 +406,27 @@ extern void* af_debug_hints_;
    406 406
     
    
    407 407
       typedef struct AF_FaceGlobalsRec_*  AF_FaceGlobals;
    
    408 408
     
    
    409
    +
    
    410
    +  /* Store a mapping from glyphs to unicode codepoints. */
    
    411
    +  /* See `afadjust.c` for details.                      */
    
    412
    +  typedef struct  AF_ReverseMapEntry_
    
    413
    +  {
    
    414
    +    FT_Int     glyph_index;
    
    415
    +    FT_UInt32  codepoint;
    
    416
    +
    
    417
    +  } AF_ReverseMapEntry;
    
    418
    +
    
    419
    +
    
    420
    +  typedef struct  AF_ReverseCharacterMapRec_
    
    421
    +  {
    
    422
    +    FT_Long              length;
    
    423
    +    AF_ReverseMapEntry  *entries;
    
    424
    +
    
    425
    +  } AF_ReverseCharacterMapRec;
    
    426
    +
    
    427
    +  typedef struct  AF_ReverseCharacterMapRec_*  AF_ReverseCharacterMap;
    
    428
    +
    
    429
    +
    
    409 430
       /* This is the main structure that combines everything.  Autofit modules */
    
    410 431
       /* specific to writing systems derive their structures from it, for      */
    
    411 432
       /* example `AF_LatinMetrics'.                                            */
    
    ... ... @@ -418,6 +439,8 @@ extern void* af_debug_hints_;
    418 439
     
    
    419 440
         AF_FaceGlobals  globals;    /* to access properties */
    
    420 441
     
    
    442
    +    AF_ReverseCharacterMap  reverse_charmap;
    
    443
    +
    
    421 444
       } AF_StyleMetricsRec;
    
    422 445
     
    
    423 446
     
    

  • src/autofit/autofit.c
    ... ... @@ -19,6 +19,7 @@
    19 19
     #define FT_MAKE_OPTION_SINGLE_OBJECT
    
    20 20
     
    
    21 21
     #include "ft-hb.c"
    
    22
    +#include "afadjust.c"
    
    22 23
     #include "afblue.c"
    
    23 24
     #include "afcjk.c"
    
    24 25
     #include "afdummy.c"
    

  • src/autofit/rules.mk
    ... ... @@ -28,7 +28,8 @@ AUTOF_COMPILE := $(CC) $(ANSIFLAGS) \
    28 28
     
    
    29 29
     # AUTOF driver sources (i.e., C files)
    
    30 30
     #
    
    31
    -AUTOF_DRV_SRC := $(AUTOF_DIR)/afblue.c   \
    
    31
    +AUTOF_DRV_SRC := $(AUTOF_DIR)/afadjust.c \
    
    32
    +                 $(AUTOF_DIR)/afblue.c   \
    
    32 33
                      $(AUTOF_DIR)/afcjk.c    \
    
    33 34
                      $(AUTOF_DIR)/afdummy.c  \
    
    34 35
                      $(AUTOF_DIR)/afglobal.c \
    

  • src/base/ftobjs.c
    ... ... @@ -1359,21 +1359,9 @@
    1359 1359
       }
    
    1360 1360
     
    
    1361 1361
     
    
    1362
    -  /**************************************************************************
    
    1363
    -   *
    
    1364
    -   * @Function:
    
    1365
    -   *   find_unicode_charmap
    
    1366
    -   *
    
    1367
    -   * @Description:
    
    1368
    -   *   This function finds a Unicode charmap, if there is one.
    
    1369
    -   *   And if there is more than one, it tries to favour the more
    
    1370
    -   *   extensive one, i.e., one that supports UCS-4 against those which
    
    1371
    -   *   are limited to the BMP (said UCS-2 encoding.)
    
    1372
    -   *
    
    1373
    -   *   This function is called from open_face() (just below), and also
    
    1374
    -   *   from FT_Select_Charmap( ..., FT_ENCODING_UNICODE ).
    
    1375
    -   */
    
    1376
    -  static FT_Error
    
    1362
    +  /* documentation is in ftobjs.h */
    
    1363
    +
    
    1364
    +  FT_BASE_DEF( FT_Error )
    
    1377 1365
       find_unicode_charmap( FT_Face  face )
    
    1378 1366
       {
    
    1379 1367
         FT_CharMap*  first;
    

  • src/cff/cffobjs.c
    ... ... @@ -694,8 +694,7 @@
    694 694
             FT_UInt  instance_index = (FT_UInt)face_index >> 16;
    
    695 695
     
    
    696 696
     
    
    697
    -        if ( FT_HAS_MULTIPLE_MASTERS( cffface ) &&
    
    698
    -             instance_index > 0                 )
    
    697
    +        if ( FT_HAS_MULTIPLE_MASTERS( cffface ) )
    
    699 698
             {
    
    700 699
               error = FT_Set_Named_Instance( cffface, instance_index );
    
    701 700
               if ( error )
    

  • src/cid/cidparse.c
    ... ... @@ -90,10 +90,15 @@
    90 90
         if ( error )
    
    91 91
           goto Exit;
    
    92 92
     
    
    93
    -  Again:
    
    94
    -    /* now, read the rest of the file until we find */
    
    95
    -    /* `StartData' or `/sfnts'                      */
    
    93
    +    if ( !stream->read ) {
    
    94
    +      /* just parse memory-based streams */
    
    95
    +      offset = stream->size;
    
    96
    +    }
    
    97
    +    else
    
    96 98
         {
    
    99
    +      /* Find the last `StartData` or `/sfnts`.  The parser requires */
    
    100
    +      /* contiguous memory; attempt to pin as little as necessary.   */
    
    101
    +
    
    97 102
           /*
    
    98 103
            * The algorithm is as follows (omitting the case with less than 256
    
    99 104
            * bytes to fill for simplicity).
    
    ... ... @@ -119,7 +124,8 @@
    119 124
           FT_Byte*  p           = buffer;
    
    120 125
     
    
    121 126
     
    
    122
    -      for ( offset = FT_STREAM_POS(); ; offset += 256 )
    
    127
    +      offset = 0;
    
    128
    +      while ( 1 )
    
    123 129
           {
    
    124 130
             FT_ULong  stream_len;
    
    125 131
     
    
    ... ... @@ -127,7 +133,7 @@
    127 133
             stream_len = stream->size - FT_STREAM_POS();
    
    128 134
     
    
    129 135
             read_len = FT_MIN( read_len, stream_len );
    
    130
    -        if ( FT_STREAM_READ( p, read_len ) )
    
    136
    +        if ( read_len && FT_STREAM_READ( p, read_len ) )
    
    131 137
               goto Exit;
    
    132 138
     
    
    133 139
             /* ensure that we do not compare with data beyond the buffer */
    
    ... ... @@ -141,20 +147,23 @@
    141 147
                    ft_strncmp( (char*)p, STARTDATA, STARTDATA_LEN ) == 0 )
    
    142 148
               {
    
    143 149
                 /* save offset of binary data after `StartData' */
    
    144
    -            offset += (FT_ULong)( p - buffer ) + STARTDATA_LEN + 1;
    
    145
    -            goto Found;
    
    150
    +            offset = FT_STREAM_POS() - read_len - read_offset
    
    151
    +                     + (FT_ULong)( p - buffer ) + STARTDATA_LEN + 1;
    
    146 152
               }
    
    147 153
               else if ( p[1] == 's'                                   &&
    
    148 154
                         ft_strncmp( (char*)p, SFNTS, SFNTS_LEN ) == 0 )
    
    149 155
               {
    
    150
    -            offset += (FT_ULong)( p - buffer ) + SFNTS_LEN + 1;
    
    151
    -            goto Found;
    
    156
    +            offset = FT_STREAM_POS() - read_len - read_offset
    
    157
    +                     + (FT_ULong)( p - buffer ) + SFNTS_LEN + 1;
    
    152 158
               }
    
    153 159
             }
    
    154 160
     
    
    155
    -        if ( read_offset + read_len < STARTDATA_LEN )
    
    161
    +        if ( read_offset + read_len <= STARTDATA_LEN )
    
    156 162
             {
    
    157
    -          FT_TRACE2(( "cid_parser_new: no `StartData' keyword found\n" ));
    
    163
    +          if ( offset )
    
    164
    +            goto Found;
    
    165
    +
    
    166
    +          FT_TRACE2(( "cid_parser_new: no `StartData` keyword found\n" ));
    
    158 167
               error = FT_THROW( Invalid_File_Format );
    
    159 168
               goto Exit;
    
    160 169
             }
    
    ... ... @@ -171,9 +180,9 @@
    171 180
         }
    
    172 181
     
    
    173 182
       Found:
    
    174
    -    /* We have found the start of the binary data or the `/sfnts' token. */
    
    175
    -    /* Now rewind and extract the frame corresponding to this PostScript */
    
    176
    -    /* section.                                                          */
    
    183
    +    /* We have found an efficient range to look for the binary data or    */
    
    184
    +    /* `/sfnts' token.  Now rewind and extract the frame corresponding to */
    
    185
    +    /* this PostScript section.                                           */
    
    177 186
     
    
    178 187
         ps_len = offset - base_offset;
    
    179 188
         if ( FT_STREAM_SEEK( base_offset )                  ||
    
    ... ... @@ -187,8 +196,8 @@
    187 196
         parser->root.limit     = parser->root.cursor + ps_len;
    
    188 197
         parser->num_dict       = FT_UINT_MAX;
    
    189 198
     
    
    190
    -    /* Finally, we check whether `StartData' or `/sfnts' was real --  */
    
    191
    -    /* it could be in a comment or string.  We also get the arguments */
    
    199
    +    /* Find the first real `StartData' or `/sfnts' -- the last one    */
    
    200
    +    /* could be in a comment or string.  We also get the arguments    */
    
    192 201
         /* of `StartData' to find out whether the data is represented in  */
    
    193 202
         /* binary or hex format.                                          */
    
    194 203
     
    
    ... ... @@ -216,6 +225,7 @@
    216 225
           {
    
    217 226
             T1_TokenRec  type_token;
    
    218 227
             FT_Long      binary_length;
    
    228
    +        FT_ULong     found_offset;
    
    219 229
     
    
    220 230
     
    
    221 231
             parser->root.cursor = arg1;
    
    ... ... @@ -234,6 +244,24 @@
    234 244
                 parser->binary_length = (FT_ULong)binary_length;
    
    235 245
             }
    
    236 246
     
    
    247
    +        /* set the real values for the parser, if different */
    
    248
    +        found_offset = (FT_ULong)( cur - parser->postscript )
    
    249
    +                       + STARTDATA_LEN + 1;
    
    250
    +        if ( found_offset != offset )
    
    251
    +        {
    
    252
    +          FT_FRAME_RELEASE( parser->postscript );
    
    253
    +
    
    254
    +          ps_len = found_offset - base_offset;
    
    255
    +          if ( FT_STREAM_SEEK( base_offset )                  ||
    
    256
    +               FT_FRAME_EXTRACT( ps_len, parser->postscript ) )
    
    257
    +            goto Exit;
    
    258
    +
    
    259
    +          parser->data_offset    = found_offset;
    
    260
    +          parser->postscript_len = ps_len;
    
    261
    +          parser->root.base      = parser->postscript;
    
    262
    +          parser->root.cursor    = parser->postscript;
    
    263
    +          parser->root.limit     = parser->root.cursor + ps_len;
    
    264
    +        }
    
    237 265
             goto Exit;
    
    238 266
           }
    
    239 267
           else if ( cur[1] == 's'                                   &&
    
    ... ... @@ -251,11 +279,8 @@
    251 279
           cur  = parser->root.cursor;
    
    252 280
         }
    
    253 281
     
    
    254
    -    /* we haven't found the correct `StartData'; go back and continue */
    
    255
    -    /* searching                                                      */
    
    256
    -    FT_FRAME_RELEASE( parser->postscript );
    
    257
    -    if ( !FT_STREAM_SEEK( offset ) )
    
    258
    -      goto Again;
    
    282
    +    FT_TRACE2(( "cid_parser_new: no `StartData` token found\n" ));
    
    283
    +    error = FT_THROW( Invalid_File_Format );
    
    259 284
     
    
    260 285
       Exit:
    
    261 286
         return error;
    

  • src/sfnt/ttcolr.c
    ... ... @@ -661,6 +661,7 @@
    661 661
           FT_UInt32  first_layer_index;
    
    662 662
     
    
    663 663
     
    
    664
    +      ENSURE_READ_BYTES( 5 );
    
    664 665
           num_layers = FT_NEXT_BYTE( p );
    
    665 666
           if ( num_layers > colr->num_layers_v1 )
    
    666 667
             return 0;
    

  • src/truetype/ttgxvar.c
    ... ... @@ -2142,7 +2142,7 @@
    2142 2142
                                              innerIndex );
    
    2143 2143
     
    
    2144 2144
               /* Convert to 16.16 format before adding. */
    
    2145
    -	  v += delta * 4;
    
    2145
    +	  v += MUL_INT( delta, 4 );
    
    2146 2146
     
    
    2147 2147
     	  /* Clamp value range. */
    
    2148 2148
     	  v = v >=  0x10000L ?  0x10000 : v;
    

  • src/truetype/ttobjs.c
    ... ... @@ -784,8 +784,7 @@
    784 784
           FT_UInt  instance_index = (FT_UInt)face_index >> 16;
    
    785 785
     
    
    786 786
     
    
    787
    -      if ( FT_HAS_MULTIPLE_MASTERS( ttface ) &&
    
    788
    -           instance_index > 0                )
    
    787
    +      if ( FT_HAS_MULTIPLE_MASTERS( ttface ) )
    
    789 788
           {
    
    790 789
             error = FT_Set_Named_Instance( ttface, instance_index );
    
    791 790
             if ( error )
    


  • reply via email to

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