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-draw.hh"
32#include "hb-algs.hh"
33#include "hb-ot-cff1-table.hh"
34#include "hb-cff1-interp-cs.hh"
35
36using namespace CFF;
37
38struct sid_to_gid_t
39{
40 uint16_t sid;
41 uint8_t gid;
42
43 int cmp (uint16_t a) const
44 {
45 if (a == sid) return 0;
46 return (a < sid) ? -1 : 1;
47 }
48};
49
50/* SID to code */
51static const uint8_t standard_encoding_to_code [] =
52{
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
63};
64
65/* SID to code */
66static const uint8_t expert_encoding_to_code [] =
67{
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
92};
93
94/* glyph ID to SID */
95static const uint16_t expert_charset_to_sid [] =
96{
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
108};
109
110/* glyph ID to SID */
111static const uint16_t expert_subset_charset_to_sid [] =
112{
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
119};
120
121/* SID to glyph ID */
122static const sid_to_gid_t expert_charset_sid_to_gid [] =
123{
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 },
165 { 378, 165 }
166};
167
168/* SID to glyph ID */
169static const sid_to_gid_t expert_subset_charset_sid_to_gid [] =
170{
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 }
193};
194
195/* code to SID */
196static const uint8_t standard_encoding_to_sid [] =
197{
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
214};
215
216hb_codepoint_t OT::cff1::lookup_standard_encoding_for_code (hb_codepoint_t sid)
217{
218 if (sid < ARRAY_LENGTH (standard_encoding_to_code))
219 return (hb_codepoint_t)standard_encoding_to_code[sid];
220 else
221 return 0;
222}
223
224hb_codepoint_t OT::cff1::lookup_expert_encoding_for_code (hb_codepoint_t sid)
225{
226 if (sid < ARRAY_LENGTH (expert_encoding_to_code))
227 return (hb_codepoint_t)expert_encoding_to_code[sid];
228 else
229 return 0;
230}
231
232hb_codepoint_t OT::cff1::lookup_expert_charset_for_sid (hb_codepoint_t glyph)
233{
234 if (glyph < ARRAY_LENGTH (expert_charset_to_sid))
235 return (hb_codepoint_t)expert_charset_to_sid[glyph];
236 else
237 return 0;
238}
239
240hb_codepoint_t OT::cff1::lookup_expert_subset_charset_for_sid (hb_codepoint_t glyph)
241{
242 if (glyph < ARRAY_LENGTH (expert_subset_charset_to_sid))
243 return (hb_codepoint_t)expert_subset_charset_to_sid[glyph];
244 else
245 return 0;
246}
247
248hb_codepoint_t OT::cff1::lookup_expert_charset_for_glyph (hb_codepoint_t sid)
249{
250 const auto *pair = hb_sorted_array (expert_charset_sid_to_gid).bsearch (sid);
251 return pair ? pair->gid : 0;
252}
253
254hb_codepoint_t OT::cff1::lookup_expert_subset_charset_for_glyph (hb_codepoint_t sid)
255{
256 const auto *pair = hb_sorted_array (expert_subset_charset_sid_to_gid).bsearch (sid);
257 return pair ? pair->gid : 0;
258}
259
260hb_codepoint_t OT::cff1::lookup_standard_encoding_for_sid (hb_codepoint_t code)
261{
262 if (code < ARRAY_LENGTH (standard_encoding_to_sid))
263 return (hb_codepoint_t)standard_encoding_to_sid[code];
264 else
265 return CFF_UNDEF_SID;
266}
267
268struct bounds_t
269{
270 void init ()
271 {
272 min.set_int (INT_MAX, INT_MAX);
273 max.set_int (INT_MIN, INT_MIN);
274 }
275
276 void update (const point_t &pt)
277 {
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;
282 }
283
284 void merge (const bounds_t &b)
285 {
286 if (empty ())
287 *this = b;
288 else if (!b.empty ())
289 {
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;
294 }
295 }
296
297 void offset (const point_t &delta)
298 {
299 if (!empty ())
300 {
301 min.move (delta);
302 max.move (delta);
303 }
304 }
305
306 bool empty () const { return (min.x >= max.x) || (min.y >= max.y); }
307
308 point_t min;
309 point_t max;
310};
311
312struct cff1_extents_param_t
313{
314 void init (const OT::cff1::accelerator_t *_cff)
315 {
316 path_open = false;
317 cff = _cff;
318 bounds.init ();
319 }
320
321 void start_path () { path_open = true; }
322 void end_path () { path_open = false; }
323 bool is_path_open () const { return path_open; }
324
325 bool path_open;
326 bounds_t bounds;
327
328 const OT::cff1::accelerator_t *cff;
329};
330
331struct cff1_path_procs_extents_t : path_procs_t<cff1_path_procs_extents_t, cff1_cs_interp_env_t, cff1_extents_param_t>
332{
333 static void moveto (cff1_cs_interp_env_t &env, cff1_extents_param_t& param, const point_t &pt)
334 {
335 param.end_path ();
336 env.moveto (pt);
337 }
338
339 static void line (cff1_cs_interp_env_t &env, cff1_extents_param_t& param, const point_t &pt1)
340 {
341 if (!param.is_path_open ())
342 {
343 param.start_path ();
344 param.bounds.update (env.get_pt ());
345 }
346 env.moveto (pt1);
347 param.bounds.update (env.get_pt ());
348 }
349
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)
351 {
352 if (!param.is_path_open ())
353 {
354 param.start_path ();
355 param.bounds.update (env.get_pt ());
356 }
357 /* include control points */
358 param.bounds.update (pt1);
359 param.bounds.update (pt2);
360 env.moveto (pt3);
361 param.bounds.update (env.get_pt ());
362 }
363};
364
365static bool _get_bounds (const OT::cff1::accelerator_t *cff, hb_codepoint_t glyph, bounds_t &bounds, bool in_seac=false);
366
367struct cff1_cs_opset_extents_t : cff1_cs_opset_t<cff1_cs_opset_extents_t, cff1_extents_param_t, cff1_path_procs_extents_t>
368{
369 static void process_seac (cff1_cs_interp_env_t &env, cff1_extents_param_t& param)
370 {
371 unsigned int n = env.argStack.get_count ();
372 point_t delta;
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 ());
377
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)))
382 {
383 param.bounds.merge (base_bounds);
384 accent_bounds.offset (delta);
385 param.bounds.merge (accent_bounds);
386 }
387 else
388 env.set_error ();
389 }
390};
391
392bool _get_bounds (const OT::cff1::accelerator_t *cff, hb_codepoint_t glyph, bounds_t &bounds, bool in_seac)
393{
394 bounds.init ();
395 if (unlikely (!cff->is_valid () || (glyph >= cff->num_glyphs))) return false;
396
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;
403 param.init (cff);
404 if (unlikely (!interp.interpret (param))) return false;
405 bounds = param.bounds;
406 return true;
407}
408
409bool OT::cff1::accelerator_t::get_extents (hb_font_t *font, hb_codepoint_t glyph, hb_glyph_extents_t *extents) const
410{
411#ifdef HB_NO_OT_FONT_CFF
412 /* XXX Remove check when this code moves to .hh file. */
413 return true;
414#endif
415
416 bounds_t bounds;
417
418 if (!_get_bounds (this, glyph, bounds))
419 return false;
420
421 if (bounds.min.x >= bounds.max.x)
422 {
423 extents->width = 0;
424 extents->x_bearing = 0;
425 }
426 else
427 {
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 ());
430 }
431 if (bounds.min.y >= bounds.max.y)
432 {
433 extents->height = 0;
434 extents->y_bearing = 0;
435 }
436 else
437 {
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 ());
440 }
441
442 return true;
443}
444
445#ifdef HB_EXPERIMENTAL_API
446struct cff1_path_param_t
447{
448 cff1_path_param_t (const OT::cff1::accelerator_t *cff_, hb_font_t *font_,
449 draw_helper_t &draw_helper_, point_t *delta_)
450 {
451 draw_helper = &draw_helper_;
452 cff = cff_;
453 font = font_;
454 delta = delta_;
455 }
456
457 void move_to (const point_t &p)
458 {
459 point_t point = 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 ()));
462 }
463
464 void line_to (const point_t &p)
465 {
466 point_t point = 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 ()));
469 }
470
471 void cubic_to (const point_t &p1, const point_t &p2, const point_t &p3)
472 {
473 point_t point1 = p1, point2 = p2, point3 = p3;
474 if (delta)
475 {
476 point1.move (*delta);
477 point2.move (*delta);
478 point3.move (*delta);
479 }
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 ()));
483 }
484
485 void end_path () { draw_helper->end_path (); }
486
487 hb_font_t *font;
488 draw_helper_t *draw_helper;
489 point_t *delta;
490
491 const OT::cff1::accelerator_t *cff;
492};
493
494struct cff1_path_procs_path_t : path_procs_t<cff1_path_procs_path_t, cff1_cs_interp_env_t, cff1_path_param_t>
495{
496 static void moveto (cff1_cs_interp_env_t &env, cff1_path_param_t& param, const point_t &pt)
497 {
498 param.move_to (pt);
499 env.moveto (pt);
500 }
501
502 static void line (cff1_cs_interp_env_t &env, cff1_path_param_t &param, const point_t &pt1)
503 {
504 param.line_to (pt1);
505 env.moveto (pt1);
506 }
507
508 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)
509 {
510 param.cubic_to (pt1, pt2, pt3);
511 env.moveto (pt3);
512 }
513};
514
515static 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);
517
518struct cff1_cs_opset_path_t : cff1_cs_opset_t<cff1_cs_opset_path_t, cff1_path_param_t, cff1_path_procs_path_t>
519{
520 static void process_seac (cff1_cs_interp_env_t &env, cff1_path_param_t& param)
521 {
522 /* End previous path */
523 param.end_path ();
524
525 unsigned int n = env.argStack.get_count ();
526 point_t delta;
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 ());
531
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))))
535 env.set_error ();
536 }
537};
538
539bool _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)
541{
542 if (unlikely (!cff->is_valid () || (glyph >= cff->num_glyphs))) return false;
543
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;
551
552 /* Let's end the path specially since it is called inside seac also */
553 param.end_path ();
554
555 return true;
556}
557
558bool OT::cff1::accelerator_t::get_path (hb_font_t *font, hb_codepoint_t glyph, draw_helper_t &draw_helper) const
559{
560#ifdef HB_NO_OT_FONT_CFF
561 /* XXX Remove check when this code moves to .hh file. */
562 return true;
563#endif
564
565 return _get_path (this, font, glyph, draw_helper);
566}
567#endif
568
569struct get_seac_param_t
570{
571 void init (const OT::cff1::accelerator_t *_cff)
572 {
573 cff = _cff;
574 base = 0;
575 accent = 0;
576 }
577
578 bool has_seac () const { return base && accent; }
579
580 const OT::cff1::accelerator_t *cff;
581 hb_codepoint_t base;
582 hb_codepoint_t accent;
583};
584
585struct 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 {
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 ();
592
593 param.base = param.cff->std_code_to_glyph (base_char);
594 param.accent = param.cff->std_code_to_glyph (accent_char);
595 }
596};
597
598bool OT::cff1::accelerator_t::get_seac_components (hb_codepoint_t glyph, hb_codepoint_t *base, hb_codepoint_t *accent) const
599{
600 if (unlikely (!is_valid () || (glyph >= num_glyphs))) return false;
601
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;
607 param.init (this);
608 if (unlikely (!interp.interpret (param))) return false;
609
610 if (param.has_seac ())
611 {
612 *base = param.base;
613 *accent = param.accent;
614 return true;
615 }
616 return false;
617}
618
619
620#endif
621