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 {
cff1_extents_param_tcff1_extents_param_t314 cff1_extents_param_t (const OT::cff1::accelerator_t *_cff) : cff (_cff)
315 {
316 bounds.init ();
317 }
318
start_pathcff1_extents_param_t319 void start_path () { path_open = true; }
end_pathcff1_extents_param_t320 void end_path () { path_open = false; }
is_path_opencff1_extents_param_t321 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
329 struct cff1_path_procs_extents_t : path_procs_t<cff1_path_procs_extents_t, cff1_cs_interp_env_t, cff1_extents_param_t>
330 {
movetocff1_path_procs_extents_t331 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
linecff1_path_procs_extents_t337 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
curvecff1_path_procs_extents_t348 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
363 static bool _get_bounds (const OT::cff1::accelerator_t *cff, hb_codepoint_t glyph, bounds_t &bounds, bool in_seac=false);
364
365 struct cff1_cs_opset_extents_t : cff1_cs_opset_t<cff1_cs_opset_extents_t, cff1_extents_param_t, cff1_path_procs_extents_t>
366 {
process_seaccff1_cs_opset_extents_t367 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
_get_bounds(const OT::cff1::accelerator_t * cff,hb_codepoint_t glyph,bounds_t & bounds,bool in_seac)390 bool _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
get_extents(hb_font_t * font,hb_codepoint_t glyph,hb_glyph_extents_t * extents) const406 bool 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 = font->em_scalef_x (bounds.min.x.to_real ());
426 extents->width = font->em_scalef_x (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 = font->em_scalef_y (bounds.max.y.to_real ());
436 extents->height = font->em_scalef_y (bounds.min.y.to_real ()) - extents->y_bearing;
437 }
438
439 return true;
440 }
441
442 struct cff1_path_param_t
443 {
cff1_path_param_tcff1_path_param_t444 cff1_path_param_t (const OT::cff1::accelerator_t *cff_, hb_font_t *font_,
445 hb_draw_session_t &draw_session_, point_t *delta_)
446 {
447 draw_session = &draw_session_;
448 cff = cff_;
449 font = font_;
450 delta = delta_;
451 }
452
move_tocff1_path_param_t453 void move_to (const point_t &p)
454 {
455 point_t point = p;
456 if (delta) point.move (*delta);
457 draw_session->move_to (font->em_fscalef_x (point.x.to_real ()), font->em_fscalef_y (point.y.to_real ()));
458 }
459
line_tocff1_path_param_t460 void line_to (const point_t &p)
461 {
462 point_t point = p;
463 if (delta) point.move (*delta);
464 draw_session->line_to (font->em_fscalef_x (point.x.to_real ()), font->em_fscalef_y (point.y.to_real ()));
465 }
466
cubic_tocff1_path_param_t467 void cubic_to (const point_t &p1, const point_t &p2, const point_t &p3)
468 {
469 point_t point1 = p1, point2 = p2, point3 = p3;
470 if (delta)
471 {
472 point1.move (*delta);
473 point2.move (*delta);
474 point3.move (*delta);
475 }
476 draw_session->cubic_to (font->em_fscalef_x (point1.x.to_real ()), font->em_fscalef_y (point1.y.to_real ()),
477 font->em_fscalef_x (point2.x.to_real ()), font->em_fscalef_y (point2.y.to_real ()),
478 font->em_fscalef_x (point3.x.to_real ()), font->em_fscalef_y (point3.y.to_real ()));
479 }
480
end_pathcff1_path_param_t481 void end_path () { draw_session->close_path (); }
482
483 hb_font_t *font;
484 hb_draw_session_t *draw_session;
485 point_t *delta;
486
487 const OT::cff1::accelerator_t *cff;
488 };
489
490 struct cff1_path_procs_path_t : path_procs_t<cff1_path_procs_path_t, cff1_cs_interp_env_t, cff1_path_param_t>
491 {
movetocff1_path_procs_path_t492 static void moveto (cff1_cs_interp_env_t &env, cff1_path_param_t& param, const point_t &pt)
493 {
494 param.move_to (pt);
495 env.moveto (pt);
496 }
497
linecff1_path_procs_path_t498 static void line (cff1_cs_interp_env_t &env, cff1_path_param_t ¶m, const point_t &pt1)
499 {
500 param.line_to (pt1);
501 env.moveto (pt1);
502 }
503
curvecff1_path_procs_path_t504 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)
505 {
506 param.cubic_to (pt1, pt2, pt3);
507 env.moveto (pt3);
508 }
509 };
510
511 static bool _get_path (const OT::cff1::accelerator_t *cff, hb_font_t *font, hb_codepoint_t glyph,
512 hb_draw_session_t &draw_session, bool in_seac = false, point_t *delta = nullptr);
513
514 struct cff1_cs_opset_path_t : cff1_cs_opset_t<cff1_cs_opset_path_t, cff1_path_param_t, cff1_path_procs_path_t>
515 {
process_seaccff1_cs_opset_path_t516 static void process_seac (cff1_cs_interp_env_t &env, cff1_path_param_t& param)
517 {
518 /* End previous path */
519 param.end_path ();
520
521 unsigned int n = env.argStack.get_count ();
522 point_t delta;
523 delta.x = env.argStack[n-4];
524 delta.y = env.argStack[n-3];
525 hb_codepoint_t base = param.cff->std_code_to_glyph (env.argStack[n-2].to_int ());
526 hb_codepoint_t accent = param.cff->std_code_to_glyph (env.argStack[n-1].to_int ());
527
528 if (unlikely (!(!env.in_seac && base && accent
529 && _get_path (param.cff, param.font, base, *param.draw_session, true)
530 && _get_path (param.cff, param.font, accent, *param.draw_session, true, &delta))))
531 env.set_error ();
532 }
533 };
534
_get_path(const OT::cff1::accelerator_t * cff,hb_font_t * font,hb_codepoint_t glyph,hb_draw_session_t & draw_session,bool in_seac,point_t * delta)535 bool _get_path (const OT::cff1::accelerator_t *cff, hb_font_t *font, hb_codepoint_t glyph,
536 hb_draw_session_t &draw_session, bool in_seac, point_t *delta)
537 {
538 if (unlikely (!cff->is_valid () || (glyph >= cff->num_glyphs))) return false;
539
540 unsigned int fd = cff->fdSelect->get_fd (glyph);
541 const hb_ubytes_t str = (*cff->charStrings)[glyph];
542 cff1_cs_interp_env_t env (str, *cff, fd);
543 env.set_in_seac (in_seac);
544 cff1_cs_interpreter_t<cff1_cs_opset_path_t, cff1_path_param_t> interp (env);
545 cff1_path_param_t param (cff, font, draw_session, delta);
546 if (unlikely (!interp.interpret (param))) return false;
547
548 /* Let's end the path specially since it is called inside seac also */
549 param.end_path ();
550
551 return true;
552 }
553
get_path(hb_font_t * font,hb_codepoint_t glyph,hb_draw_session_t & draw_session) const554 bool OT::cff1::accelerator_t::get_path (hb_font_t *font, hb_codepoint_t glyph, hb_draw_session_t &draw_session) const
555 {
556 #ifdef HB_NO_OT_FONT_CFF
557 /* XXX Remove check when this code moves to .hh file. */
558 return true;
559 #endif
560
561 return _get_path (this, font, glyph, draw_session);
562 }
563
564 struct get_seac_param_t
565 {
get_seac_param_tget_seac_param_t566 get_seac_param_t (const OT::cff1::accelerator_t *_cff) : cff (_cff) {}
567
has_seacget_seac_param_t568 bool has_seac () const { return base && accent; }
569
570 const OT::cff1::accelerator_t *cff;
571 hb_codepoint_t base = 0;
572 hb_codepoint_t accent = 0;
573 };
574
575 struct cff1_cs_opset_seac_t : cff1_cs_opset_t<cff1_cs_opset_seac_t, get_seac_param_t>
576 {
process_seaccff1_cs_opset_seac_t577 static void process_seac (cff1_cs_interp_env_t &env, get_seac_param_t& param)
578 {
579 unsigned int n = env.argStack.get_count ();
580 hb_codepoint_t base_char = (hb_codepoint_t)env.argStack[n-2].to_int ();
581 hb_codepoint_t accent_char = (hb_codepoint_t)env.argStack[n-1].to_int ();
582
583 param.base = param.cff->std_code_to_glyph (base_char);
584 param.accent = param.cff->std_code_to_glyph (accent_char);
585 }
586 };
587
get_seac_components(hb_codepoint_t glyph,hb_codepoint_t * base,hb_codepoint_t * accent) const588 bool OT::cff1::accelerator_t::get_seac_components (hb_codepoint_t glyph, hb_codepoint_t *base, hb_codepoint_t *accent) const
589 {
590 if (unlikely (!is_valid () || (glyph >= num_glyphs))) return false;
591
592 unsigned int fd = fdSelect->get_fd (glyph);
593 const hb_ubytes_t str = (*charStrings)[glyph];
594 cff1_cs_interp_env_t env (str, *this, fd);
595 cff1_cs_interpreter_t<cff1_cs_opset_seac_t, get_seac_param_t> interp (env);
596 get_seac_param_t param (this);
597 if (unlikely (!interp.interpret (param))) return false;
598
599 if (param.has_seac ())
600 {
601 *base = param.base;
602 *accent = param.accent;
603 return true;
604 }
605 return false;
606 }
607
608
609 #endif
610