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-ot-cff1-table.hh"
28 #include "hb-cff1-interp-cs.hh"
29
30 using namespace CFF;
31
32 /* SID to code */
33 static const uint8_t standard_encoding_to_code [] =
34 {
35 0, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46,
36 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62,
37 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78,
38 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94,
39 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110,
40 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126,
41 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 177,
42 178, 179, 180, 182, 183, 184, 185, 186, 187, 188, 189, 191, 193, 194, 195, 196,
43 197, 198, 199, 200, 202, 203, 205, 206, 207, 208, 225, 227, 232, 233, 234, 235,
44 241, 245, 248, 249, 250, 251
45 };
46
47 /* SID to code */
48 static const uint8_t expert_encoding_to_code [] =
49 {
50 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 44, 45, 46,
51 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 58, 59, 0, 0, 0,
52 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
53 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
54 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
55 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
56 0, 0, 0, 47, 0, 0, 0, 0, 0, 0, 0, 0, 0, 87, 88, 0,
57 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
58 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
59 0, 0, 0, 0, 0, 0, 201, 0, 0, 0, 0, 189, 0, 0, 188, 0,
60 0, 0, 0, 190, 202, 0, 0, 0, 0, 203, 0, 0, 0, 0, 0, 0,
61 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
62 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
63 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
64 0, 0, 0, 0, 0, 33, 34, 36, 37, 38, 39, 40, 41, 42, 43, 48,
65 49, 50, 51, 52, 53, 54, 55, 56, 57, 60, 61, 62, 63, 65, 66, 67,
66 68, 69, 73, 76, 77, 78, 79, 82, 83, 84, 86, 89, 90, 91, 93, 94,
67 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110,
68 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126,
69 161, 162, 163, 166, 167, 168, 169, 170, 172, 175, 178, 179, 182, 183, 184, 191,
70 192, 193, 194, 195, 196, 197, 200, 204, 205, 206, 207, 208, 209, 210, 211, 212,
71 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228,
72 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244,
73 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255
74 };
75
76 /* glyph ID to SID */
77 static const uint16_t expert_charset_to_sid [] =
78 {
79 0, 1, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 13, 14, 15, 99,
80 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 27, 28, 249, 250, 251, 252,
81 253, 254, 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 109, 110,
82 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, 280, 281, 282,
83 283, 284, 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 298,
84 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314,
85 315, 316, 317, 318, 158, 155, 163, 319, 320, 321, 322, 323, 324, 325, 326, 150,
86 164, 169, 327, 328, 329, 330, 331, 332, 333, 334, 335, 336, 337, 338, 339, 340,
87 341, 342, 343, 344, 345, 346, 347, 348, 349, 350, 351, 352, 353, 354, 355, 356,
88 357, 358, 359, 360, 361, 362, 363, 364, 365, 366, 367, 368, 369, 370, 371, 372,
89 373, 374, 375, 376, 377, 378
90 };
91
92 /* glyph ID to SID */
93 static const uint16_t expert_subset_charset_to_sid [] =
94 {
95 0, 1, 231, 232, 235, 236, 237, 238, 13, 14, 15, 99, 239, 240, 241, 242,
96 243, 244, 245, 246, 247, 248, 27, 28, 249, 250, 251, 253, 254, 255, 256, 257,
97 258, 259, 260, 261, 262, 263, 264, 265, 266, 109, 110, 267, 268, 269, 270, 272,
98 300, 301, 302, 305, 314, 315, 158, 155, 163, 320, 321, 322, 323, 324, 325, 326,
99 150, 164, 169, 327, 328, 329, 330, 331, 332, 333, 334, 335, 336, 337, 338, 339,
100 340, 341, 342, 343, 344, 345, 346
101 };
102
103 /* code to SID */
104 static const uint8_t standard_encoding_to_sid [] =
105 {
106 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
107 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
108 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
109 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32,
110 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
111 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64,
112 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80,
113 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 0,
114 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
115 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
116 0, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110,
117 0, 111, 112, 113, 114, 0, 115, 116, 117, 118, 119, 120, 121, 122, 0, 123,
118 0, 124, 125, 126, 127, 128, 129, 130, 131, 0, 132, 133, 0, 134, 135, 136,
119 137, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
120 0, 138, 0, 139, 0, 0, 0, 0, 140, 141, 142, 143, 0, 0, 0, 0,
121 0, 144, 0, 0, 0, 145, 0, 0, 146, 147, 148, 149, 0, 0, 0, 0
122 };
123
lookup_standard_encoding_for_code(hb_codepoint_t sid)124 hb_codepoint_t OT::cff1::lookup_standard_encoding_for_code (hb_codepoint_t sid)
125 {
126 if (sid < ARRAY_LENGTH (standard_encoding_to_code))
127 return (hb_codepoint_t)standard_encoding_to_code[sid];
128 else
129 return 0;
130 }
131
lookup_expert_encoding_for_code(hb_codepoint_t sid)132 hb_codepoint_t OT::cff1::lookup_expert_encoding_for_code (hb_codepoint_t sid)
133 {
134 if (sid < ARRAY_LENGTH (expert_encoding_to_code))
135 return (hb_codepoint_t)expert_encoding_to_code[sid];
136 else
137 return 0;
138 }
139
lookup_expert_charset_for_sid(hb_codepoint_t glyph)140 hb_codepoint_t OT::cff1::lookup_expert_charset_for_sid (hb_codepoint_t glyph)
141 {
142 if (glyph < ARRAY_LENGTH (expert_charset_to_sid))
143 return (hb_codepoint_t)expert_charset_to_sid[glyph];
144 else
145 return 0;
146 }
147
lookup_expert_subset_charset_for_sid(hb_codepoint_t glyph)148 hb_codepoint_t OT::cff1::lookup_expert_subset_charset_for_sid (hb_codepoint_t glyph)
149 {
150 if (glyph < ARRAY_LENGTH (expert_subset_charset_to_sid))
151 return (hb_codepoint_t)expert_subset_charset_to_sid[glyph];
152 else
153 return 0;
154 }
155
lookup_standard_encoding_for_sid(hb_codepoint_t code)156 hb_codepoint_t OT::cff1::lookup_standard_encoding_for_sid (hb_codepoint_t code)
157 {
158 if (code < ARRAY_LENGTH (standard_encoding_to_sid))
159 return (hb_codepoint_t)standard_encoding_to_sid[code];
160 else
161 return CFF_UNDEF_SID;
162 }
163
164 struct Bounds
165 {
initBounds166 void init ()
167 {
168 min.set_int (0x7FFFFFFF, 0x7FFFFFFF);
169 max.set_int (-0x80000000, -0x80000000);
170 }
171
updateBounds172 void update (const Point &pt)
173 {
174 if (pt.x < min.x) min.x = pt.x;
175 if (pt.x > max.x) max.x = pt.x;
176 if (pt.y < min.y) min.y = pt.y;
177 if (pt.y > max.y) max.y = pt.y;
178 }
179
mergeBounds180 void merge (const Bounds &b)
181 {
182 if (empty ())
183 *this = b;
184 else if (!b.empty ())
185 {
186 if (b.min.x < min.x) min.x = b.min.x;
187 if (b.max.x > max.x) max.x = b.max.x;
188 if (b.min.y < min.y) min.y = b.min.y;
189 if (b.max.y > max.y) max.y = b.max.y;
190 }
191 }
192
offsetBounds193 void offset (const Point &delta)
194 {
195 if (!empty ())
196 {
197 min.move (delta);
198 max.move (delta);
199 }
200 }
201
emptyBounds202 bool empty () const
203 { return (min.x >= max.x) || (min.y >= max.y); }
204
205 Point min;
206 Point max;
207 };
208
209 struct ExtentsParam
210 {
initExtentsParam211 void init (const OT::cff1::accelerator_t *_cff)
212 {
213 path_open = false;
214 cff = _cff;
215 bounds.init ();
216 }
217
start_pathExtentsParam218 void start_path () { path_open = true; }
end_pathExtentsParam219 void end_path () { path_open = false; }
is_path_openExtentsParam220 bool is_path_open () const { return path_open; }
221
222 bool path_open;
223 Bounds bounds;
224
225 const OT::cff1::accelerator_t *cff;
226 };
227
228 struct CFF1PathProcs_Extents : PathProcs<CFF1PathProcs_Extents, CFF1CSInterpEnv, ExtentsParam>
229 {
movetoCFF1PathProcs_Extents230 static void moveto (CFF1CSInterpEnv &env, ExtentsParam& param, const Point &pt)
231 {
232 param.end_path ();
233 env.moveto (pt);
234 }
235
lineCFF1PathProcs_Extents236 static void line (CFF1CSInterpEnv &env, ExtentsParam& param, const Point &pt1)
237 {
238 if (!param.is_path_open ())
239 {
240 param.start_path ();
241 param.bounds.update (env.get_pt ());
242 }
243 env.moveto (pt1);
244 param.bounds.update (env.get_pt ());
245 }
246
curveCFF1PathProcs_Extents247 static void curve (CFF1CSInterpEnv &env, ExtentsParam& param, const Point &pt1, const Point &pt2, const Point &pt3)
248 {
249 if (!param.is_path_open ())
250 {
251 param.start_path ();
252 param.bounds.update (env.get_pt ());
253 }
254 /* include control points */
255 param.bounds.update (pt1);
256 param.bounds.update (pt2);
257 env.moveto (pt3);
258 param.bounds.update (env.get_pt ());
259 }
260 };
261
262 static bool _get_bounds (const OT::cff1::accelerator_t *cff, hb_codepoint_t glyph, Bounds &bounds, bool in_seac=false);
263
264 struct CFF1CSOpSet_Extents : CFF1CSOpSet<CFF1CSOpSet_Extents, ExtentsParam, CFF1PathProcs_Extents>
265 {
process_seacCFF1CSOpSet_Extents266 static void process_seac (CFF1CSInterpEnv &env, ExtentsParam& param)
267 {
268 unsigned int n = env.argStack.get_count ();
269 Point delta;
270 delta.x = env.argStack[n-4];
271 delta.y = env.argStack[n-3];
272 hb_codepoint_t base = param.cff->std_code_to_glyph (env.argStack[n-2].to_int ());
273 hb_codepoint_t accent = param.cff->std_code_to_glyph (env.argStack[n-1].to_int ());
274
275 Bounds base_bounds, accent_bounds;
276 if (likely (!env.in_seac && base && accent
277 && _get_bounds (param.cff, base, base_bounds, true)
278 && _get_bounds (param.cff, accent, accent_bounds, true)))
279 {
280 param.bounds.merge (base_bounds);
281 accent_bounds.offset (delta);
282 param.bounds.merge (accent_bounds);
283 }
284 else
285 env.set_error ();
286 }
287 };
288
_get_bounds(const OT::cff1::accelerator_t * cff,hb_codepoint_t glyph,Bounds & bounds,bool in_seac)289 bool _get_bounds (const OT::cff1::accelerator_t *cff, hb_codepoint_t glyph, Bounds &bounds, bool in_seac)
290 {
291 bounds.init ();
292 if (unlikely (!cff->is_valid () || (glyph >= cff->num_glyphs))) return false;
293
294 unsigned int fd = cff->fdSelect->get_fd (glyph);
295 CFF1CSInterpreter<CFF1CSOpSet_Extents, ExtentsParam> interp;
296 const ByteStr str = (*cff->charStrings)[glyph];
297 interp.env.init (str, *cff, fd);
298 interp.env.set_in_seac (in_seac);
299 ExtentsParam param;
300 param.init (cff);
301 if (unlikely (!interp.interpret (param))) return false;
302 bounds = param.bounds;
303 return true;
304 }
305
get_extents(hb_codepoint_t glyph,hb_glyph_extents_t * extents) const306 bool OT::cff1::accelerator_t::get_extents (hb_codepoint_t glyph, hb_glyph_extents_t *extents) const
307 {
308 Bounds bounds;
309
310 if (!_get_bounds (this, glyph, bounds))
311 return false;
312
313 if (bounds.min.x >= bounds.max.x)
314 {
315 extents->width = 0;
316 extents->x_bearing = 0;
317 }
318 else
319 {
320 extents->x_bearing = (int32_t)bounds.min.x.floor ();
321 extents->width = (int32_t)bounds.max.x.ceil () - extents->x_bearing;
322 }
323 if (bounds.min.y >= bounds.max.y)
324 {
325 extents->height = 0;
326 extents->y_bearing = 0;
327 }
328 else
329 {
330 extents->y_bearing = (int32_t)bounds.max.y.ceil ();
331 extents->height = (int32_t)bounds.min.y.floor () - extents->y_bearing;
332 }
333
334 return true;
335 }
336
337 struct GetSeacParam
338 {
initGetSeacParam339 void init (const OT::cff1::accelerator_t *_cff)
340 {
341 cff = _cff;
342 base = 0;
343 accent = 0;
344 }
345
has_seacGetSeacParam346 bool has_seac () const { return base && accent; }
347
348 const OT::cff1::accelerator_t *cff;
349 hb_codepoint_t base;
350 hb_codepoint_t accent;
351 };
352
353 struct CFF1CSOpSet_Seac : CFF1CSOpSet<CFF1CSOpSet_Seac, GetSeacParam>
354 {
process_seacCFF1CSOpSet_Seac355 static void process_seac (CFF1CSInterpEnv &env, GetSeacParam& param)
356 {
357 unsigned int n = env.argStack.get_count ();
358 hb_codepoint_t base_char = (hb_codepoint_t)env.argStack[n-2].to_int ();
359 hb_codepoint_t accent_char = (hb_codepoint_t)env.argStack[n-1].to_int ();
360
361 param.base = param.cff->std_code_to_glyph (base_char);
362 param.accent = param.cff->std_code_to_glyph (accent_char);
363 }
364 };
365
get_seac_components(hb_codepoint_t glyph,hb_codepoint_t * base,hb_codepoint_t * accent) const366 bool OT::cff1::accelerator_t::get_seac_components (hb_codepoint_t glyph, hb_codepoint_t *base, hb_codepoint_t *accent) const
367 {
368 if (unlikely (!is_valid () || (glyph >= num_glyphs))) return false;
369
370 unsigned int fd = fdSelect->get_fd (glyph);
371 CFF1CSInterpreter<CFF1CSOpSet_Seac, GetSeacParam> interp;
372 const ByteStr str = (*charStrings)[glyph];
373 interp.env.init (str, *this, fd);
374 GetSeacParam param;
375 param.init (this);
376 if (unlikely (!interp.interpret (param))) return false;
377
378 if (param.has_seac ())
379 {
380 *base = param.base;
381 *accent = param.accent;
382 return true;
383 }
384 return false;
385 }
386