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-ot-cff1-table.hh"
28#include "hb-cff1-interp-cs.hh"
29
30using namespace CFF;
31
32/* SID to code */
33static const uint8_t standard_encoding_to_code [] =
34{
35 0, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46,
36 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62,
37 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78,
38 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94,
39 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110,
40 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126,
41 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 177,
42 178, 179, 180, 182, 183, 184, 185, 186, 187, 188, 189, 191, 193, 194, 195, 196,
43 197, 198, 199, 200, 202, 203, 205, 206, 207, 208, 225, 227, 232, 233, 234, 235,
44 241, 245, 248, 249, 250, 251
45};
46
47/* SID to code */
48static const uint8_t expert_encoding_to_code [] =
49{
50 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 44, 45, 46,
51 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 58, 59, 0, 0, 0,
52 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
53 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
54 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
55 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
56 0, 0, 0, 47, 0, 0, 0, 0, 0, 0, 0, 0, 0, 87, 88, 0,
57 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
58 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
59 0, 0, 0, 0, 0, 0, 201, 0, 0, 0, 0, 189, 0, 0, 188, 0,
60 0, 0, 0, 190, 202, 0, 0, 0, 0, 203, 0, 0, 0, 0, 0, 0,
61 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
62 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
63 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
64 0, 0, 0, 0, 0, 33, 34, 36, 37, 38, 39, 40, 41, 42, 43, 48,
65 49, 50, 51, 52, 53, 54, 55, 56, 57, 60, 61, 62, 63, 65, 66, 67,
66 68, 69, 73, 76, 77, 78, 79, 82, 83, 84, 86, 89, 90, 91, 93, 94,
67 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110,
68 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126,
69 161, 162, 163, 166, 167, 168, 169, 170, 172, 175, 178, 179, 182, 183, 184, 191,
70 192, 193, 194, 195, 196, 197, 200, 204, 205, 206, 207, 208, 209, 210, 211, 212,
71 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228,
72 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244,
73 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255
74};
75
76/* glyph ID to SID */
77static const uint16_t expert_charset_to_sid [] =
78{
79 0, 1, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 13, 14, 15, 99,
80 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 27, 28, 249, 250, 251, 252,
81 253, 254, 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 109, 110,
82 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, 280, 281, 282,
83 283, 284, 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 298,
84 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314,
85 315, 316, 317, 318, 158, 155, 163, 319, 320, 321, 322, 323, 324, 325, 326, 150,
86 164, 169, 327, 328, 329, 330, 331, 332, 333, 334, 335, 336, 337, 338, 339, 340,
87 341, 342, 343, 344, 345, 346, 347, 348, 349, 350, 351, 352, 353, 354, 355, 356,
88 357, 358, 359, 360, 361, 362, 363, 364, 365, 366, 367, 368, 369, 370, 371, 372,
89 373, 374, 375, 376, 377, 378
90};
91
92/* glyph ID to SID */
93static const uint16_t expert_subset_charset_to_sid [] =
94{
95 0, 1, 231, 232, 235, 236, 237, 238, 13, 14, 15, 99, 239, 240, 241, 242,
96 243, 244, 245, 246, 247, 248, 27, 28, 249, 250, 251, 253, 254, 255, 256, 257,
97 258, 259, 260, 261, 262, 263, 264, 265, 266, 109, 110, 267, 268, 269, 270, 272,
98 300, 301, 302, 305, 314, 315, 158, 155, 163, 320, 321, 322, 323, 324, 325, 326,
99 150, 164, 169, 327, 328, 329, 330, 331, 332, 333, 334, 335, 336, 337, 338, 339,
100 340, 341, 342, 343, 344, 345, 346
101};
102
103/* code to SID */
104static const uint8_t standard_encoding_to_sid [] =
105{
106 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
107 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
108 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
109 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32,
110 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
111 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64,
112 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80,
113 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 0,
114 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
115 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
116 0, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110,
117 0, 111, 112, 113, 114, 0, 115, 116, 117, 118, 119, 120, 121, 122, 0, 123,
118 0, 124, 125, 126, 127, 128, 129, 130, 131, 0, 132, 133, 0, 134, 135, 136,
119 137, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
120 0, 138, 0, 139, 0, 0, 0, 0, 140, 141, 142, 143, 0, 0, 0, 0,
121 0, 144, 0, 0, 0, 145, 0, 0, 146, 147, 148, 149, 0, 0, 0, 0
122};
123
124hb_codepoint_t OT::cff1::lookup_standard_encoding_for_code (hb_codepoint_t sid)
125{
126 if (sid < ARRAY_LENGTH (standard_encoding_to_code))
127 return (hb_codepoint_t)standard_encoding_to_code[sid];
128 else
129 return 0;
130}
131
132hb_codepoint_t OT::cff1::lookup_expert_encoding_for_code (hb_codepoint_t sid)
133{
134 if (sid < ARRAY_LENGTH (expert_encoding_to_code))
135 return (hb_codepoint_t)expert_encoding_to_code[sid];
136 else
137 return 0;
138}
139
140hb_codepoint_t OT::cff1::lookup_expert_charset_for_sid (hb_codepoint_t glyph)
141{
142 if (glyph < ARRAY_LENGTH (expert_charset_to_sid))
143 return (hb_codepoint_t)expert_charset_to_sid[glyph];
144 else
145 return 0;
146}
147
148hb_codepoint_t OT::cff1::lookup_expert_subset_charset_for_sid (hb_codepoint_t glyph)
149{
150 if (glyph < ARRAY_LENGTH (expert_subset_charset_to_sid))
151 return (hb_codepoint_t)expert_subset_charset_to_sid[glyph];
152 else
153 return 0;
154}
155
156hb_codepoint_t OT::cff1::lookup_standard_encoding_for_sid (hb_codepoint_t code)
157{
158 if (code < ARRAY_LENGTH (standard_encoding_to_sid))
159 return (hb_codepoint_t)standard_encoding_to_sid[code];
160 else
161 return CFF_UNDEF_SID;
162}
163
164struct bounds_t
165{
166 void init ()
167 {
168 min.set_int (0x7FFFFFFF, 0x7FFFFFFF);
169 max.set_int (-0x80000000, -0x80000000);
170 }
171
172 void update (const point_t &pt)
173 {
174 if (pt.x < min.x) min.x = pt.x;
175 if (pt.x > max.x) max.x = pt.x;
176 if (pt.y < min.y) min.y = pt.y;
177 if (pt.y > max.y) max.y = pt.y;
178 }
179
180 void merge (const bounds_t &b)
181 {
182 if (empty ())
183 *this = b;
184 else if (!b.empty ())
185 {
186 if (b.min.x < min.x) min.x = b.min.x;
187 if (b.max.x > max.x) max.x = b.max.x;
188 if (b.min.y < min.y) min.y = b.min.y;
189 if (b.max.y > max.y) max.y = b.max.y;
190 }
191 }
192
193 void offset (const point_t &delta)
194 {
195 if (!empty ())
196 {
197 min.move (delta);
198 max.move (delta);
199 }
200 }
201
202 bool empty () const
203 { return (min.x >= max.x) || (min.y >= max.y); }
204
205 point_t min;
206 point_t max;
207};
208
209struct extents_param_t
210{
211 void init (const OT::cff1::accelerator_t *_cff)
212 {
213 path_open = false;
214 cff = _cff;
215 bounds.init ();
216 }
217
218 void start_path () { path_open = true; }
219 void end_path () { path_open = false; }
220 bool is_path_open () const { return path_open; }
221
222 bool path_open;
223 bounds_t bounds;
224
225 const OT::cff1::accelerator_t *cff;
226};
227
228struct cff1_path_procs_extents_t : path_procs_t<cff1_path_procs_extents_t, cff1_cs_interp_env_t, extents_param_t>
229{
230 static void moveto (cff1_cs_interp_env_t &env, extents_param_t& param, const point_t &pt)
231 {
232 param.end_path ();
233 env.moveto (pt);
234 }
235
236 static void line (cff1_cs_interp_env_t &env, extents_param_t& param, const point_t &pt1)
237 {
238 if (!param.is_path_open ())
239 {
240 param.start_path ();
241 param.bounds.update (env.get_pt ());
242 }
243 env.moveto (pt1);
244 param.bounds.update (env.get_pt ());
245 }
246
247 static void curve (cff1_cs_interp_env_t &env, extents_param_t& param, const point_t &pt1, const point_t &pt2, const point_t &pt3)
248 {
249 if (!param.is_path_open ())
250 {
251 param.start_path ();
252 param.bounds.update (env.get_pt ());
253 }
254 /* include control points */
255 param.bounds.update (pt1);
256 param.bounds.update (pt2);
257 env.moveto (pt3);
258 param.bounds.update (env.get_pt ());
259 }
260};
261
262static bool _get_bounds (const OT::cff1::accelerator_t *cff, hb_codepoint_t glyph, bounds_t &bounds, bool in_seac=false);
263
264struct cff1_cs_opset_extents_t : cff1_cs_opset_t<cff1_cs_opset_extents_t, extents_param_t, cff1_path_procs_extents_t>
265{
266 static void process_seac (cff1_cs_interp_env_t &env, extents_param_t& param)
267 {
268 unsigned int n = env.argStack.get_count ();
269 point_t delta;
270 delta.x = env.argStack[n-4];
271 delta.y = env.argStack[n-3];
272 hb_codepoint_t base = param.cff->std_code_to_glyph (env.argStack[n-2].to_int ());
273 hb_codepoint_t accent = param.cff->std_code_to_glyph (env.argStack[n-1].to_int ());
274
275 bounds_t base_bounds, accent_bounds;
276 if (likely (!env.in_seac && base && accent
277 && _get_bounds (param.cff, base, base_bounds, true)
278 && _get_bounds (param.cff, accent, accent_bounds, true)))
279 {
280 param.bounds.merge (base_bounds);
281 accent_bounds.offset (delta);
282 param.bounds.merge (accent_bounds);
283 }
284 else
285 env.set_error ();
286 }
287};
288
289bool _get_bounds (const OT::cff1::accelerator_t *cff, hb_codepoint_t glyph, bounds_t &bounds, bool in_seac)
290{
291 bounds.init ();
292 if (unlikely (!cff->is_valid () || (glyph >= cff->num_glyphs))) return false;
293
294 unsigned int fd = cff->fdSelect->get_fd (glyph);
295 cff1_cs_interpreter_t<cff1_cs_opset_extents_t, extents_param_t> interp;
296 const byte_str_t str = (*cff->charStrings)[glyph];
297 interp.env.init (str, *cff, fd);
298 interp.env.set_in_seac (in_seac);
299 extents_param_t param;
300 param.init (cff);
301 if (unlikely (!interp.interpret (param))) return false;
302 bounds = param.bounds;
303 return true;
304}
305
306bool OT::cff1::accelerator_t::get_extents (hb_codepoint_t glyph, hb_glyph_extents_t *extents) const
307{
308 bounds_t bounds;
309
310 if (!_get_bounds (this, glyph, bounds))
311 return false;
312
313 if (bounds.min.x >= bounds.max.x)
314 {
315 extents->width = 0;
316 extents->x_bearing = 0;
317 }
318 else
319 {
320 extents->x_bearing = (int32_t)bounds.min.x.floor ();
321 extents->width = (int32_t)bounds.max.x.ceil () - extents->x_bearing;
322 }
323 if (bounds.min.y >= bounds.max.y)
324 {
325 extents->height = 0;
326 extents->y_bearing = 0;
327 }
328 else
329 {
330 extents->y_bearing = (int32_t)bounds.max.y.ceil ();
331 extents->height = (int32_t)bounds.min.y.floor () - extents->y_bearing;
332 }
333
334 return true;
335}
336
337struct get_seac_param_t
338{
339 void init (const OT::cff1::accelerator_t *_cff)
340 {
341 cff = _cff;
342 base = 0;
343 accent = 0;
344 }
345
346 bool has_seac () const { return base && accent; }
347
348 const OT::cff1::accelerator_t *cff;
349 hb_codepoint_t base;
350 hb_codepoint_t accent;
351};
352
353struct cff1_cs_opset_seac_t : cff1_cs_opset_t<cff1_cs_opset_seac_t, get_seac_param_t>
354{
355 static void process_seac (cff1_cs_interp_env_t &env, get_seac_param_t& param)
356 {
357 unsigned int n = env.argStack.get_count ();
358 hb_codepoint_t base_char = (hb_codepoint_t)env.argStack[n-2].to_int ();
359 hb_codepoint_t accent_char = (hb_codepoint_t)env.argStack[n-1].to_int ();
360
361 param.base = param.cff->std_code_to_glyph (base_char);
362 param.accent = param.cff->std_code_to_glyph (accent_char);
363 }
364};
365
366bool OT::cff1::accelerator_t::get_seac_components (hb_codepoint_t glyph, hb_codepoint_t *base, hb_codepoint_t *accent) const
367{
368 if (unlikely (!is_valid () || (glyph >= num_glyphs))) return false;
369
370 unsigned int fd = fdSelect->get_fd (glyph);
371 cff1_cs_interpreter_t<cff1_cs_opset_seac_t, get_seac_param_t> interp;
372 const byte_str_t str = (*charStrings)[glyph];
373 interp.env.init (str, *this, fd);
374 get_seac_param_t param;
375 param.init (this);
376 if (unlikely (!interp.interpret (param))) return false;
377
378 if (param.has_seac ())
379 {
380 *base = param.base;
381 *accent = param.accent;
382 return true;
383 }
384 return false;
385}
386