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 cff1_extents_param_t (const OT::cff1::accelerator_t *_cff) : cff (_cff)
315 {
316 bounds.init ();
317 }
318
319 void start_path () { path_open = true; }
320 void end_path () { path_open = false; }
321 bool is_path_open () const { return path_open; }
322
323 bool path_open = false;
324 bounds_t bounds;
325
326 const OT::cff1::accelerator_t *cff;
327};
328
329struct cff1_path_procs_extents_t : path_procs_t<cff1_path_procs_extents_t, cff1_cs_interp_env_t, cff1_extents_param_t>
330{
331 static void moveto (cff1_cs_interp_env_t &env, cff1_extents_param_t& param, const point_t &pt)
332 {
333 param.end_path ();
334 env.moveto (pt);
335 }
336
337 static void line (cff1_cs_interp_env_t &env, cff1_extents_param_t& param, const point_t &pt1)
338 {
339 if (!param.is_path_open ())
340 {
341 param.start_path ();
342 param.bounds.update (env.get_pt ());
343 }
344 env.moveto (pt1);
345 param.bounds.update (env.get_pt ());
346 }
347
348 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)
349 {
350 if (!param.is_path_open ())
351 {
352 param.start_path ();
353 param.bounds.update (env.get_pt ());
354 }
355 /* include control points */
356 param.bounds.update (pt1);
357 param.bounds.update (pt2);
358 env.moveto (pt3);
359 param.bounds.update (env.get_pt ());
360 }
361};
362
363static bool _get_bounds (const OT::cff1::accelerator_t *cff, hb_codepoint_t glyph, bounds_t &bounds, bool in_seac=false);
364
365struct cff1_cs_opset_extents_t : cff1_cs_opset_t<cff1_cs_opset_extents_t, cff1_extents_param_t, cff1_path_procs_extents_t>
366{
367 static void process_seac (cff1_cs_interp_env_t &env, cff1_extents_param_t& param)
368 {
369 unsigned int n = env.argStack.get_count ();
370 point_t delta;
371 delta.x = env.argStack[n-4];
372 delta.y = env.argStack[n-3];
373 hb_codepoint_t base = param.cff->std_code_to_glyph (env.argStack[n-2].to_int ());
374 hb_codepoint_t accent = param.cff->std_code_to_glyph (env.argStack[n-1].to_int ());
375
376 bounds_t base_bounds, accent_bounds;
377 if (likely (!env.in_seac && base && accent
378 && _get_bounds (param.cff, base, base_bounds, true)
379 && _get_bounds (param.cff, accent, accent_bounds, true)))
380 {
381 param.bounds.merge (base_bounds);
382 accent_bounds.offset (delta);
383 param.bounds.merge (accent_bounds);
384 }
385 else
386 env.set_error ();
387 }
388};
389
390bool _get_bounds (const OT::cff1::accelerator_t *cff, hb_codepoint_t glyph, bounds_t &bounds, bool in_seac)
391{
392 bounds.init ();
393 if (unlikely (!cff->is_valid () || (glyph >= cff->num_glyphs))) return false;
394
395 unsigned int fd = cff->fdSelect->get_fd (glyph);
396 const hb_ubytes_t str = (*cff->charStrings)[glyph];
397 cff1_cs_interp_env_t env (str, *cff, fd);
398 env.set_in_seac (in_seac);
399 cff1_cs_interpreter_t<cff1_cs_opset_extents_t, cff1_extents_param_t> interp (env);
400 cff1_extents_param_t param (cff);
401 if (unlikely (!interp.interpret (param))) return false;
402 bounds = param.bounds;
403 return true;
404}
405
406bool OT::cff1::accelerator_t::get_extents (hb_font_t *font, hb_codepoint_t glyph, hb_glyph_extents_t *extents) const
407{
408#ifdef HB_NO_OT_FONT_CFF
409 /* XXX Remove check when this code moves to .hh file. */
410 return true;
411#endif
412
413 bounds_t bounds;
414
415 if (!_get_bounds (this, glyph, bounds))
416 return false;
417
418 if (bounds.min.x >= bounds.max.x)
419 {
420 extents->width = 0;
421 extents->x_bearing = 0;
422 }
423 else
424 {
425 extents->x_bearing = roundf (bounds.min.x.to_real ());
426 extents->width = roundf (bounds.max.x.to_real () - extents->x_bearing);
427 }
428 if (bounds.min.y >= bounds.max.y)
429 {
430 extents->height = 0;
431 extents->y_bearing = 0;
432 }
433 else
434 {
435 extents->y_bearing = roundf (bounds.max.y.to_real ());
436 extents->height = roundf (bounds.min.y.to_real () - extents->y_bearing);
437 }
438
439 font->scale_glyph_extents (extents);
440
441 return true;
442}
443
444struct cff1_path_param_t
445{
446 cff1_path_param_t (const OT::cff1::accelerator_t *cff_, hb_font_t *font_,
447 hb_draw_session_t &draw_session_, point_t *delta_)
448 {
449 draw_session = &draw_session_;
450 cff = cff_;
451 font = font_;
452 delta = delta_;
453 }
454
455 void move_to (const point_t &p)
456 {
457 point_t point = p;
458 if (delta) point.move (*delta);
459 draw_session->move_to (font->em_fscalef_x (point.x.to_real ()), font->em_fscalef_y (point.y.to_real ()));
460 }
461
462 void line_to (const point_t &p)
463 {
464 point_t point = p;
465 if (delta) point.move (*delta);
466 draw_session->line_to (font->em_fscalef_x (point.x.to_real ()), font->em_fscalef_y (point.y.to_real ()));
467 }
468
469 void cubic_to (const point_t &p1, const point_t &p2, const point_t &p3)
470 {
471 point_t point1 = p1, point2 = p2, point3 = p3;
472 if (delta)
473 {
474 point1.move (*delta);
475 point2.move (*delta);
476 point3.move (*delta);
477 }
478 draw_session->cubic_to (font->em_fscalef_x (point1.x.to_real ()), font->em_fscalef_y (point1.y.to_real ()),
479 font->em_fscalef_x (point2.x.to_real ()), font->em_fscalef_y (point2.y.to_real ()),
480 font->em_fscalef_x (point3.x.to_real ()), font->em_fscalef_y (point3.y.to_real ()));
481 }
482
483 void end_path () { draw_session->close_path (); }
484
485 hb_font_t *font;
486 hb_draw_session_t *draw_session;
487 point_t *delta;
488
489 const OT::cff1::accelerator_t *cff;
490};
491
492struct cff1_path_procs_path_t : path_procs_t<cff1_path_procs_path_t, cff1_cs_interp_env_t, cff1_path_param_t>
493{
494 static void moveto (cff1_cs_interp_env_t &env, cff1_path_param_t& param, const point_t &pt)
495 {
496 param.move_to (pt);
497 env.moveto (pt);
498 }
499
500 static void line (cff1_cs_interp_env_t &env, cff1_path_param_t &param, const point_t &pt1)
501 {
502 param.line_to (pt1);
503 env.moveto (pt1);
504 }
505
506 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)
507 {
508 param.cubic_to (pt1, pt2, pt3);
509 env.moveto (pt3);
510 }
511};
512
513static bool _get_path (const OT::cff1::accelerator_t *cff, hb_font_t *font, hb_codepoint_t glyph,
514 hb_draw_session_t &draw_session, bool in_seac = false, point_t *delta = nullptr);
515
516struct cff1_cs_opset_path_t : cff1_cs_opset_t<cff1_cs_opset_path_t, cff1_path_param_t, cff1_path_procs_path_t>
517{
518 static void process_seac (cff1_cs_interp_env_t &env, cff1_path_param_t& param)
519 {
520 /* End previous path */
521 param.end_path ();
522
523 unsigned int n = env.argStack.get_count ();
524 point_t delta;
525 delta.x = env.argStack[n-4];
526 delta.y = env.argStack[n-3];
527 hb_codepoint_t base = param.cff->std_code_to_glyph (env.argStack[n-2].to_int ());
528 hb_codepoint_t accent = param.cff->std_code_to_glyph (env.argStack[n-1].to_int ());
529
530 if (unlikely (!(!env.in_seac && base && accent
531 && _get_path (param.cff, param.font, base, *param.draw_session, true)
532 && _get_path (param.cff, param.font, accent, *param.draw_session, true, &delta))))
533 env.set_error ();
534 }
535};
536
537bool _get_path (const OT::cff1::accelerator_t *cff, hb_font_t *font, hb_codepoint_t glyph,
538 hb_draw_session_t &draw_session, bool in_seac, point_t *delta)
539{
540 if (unlikely (!cff->is_valid () || (glyph >= cff->num_glyphs))) return false;
541
542 unsigned int fd = cff->fdSelect->get_fd (glyph);
543 const hb_ubytes_t str = (*cff->charStrings)[glyph];
544 cff1_cs_interp_env_t env (str, *cff, fd);
545 env.set_in_seac (in_seac);
546 cff1_cs_interpreter_t<cff1_cs_opset_path_t, cff1_path_param_t> interp (env);
547 cff1_path_param_t param (cff, font, draw_session, delta);
548 if (unlikely (!interp.interpret (param))) return false;
549
550 /* Let's end the path specially since it is called inside seac also */
551 param.end_path ();
552
553 return true;
554}
555
556bool OT::cff1::accelerator_t::paint_glyph (hb_font_t *font, hb_codepoint_t glyph, hb_paint_funcs_t *funcs, void *data, hb_color_t foreground) const
557{
558 funcs->push_clip_glyph (data, glyph, font);
559 funcs->color (data, true, foreground);
560 funcs->pop_clip (data);
561
562 return true;
563}
564
565bool OT::cff1::accelerator_t::get_path (hb_font_t *font, hb_codepoint_t glyph, hb_draw_session_t &draw_session) const
566{
567#ifdef HB_NO_OT_FONT_CFF
568 /* XXX Remove check when this code moves to .hh file. */
569 return true;
570#endif
571
572 return _get_path (this, font, glyph, draw_session);
573}
574
575struct get_seac_param_t
576{
577 get_seac_param_t (const OT::cff1::accelerator_subset_t *_cff) : cff (_cff) {}
578
579 bool has_seac () const { return base && accent; }
580
581 const OT::cff1::accelerator_subset_t *cff;
582 hb_codepoint_t base = 0;
583 hb_codepoint_t accent = 0;
584};
585
586struct cff1_cs_opset_seac_t : cff1_cs_opset_t<cff1_cs_opset_seac_t, get_seac_param_t>
587{
588 static void process_seac (cff1_cs_interp_env_t &env, get_seac_param_t& param)
589 {
590 unsigned int n = env.argStack.get_count ();
591 hb_codepoint_t base_char = (hb_codepoint_t)env.argStack[n-2].to_int ();
592 hb_codepoint_t accent_char = (hb_codepoint_t)env.argStack[n-1].to_int ();
593
594 param.base = param.cff->std_code_to_glyph (base_char);
595 param.accent = param.cff->std_code_to_glyph (accent_char);
596 }
597};
598
599bool OT::cff1::accelerator_subset_t::get_seac_components (hb_codepoint_t glyph, hb_codepoint_t *base, hb_codepoint_t *accent) const
600{
601 if (unlikely (!is_valid () || (glyph >= num_glyphs))) return false;
602
603 unsigned int fd = fdSelect->get_fd (glyph);
604 const hb_ubytes_t str = (*charStrings)[glyph];
605 cff1_cs_interp_env_t env (str, *this, fd);
606 cff1_cs_interpreter_t<cff1_cs_opset_seac_t, get_seac_param_t> interp (env);
607 get_seac_param_t param (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