Coverage Report

Created: 2026-09-28 10:59

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/work/workdir/UnpackedTarball/harfbuzz/src/hb-ot-cff1-table.cc
Line
Count
Source
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
#ifndef HB_OT_CFF1_TABLE_CC
28
#define HB_OT_CFF1_TABLE_CC
29
#ifdef HB_OT_CFF1_TABLE_CC /* Pacify -Wunused-macros. */
30
31
#include "hb.hh"
32
33
#ifndef HB_NO_CFF
34
35
#include "hb-draw.hh"
36
#include "hb-algs.hh"
37
#include "hb-ot-cff1-table.hh"
38
#include "hb-cff1-interp-cs.hh"
39
40
using namespace CFF;
41
42
struct sid_to_gid_t
43
{
44
  uint16_t  sid;
45
  uint8_t   gid;
46
47
  int cmp (uint16_t a) const
48
0
  {
49
0
    if (a == sid) return 0;
50
0
    return (a < sid) ? -1 : 1;
51
0
  }
52
};
53
54
/* SID to code */
55
static const uint8_t standard_encoding_to_code [] =
56
{
57
    0,   32,   33,   34,   35,   36,   37,   38,  39,   40,   41,   42,   43,   44,   45,   46,
58
   47,   48,   49,   50,   51,   52,   53,   54,  55,   56,   57,   58,   59,   60,   61,   62,
59
   63,   64,   65,   66,   67,   68,   69,   70,  71,   72,   73,   74,   75,   76,   77,   78,
60
   79,   80,   81,   82,   83,   84,   85,   86,  87,   88,   89,   90,   91,   92,   93,   94,
61
   95,   96,   97,   98,   99,  100,  101,  102, 103,  104,  105,  106,  107,  108,  109,  110,
62
  111,  112,  113,  114,  115,  116,  117,  118, 119,  120,  121,  122,  123,  124,  125,  126,
63
  161,  162,  163,  164,  165,  166,  167,  168, 169,  170,  171,  172,  173,  174,  175,  177,
64
  178,  179,  180,  182,  183,  184,  185,  186, 187,  188,  189,  191,  193,  194,  195,  196,
65
  197,  198,  199,  200,  202,  203,  205,  206, 207,  208,  225,  227,  232,  233,  234,  235,
66
  241,  245,  248,  249,  250,  251
67
};
68
69
/* SID to code */
70
static const uint8_t expert_encoding_to_code [] =
71
{
72
    0,   32,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,   44,   45,   46,
73
    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,   58,   59,    0,    0,    0,
74
    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    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,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
78
    0,    0,    0,   47,    0,    0,    0,    0,    0,    0,    0,    0,    0,   87,   88,    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,  201,    0,    0,    0,    0,  189,    0,    0,  188,    0,
82
    0,    0,    0,  190,  202,    0,    0,    0,    0,  203,    0,    0,    0,    0,    0,    0,
83
    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
84
    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
85
    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
86
    0,    0,    0,    0,    0,   33,   34,   36,   37,   38,   39,   40,   41,   42,   43,   48,
87
   49,   50,   51,   52,   53,   54,   55,   56,   57,   60,   61,   62,   63,   65,   66,   67,
88
   68,   69,   73,   76,   77,   78,   79,   82,   83,   84,   86,   89,   90,   91,   93,   94,
89
   95,   96,   97,   98,   99,  100,  101,  102,  103,  104,  105,  106,  107,  108,  109,  110,
90
  111,  112,  113,  114,  115,  116,  117,  118,  119,  120,  121,  122,  123,  124,  125,  126,
91
  161,  162,  163,  166,  167,  168,  169,  170,  172,  175,  178,  179,  182,  183,  184,  191,
92
  192,  193,  194,  195,  196,  197,  200,  204,  205,  206,  207,  208,  209,  210,  211,  212,
93
  213,  214,  215,  216,  217,  218,  219,  220,  221,  222,  223,  224,  225,  226,  227,  228,
94
  229,  230,  231,  232,  233,  234,  235,  236,  237,  238,  239,  240,  241,  242,  243,  244,
95
  245,  246,  247,  248,  249,  250,  251,  252,  253,  254,  255
96
};
97
98
/* glyph ID to SID */
99
static const uint16_t expert_charset_to_sid [] =
100
{
101
    0,    1,  229,  230,  231,  232,  233,  234,  235,  236,  237,  238,   13,   14,   15,   99,
102
  239,  240,  241,  242,  243,  244,  245,  246,  247,  248,   27,   28,  249,  250,  251,  252,
103
  253,  254,  255,  256,  257,  258,  259,  260,  261,  262,  263,  264,  265,  266,  109,  110,
104
  267,  268,  269,  270,  271,  272,  273,  274,  275,  276,  277,  278,  279,  280,  281,  282,
105
  283,  284,  285,  286,  287,  288,  289,  290,  291,  292,  293,  294,  295,  296,  297,  298,
106
  299,  300,  301,  302,  303,  304,  305,  306,  307,  308,  309,  310,  311,  312,  313,  314,
107
  315,  316,  317,  318,  158,  155,  163,  319,  320,  321,  322,  323,  324,  325,  326,  150,
108
  164,  169,  327,  328,  329,  330,  331,  332,  333,  334,  335,  336,  337,  338,  339,  340,
109
  341,  342,  343,  344,  345,  346,  347,  348,  349,  350,  351,  352,  353,  354,  355,  356,
110
  357,  358,  359,  360,  361,  362,  363,  364,  365,  366,  367,  368,  369,  370,  371,  372,
111
  373,  374,  375,  376,  377,  378
112
};
113
114
/* glyph ID to SID */
115
static const uint16_t expert_subset_charset_to_sid [] =
116
{
117
    0,    1,  231,  232,  235,  236,  237,  238,   13,   14,   15,   99,  239,  240,  241,  242,
118
  243,  244,  245,  246,  247,  248,   27,   28,  249,  250,  251,  253,  254,  255,  256,  257,
119
  258,  259,  260,  261,  262,  263,  264,  265,  266,  109,  110,  267,  268,  269,  270,  272,
120
  300,  301,  302,  305,  314,  315,  158,  155,  163,  320,  321,  322,  323,  324,  325,  326,
121
  150,  164,  169,  327,  328,  329,  330,  331,  332,  333,  334,  335,  336,  337,  338,  339,
122
  340,  341,  342,  343,  344,  345,  346
123
};
124
125
/* SID to glyph ID */
126
static const sid_to_gid_t expert_charset_sid_to_gid [] =
127
{
128
    { 1, 1 },     { 13, 12 },   { 14, 13 },   { 15, 14 },
129
    { 27, 26 },   { 28, 27 },   { 99, 15 },   { 109, 46 },
130
    { 110, 47 },  { 150, 111 }, { 155, 101 }, { 158, 100 },
131
    { 163, 102 }, { 164, 112 }, { 169, 113 }, { 229, 2 },
132
    { 230, 3 },   { 231, 4 },   { 232, 5 },   { 233, 6 },
133
    { 234, 7 },   { 235, 8 },   { 236, 9 },   { 237, 10 },
134
    { 238, 11 },  { 239, 16 },  { 240, 17 },  { 241, 18 },
135
    { 242, 19 },  { 243, 20 },  { 244, 21 },  { 245, 22 },
136
    { 246, 23 },  { 247, 24 },  { 248, 25 },  { 249, 28 },
137
    { 250, 29 },  { 251, 30 },  { 252, 31 },  { 253, 32 },
138
    { 254, 33 },  { 255, 34 },  { 256, 35 },  { 257, 36 },
139
    { 258, 37 },  { 259, 38 },  { 260, 39 },  { 261, 40 },
140
    { 262, 41 },  { 263, 42 },  { 264, 43 },  { 265, 44 },
141
    { 266, 45 },  { 267, 48 },  { 268, 49 },  { 269, 50 },
142
    { 270, 51 },  { 271, 52 },  { 272, 53 },  { 273, 54 },
143
    { 274, 55 },  { 275, 56 },  { 276, 57 },  { 277, 58 },
144
    { 278, 59 },  { 279, 60 },  { 280, 61 },  { 281, 62 },
145
    { 282, 63 },  { 283, 64 },  { 284, 65 },  { 285, 66 },
146
    { 286, 67 },  { 287, 68 },  { 288, 69 },  { 289, 70 },
147
    { 290, 71 },  { 291, 72 },  { 292, 73 },  { 293, 74 },
148
    { 294, 75 },  { 295, 76 },  { 296, 77 },  { 297, 78 },
149
    { 298, 79 },  { 299, 80 },  { 300, 81 },  { 301, 82 },
150
    { 302, 83 },  { 303, 84 },  { 304, 85 },  { 305, 86 },
151
    { 306, 87 },  { 307, 88 },  { 308, 89 },  { 309, 90 },
152
    { 310, 91 },  { 311, 92 },  { 312, 93 },  { 313, 94 },
153
    { 314, 95 },  { 315, 96 },  { 316, 97 },  { 317, 98 },
154
    { 318, 99 },  { 319, 103 }, { 320, 104 }, { 321, 105 },
155
    { 322, 106 }, { 323, 107 }, { 324, 108 }, { 325, 109 },
156
    { 326, 110 }, { 327, 114 }, { 328, 115 }, { 329, 116 },
157
    { 330, 117 }, { 331, 118 }, { 332, 119 }, { 333, 120 },
158
    { 334, 121 }, { 335, 122 }, { 336, 123 }, { 337, 124 },
159
    { 338, 125 }, { 339, 126 }, { 340, 127 }, { 341, 128 },
160
    { 342, 129 }, { 343, 130 }, { 344, 131 }, { 345, 132 },
161
    { 346, 133 }, { 347, 134 }, { 348, 135 }, { 349, 136 },
162
    { 350, 137 }, { 351, 138 }, { 352, 139 }, { 353, 140 },
163
    { 354, 141 }, { 355, 142 }, { 356, 143 }, { 357, 144 },
164
    { 358, 145 }, { 359, 146 }, { 360, 147 }, { 361, 148 },
165
    { 362, 149 }, { 363, 150 }, { 364, 151 }, { 365, 152 },
166
    { 366, 153 }, { 367, 154 }, { 368, 155 }, { 369, 156 },
167
    { 370, 157 }, { 371, 158 }, { 372, 159 }, { 373, 160 },
168
    { 374, 161 }, { 375, 162 }, { 376, 163 }, { 377, 164 },
169
    { 378, 165 }
170
};
171
172
/* SID to glyph ID */
173
static const sid_to_gid_t expert_subset_charset_sid_to_gid [] =
174
{
175
  { 1, 1 },       { 13, 8 },      { 14, 9 },      { 15, 10 },
176
  { 27, 22 },     { 28, 23 },     { 99, 11 },     { 109, 41 },
177
  { 110, 42 },    { 150, 64 },    { 155, 55 },    { 158, 54 },
178
  { 163, 56 },    { 164, 65 },    { 169, 66 },    { 231, 2 },
179
  { 232, 3 },     { 235, 4 },     { 236, 5 },     { 237, 6 },
180
  { 238, 7 },     { 239, 12 },    { 240, 13 },    { 241, 14 },
181
  { 242, 15 },    { 243, 16 },    { 244, 17 },    { 245, 18 },
182
  { 246, 19 },    { 247, 20 },    { 248, 21 },    { 249, 24 },
183
  { 250, 25 },    { 251, 26 },    { 253, 27 },    { 254, 28 },
184
  { 255, 29 },    { 256, 30 },    { 257, 31 },    { 258, 32 },
185
  { 259, 33 },    { 260, 34 },    { 261, 35 },    { 262, 36 },
186
  { 263, 37 },    { 264, 38 },    { 265, 39 },    { 266, 40 },
187
  { 267, 43 },    { 268, 44 },    { 269, 45 },    { 270, 46 },
188
  { 272, 47 },    { 300, 48 },    { 301, 49 },    { 302, 50 },
189
  { 305, 51 },    { 314, 52 },    { 315, 53 },    { 320, 57 },
190
  { 321, 58 },    { 322, 59 },    { 323, 60 },    { 324, 61 },
191
  { 325, 62 },    { 326, 63 },    { 327, 67 },    { 328, 68 },
192
  { 329, 69 },    { 330, 70 },    { 331, 71 },    { 332, 72 },
193
  { 333, 73 },    { 334, 74 },    { 335, 75 },    { 336, 76 },
194
  { 337, 77 },    { 338, 78 },    { 339, 79 },    { 340, 80 },
195
  { 341, 81 },    { 342, 82 },    { 343, 83 },    { 344, 84 },
196
  { 345, 85 },    { 346, 86 }
197
};
198
199
/* code to SID */
200
static const uint8_t standard_encoding_to_sid [] =
201
{
202
    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
203
    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
204
    1,    2,    3,    4,    5,    6,    7,    8,    9,   10,   11,   12,   13,   14,   15,   16,
205
    17,  18,   19,   20,   21,   22,   23,   24,   25,   26,   27,   28,   29,   30,   31,   32,
206
    33,  34,   35,   36,   37,   38,   39,   40,   41,   42,   43,   44,   45,   46,   47,   48,
207
    49,  50,   51,   52,   53,   54,   55,   56,   57,   58,   59,   60,   61,   62,   63,   64,
208
    65,  66,   67,   68,   69,   70,   71,   72,   73,   74,   75,   76,   77,   78,   79,   80,
209
    81,  82,   83,   84,   85,   86,   87,   88,   89,   90,   91,   92,   93,   94,   95,    0,
210
    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
211
    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
212
    0,   96,   97,   98,   99,  100,  101,  102,  103,  104,  105,  106,  107,  108,  109,  110,
213
    0,  111,  112,  113,  114,    0,  115,  116,  117,  118,  119,  120,  121,  122,    0,  123,
214
    0,  124,  125,  126,  127,  128,  129,  130,  131,    0,  132,  133,    0,  134,  135,  136,
215
  137,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
216
    0,   138,   0,  139,    0,    0,    0,    0,  140,  141,  142,  143,    0,    0,    0,    0,
217
    0,   144,   0,    0,    0,  145,    0,    0,  146,  147,  148,  149,    0,    0,    0,    0
218
};
219
220
hb_codepoint_t OT::cff1::lookup_standard_encoding_for_code (hb_codepoint_t sid)
221
0
{
222
0
  if (sid < ARRAY_LENGTH (standard_encoding_to_code))
223
0
    return (hb_codepoint_t)standard_encoding_to_code[sid];
224
0
  else
225
0
    return 0;
226
0
}
227
228
hb_codepoint_t OT::cff1::lookup_expert_encoding_for_code (hb_codepoint_t sid)
229
0
{
230
0
  if (sid < ARRAY_LENGTH (expert_encoding_to_code))
231
0
    return (hb_codepoint_t)expert_encoding_to_code[sid];
232
0
  else
233
0
    return 0;
234
0
}
235
236
hb_codepoint_t OT::cff1::lookup_expert_charset_for_sid (hb_codepoint_t glyph)
237
0
{
238
0
  if (glyph < ARRAY_LENGTH (expert_charset_to_sid))
239
0
    return (hb_codepoint_t)expert_charset_to_sid[glyph];
240
0
  else
241
0
    return 0;
242
0
}
243
244
hb_codepoint_t OT::cff1::lookup_expert_subset_charset_for_sid (hb_codepoint_t glyph)
245
0
{
246
0
  if (glyph < ARRAY_LENGTH (expert_subset_charset_to_sid))
247
0
    return (hb_codepoint_t)expert_subset_charset_to_sid[glyph];
248
0
  else
249
0
    return 0;
250
0
}
251
252
hb_codepoint_t OT::cff1::lookup_expert_charset_for_glyph (hb_codepoint_t sid)
253
0
{
254
0
  const auto *pair = hb_sorted_array (expert_charset_sid_to_gid).bsearch (sid);
255
0
  return pair ? pair->gid : 0;
256
0
}
257
258
hb_codepoint_t OT::cff1::lookup_expert_subset_charset_for_glyph (hb_codepoint_t sid)
259
0
{
260
0
  const auto *pair = hb_sorted_array (expert_subset_charset_sid_to_gid).bsearch (sid);
261
0
  return pair ? pair->gid : 0;
262
0
}
263
264
hb_codepoint_t OT::cff1::lookup_standard_encoding_for_sid (hb_codepoint_t code)
265
0
{
266
0
  if (code < ARRAY_LENGTH (standard_encoding_to_sid))
267
0
    return (hb_codepoint_t)standard_encoding_to_sid[code];
268
0
  else
269
0
    return CFF_UNDEF_SID;
270
0
}
271
272
struct bounds_t
273
{
274
  void init ()
275
0
  {
276
0
    min.set_int (INT_MAX, INT_MAX);
277
0
    max.set_int (INT_MIN, INT_MIN);
278
0
  }
279
280
  void update (const point_t &pt)
281
0
  {
282
0
    if (pt.x < min.x) min.x = pt.x;
283
0
    if (pt.x > max.x) max.x = pt.x;
284
0
    if (pt.y < min.y) min.y = pt.y;
285
0
    if (pt.y > max.y) max.y = pt.y;
286
0
  }
287
288
  void merge (const bounds_t &b)
289
0
  {
290
0
    if (empty ())
291
0
      *this = b;
292
0
    else if (!b.empty ())
293
0
    {
294
0
      if (b.min.x < min.x) min.x = b.min.x;
295
0
      if (b.max.x > max.x) max.x = b.max.x;
296
0
      if (b.min.y < min.y) min.y = b.min.y;
297
0
      if (b.max.y > max.y) max.y = b.max.y;
298
0
    }
299
0
  }
300
301
  void offset (const point_t &delta)
302
0
  {
303
0
    if (!empty ())
304
0
    {
305
0
      min.move (delta);
306
0
      max.move (delta);
307
0
    }
308
0
  }
309
310
0
  bool empty () const { return (min.x >= max.x) || (min.y >= max.y); }
311
312
  point_t min;
313
  point_t max;
314
};
315
316
struct cff1_extents_param_t
317
{
318
0
  cff1_extents_param_t (const OT::cff1::accelerator_t *_cff) : cff (_cff)
319
0
  {
320
0
    bounds.init ();
321
0
  }
322
323
0
  void start_path   ()       { path_open = true; }
324
0
  void end_path     ()       { path_open = false; }
325
0
  bool is_path_open () const { return path_open; }
326
327
  bool path_open = false;
328
  bounds_t bounds;
329
330
  const OT::cff1::accelerator_t *cff;
331
};
332
333
struct cff1_path_procs_extents_t : path_procs_t<cff1_path_procs_extents_t, cff1_cs_interp_env_t, cff1_extents_param_t>
334
{
335
  static void moveto (cff1_cs_interp_env_t &env, cff1_extents_param_t& param, const point_t &pt)
336
0
  {
337
0
    param.end_path ();
338
0
    env.moveto (pt);
339
0
  }
340
341
  static void line (cff1_cs_interp_env_t &env, cff1_extents_param_t& param, const point_t &pt1)
342
0
  {
343
0
    if (!param.is_path_open ())
344
0
    {
345
0
      param.start_path ();
346
0
      param.bounds.update (env.get_pt ());
347
0
    }
348
0
    env.moveto (pt1);
349
0
    param.bounds.update (env.get_pt ());
350
0
  }
351
352
  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)
353
0
  {
354
0
    if (!param.is_path_open ())
355
0
    {
356
0
      param.start_path ();
357
0
      param.bounds.update (env.get_pt ());
358
0
    }
359
    /* include control points */
360
0
    param.bounds.update (pt1);
361
0
    param.bounds.update (pt2);
362
0
    env.moveto (pt3);
363
0
    param.bounds.update (env.get_pt ());
364
0
  }
365
};
366
367
static bool _get_bounds (const OT::cff1::accelerator_t *cff, hb_codepoint_t glyph, bounds_t &bounds, bool in_seac=false, int64_t *budget = nullptr);
368
369
struct cff1_cs_opset_extents_t : cff1_cs_opset_t<cff1_cs_opset_extents_t, cff1_extents_param_t, cff1_path_procs_extents_t>
370
{
371
  static void process_seac (cff1_cs_interp_env_t &env, cff1_extents_param_t& param)
372
0
  {
373
0
    unsigned int  n = env.argStack.get_count ();
374
0
    point_t delta;
375
0
    delta.x = env.argStack[n-4];
376
0
    delta.y = env.argStack[n-3];
377
0
    hb_codepoint_t base = param.cff->std_code_to_glyph (env.argStack[n-2].to_int ());
378
0
    hb_codepoint_t accent = param.cff->std_code_to_glyph (env.argStack[n-1].to_int ());
379
380
0
    bounds_t  base_bounds, accent_bounds;
381
0
    if (likely (!env.in_seac && base && accent
382
0
         && _get_bounds (param.cff, base, base_bounds, true, env.get_budget ())
383
0
         && _get_bounds (param.cff, accent, accent_bounds, true, env.get_budget ())))
384
0
    {
385
0
      param.bounds.merge (base_bounds);
386
0
      accent_bounds.offset (delta);
387
0
      param.bounds.merge (accent_bounds);
388
0
    }
389
0
    else
390
0
      env.set_error ();
391
0
  }
392
};
393
394
bool _get_bounds (const OT::cff1::accelerator_t *cff, hb_codepoint_t glyph, bounds_t &bounds, bool in_seac, int64_t *budget)
395
0
{
396
0
  bounds.init ();
397
0
  if (unlikely (!cff->is_valid () || (glyph >= cff->num_glyphs))) return false;
398
399
0
  unsigned int fd = cff->fdSelect->get_fd (glyph);
400
0
  const hb_ubytes_t str = (*cff->charStrings)[glyph];
401
0
  cff1_cs_interp_env_t env (str, *cff, fd);
402
0
  env.set_in_seac (in_seac);
403
0
  cff1_cs_interpreter_t<cff1_cs_opset_extents_t, cff1_extents_param_t> interp (env);
404
0
  cff1_extents_param_t param (cff);
405
0
  if (unlikely (!interp.interpret (param, budget))) return false;
406
0
  bounds = param.bounds;
407
0
  return true;
408
0
}
409
410
bool OT::cff1::accelerator_t::get_extents (hb_font_t *font, hb_codepoint_t glyph, hb_glyph_extents_t *extents, int64_t *budget) const
411
0
{
412
#ifdef HB_NO_OT_FONT_CFF
413
  /* XXX Remove check when this code moves to .hh file. */
414
  return true;
415
#endif
416
417
0
  bounds_t bounds;
418
419
0
  int64_t stack_budget = HB_BUDGET_GLYPH;
420
0
  if (!budget) budget = &stack_budget;
421
422
0
  if (!_get_bounds (this, glyph, bounds, false, budget))
423
0
    return false;
424
425
0
  if (bounds.min.x >= bounds.max.x)
426
0
  {
427
0
    extents->width = 0;
428
0
    extents->x_bearing = 0;
429
0
  }
430
0
  else
431
0
  {
432
0
    double x_bearing = roundf (bounds.min.x.to_real ());
433
0
    extents->x_bearing = hb_clamp_to<hb_position_t> (x_bearing);
434
0
    extents->width = hb_clamp_to<hb_position_t> ((double) roundf (bounds.max.x.to_real ()) - x_bearing);
435
0
  }
436
0
  if (bounds.min.y >= bounds.max.y)
437
0
  {
438
0
    extents->height = 0;
439
0
    extents->y_bearing = 0;
440
0
  }
441
0
  else
442
0
  {
443
0
    double y_bearing = roundf (bounds.max.y.to_real ());
444
0
    extents->y_bearing = hb_clamp_to<hb_position_t> (y_bearing);
445
0
    extents->height = hb_clamp_to<hb_position_t> ((double) roundf (bounds.min.y.to_real ()) - y_bearing);
446
0
  }
447
448
0
  font->scale_glyph_extents (extents);
449
450
0
  return true;
451
0
}
452
453
struct cff1_path_param_t
454
{
455
  cff1_path_param_t (const OT::cff1::accelerator_t *cff_, hb_font_t *font_,
456
         hb_draw_session_t &draw_session_, point_t *delta_)
457
0
  {
458
0
    draw_session = &draw_session_;
459
0
    cff = cff_;
460
0
    font = font_;
461
0
    delta = delta_;
462
0
  }
463
464
  void move_to (const point_t &p)
465
0
  {
466
0
    point_t point = p;
467
0
    if (delta) point.move (*delta);
468
0
    draw_session->move_to (font->em_fscalef_x (point.x.to_real ()), font->em_fscalef_y (point.y.to_real ()));
469
0
  }
470
471
  void line_to (const point_t &p)
472
0
  {
473
0
    point_t point = p;
474
0
    if (delta) point.move (*delta);
475
0
    draw_session->line_to (font->em_fscalef_x (point.x.to_real ()), font->em_fscalef_y (point.y.to_real ()));
476
0
  }
477
478
  void cubic_to (const point_t &p1, const point_t &p2, const point_t &p3)
479
0
  {
480
0
    point_t point1 = p1, point2 = p2, point3 = p3;
481
0
    if (delta)
482
0
    {
483
0
      point1.move (*delta);
484
0
      point2.move (*delta);
485
0
      point3.move (*delta);
486
0
    }
487
0
    draw_session->cubic_to (font->em_fscalef_x (point1.x.to_real ()), font->em_fscalef_y (point1.y.to_real ()),
488
0
         font->em_fscalef_x (point2.x.to_real ()), font->em_fscalef_y (point2.y.to_real ()),
489
0
         font->em_fscalef_x (point3.x.to_real ()), font->em_fscalef_y (point3.y.to_real ()));
490
0
  }
491
492
0
  void end_path () { draw_session->close_path (); }
493
494
  hb_font_t *font;
495
  hb_draw_session_t *draw_session;
496
  point_t *delta;
497
498
  const OT::cff1::accelerator_t *cff;
499
};
500
501
struct cff1_path_procs_path_t : path_procs_t<cff1_path_procs_path_t, cff1_cs_interp_env_t, cff1_path_param_t>
502
{
503
  static void moveto (cff1_cs_interp_env_t &env, cff1_path_param_t& param, const point_t &pt)
504
0
  {
505
0
    param.move_to (pt);
506
0
    env.moveto (pt);
507
0
  }
508
509
  static void line (cff1_cs_interp_env_t &env, cff1_path_param_t &param, const point_t &pt1)
510
0
  {
511
0
    param.line_to (pt1);
512
0
    env.moveto (pt1);
513
0
  }
514
515
  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)
516
0
  {
517
0
    param.cubic_to (pt1, pt2, pt3);
518
0
    env.moveto (pt3);
519
0
  }
520
};
521
522
static bool _get_path (const OT::cff1::accelerator_t *cff, hb_font_t *font, hb_codepoint_t glyph,
523
           hb_draw_session_t &draw_session, bool in_seac = false, point_t *delta = nullptr,
524
           int64_t *budget = nullptr);
525
526
struct cff1_cs_opset_path_t : cff1_cs_opset_t<cff1_cs_opset_path_t, cff1_path_param_t, cff1_path_procs_path_t>
527
{
528
  static void process_seac (cff1_cs_interp_env_t &env, cff1_path_param_t& param)
529
0
  {
530
    /* End previous path */
531
0
    param.end_path ();
532
533
0
    unsigned int n = env.argStack.get_count ();
534
0
    point_t delta;
535
0
    delta.x = env.argStack[n-4];
536
0
    delta.y = env.argStack[n-3];
537
0
    hb_codepoint_t base = param.cff->std_code_to_glyph (env.argStack[n-2].to_int ());
538
0
    hb_codepoint_t accent = param.cff->std_code_to_glyph (env.argStack[n-1].to_int ());
539
540
0
    if (unlikely (!(!env.in_seac && base && accent
541
0
        && _get_path (param.cff, param.font, base, *param.draw_session, true, nullptr, env.get_budget ())
542
0
        && _get_path (param.cff, param.font, accent, *param.draw_session, true, &delta, env.get_budget ()))))
543
0
      env.set_error ();
544
0
  }
545
};
546
547
bool _get_path (const OT::cff1::accelerator_t *cff, hb_font_t *font, hb_codepoint_t glyph,
548
    hb_draw_session_t &draw_session, bool in_seac, point_t *delta,
549
    int64_t *budget)
550
1
{
551
1
  if (unlikely (!cff->is_valid () || (glyph >= cff->num_glyphs))) return false;
552
553
0
  unsigned int fd = cff->fdSelect->get_fd (glyph);
554
0
  const hb_ubytes_t str = (*cff->charStrings)[glyph];
555
0
  cff1_cs_interp_env_t env (str, *cff, fd);
556
0
  env.set_in_seac (in_seac);
557
0
  cff1_cs_interpreter_t<cff1_cs_opset_path_t, cff1_path_param_t> interp (env);
558
0
  cff1_path_param_t param (cff, font, draw_session, delta);
559
0
  if (unlikely (!interp.interpret (param, budget))) return false;
560
561
  /* Let's end the path specially since it is called inside seac also */
562
0
  param.end_path ();
563
564
0
  return true;
565
0
}
566
567
bool OT::cff1::accelerator_t::get_path (hb_font_t *font, hb_codepoint_t glyph, hb_draw_session_t &draw_session, int64_t *budget) const
568
1
{
569
#ifdef HB_NO_OT_FONT_CFF
570
  /* XXX Remove check when this code moves to .hh file. */
571
  return true;
572
#endif
573
574
1
  int64_t stack_budget = HB_BUDGET_GLYPH;
575
1
  if (!budget) budget = &stack_budget;
576
577
1
  return _get_path (this, font, glyph, draw_session, false, nullptr, budget);
578
1
}
579
580
struct get_seac_param_t
581
{
582
0
  get_seac_param_t (const OT::cff1::accelerator_subset_t *_cff) : cff (_cff) {}
583
584
0
  bool has_seac () const { return base && accent; }
585
586
  const OT::cff1::accelerator_subset_t *cff;
587
  hb_codepoint_t  base = 0;
588
  hb_codepoint_t  accent = 0;
589
};
590
591
struct cff1_cs_opset_seac_t : cff1_cs_opset_t<cff1_cs_opset_seac_t, get_seac_param_t>
592
{
593
  static void process_seac (cff1_cs_interp_env_t &env, get_seac_param_t& param)
594
0
  {
595
0
    unsigned int  n = env.argStack.get_count ();
596
0
    hb_codepoint_t  base_char = (hb_codepoint_t)env.argStack[n-2].to_int ();
597
0
    hb_codepoint_t  accent_char = (hb_codepoint_t)env.argStack[n-1].to_int ();
598
599
0
    param.base = param.cff->std_code_to_glyph (base_char);
600
0
    param.accent = param.cff->std_code_to_glyph (accent_char);
601
0
  }
602
};
603
604
static bool
605
_cff1_charstring_may_end_in_seac (const hb_ubytes_t &str)
606
0
{
607
0
  if (unlikely (!str.length || str[str.length - 1] != OpCode_endchar))
608
0
    return false;
609
610
0
  unsigned int end = str.length - 1;
611
0
  if (!end) return false;
612
613
0
  unsigned int last = str[end - 1];
614
615
  /* Type 2 numbers are not self-synchronizing when read backwards.
616
   * Keep interpreting if any number encoding could end at endchar. */
617
0
  if (OpCode_OneByteIntFirst <= last && last <= OpCode_OneByteIntLast)
618
0
    return true;
619
0
  if (end >= 2 &&
620
0
      OpCode_TwoBytePosInt0 <= str[end - 2] &&
621
0
      str[end - 2] <= OpCode_TwoByteNegInt3)
622
0
    return true;
623
0
  if (end >= 3 && str[end - 3] == OpCode_shortint)
624
0
    return true;
625
0
  if (end >= 5 && str[end - 5] == OpCode_fixedcs)
626
0
    return true;
627
628
  /* A subroutine can leave the seac operands on the shared stack. */
629
0
  return last == OpCode_callsubr || last == OpCode_callgsubr;
630
0
}
631
632
bool OT::cff1::accelerator_subset_t::get_seac_components (hb_codepoint_t glyph, hb_codepoint_t *base, hb_codepoint_t *accent) const
633
0
{
634
0
  if (unlikely (!is_valid () || (glyph >= num_glyphs))) return false;
635
636
0
  unsigned int fd = fdSelect->get_fd (glyph);
637
0
  const hb_ubytes_t str = (*charStrings)[glyph];
638
0
  if (unlikely (!_cff1_charstring_may_end_in_seac (str))) return false;
639
0
  cff1_cs_interp_env_t env (str, *this, fd);
640
0
  cff1_cs_interpreter_t<cff1_cs_opset_seac_t, get_seac_param_t> interp (env);
641
0
  get_seac_param_t  param (this);
642
0
  if (unlikely (!interp.interpret (param))) return false;
643
644
0
  if (param.has_seac ())
645
0
  {
646
0
    *base = param.base;
647
0
    *accent = param.accent;
648
0
    return true;
649
0
  }
650
0
  return false;
651
0
}
652
653
654
#endif
655
656
#endif /* HB_OT_CFF1_TABLE_CC pacify */
657
#endif /* HB_OT_CFF1_TABLE_CC guard */