tor-browser

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

hb-ot-cff1-table.cc (23687B)


      1 /*
      2 * Copyright © 2018 Adobe Inc.
      3 *
      4 *  This is part of HarfBuzz, a text shaping library.
      5 *
      6 * Permission is hereby granted, without written agreement and without
      7 * license or royalty fees, to use, copy, modify, and distribute this
      8 * software and its documentation for any purpose, provided that the
      9 * above copyright notice and the following two paragraphs appear in
     10 * all copies of this software.
     11 *
     12 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
     13 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
     14 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
     15 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
     16 * DAMAGE.
     17 *
     18 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
     19 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
     20 * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
     21 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
     22 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
     23 *
     24 * Adobe Author(s): Michiharu Ariza
     25 */
     26 
     27 #include "hb.hh"
     28 
     29 #ifndef HB_NO_CFF
     30 
     31 #include "hb-draw.hh"
     32 #include "hb-algs.hh"
     33 #include "hb-ot-cff1-table.hh"
     34 #include "hb-cff1-interp-cs.hh"
     35 
     36 using namespace CFF;
     37 
     38 struct sid_to_gid_t
     39 {
     40  uint16_t  sid;
     41  uint8_t   gid;
     42 
     43  int cmp (uint16_t a) const
     44  {
     45    if (a == sid) return 0;
     46    return (a < sid) ? -1 : 1;
     47  }
     48 };
     49 
     50 /* SID to code */
     51 static const uint8_t standard_encoding_to_code [] =
     52 {
     53    0,   32,   33,   34,   35,   36,   37,   38,  39,   40,   41,   42,   43,   44,   45,   46,
     54   47,   48,   49,   50,   51,   52,   53,   54,  55,   56,   57,   58,   59,   60,   61,   62,
     55   63,   64,   65,   66,   67,   68,   69,   70,  71,   72,   73,   74,   75,   76,   77,   78,
     56   79,   80,   81,   82,   83,   84,   85,   86,  87,   88,   89,   90,   91,   92,   93,   94,
     57   95,   96,   97,   98,   99,  100,  101,  102, 103,  104,  105,  106,  107,  108,  109,  110,
     58  111,  112,  113,  114,  115,  116,  117,  118, 119,  120,  121,  122,  123,  124,  125,  126,
     59  161,  162,  163,  164,  165,  166,  167,  168, 169,  170,  171,  172,  173,  174,  175,  177,
     60  178,  179,  180,  182,  183,  184,  185,  186, 187,  188,  189,  191,  193,  194,  195,  196,
     61  197,  198,  199,  200,  202,  203,  205,  206, 207,  208,  225,  227,  232,  233,  234,  235,
     62  241,  245,  248,  249,  250,  251
     63 };
     64 
     65 /* SID to code */
     66 static const uint8_t expert_encoding_to_code [] =
     67 {
     68    0,   32,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,   44,   45,   46,
     69    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,   58,   59,    0,    0,    0,
     70    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
     71    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
     72    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
     73    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
     74    0,    0,    0,   47,    0,    0,    0,    0,    0,    0,    0,    0,    0,   87,   88,    0,
     75    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
     76    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
     77    0,    0,    0,    0,    0,    0,  201,    0,    0,    0,    0,  189,    0,    0,  188,    0,
     78    0,    0,    0,  190,  202,    0,    0,    0,    0,  203,    0,    0,    0,    0,    0,    0,
     79    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
     80    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
     81    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
     82    0,    0,    0,    0,    0,   33,   34,   36,   37,   38,   39,   40,   41,   42,   43,   48,
     83   49,   50,   51,   52,   53,   54,   55,   56,   57,   60,   61,   62,   63,   65,   66,   67,
     84   68,   69,   73,   76,   77,   78,   79,   82,   83,   84,   86,   89,   90,   91,   93,   94,
     85   95,   96,   97,   98,   99,  100,  101,  102,  103,  104,  105,  106,  107,  108,  109,  110,
     86  111,  112,  113,  114,  115,  116,  117,  118,  119,  120,  121,  122,  123,  124,  125,  126,
     87  161,  162,  163,  166,  167,  168,  169,  170,  172,  175,  178,  179,  182,  183,  184,  191,
     88  192,  193,  194,  195,  196,  197,  200,  204,  205,  206,  207,  208,  209,  210,  211,  212,
     89  213,  214,  215,  216,  217,  218,  219,  220,  221,  222,  223,  224,  225,  226,  227,  228,
     90  229,  230,  231,  232,  233,  234,  235,  236,  237,  238,  239,  240,  241,  242,  243,  244,
     91  245,  246,  247,  248,  249,  250,  251,  252,  253,  254,  255
     92 };
     93 
     94 /* glyph ID to SID */
     95 static const uint16_t expert_charset_to_sid [] =
     96 {
     97    0,    1,  229,  230,  231,  232,  233,  234,  235,  236,  237,  238,   13,   14,   15,   99,
     98  239,  240,  241,  242,  243,  244,  245,  246,  247,  248,   27,   28,  249,  250,  251,  252,
     99  253,  254,  255,  256,  257,  258,  259,  260,  261,  262,  263,  264,  265,  266,  109,  110,
    100  267,  268,  269,  270,  271,  272,  273,  274,  275,  276,  277,  278,  279,  280,  281,  282,
    101  283,  284,  285,  286,  287,  288,  289,  290,  291,  292,  293,  294,  295,  296,  297,  298,
    102  299,  300,  301,  302,  303,  304,  305,  306,  307,  308,  309,  310,  311,  312,  313,  314,
    103  315,  316,  317,  318,  158,  155,  163,  319,  320,  321,  322,  323,  324,  325,  326,  150,
    104  164,  169,  327,  328,  329,  330,  331,  332,  333,  334,  335,  336,  337,  338,  339,  340,
    105  341,  342,  343,  344,  345,  346,  347,  348,  349,  350,  351,  352,  353,  354,  355,  356,
    106  357,  358,  359,  360,  361,  362,  363,  364,  365,  366,  367,  368,  369,  370,  371,  372,
    107  373,  374,  375,  376,  377,  378
    108 };
    109 
    110 /* glyph ID to SID */
    111 static const uint16_t expert_subset_charset_to_sid [] =
    112 {
    113    0,    1,  231,  232,  235,  236,  237,  238,   13,   14,   15,   99,  239,  240,  241,  242,
    114  243,  244,  245,  246,  247,  248,   27,   28,  249,  250,  251,  253,  254,  255,  256,  257,
    115  258,  259,  260,  261,  262,  263,  264,  265,  266,  109,  110,  267,  268,  269,  270,  272,
    116  300,  301,  302,  305,  314,  315,  158,  155,  163,  320,  321,  322,  323,  324,  325,  326,
    117  150,  164,  169,  327,  328,  329,  330,  331,  332,  333,  334,  335,  336,  337,  338,  339,
    118  340,  341,  342,  343,  344,  345,  346
    119 };
    120 
    121 /* SID to glyph ID */
    122 static const sid_to_gid_t expert_charset_sid_to_gid [] =
    123 {
    124    { 1, 1 },     { 13, 12 },   { 14, 13 },   { 15, 14 },
    125    { 27, 26 },   { 28, 27 },   { 99, 15 },   { 109, 46 },
    126    { 110, 47 },  { 150, 111 }, { 155, 101 }, { 158, 100 },
    127    { 163, 102 }, { 164, 112 }, { 169, 113 }, { 229, 2 },
    128    { 230, 3 },   { 231, 4 },   { 232, 5 },   { 233, 6 },
    129    { 234, 7 },   { 235, 8 },   { 236, 9 },   { 237, 10 },
    130    { 238, 11 },  { 239, 16 },  { 240, 17 },  { 241, 18 },
    131    { 242, 19 },  { 243, 20 },  { 244, 21 },  { 245, 22 },
    132    { 246, 23 },  { 247, 24 },  { 248, 25 },  { 249, 28 },
    133    { 250, 29 },  { 251, 30 },  { 252, 31 },  { 253, 32 },
    134    { 254, 33 },  { 255, 34 },  { 256, 35 },  { 257, 36 },
    135    { 258, 37 },  { 259, 38 },  { 260, 39 },  { 261, 40 },
    136    { 262, 41 },  { 263, 42 },  { 264, 43 },  { 265, 44 },
    137    { 266, 45 },  { 267, 48 },  { 268, 49 },  { 269, 50 },
    138    { 270, 51 },  { 271, 52 },  { 272, 53 },  { 273, 54 },
    139    { 274, 55 },  { 275, 56 },  { 276, 57 },  { 277, 58 },
    140    { 278, 59 },  { 279, 60 },  { 280, 61 },  { 281, 62 },
    141    { 282, 63 },  { 283, 64 },  { 284, 65 },  { 285, 66 },
    142    { 286, 67 },  { 287, 68 },  { 288, 69 },  { 289, 70 },
    143    { 290, 71 },  { 291, 72 },  { 292, 73 },  { 293, 74 },
    144    { 294, 75 },  { 295, 76 },  { 296, 77 },  { 297, 78 },
    145    { 298, 79 },  { 299, 80 },  { 300, 81 },  { 301, 82 },
    146    { 302, 83 },  { 303, 84 },  { 304, 85 },  { 305, 86 },
    147    { 306, 87 },  { 307, 88 },  { 308, 89 },  { 309, 90 },
    148    { 310, 91 },  { 311, 92 },  { 312, 93 },  { 313, 94 },
    149    { 314, 95 },  { 315, 96 },  { 316, 97 },  { 317, 98 },
    150    { 318, 99 },  { 319, 103 }, { 320, 104 }, { 321, 105 },
    151    { 322, 106 }, { 323, 107 }, { 324, 108 }, { 325, 109 },
    152    { 326, 110 }, { 327, 114 }, { 328, 115 }, { 329, 116 },
    153    { 330, 117 }, { 331, 118 }, { 332, 119 }, { 333, 120 },
    154    { 334, 121 }, { 335, 122 }, { 336, 123 }, { 337, 124 },
    155    { 338, 125 }, { 339, 126 }, { 340, 127 }, { 341, 128 },
    156    { 342, 129 }, { 343, 130 }, { 344, 131 }, { 345, 132 },
    157    { 346, 133 }, { 347, 134 }, { 348, 135 }, { 349, 136 },
    158    { 350, 137 }, { 351, 138 }, { 352, 139 }, { 353, 140 },
    159    { 354, 141 }, { 355, 142 }, { 356, 143 }, { 357, 144 },
    160    { 358, 145 }, { 359, 146 }, { 360, 147 }, { 361, 148 },
    161    { 362, 149 }, { 363, 150 }, { 364, 151 }, { 365, 152 },
    162    { 366, 153 }, { 367, 154 }, { 368, 155 }, { 369, 156 },
    163    { 370, 157 }, { 371, 158 }, { 372, 159 }, { 373, 160 },
    164    { 374, 161 }, { 375, 162 }, { 376, 163 }, { 377, 164 },
    165    { 378, 165 }
    166 };
    167 
    168 /* SID to glyph ID */
    169 static const sid_to_gid_t expert_subset_charset_sid_to_gid [] =
    170 {
    171  { 1, 1 },       { 13, 8 },      { 14, 9 },      { 15, 10 },
    172  { 27, 22 },     { 28, 23 },     { 99, 11 },     { 109, 41 },
    173  { 110, 42 },    { 150, 64 },    { 155, 55 },    { 158, 54 },
    174  { 163, 56 },    { 164, 65 },    { 169, 66 },    { 231, 2 },
    175  { 232, 3 },     { 235, 4 },     { 236, 5 },     { 237, 6 },
    176  { 238, 7 },     { 239, 12 },    { 240, 13 },    { 241, 14 },
    177  { 242, 15 },    { 243, 16 },    { 244, 17 },    { 245, 18 },
    178  { 246, 19 },    { 247, 20 },    { 248, 21 },    { 249, 24 },
    179  { 250, 25 },    { 251, 26 },    { 253, 27 },    { 254, 28 },
    180  { 255, 29 },    { 256, 30 },    { 257, 31 },    { 258, 32 },
    181  { 259, 33 },    { 260, 34 },    { 261, 35 },    { 262, 36 },
    182  { 263, 37 },    { 264, 38 },    { 265, 39 },    { 266, 40 },
    183  { 267, 43 },    { 268, 44 },    { 269, 45 },    { 270, 46 },
    184  { 272, 47 },    { 300, 48 },    { 301, 49 },    { 302, 50 },
    185  { 305, 51 },    { 314, 52 },    { 315, 53 },    { 320, 57 },
    186  { 321, 58 },    { 322, 59 },    { 323, 60 },    { 324, 61 },
    187  { 325, 62 },    { 326, 63 },    { 327, 67 },    { 328, 68 },
    188  { 329, 69 },    { 330, 70 },    { 331, 71 },    { 332, 72 },
    189  { 333, 73 },    { 334, 74 },    { 335, 75 },    { 336, 76 },
    190  { 337, 77 },    { 338, 78 },    { 339, 79 },    { 340, 80 },
    191  { 341, 81 },    { 342, 82 },    { 343, 83 },    { 344, 84 },
    192  { 345, 85 },    { 346, 86 }
    193 };
    194 
    195 /* code to SID */
    196 static const uint8_t standard_encoding_to_sid [] =
    197 {
    198    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
    199    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
    200    1,    2,    3,    4,    5,    6,    7,    8,    9,   10,   11,   12,   13,   14,   15,   16,
    201    17,  18,   19,   20,   21,   22,   23,   24,   25,   26,   27,   28,   29,   30,   31,   32,
    202    33,  34,   35,   36,   37,   38,   39,   40,   41,   42,   43,   44,   45,   46,   47,   48,
    203    49,  50,   51,   52,   53,   54,   55,   56,   57,   58,   59,   60,   61,   62,   63,   64,
    204    65,  66,   67,   68,   69,   70,   71,   72,   73,   74,   75,   76,   77,   78,   79,   80,
    205    81,  82,   83,   84,   85,   86,   87,   88,   89,   90,   91,   92,   93,   94,   95,    0,
    206    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
    207    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
    208    0,   96,   97,   98,   99,  100,  101,  102,  103,  104,  105,  106,  107,  108,  109,  110,
    209    0,  111,  112,  113,  114,    0,  115,  116,  117,  118,  119,  120,  121,  122,    0,  123,
    210    0,  124,  125,  126,  127,  128,  129,  130,  131,    0,  132,  133,    0,  134,  135,  136,
    211  137,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
    212    0,   138,   0,  139,    0,    0,    0,    0,  140,  141,  142,  143,    0,    0,    0,    0,
    213    0,   144,   0,    0,    0,  145,    0,    0,  146,  147,  148,  149,    0,    0,    0,    0
    214 };
    215 
    216 hb_codepoint_t OT::cff1::lookup_standard_encoding_for_code (hb_codepoint_t sid)
    217 {
    218  if (sid < ARRAY_LENGTH (standard_encoding_to_code))
    219    return (hb_codepoint_t)standard_encoding_to_code[sid];
    220  else
    221    return 0;
    222 }
    223 
    224 hb_codepoint_t OT::cff1::lookup_expert_encoding_for_code (hb_codepoint_t sid)
    225 {
    226  if (sid < ARRAY_LENGTH (expert_encoding_to_code))
    227    return (hb_codepoint_t)expert_encoding_to_code[sid];
    228  else
    229    return 0;
    230 }
    231 
    232 hb_codepoint_t OT::cff1::lookup_expert_charset_for_sid (hb_codepoint_t glyph)
    233 {
    234  if (glyph < ARRAY_LENGTH (expert_charset_to_sid))
    235    return (hb_codepoint_t)expert_charset_to_sid[glyph];
    236  else
    237    return 0;
    238 }
    239 
    240 hb_codepoint_t OT::cff1::lookup_expert_subset_charset_for_sid (hb_codepoint_t glyph)
    241 {
    242  if (glyph < ARRAY_LENGTH (expert_subset_charset_to_sid))
    243    return (hb_codepoint_t)expert_subset_charset_to_sid[glyph];
    244  else
    245    return 0;
    246 }
    247 
    248 hb_codepoint_t OT::cff1::lookup_expert_charset_for_glyph (hb_codepoint_t sid)
    249 {
    250  const auto *pair = hb_sorted_array (expert_charset_sid_to_gid).bsearch (sid);
    251  return pair ? pair->gid : 0;
    252 }
    253 
    254 hb_codepoint_t OT::cff1::lookup_expert_subset_charset_for_glyph (hb_codepoint_t sid)
    255 {
    256  const auto *pair = hb_sorted_array (expert_subset_charset_sid_to_gid).bsearch (sid);
    257  return pair ? pair->gid : 0;
    258 }
    259 
    260 hb_codepoint_t OT::cff1::lookup_standard_encoding_for_sid (hb_codepoint_t code)
    261 {
    262  if (code < ARRAY_LENGTH (standard_encoding_to_sid))
    263    return (hb_codepoint_t)standard_encoding_to_sid[code];
    264  else
    265    return CFF_UNDEF_SID;
    266 }
    267 
    268 struct bounds_t
    269 {
    270  void init ()
    271  {
    272    min.set_int (INT_MAX, INT_MAX);
    273    max.set_int (INT_MIN, INT_MIN);
    274  }
    275 
    276  void update (const point_t &pt)
    277  {
    278    if (pt.x < min.x) min.x = pt.x;
    279    if (pt.x > max.x) max.x = pt.x;
    280    if (pt.y < min.y) min.y = pt.y;
    281    if (pt.y > max.y) max.y = pt.y;
    282  }
    283 
    284  void merge (const bounds_t &b)
    285  {
    286    if (empty ())
    287      *this = b;
    288    else if (!b.empty ())
    289    {
    290      if (b.min.x < min.x) min.x = b.min.x;
    291      if (b.max.x > max.x) max.x = b.max.x;
    292      if (b.min.y < min.y) min.y = b.min.y;
    293      if (b.max.y > max.y) max.y = b.max.y;
    294    }
    295  }
    296 
    297  void offset (const point_t &delta)
    298  {
    299    if (!empty ())
    300    {
    301      min.move (delta);
    302      max.move (delta);
    303    }
    304  }
    305 
    306  bool empty () const { return (min.x >= max.x) || (min.y >= max.y); }
    307 
    308  point_t min;
    309  point_t max;
    310 };
    311 
    312 struct cff1_extents_param_t
    313 {
    314  cff1_extents_param_t (const OT::cff1::accelerator_t *_cff) : cff (_cff)
    315  {
    316    bounds.init ();
    317  }
    318 
    319  void start_path   ()       { path_open = true; }
    320  void end_path     ()       { path_open = false; }
    321  bool is_path_open () const { return path_open; }
    322 
    323  bool path_open = false;
    324  bounds_t bounds;
    325 
    326  const OT::cff1::accelerator_t *cff;
    327 };
    328 
    329 struct cff1_path_procs_extents_t : path_procs_t<cff1_path_procs_extents_t, cff1_cs_interp_env_t, cff1_extents_param_t>
    330 {
    331  static void moveto (cff1_cs_interp_env_t &env, cff1_extents_param_t& param, const point_t &pt)
    332  {
    333    param.end_path ();
    334    env.moveto (pt);
    335  }
    336 
    337  static void line (cff1_cs_interp_env_t &env, cff1_extents_param_t& param, const point_t &pt1)
    338  {
    339    if (!param.is_path_open ())
    340    {
    341      param.start_path ();
    342      param.bounds.update (env.get_pt ());
    343    }
    344    env.moveto (pt1);
    345    param.bounds.update (env.get_pt ());
    346  }
    347 
    348  static void curve (cff1_cs_interp_env_t &env, cff1_extents_param_t& param, const point_t &pt1, const point_t &pt2, const point_t &pt3)
    349  {
    350    if (!param.is_path_open ())
    351    {
    352      param.start_path ();
    353      param.bounds.update (env.get_pt ());
    354    }
    355    /* include control points */
    356    param.bounds.update (pt1);
    357    param.bounds.update (pt2);
    358    env.moveto (pt3);
    359    param.bounds.update (env.get_pt ());
    360  }
    361 };
    362 
    363 static bool _get_bounds (const OT::cff1::accelerator_t *cff, hb_codepoint_t glyph, bounds_t &bounds, bool in_seac=false);
    364 
    365 struct cff1_cs_opset_extents_t : cff1_cs_opset_t<cff1_cs_opset_extents_t, cff1_extents_param_t, cff1_path_procs_extents_t>
    366 {
    367  static void process_seac (cff1_cs_interp_env_t &env, cff1_extents_param_t& param)
    368  {
    369    unsigned int  n = env.argStack.get_count ();
    370    point_t delta;
    371    delta.x = env.argStack[n-4];
    372    delta.y = env.argStack[n-3];
    373    hb_codepoint_t base = param.cff->std_code_to_glyph (env.argStack[n-2].to_int ());
    374    hb_codepoint_t accent = param.cff->std_code_to_glyph (env.argStack[n-1].to_int ());
    375 
    376    bounds_t  base_bounds, accent_bounds;
    377    if (likely (!env.in_seac && base && accent
    378        && _get_bounds (param.cff, base, base_bounds, true)
    379        && _get_bounds (param.cff, accent, accent_bounds, true)))
    380    {
    381      param.bounds.merge (base_bounds);
    382      accent_bounds.offset (delta);
    383      param.bounds.merge (accent_bounds);
    384    }
    385    else
    386      env.set_error ();
    387  }
    388 };
    389 
    390 bool _get_bounds (const OT::cff1::accelerator_t *cff, hb_codepoint_t glyph, bounds_t &bounds, bool in_seac)
    391 {
    392  bounds.init ();
    393  if (unlikely (!cff->is_valid () || (glyph >= cff->num_glyphs))) return false;
    394 
    395  unsigned int fd = cff->fdSelect->get_fd (glyph);
    396  const hb_ubytes_t str = (*cff->charStrings)[glyph];
    397  cff1_cs_interp_env_t env (str, *cff, fd);
    398  env.set_in_seac (in_seac);
    399  cff1_cs_interpreter_t<cff1_cs_opset_extents_t, cff1_extents_param_t> interp (env);
    400  cff1_extents_param_t param (cff);
    401  if (unlikely (!interp.interpret (param))) return false;
    402  bounds = param.bounds;
    403  return true;
    404 }
    405 
    406 bool OT::cff1::accelerator_t::get_extents (hb_font_t *font, hb_codepoint_t glyph, hb_glyph_extents_t *extents) const
    407 {
    408 #ifdef HB_NO_OT_FONT_CFF
    409  /* XXX Remove check when this code moves to .hh file. */
    410  return true;
    411 #endif
    412 
    413  bounds_t bounds;
    414 
    415  if (!_get_bounds (this, glyph, bounds))
    416    return false;
    417 
    418  if (bounds.min.x >= bounds.max.x)
    419  {
    420    extents->width = 0;
    421    extents->x_bearing = 0;
    422  }
    423  else
    424  {
    425    extents->x_bearing = roundf (bounds.min.x.to_real ());
    426    extents->width = roundf (bounds.max.x.to_real () - extents->x_bearing);
    427  }
    428  if (bounds.min.y >= bounds.max.y)
    429  {
    430    extents->height = 0;
    431    extents->y_bearing = 0;
    432  }
    433  else
    434  {
    435    extents->y_bearing = roundf (bounds.max.y.to_real ());
    436    extents->height = roundf (bounds.min.y.to_real () - extents->y_bearing);
    437  }
    438 
    439  font->scale_glyph_extents (extents);
    440 
    441  return true;
    442 }
    443 
    444 struct cff1_path_param_t
    445 {
    446  cff1_path_param_t (const OT::cff1::accelerator_t *cff_, hb_font_t *font_,
    447 	     hb_draw_session_t &draw_session_, point_t *delta_)
    448  {
    449    draw_session = &draw_session_;
    450    cff = cff_;
    451    font = font_;
    452    delta = delta_;
    453  }
    454 
    455  void move_to (const point_t &p)
    456  {
    457    point_t point = p;
    458    if (delta) point.move (*delta);
    459    draw_session->move_to (font->em_fscalef_x (point.x.to_real ()), font->em_fscalef_y (point.y.to_real ()));
    460  }
    461 
    462  void line_to (const point_t &p)
    463  {
    464    point_t point = p;
    465    if (delta) point.move (*delta);
    466    draw_session->line_to (font->em_fscalef_x (point.x.to_real ()), font->em_fscalef_y (point.y.to_real ()));
    467  }
    468 
    469  void cubic_to (const point_t &p1, const point_t &p2, const point_t &p3)
    470  {
    471    point_t point1 = p1, point2 = p2, point3 = p3;
    472    if (delta)
    473    {
    474      point1.move (*delta);
    475      point2.move (*delta);
    476      point3.move (*delta);
    477    }
    478    draw_session->cubic_to (font->em_fscalef_x (point1.x.to_real ()), font->em_fscalef_y (point1.y.to_real ()),
    479 		   font->em_fscalef_x (point2.x.to_real ()), font->em_fscalef_y (point2.y.to_real ()),
    480 		   font->em_fscalef_x (point3.x.to_real ()), font->em_fscalef_y (point3.y.to_real ()));
    481  }
    482 
    483  void end_path () { draw_session->close_path (); }
    484 
    485  hb_font_t *font;
    486  hb_draw_session_t *draw_session;
    487  point_t *delta;
    488 
    489  const OT::cff1::accelerator_t *cff;
    490 };
    491 
    492 struct cff1_path_procs_path_t : path_procs_t<cff1_path_procs_path_t, cff1_cs_interp_env_t, cff1_path_param_t>
    493 {
    494  static void moveto (cff1_cs_interp_env_t &env, cff1_path_param_t& param, const point_t &pt)
    495  {
    496    param.move_to (pt);
    497    env.moveto (pt);
    498  }
    499 
    500  static void line (cff1_cs_interp_env_t &env, cff1_path_param_t &param, const point_t &pt1)
    501  {
    502    param.line_to (pt1);
    503    env.moveto (pt1);
    504  }
    505 
    506  static void curve (cff1_cs_interp_env_t &env, cff1_path_param_t &param, const point_t &pt1, const point_t &pt2, const point_t &pt3)
    507  {
    508    param.cubic_to (pt1, pt2, pt3);
    509    env.moveto (pt3);
    510  }
    511 };
    512 
    513 static bool _get_path (const OT::cff1::accelerator_t *cff, hb_font_t *font, hb_codepoint_t glyph,
    514 	       hb_draw_session_t &draw_session, bool in_seac = false, point_t *delta = nullptr);
    515 
    516 struct cff1_cs_opset_path_t : cff1_cs_opset_t<cff1_cs_opset_path_t, cff1_path_param_t, cff1_path_procs_path_t>
    517 {
    518  static void process_seac (cff1_cs_interp_env_t &env, cff1_path_param_t& param)
    519  {
    520    /* End previous path */
    521    param.end_path ();
    522 
    523    unsigned int n = env.argStack.get_count ();
    524    point_t delta;
    525    delta.x = env.argStack[n-4];
    526    delta.y = env.argStack[n-3];
    527    hb_codepoint_t base = param.cff->std_code_to_glyph (env.argStack[n-2].to_int ());
    528    hb_codepoint_t accent = param.cff->std_code_to_glyph (env.argStack[n-1].to_int ());
    529 
    530    if (unlikely (!(!env.in_seac && base && accent
    531 	    && _get_path (param.cff, param.font, base, *param.draw_session, true)
    532 	    && _get_path (param.cff, param.font, accent, *param.draw_session, true, &delta))))
    533      env.set_error ();
    534  }
    535 };
    536 
    537 bool _get_path (const OT::cff1::accelerator_t *cff, hb_font_t *font, hb_codepoint_t glyph,
    538 	hb_draw_session_t &draw_session, bool in_seac, point_t *delta)
    539 {
    540  if (unlikely (!cff->is_valid () || (glyph >= cff->num_glyphs))) return false;
    541 
    542  unsigned int fd = cff->fdSelect->get_fd (glyph);
    543  const hb_ubytes_t str = (*cff->charStrings)[glyph];
    544  cff1_cs_interp_env_t env (str, *cff, fd);
    545  env.set_in_seac (in_seac);
    546  cff1_cs_interpreter_t<cff1_cs_opset_path_t, cff1_path_param_t> interp (env);
    547  cff1_path_param_t param (cff, font, draw_session, delta);
    548  if (unlikely (!interp.interpret (param))) return false;
    549 
    550  /* Let's end the path specially since it is called inside seac also */
    551  param.end_path ();
    552 
    553  return true;
    554 }
    555 
    556 bool OT::cff1::accelerator_t::get_path (hb_font_t *font, hb_codepoint_t glyph, hb_draw_session_t &draw_session) const
    557 {
    558 #ifdef HB_NO_OT_FONT_CFF
    559  /* XXX Remove check when this code moves to .hh file. */
    560  return true;
    561 #endif
    562 
    563  return _get_path (this, font, glyph, draw_session);
    564 }
    565 
    566 struct get_seac_param_t
    567 {
    568  get_seac_param_t (const OT::cff1::accelerator_subset_t *_cff) : cff (_cff) {}
    569 
    570  bool has_seac () const { return base && accent; }
    571 
    572  const OT::cff1::accelerator_subset_t *cff;
    573  hb_codepoint_t  base = 0;
    574  hb_codepoint_t  accent = 0;
    575 };
    576 
    577 struct cff1_cs_opset_seac_t : cff1_cs_opset_t<cff1_cs_opset_seac_t, get_seac_param_t>
    578 {
    579  static void process_seac (cff1_cs_interp_env_t &env, get_seac_param_t& param)
    580  {
    581    unsigned int  n = env.argStack.get_count ();
    582    hb_codepoint_t  base_char = (hb_codepoint_t)env.argStack[n-2].to_int ();
    583    hb_codepoint_t  accent_char = (hb_codepoint_t)env.argStack[n-1].to_int ();
    584 
    585    param.base = param.cff->std_code_to_glyph (base_char);
    586    param.accent = param.cff->std_code_to_glyph (accent_char);
    587  }
    588 };
    589 
    590 bool OT::cff1::accelerator_subset_t::get_seac_components (hb_codepoint_t glyph, hb_codepoint_t *base, hb_codepoint_t *accent) const
    591 {
    592  if (unlikely (!is_valid () || (glyph >= num_glyphs))) return false;
    593 
    594  unsigned int fd = fdSelect->get_fd (glyph);
    595  const hb_ubytes_t str = (*charStrings)[glyph];
    596  cff1_cs_interp_env_t env (str, *this, fd);
    597  cff1_cs_interpreter_t<cff1_cs_opset_seac_t, get_seac_param_t> interp (env);
    598  get_seac_param_t  param (this);
    599  if (unlikely (!interp.interpret (param))) return false;
    600 
    601  if (param.has_seac ())
    602  {
    603    *base = param.base;
    604    *accent = param.accent;
    605    return true;
    606  }
    607  return false;
    608 }
    609 
    610 
    611 #endif