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
36 using namespace CFF;
37
38 struct sid_to_gid_t
39 {
40 uint16_t sid;
41 uint8_t gid;
42
cmpsid_to_gid_t43 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 */
51 static 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 */
66 static 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 */
95 static 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 */
111 static 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 */
122 static 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 */
169 static 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 */
196 static 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
lookup_standard_encoding_for_code(hb_codepoint_t sid)216 hb_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
lookup_expert_encoding_for_code(hb_codepoint_t sid)224 hb_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
lookup_expert_charset_for_sid(hb_codepoint_t glyph)232 hb_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
lookup_expert_subset_charset_for_sid(hb_codepoint_t glyph)240 hb_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
lookup_expert_charset_for_glyph(hb_codepoint_t sid)248 hb_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
lookup_expert_subset_charset_for_glyph(hb_codepoint_t sid)254 hb_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
lookup_standard_encoding_for_sid(hb_codepoint_t code)260 hb_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
268 struct bounds_t
269 {
initbounds_t270 void init ()
271 {
272 min.set_int (INT_MAX, INT_MAX);
273 max.set_int (INT_MIN, INT_MIN);
274 }
275
updatebounds_t276 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
mergebounds_t284 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
offsetbounds_t297 void offset (const point_t &delta)
298 {
299 if (!empty ())
300 {
301 min.move (delta);
302 max.move (delta);
303 }
304 }
305
emptybounds_t306 bool empty () const { return (min.x >= max.x) || (min.y >= max.y); }
307
308 point_t min;
309 point_t max;
310 };
311
312 struct cff1_extents_param_t
313 {
initcff1_extents_param_t314 void init (const OT::cff1::accelerator_t *_cff)
315 {
316 path_open = false;
317 cff = _cff;
318 bounds.init ();
319 }
320
start_pathcff1_extents_param_t321 void start_path () { path_open = true; }
end_pathcff1_extents_param_t322 void end_path () { path_open = false; }
is_path_opencff1_extents_param_t323 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
331 struct cff1_path_procs_extents_t : path_procs_t<cff1_path_procs_extents_t, cff1_cs_interp_env_t, cff1_extents_param_t>
332 {
movetocff1_path_procs_extents_t333 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
linecff1_path_procs_extents_t339 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
curvecff1_path_procs_extents_t350 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
365 static bool _get_bounds (const OT::cff1::accelerator_t *cff, hb_codepoint_t glyph, bounds_t &bounds, bool in_seac=false);
366
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>
368 {
process_seaccff1_cs_opset_extents_t369 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
_get_bounds(const OT::cff1::accelerator_t * cff,hb_codepoint_t glyph,bounds_t & bounds,bool in_seac)392 bool _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
get_extents(hb_font_t * font,hb_codepoint_t glyph,hb_glyph_extents_t * extents) const409 bool 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 ()) - extents->x_bearing;
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 ()) - extents->y_bearing;
440 }
441
442 return true;
443 }
444
445 #ifdef HB_EXPERIMENTAL_API
446 struct cff1_path_param_t
447 {
cff1_path_param_tcff1_path_param_t448 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
move_tocff1_path_param_t457 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
line_tocff1_path_param_t464 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
cubic_tocff1_path_param_t471 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
end_pathcff1_path_param_t485 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
494 struct cff1_path_procs_path_t : path_procs_t<cff1_path_procs_path_t, cff1_cs_interp_env_t, cff1_path_param_t>
495 {
movetocff1_path_procs_path_t496 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
linecff1_path_procs_path_t502 static void line (cff1_cs_interp_env_t &env, cff1_path_param_t ¶m, const point_t &pt1)
503 {
504 param.line_to (pt1);
505 env.moveto (pt1);
506 }
507
curvecff1_path_procs_path_t508 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)
509 {
510 param.cubic_to (pt1, pt2, pt3);
511 env.moveto (pt3);
512 }
513 };
514
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);
517
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>
519 {
process_seaccff1_cs_opset_path_t520 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
_get_path(const OT::cff1::accelerator_t * cff,hb_font_t * font,hb_codepoint_t glyph,draw_helper_t & draw_helper,bool in_seac,point_t * 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)
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
get_path(hb_font_t * font,hb_codepoint_t glyph,draw_helper_t & draw_helper) const558 bool 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
569 struct get_seac_param_t
570 {
initget_seac_param_t571 void init (const OT::cff1::accelerator_t *_cff)
572 {
573 cff = _cff;
574 base = 0;
575 accent = 0;
576 }
577
has_seacget_seac_param_t578 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
585 struct cff1_cs_opset_seac_t : cff1_cs_opset_t<cff1_cs_opset_seac_t, get_seac_param_t>
586 {
process_seaccff1_cs_opset_seac_t587 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
get_seac_components(hb_codepoint_t glyph,hb_codepoint_t * base,hb_codepoint_t * accent) const598 bool 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