2 * Copyright © 2018 Adobe Inc.
4 * This is part of HarfBuzz, a text shaping library.
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.
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
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.
24 * Adobe Author(s): Michiharu Ariza
33 #include "hb-ot-cff1-table.hh"
34 #include "hb-cff1-interp-cs.hh"
43 int cmp (uint16_t a) const
45 if (a == sid) return 0;
46 return (a < sid) ? -1 : 1;
51 static const uint8_t standard_encoding_to_code [] =
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
66 static const uint8_t expert_encoding_to_code [] =
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
95 static const uint16_t expert_charset_to_sid [] =
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
110 /* glyph ID to SID */
111 static const uint16_t expert_subset_charset_to_sid [] =
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
121 /* SID to glyph ID */
122 static const sid_to_gid_t expert_charset_sid_to_gid [] =
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 },
168 /* SID to glyph ID */
169 static const sid_to_gid_t expert_subset_charset_sid_to_gid [] =
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 }
196 static const uint8_t standard_encoding_to_sid [] =
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
216 hb_codepoint_t OT::cff1::lookup_standard_encoding_for_code (hb_codepoint_t sid)
218 if (sid < ARRAY_LENGTH (standard_encoding_to_code))
219 return (hb_codepoint_t)standard_encoding_to_code[sid];
224 hb_codepoint_t OT::cff1::lookup_expert_encoding_for_code (hb_codepoint_t sid)
226 if (sid < ARRAY_LENGTH (expert_encoding_to_code))
227 return (hb_codepoint_t)expert_encoding_to_code[sid];
232 hb_codepoint_t OT::cff1::lookup_expert_charset_for_sid (hb_codepoint_t glyph)
234 if (glyph < ARRAY_LENGTH (expert_charset_to_sid))
235 return (hb_codepoint_t)expert_charset_to_sid[glyph];
240 hb_codepoint_t OT::cff1::lookup_expert_subset_charset_for_sid (hb_codepoint_t glyph)
242 if (glyph < ARRAY_LENGTH (expert_subset_charset_to_sid))
243 return (hb_codepoint_t)expert_subset_charset_to_sid[glyph];
248 hb_codepoint_t OT::cff1::lookup_expert_charset_for_glyph (hb_codepoint_t sid)
250 const auto *pair = hb_sorted_array (expert_charset_sid_to_gid).bsearch (sid);
251 return pair ? pair->gid : 0;
254 hb_codepoint_t OT::cff1::lookup_expert_subset_charset_for_glyph (hb_codepoint_t sid)
256 const auto *pair = hb_sorted_array (expert_subset_charset_sid_to_gid).bsearch (sid);
257 return pair ? pair->gid : 0;
260 hb_codepoint_t OT::cff1::lookup_standard_encoding_for_sid (hb_codepoint_t code)
262 if (code < ARRAY_LENGTH (standard_encoding_to_sid))
263 return (hb_codepoint_t)standard_encoding_to_sid[code];
265 return CFF_UNDEF_SID;
272 min.set_int (INT_MAX, INT_MAX);
273 max.set_int (INT_MIN, INT_MIN);
276 void update (const point_t &pt)
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;
284 void merge (const bounds_t &b)
288 else if (!b.empty ())
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;
297 void offset (const point_t &delta)
306 bool empty () const { return (min.x >= max.x) || (min.y >= max.y); }
312 struct cff1_extents_param_t
314 void init (const OT::cff1::accelerator_t *_cff)
321 void start_path () { path_open = true; }
322 void end_path () { path_open = false; }
323 bool is_path_open () const { return path_open; }
328 const OT::cff1::accelerator_t *cff;
331 struct cff1_path_procs_extents_t : path_procs_t<cff1_path_procs_extents_t, cff1_cs_interp_env_t, cff1_extents_param_t>
333 static void moveto (cff1_cs_interp_env_t &env, cff1_extents_param_t& param, const point_t &pt)
339 static void line (cff1_cs_interp_env_t &env, cff1_extents_param_t& param, const point_t &pt1)
341 if (!param.is_path_open ())
344 param.bounds.update (env.get_pt ());
347 param.bounds.update (env.get_pt ());
350 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)
352 if (!param.is_path_open ())
355 param.bounds.update (env.get_pt ());
357 /* include control points */
358 param.bounds.update (pt1);
359 param.bounds.update (pt2);
361 param.bounds.update (env.get_pt ());
365 static bool _get_bounds (const OT::cff1::accelerator_t *cff, hb_codepoint_t glyph, bounds_t &bounds, bool in_seac=false);
367 struct cff1_cs_opset_extents_t : cff1_cs_opset_t<cff1_cs_opset_extents_t, cff1_extents_param_t, cff1_path_procs_extents_t>
369 static void process_seac (cff1_cs_interp_env_t &env, cff1_extents_param_t& param)
371 unsigned int n = env.argStack.get_count ();
373 delta.x = env.argStack[n-4];
374 delta.y = env.argStack[n-3];
375 hb_codepoint_t base = param.cff->std_code_to_glyph (env.argStack[n-2].to_int ());
376 hb_codepoint_t accent = param.cff->std_code_to_glyph (env.argStack[n-1].to_int ());
378 bounds_t base_bounds, accent_bounds;
379 if (likely (!env.in_seac && base && accent
380 && _get_bounds (param.cff, base, base_bounds, true)
381 && _get_bounds (param.cff, accent, accent_bounds, true)))
383 param.bounds.merge (base_bounds);
384 accent_bounds.offset (delta);
385 param.bounds.merge (accent_bounds);
392 bool _get_bounds (const OT::cff1::accelerator_t *cff, hb_codepoint_t glyph, bounds_t &bounds, bool in_seac)
395 if (unlikely (!cff->is_valid () || (glyph >= cff->num_glyphs))) return false;
397 unsigned int fd = cff->fdSelect->get_fd (glyph);
398 cff1_cs_interpreter_t<cff1_cs_opset_extents_t, cff1_extents_param_t> interp;
399 const byte_str_t str = (*cff->charStrings)[glyph];
400 interp.env.init (str, *cff, fd);
401 interp.env.set_in_seac (in_seac);
402 cff1_extents_param_t param;
404 if (unlikely (!interp.interpret (param))) return false;
405 bounds = param.bounds;
409 bool OT::cff1::accelerator_t::get_extents (hb_font_t *font, hb_codepoint_t glyph, hb_glyph_extents_t *extents) const
411 #ifdef HB_NO_OT_FONT_CFF
412 /* XXX Remove check when this code moves to .hh file. */
418 if (!_get_bounds (this, glyph, bounds))
421 if (bounds.min.x >= bounds.max.x)
424 extents->x_bearing = 0;
428 extents->x_bearing = font->em_scalef_x (bounds.min.x.to_real ());
429 extents->width = font->em_scalef_x (bounds.max.x.to_real () - bounds.min.x.to_real ());
431 if (bounds.min.y >= bounds.max.y)
434 extents->y_bearing = 0;
438 extents->y_bearing = font->em_scalef_y (bounds.max.y.to_real ());
439 extents->height = font->em_scalef_y (bounds.min.y.to_real () - bounds.max.y.to_real ());
445 #ifdef HB_EXPERIMENTAL_API
446 struct cff1_path_param_t
448 cff1_path_param_t (const OT::cff1::accelerator_t *cff_, hb_font_t *font_,
449 draw_helper_t &draw_helper_, point_t *delta_)
451 draw_helper = &draw_helper_;
457 void move_to (const point_t &p)
460 if (delta) point.move (*delta);
461 draw_helper->move_to (font->em_scalef_x (point.x.to_real ()), font->em_scalef_y (point.y.to_real ()));
464 void line_to (const point_t &p)
467 if (delta) point.move (*delta);
468 draw_helper->line_to (font->em_scalef_x (point.x.to_real ()), font->em_scalef_y (point.y.to_real ()));
471 void cubic_to (const point_t &p1, const point_t &p2, const point_t &p3)
473 point_t point1 = p1, point2 = p2, point3 = p3;
476 point1.move (*delta);
477 point2.move (*delta);
478 point3.move (*delta);
480 draw_helper->cubic_to (font->em_scalef_x (point1.x.to_real ()), font->em_scalef_y (point1.y.to_real ()),
481 font->em_scalef_x (point2.x.to_real ()), font->em_scalef_y (point2.y.to_real ()),
482 font->em_scalef_x (point3.x.to_real ()), font->em_scalef_y (point3.y.to_real ()));
485 void end_path () { draw_helper->end_path (); }
488 draw_helper_t *draw_helper;
491 const OT::cff1::accelerator_t *cff;
494 struct cff1_path_procs_path_t : path_procs_t<cff1_path_procs_path_t, cff1_cs_interp_env_t, cff1_path_param_t>
496 static void moveto (cff1_cs_interp_env_t &env, cff1_path_param_t& param, const point_t &pt)
502 static void line (cff1_cs_interp_env_t &env, cff1_path_param_t ¶m, const point_t &pt1)
508 static void curve (cff1_cs_interp_env_t &env, cff1_path_param_t ¶m, const point_t &pt1, const point_t &pt2, const point_t &pt3)
510 param.cubic_to (pt1, pt2, pt3);
515 static bool _get_path (const OT::cff1::accelerator_t *cff, hb_font_t *font, hb_codepoint_t glyph,
516 draw_helper_t &draw_helper, bool in_seac = false, point_t *delta = nullptr);
518 struct cff1_cs_opset_path_t : cff1_cs_opset_t<cff1_cs_opset_path_t, cff1_path_param_t, cff1_path_procs_path_t>
520 static void process_seac (cff1_cs_interp_env_t &env, cff1_path_param_t& param)
522 /* End previous path */
525 unsigned int n = env.argStack.get_count ();
527 delta.x = env.argStack[n-4];
528 delta.y = env.argStack[n-3];
529 hb_codepoint_t base = param.cff->std_code_to_glyph (env.argStack[n-2].to_int ());
530 hb_codepoint_t accent = param.cff->std_code_to_glyph (env.argStack[n-1].to_int ());
532 if (unlikely (!(!env.in_seac && base && accent
533 && _get_path (param.cff, param.font, base, *param.draw_helper, true)
534 && _get_path (param.cff, param.font, accent, *param.draw_helper, true, &delta))))
539 bool _get_path (const OT::cff1::accelerator_t *cff, hb_font_t *font, hb_codepoint_t glyph,
540 draw_helper_t &draw_helper, bool in_seac, point_t *delta)
542 if (unlikely (!cff->is_valid () || (glyph >= cff->num_glyphs))) return false;
544 unsigned int fd = cff->fdSelect->get_fd (glyph);
545 cff1_cs_interpreter_t<cff1_cs_opset_path_t, cff1_path_param_t> interp;
546 const byte_str_t str = (*cff->charStrings)[glyph];
547 interp.env.init (str, *cff, fd);
548 interp.env.set_in_seac (in_seac);
549 cff1_path_param_t param (cff, font, draw_helper, delta);
550 if (unlikely (!interp.interpret (param))) return false;
552 /* Let's end the path specially since it is called inside seac also */
558 bool OT::cff1::accelerator_t::get_path (hb_font_t *font, hb_codepoint_t glyph, draw_helper_t &draw_helper) const
560 #ifdef HB_NO_OT_FONT_CFF
561 /* XXX Remove check when this code moves to .hh file. */
565 return _get_path (this, font, glyph, draw_helper);
569 struct get_seac_param_t
571 void init (const OT::cff1::accelerator_t *_cff)
578 bool has_seac () const { return base && accent; }
580 const OT::cff1::accelerator_t *cff;
582 hb_codepoint_t accent;
585 struct cff1_cs_opset_seac_t : cff1_cs_opset_t<cff1_cs_opset_seac_t, get_seac_param_t>
587 static void process_seac (cff1_cs_interp_env_t &env, get_seac_param_t& param)
589 unsigned int n = env.argStack.get_count ();
590 hb_codepoint_t base_char = (hb_codepoint_t)env.argStack[n-2].to_int ();
591 hb_codepoint_t accent_char = (hb_codepoint_t)env.argStack[n-1].to_int ();
593 param.base = param.cff->std_code_to_glyph (base_char);
594 param.accent = param.cff->std_code_to_glyph (accent_char);
598 bool OT::cff1::accelerator_t::get_seac_components (hb_codepoint_t glyph, hb_codepoint_t *base, hb_codepoint_t *accent) const
600 if (unlikely (!is_valid () || (glyph >= num_glyphs))) return false;
602 unsigned int fd = fdSelect->get_fd (glyph);
603 cff1_cs_interpreter_t<cff1_cs_opset_seac_t, get_seac_param_t> interp;
604 const byte_str_t str = (*charStrings)[glyph];
605 interp.env.init (str, *this, fd);
606 get_seac_param_t param;
608 if (unlikely (!interp.interpret (param))) return false;
610 if (param.has_seac ())
613 *accent = param.accent;