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