Coverage Report

Created: 2026-09-01 06:20

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/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)
383
0
         && _get_bounds (param.cff, accent, accent_bounds, true)))
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
  if (!_get_bounds (this, glyph, bounds, false, budget))
420
0
    return false;
421
422
0
  if (bounds.min.x >= bounds.max.x)
423
0
  {
424
0
    extents->width = 0;
425
0
    extents->x_bearing = 0;
426
0
  }
427
0
  else
428
0
  {
429
0
    double x_bearing = roundf (bounds.min.x.to_real ());
430
0
    extents->x_bearing = hb_clamp_to<hb_position_t> (x_bearing);
431
0
    extents->width = hb_clamp_to<hb_position_t> ((double) roundf (bounds.max.x.to_real ()) - x_bearing);
432
0
  }
433
0
  if (bounds.min.y >= bounds.max.y)
434
0
  {
435
0
    extents->height = 0;
436
0
    extents->y_bearing = 0;
437
0
  }
438
0
  else
439
0
  {
440
0
    double y_bearing = roundf (bounds.max.y.to_real ());
441
0
    extents->y_bearing = hb_clamp_to<hb_position_t> (y_bearing);
442
0
    extents->height = hb_clamp_to<hb_position_t> ((double) roundf (bounds.min.y.to_real ()) - y_bearing);
443
0
  }
444
445
0
  font->scale_glyph_extents (extents);
446
447
0
  return true;
448
0
}
449
450
struct cff1_path_param_t
451
{
452
  cff1_path_param_t (const OT::cff1::accelerator_t *cff_, hb_font_t *font_,
453
         hb_draw_session_t &draw_session_, point_t *delta_)
454
0
  {
455
0
    draw_session = &draw_session_;
456
0
    cff = cff_;
457
0
    font = font_;
458
0
    delta = delta_;
459
0
  }
460
461
  void move_to (const point_t &p)
462
0
  {
463
0
    point_t point = p;
464
0
    if (delta) point.move (*delta);
465
0
    draw_session->move_to (font->em_fscalef_x (point.x.to_real ()), font->em_fscalef_y (point.y.to_real ()));
466
0
  }
467
468
  void line_to (const point_t &p)
469
0
  {
470
0
    point_t point = p;
471
0
    if (delta) point.move (*delta);
472
0
    draw_session->line_to (font->em_fscalef_x (point.x.to_real ()), font->em_fscalef_y (point.y.to_real ()));
473
0
  }
474
475
  void cubic_to (const point_t &p1, const point_t &p2, const point_t &p3)
476
0
  {
477
0
    point_t point1 = p1, point2 = p2, point3 = p3;
478
0
    if (delta)
479
0
    {
480
0
      point1.move (*delta);
481
0
      point2.move (*delta);
482
0
      point3.move (*delta);
483
0
    }
484
0
    draw_session->cubic_to (font->em_fscalef_x (point1.x.to_real ()), font->em_fscalef_y (point1.y.to_real ()),
485
0
         font->em_fscalef_x (point2.x.to_real ()), font->em_fscalef_y (point2.y.to_real ()),
486
0
         font->em_fscalef_x (point3.x.to_real ()), font->em_fscalef_y (point3.y.to_real ()));
487
0
  }
488
489
0
  void end_path () { draw_session->close_path (); }
490
491
  hb_font_t *font;
492
  hb_draw_session_t *draw_session;
493
  point_t *delta;
494
495
  const OT::cff1::accelerator_t *cff;
496
};
497
498
struct cff1_path_procs_path_t : path_procs_t<cff1_path_procs_path_t, cff1_cs_interp_env_t, cff1_path_param_t>
499
{
500
  static void moveto (cff1_cs_interp_env_t &env, cff1_path_param_t& param, const point_t &pt)
501
0
  {
502
0
    param.move_to (pt);
503
0
    env.moveto (pt);
504
0
  }
505
506
  static void line (cff1_cs_interp_env_t &env, cff1_path_param_t &param, const point_t &pt1)
507
0
  {
508
0
    param.line_to (pt1);
509
0
    env.moveto (pt1);
510
0
  }
511
512
  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)
513
0
  {
514
0
    param.cubic_to (pt1, pt2, pt3);
515
0
    env.moveto (pt3);
516
0
  }
517
};
518
519
static bool _get_path (const OT::cff1::accelerator_t *cff, hb_font_t *font, hb_codepoint_t glyph,
520
           hb_draw_session_t &draw_session, bool in_seac = false, point_t *delta = nullptr,
521
           int64_t *budget = nullptr);
522
523
struct cff1_cs_opset_path_t : cff1_cs_opset_t<cff1_cs_opset_path_t, cff1_path_param_t, cff1_path_procs_path_t>
524
{
525
  static void process_seac (cff1_cs_interp_env_t &env, cff1_path_param_t& param)
526
0
  {
527
    /* End previous path */
528
0
    param.end_path ();
529
530
0
    unsigned int n = env.argStack.get_count ();
531
0
    point_t delta;
532
0
    delta.x = env.argStack[n-4];
533
0
    delta.y = env.argStack[n-3];
534
0
    hb_codepoint_t base = param.cff->std_code_to_glyph (env.argStack[n-2].to_int ());
535
0
    hb_codepoint_t accent = param.cff->std_code_to_glyph (env.argStack[n-1].to_int ());
536
537
0
    if (unlikely (!(!env.in_seac && base && accent
538
0
        && _get_path (param.cff, param.font, base, *param.draw_session, true)
539
0
        && _get_path (param.cff, param.font, accent, *param.draw_session, true, &delta))))
540
0
      env.set_error ();
541
0
  }
542
};
543
544
bool _get_path (const OT::cff1::accelerator_t *cff, hb_font_t *font, hb_codepoint_t glyph,
545
    hb_draw_session_t &draw_session, bool in_seac, point_t *delta,
546
    int64_t *budget)
547
0
{
548
0
  if (unlikely (!cff->is_valid () || (glyph >= cff->num_glyphs))) return false;
549
550
0
  unsigned int fd = cff->fdSelect->get_fd (glyph);
551
0
  const hb_ubytes_t str = (*cff->charStrings)[glyph];
552
0
  cff1_cs_interp_env_t env (str, *cff, fd);
553
0
  env.set_in_seac (in_seac);
554
0
  cff1_cs_interpreter_t<cff1_cs_opset_path_t, cff1_path_param_t> interp (env);
555
0
  cff1_path_param_t param (cff, font, draw_session, delta);
556
0
  if (unlikely (!interp.interpret (param, budget))) return false;
557
558
  /* Let's end the path specially since it is called inside seac also */
559
0
  param.end_path ();
560
561
0
  return true;
562
0
}
563
564
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
565
0
{
566
#ifdef HB_NO_OT_FONT_CFF
567
  /* XXX Remove check when this code moves to .hh file. */
568
  return true;
569
#endif
570
571
0
  return _get_path (this, font, glyph, draw_session, false, nullptr, budget);
572
0
}
573
574
struct get_seac_param_t
575
{
576
0
  get_seac_param_t (const OT::cff1::accelerator_subset_t *_cff) : cff (_cff) {}
577
578
0
  bool has_seac () const { return base && accent; }
579
580
  const OT::cff1::accelerator_subset_t *cff;
581
  hb_codepoint_t  base = 0;
582
  hb_codepoint_t  accent = 0;
583
};
584
585
struct cff1_cs_opset_seac_t : cff1_cs_opset_t<cff1_cs_opset_seac_t, get_seac_param_t>
586
{
587
  static void process_seac (cff1_cs_interp_env_t &env, get_seac_param_t& param)
588
0
  {
589
0
    unsigned int  n = env.argStack.get_count ();
590
0
    hb_codepoint_t  base_char = (hb_codepoint_t)env.argStack[n-2].to_int ();
591
0
    hb_codepoint_t  accent_char = (hb_codepoint_t)env.argStack[n-1].to_int ();
592
593
0
    param.base = param.cff->std_code_to_glyph (base_char);
594
0
    param.accent = param.cff->std_code_to_glyph (accent_char);
595
0
  }
596
};
597
598
static bool
599
_cff1_charstring_may_end_in_seac (const hb_ubytes_t &str)
600
0
{
601
0
  if (unlikely (!str.length || str[str.length - 1] != OpCode_endchar))
602
0
    return false;
603
604
0
  unsigned int end = str.length - 1;
605
0
  if (!end) return false;
606
607
0
  unsigned int last = str[end - 1];
608
609
  /* Type 2 numbers are not self-synchronizing when read backwards.
610
   * Keep interpreting if any number encoding could end at endchar. */
611
0
  if (OpCode_OneByteIntFirst <= last && last <= OpCode_OneByteIntLast)
612
0
    return true;
613
0
  if (end >= 2 &&
614
0
      OpCode_TwoBytePosInt0 <= str[end - 2] &&
615
0
      str[end - 2] <= OpCode_TwoByteNegInt3)
616
0
    return true;
617
0
  if (end >= 3 && str[end - 3] == OpCode_shortint)
618
0
    return true;
619
0
  if (end >= 5 && str[end - 5] == OpCode_fixedcs)
620
0
    return true;
621
622
  /* A subroutine can leave the seac operands on the shared stack. */
623
0
  return last == OpCode_callsubr || last == OpCode_callgsubr;
624
0
}
625
626
bool OT::cff1::accelerator_subset_t::get_seac_components (hb_codepoint_t glyph, hb_codepoint_t *base, hb_codepoint_t *accent) const
627
0
{
628
0
  if (unlikely (!is_valid () || (glyph >= num_glyphs))) return false;
629
630
0
  unsigned int fd = fdSelect->get_fd (glyph);
631
0
  const hb_ubytes_t str = (*charStrings)[glyph];
632
0
  if (unlikely (!_cff1_charstring_may_end_in_seac (str))) return false;
633
0
  cff1_cs_interp_env_t env (str, *this, fd);
634
0
  cff1_cs_interpreter_t<cff1_cs_opset_seac_t, get_seac_param_t> interp (env);
635
0
  get_seac_param_t  param (this);
636
0
  if (unlikely (!interp.interpret (param))) return false;
637
638
0
  if (param.has_seac ())
639
0
  {
640
0
    *base = param.base;
641
0
    *accent = param.accent;
642
0
    return true;
643
0
  }
644
0
  return false;
645
0
}
646
647
648
#endif
649
650
#endif /* HB_OT_CFF1_TABLE_CC pacify */
651
#endif /* HB_OT_CFF1_TABLE_CC guard */