blob: c637be6774f7e9dc00be7d4e569ec97954cfd45c [file] [log] [blame]
Michiharu Ariza64c54122018-08-10 11:07:07 -07001/*
2 * Copyright © 2018 Adobe Systems Incorporated.
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
Michiharu Ariza8af96902018-08-29 13:26:17 -070027#include "hb-open-type.hh"
Michiharu Arizafdbfa182018-08-16 00:13:09 -070028#include "hb-ot-cff1-table.hh"
Michiharu Ariza64c54122018-08-10 11:07:07 -070029#include "hb-set.h"
Michiharu Arizafdbfa182018-08-16 00:13:09 -070030#include "hb-subset-cff1.hh"
Michiharu Ariza64c54122018-08-10 11:07:07 -070031#include "hb-subset-plan.hh"
Michiharu Ariza8af96902018-08-29 13:26:17 -070032#include "hb-subset-cff-common.hh"
Michiharu Arizafdbfa182018-08-16 00:13:09 -070033#include "hb-cff1-interp-cs.hh"
Michiharu Ariza64c54122018-08-10 11:07:07 -070034
35using namespace CFF;
36
Michiharu Ariza9fd08cc2018-08-29 18:18:18 -070037struct CFF1SubTableOffsets : CFFSubTableOffsets
38{
Michiharu Arizafdbfa182018-08-16 00:13:09 -070039 inline CFF1SubTableOffsets (void)
Michiharu Ariza9fd08cc2018-08-29 18:18:18 -070040 : CFFSubTableOffsets (),
41 nameIndexOffset (0),
42 stringIndexOffset (0),
43 encodingOffset (0),
44 charsetOffset (0)
Michiharu Ariza64c54122018-08-10 11:07:07 -070045 {
Michiharu Ariza9fd08cc2018-08-29 18:18:18 -070046 privateDictInfo.init ();
Michiharu Ariza64c54122018-08-10 11:07:07 -070047 }
48
49 unsigned int nameIndexOffset;
Michiharu Ariza64c54122018-08-10 11:07:07 -070050 unsigned int stringIndexOffset;
Michiharu Ariza64c54122018-08-10 11:07:07 -070051 unsigned int encodingOffset;
52 unsigned int charsetOffset;
Michiharu Ariza64c54122018-08-10 11:07:07 -070053 TableInfo privateDictInfo;
54};
55
Michiharu Ariza9fd08cc2018-08-29 18:18:18 -070056struct CFF1TopDict_OpSerializer : CFFTopDict_OpSerializer
Michiharu Ariza64c54122018-08-10 11:07:07 -070057{
58 inline bool serialize (hb_serialize_context_t *c,
59 const OpStr &opstr,
Michiharu Arizafdbfa182018-08-16 00:13:09 -070060 const CFF1SubTableOffsets &offsets) const
Michiharu Ariza64c54122018-08-10 11:07:07 -070061 {
62 TRACE_SERIALIZE (this);
63
64 switch (opstr.op)
65 {
66 case OpCode_charset:
67 return_trace (FontDict::serialize_offset4_op(c, opstr.op, offsets.charsetOffset));
68
69 case OpCode_Encoding:
70 return_trace (FontDict::serialize_offset4_op(c, opstr.op, offsets.encodingOffset));
71
Michiharu Ariza64c54122018-08-10 11:07:07 -070072 case OpCode_Private:
73 {
74 if (unlikely (!UnsizedByteStr::serialize_int2 (c, offsets.privateDictInfo.size)))
75 return_trace (false);
76 if (unlikely (!UnsizedByteStr::serialize_int4 (c, offsets.privateDictInfo.offset)))
77 return_trace (false);
78 HBUINT8 *p = c->allocate_size<HBUINT8> (1);
79 if (unlikely (p == nullptr)) return_trace (false);
80 p->set (OpCode_Private);
81 }
82 break;
83
84 default:
Michiharu Ariza9fd08cc2018-08-29 18:18:18 -070085 return_trace (CFFTopDict_OpSerializer::serialize (c, opstr, offsets));
Michiharu Ariza64c54122018-08-10 11:07:07 -070086 }
87 return_trace (true);
88 }
89
90 inline unsigned int calculate_serialized_size (const OpStr &opstr) const
91 {
92 switch (opstr.op)
93 {
94 case OpCode_charset:
95 case OpCode_Encoding:
Michiharu Ariza633ce882018-08-15 12:00:19 -070096 return OpCode_Size (OpCode_longintdict) + 4 + OpCode_Size (opstr.op);
Michiharu Ariza64c54122018-08-10 11:07:07 -070097
98 case OpCode_Private:
Michiharu Ariza633ce882018-08-15 12:00:19 -070099 return OpCode_Size (OpCode_longintdict) + 4 + OpCode_Size (OpCode_shortint) + 2 + OpCode_Size (OpCode_Private);
Michiharu Ariza64c54122018-08-10 11:07:07 -0700100
101 default:
Michiharu Ariza9fd08cc2018-08-29 18:18:18 -0700102 return CFFTopDict_OpSerializer::calculate_serialized_size (opstr);
Michiharu Ariza64c54122018-08-10 11:07:07 -0700103 }
104 }
105};
106
Michiharu Ariza8c5e03b2018-08-30 17:21:56 -0700107struct CFF1CSOpSet_Flatten : CFF1CSOpSet<CFF1CSOpSet_Flatten, FlattenParam>
Michiharu Ariza5cde2f52018-08-17 16:50:13 -0700108{
Michiharu Ariza968168b2018-08-31 13:28:16 -0700109 static inline void flush_args_and_op (OpCode op, CFF1CSInterpEnv &env, FlattenParam& param)
Michiharu Ariza5cde2f52018-08-17 16:50:13 -0700110 {
Michiharu Arizaa11420b2018-08-29 12:14:30 -0700111 switch (op)
112 {
Michiharu Ariza968168b2018-08-31 13:28:16 -0700113 case OpCode_hstem:
114 case OpCode_hstemhm:
115 case OpCode_vstem:
116 case OpCode_vstemhm:
Michiharu Arizaa11420b2018-08-29 12:14:30 -0700117 case OpCode_hintmask:
118 case OpCode_cntrmask:
Michiharu Ariza968168b2018-08-31 13:28:16 -0700119 case OpCode_hflex:
120 case OpCode_flex:
121 case OpCode_hflex1:
122 case OpCode_flex1:
Michiharu Ariza8c5e03b2018-08-30 17:21:56 -0700123 if (param.drop_hints)
124 {
Michiharu Ariza968168b2018-08-31 13:28:16 -0700125 env.clear_args ();
126 return;
Michiharu Ariza8c5e03b2018-08-30 17:21:56 -0700127 }
Michiharu Ariza968168b2018-08-31 13:28:16 -0700128 /* NO BREAK */
129
Michiharu Arizaa11420b2018-08-29 12:14:30 -0700130 default:
Michiharu Ariza968168b2018-08-31 13:28:16 -0700131 SUPER::flush_args_and_op (op, env, param);
132 break;
Michiharu Arizaa11420b2018-08-29 12:14:30 -0700133 }
Michiharu Ariza5cde2f52018-08-17 16:50:13 -0700134 }
135
Michiharu Ariza968168b2018-08-31 13:28:16 -0700136 static inline void flush_n_args (unsigned int n, CFF1CSInterpEnv &env, FlattenParam& param)
Michiharu Ariza5cde2f52018-08-17 16:50:13 -0700137 {
Michiharu Ariza968168b2018-08-31 13:28:16 -0700138 for (unsigned int i = env.argStack.count - n; i < env.argStack.count; i++)
Michiharu Ariza8c5e03b2018-08-30 17:21:56 -0700139 param.flatStr.encode_num (env.argStack.elements[i]);
Michiharu Ariza968168b2018-08-31 13:28:16 -0700140 SUPER::flush_n_args (n, env, param);
141 }
142
143 static inline void flush_op (OpCode op, CFF1CSInterpEnv &env, FlattenParam& param)
144 {
145 param.flatStr.encode_op (op);
146 }
147
148 static inline void flush_hintmask (OpCode op, CFF1CSInterpEnv &env, FlattenParam& param)
149 {
150 SUPER::flush_hintmask (op, env, param);
Michiharu Arizaf2d299b2018-09-04 10:25:21 -0700151 if (!param.drop_hints)
152 for (unsigned int i = 0; i < env.hintmask_size; i++)
153 param.flatStr.encode_byte (env.substr[i]);
Michiharu Ariza5cde2f52018-08-17 16:50:13 -0700154 }
Michiharu Arizaa11420b2018-08-29 12:14:30 -0700155
156 private:
Michiharu Ariza8c5e03b2018-08-30 17:21:56 -0700157 typedef CFF1CSOpSet<CFF1CSOpSet_Flatten, FlattenParam> SUPER;
Michiharu Ariza5cde2f52018-08-17 16:50:13 -0700158};
159
Michiharu Arizaa11420b2018-08-29 12:14:30 -0700160struct CFF1CSOpSet_SubsetSubrs : CFF1CSOpSet<CFF1CSOpSet_SubsetSubrs, SubrRefMapPair>
Michiharu Ariza633ce882018-08-15 12:00:19 -0700161{
Michiharu Arizafdbfa182018-08-16 00:13:09 -0700162 static inline bool process_op (OpCode op, CFF1CSInterpEnv &env, SubrRefMapPair& refMapPair)
Michiharu Ariza633ce882018-08-15 12:00:19 -0700163 {
164 unsigned int subr_num;
165 switch (op) {
166 case OpCode_callsubr:
167 if (!unlikely (env.popSubrNum(env.localSubrs, subr_num)))
168 return false;
169 env.argStack.unpop ();
170 refMapPair.local_map->add (subr_num);
171 break;
172 case OpCode_callgsubr:
173 if (!unlikely (env.popSubrNum(env.globalSubrs, subr_num)))
174 return false;
175 env.argStack.unpop ();
176 refMapPair.global_map->add (subr_num);
177 break;
178 default:
179 break;
180 }
Michiharu Arizaa11420b2018-08-29 12:14:30 -0700181 return CFF1CSOpSet<CFF1CSOpSet_SubsetSubrs, SubrRefMapPair>::process_op (op, env, refMapPair);
Michiharu Ariza633ce882018-08-15 12:00:19 -0700182 }
183};
184
Michiharu Ariza64c54122018-08-10 11:07:07 -0700185struct cff_subset_plan {
186 inline cff_subset_plan (void)
187 : final_size (0),
188 orig_fdcount (0),
Michiharu Arizaaca73c92018-09-06 17:28:15 -0700189 subset_fdcount (1),
190 subset_fdselect_format (0),
Michiharu Arizaa11420b2018-08-29 12:14:30 -0700191 offsets (),
192 flatten_subrs (true),
193 drop_hints (false)
Michiharu Ariza64c54122018-08-10 11:07:07 -0700194 {
195 topdict_sizes.init ();
196 topdict_sizes.resize (1);
Michiharu Arizaaca73c92018-09-06 17:28:15 -0700197 topdict_mod.init ();
198 subset_fdselect_first_glyphs.init ();
Michiharu Ariza64c54122018-08-10 11:07:07 -0700199 fdmap.init ();
200 subset_charstrings.init ();
Michiharu Arizaa11420b2018-08-29 12:14:30 -0700201 flat_charstrings.init ();
Michiharu Ariza64c54122018-08-10 11:07:07 -0700202 privateDictInfos.init ();
Michiharu Arizaa11420b2018-08-29 12:14:30 -0700203 subrRefMaps.init ();
Michiharu Arizaaca73c92018-09-06 17:28:15 -0700204 subset_enc_code_ranges.init ();
205 subset_enc_supp_codes.init ();
206 subset_charset_ranges.init ();
Michiharu Ariza64c54122018-08-10 11:07:07 -0700207 }
208
209 inline ~cff_subset_plan (void)
210 {
211 topdict_sizes.fini ();
Michiharu Arizaaca73c92018-09-06 17:28:15 -0700212 topdict_mod.fini ();
213 subset_fdselect_first_glyphs.fini ();
Michiharu Ariza64c54122018-08-10 11:07:07 -0700214 fdmap.fini ();
215 subset_charstrings.fini ();
Michiharu Arizaa11420b2018-08-29 12:14:30 -0700216 flat_charstrings.fini ();
Michiharu Ariza64c54122018-08-10 11:07:07 -0700217 privateDictInfos.fini ();
Michiharu Ariza633ce882018-08-15 12:00:19 -0700218 subrRefMaps.fini ();
Michiharu Arizaaca73c92018-09-06 17:28:15 -0700219 subset_enc_code_ranges.fini ();
220 subset_enc_supp_codes.init ();
221 subset_charset_ranges.fini ();
222 }
223
224 inline unsigned int plan_subset_encoding (const OT::cff1::accelerator_subset_t &acc, hb_subset_plan_t *plan)
225 {
226 const Encoding *encoding = acc.encoding;
227 unsigned int size0, size1, supp_size;
228 hb_codepoint_t code, last_code = CFF_UNDEF_CODE;
229 hb_vector_t<hb_codepoint_t> supp_codes;
230
231 subset_enc_code_ranges.resize (0);
232 supp_size = 0;
233 supp_codes.init ();
234
235 subset_enc_num_codes = plan->glyphs.len - 1;
236 unsigned int glyph;
237 for (glyph = 1; glyph < plan->glyphs.len; glyph++)
238 {
239 hb_codepoint_t orig_glyph = plan->glyphs[glyph];
240 code = acc.glyph_to_code (orig_glyph);
241 if (code == CFF_UNDEF_CODE)
242 {
243 subset_enc_num_codes = glyph - 1;
244 break;
245 }
246
247 if (code != last_code + 1)
248 {
249 if (subset_enc_code_ranges.len > 0)
250 {
251 code_pair &pair = subset_enc_code_ranges[subset_enc_code_ranges.len - 1];
252 pair.glyph = glyph - pair.glyph - 1;
253 }
254 code_pair pair = { code, glyph };
255 subset_enc_code_ranges.push (pair);
256 }
257 last_code = code;
258
259 if (encoding != &Null(Encoding))
260 {
261 hb_codepoint_t sid = acc.glyph_to_sid (orig_glyph);
262 encoding->get_supplement_codes (sid, supp_codes);
263 for (unsigned int i = 0; i < supp_codes.len; i++)
264 {
265 code_pair pair = { supp_codes[i], sid };
266 subset_enc_supp_codes.push (pair);
267 }
268 supp_size += SuppEncoding::static_size * supp_codes.len;
269 }
270 }
271 supp_codes.fini ();
272 if (subset_enc_code_ranges.len > 0)
273 {
274 code_pair &pair = subset_enc_code_ranges[subset_enc_code_ranges.len - 1];
275 pair.glyph = glyph - pair.glyph - 1;
276 }
277
278 assert (subset_enc_num_codes <= 0xFF);
279 size0 = Encoding0::min_size + HBUINT8::static_size * subset_enc_num_codes;
280 size1 = Encoding1::min_size + Encoding1_Range::static_size * subset_enc_code_ranges.len;
281
282 if (size0 < size1)
283 subset_enc_format = 0;
284 else
285 subset_enc_format = 1;
286
287 return Encoding::calculate_serialized_size (
288 subset_enc_format,
289 subset_enc_format? subset_enc_code_ranges.len: subset_enc_num_codes,
290 subset_enc_supp_codes.len);
291 }
292
293 inline unsigned int plan_subset_charset (const OT::cff1::accelerator_subset_t &acc, hb_subset_plan_t *plan)
294 {
295 const Charset *charset = acc.charset;
296 unsigned int size0, size_ranges;
297 hb_codepoint_t sid, last_sid = CFF_UNDEF_CODE;
298 bool two_byte = false;
299
300 subset_charset_ranges.resize (0);
301 unsigned int glyph;
302 for (glyph = 1; glyph < plan->glyphs.len; glyph++)
303 {
304 hb_codepoint_t orig_glyph = plan->glyphs[glyph];
305 sid = acc.glyph_to_sid (orig_glyph);
306
307 if (sid != last_sid + 1)
308 {
309 if (subset_charset_ranges.len > 0)
310 {
311 code_pair &pair = subset_charset_ranges[subset_charset_ranges.len - 1];
312 pair.glyph = glyph - pair.glyph - 1;
313 if ((pair.glyph & ~0xFF) != 0) two_byte = true;
314 }
315 code_pair pair = { sid, glyph };
316 subset_charset_ranges.push (pair);
317 }
318 last_sid = sid;
319 }
320
321 if (subset_charset_ranges.len > 0)
322 {
323 code_pair &pair = subset_charset_ranges[subset_charset_ranges.len - 1];
324 pair.glyph = glyph - pair.glyph - 1;
325 if ((pair.glyph & ~0xFF) != 0) two_byte = true;
326 }
327
328 size0 = Charset0::min_size + HBUINT16::static_size * (plan->glyphs.len - 1);
329 if (!two_byte)
330 size_ranges = Charset1::min_size + Charset1_Range::static_size * subset_charset_ranges.len;
331 else
332 size_ranges = Charset2::min_size + Charset2_Range::static_size * subset_charset_ranges.len;
333
334 if (size0 < size_ranges)
335 subset_charset_format = 0;
336 else if (!two_byte)
337 subset_charset_format = 1;
338 else
339 subset_charset_format = 2;
340
341 return Charset::calculate_serialized_size (
342 subset_charset_format,
343 subset_charset_format? subset_charset_ranges.len: plan->glyphs.len);
Michiharu Ariza64c54122018-08-10 11:07:07 -0700344 }
345
Michiharu Arizae67bb3f2018-08-16 00:25:57 -0700346 inline bool create (const OT::cff1::accelerator_subset_t &acc,
Michiharu Ariza64c54122018-08-10 11:07:07 -0700347 hb_subset_plan_t *plan)
348 {
Michiharu Arizaaca73c92018-09-06 17:28:15 -0700349 /* make sure notdef is first */
350 if ((plan->glyphs.len == 0) || (plan->glyphs[0] != 0)) return false;
351
Michiharu Ariza64c54122018-08-10 11:07:07 -0700352 final_size = 0;
Michiharu Arizaaca73c92018-09-06 17:28:15 -0700353 num_glyphs = plan->glyphs.len;
Michiharu Ariza64c54122018-08-10 11:07:07 -0700354 orig_fdcount = acc.fdCount;
Michiharu Ariza5cde2f52018-08-17 16:50:13 -0700355 drop_hints = plan->drop_hints;
Michiharu Ariza64c54122018-08-10 11:07:07 -0700356
Michiharu Arizaaca73c92018-09-06 17:28:15 -0700357 /* check whether the subset renumbers any glyph IDs */
358 gid_renum = false;
359 for (unsigned int glyph = 0; glyph < plan->glyphs.len; glyph++)
360 {
361 if (plan->glyphs[glyph] != glyph) {
362 gid_renum = true;
363 break;
364 }
365 }
366
367 subset_charset = gid_renum || !acc.is_predef_charset ();
368 subset_encoding = !acc.is_CID() && (gid_renum || !acc.is_predef_encoding ());
369
Michiharu Ariza64c54122018-08-10 11:07:07 -0700370 /* CFF header */
Michiharu Arizae67bb3f2018-08-16 00:25:57 -0700371 final_size += OT::cff1::static_size;
Michiharu Ariza64c54122018-08-10 11:07:07 -0700372
373 /* Name INDEX */
374 offsets.nameIndexOffset = final_size;
375 final_size += acc.nameIndex->get_size ();
Michiharu Arizaaca73c92018-09-06 17:28:15 -0700376
Michiharu Ariza64c54122018-08-10 11:07:07 -0700377 /* top dict INDEX */
378 {
Michiharu Arizaaca73c92018-09-06 17:28:15 -0700379 /* Add encoding/charset to a (copy of) top dict as necessary */
380 topdict_mod.init (&acc.topDicts[0]);
381 bool need_to_add_enc = (subset_encoding && !acc.topDicts[0].hasOp (OpCode_Encoding));
382 bool need_to_add_set = (subset_charset && !acc.topDicts[0].hasOp (OpCode_charset));
383 if (need_to_add_enc || need_to_add_set)
384 {
385 if (need_to_add_enc)
386 topdict_mod.addOp (OpCode_Encoding);
387 if (need_to_add_set)
388 topdict_mod.addOp (OpCode_charset);
389 }
Michiharu Ariza633ce882018-08-15 12:00:19 -0700390 offsets.topDictInfo.offset = final_size;
Michiharu Arizafdbfa182018-08-16 00:13:09 -0700391 CFF1TopDict_OpSerializer topSzr;
Michiharu Arizaaca73c92018-09-06 17:28:15 -0700392 unsigned int topDictSize = TopDict::calculate_serialized_size (topdict_mod, topSzr);
Michiharu Ariza633ce882018-08-15 12:00:19 -0700393 offsets.topDictInfo.offSize = calcOffSize(topDictSize);
Michiharu Arizaaca73c92018-09-06 17:28:15 -0700394 final_size += CFF1IndexOf<TopDict>::calculate_serialized_size<CFF1TopDictValuesMod>
395 (offsets.topDictInfo.offSize,
396 &topdict_mod, 1, topdict_sizes, topSzr);
Michiharu Ariza64c54122018-08-10 11:07:07 -0700397 }
398
399 /* String INDEX */
400 offsets.stringIndexOffset = final_size;
401 final_size += acc.stringIndex->get_size ();
402
Michiharu Arizaa11420b2018-08-29 12:14:30 -0700403 if (flatten_subrs)
Michiharu Ariza633ce882018-08-15 12:00:19 -0700404 {
Michiharu Arizaa11420b2018-08-29 12:14:30 -0700405 /* Flatten global & local subrs */
Michiharu Ariza8c5e03b2018-08-30 17:21:56 -0700406 SubrFlattener<const OT::cff1::accelerator_subset_t, CFF1CSInterpEnv, CFF1CSOpSet_Flatten>
407 flattener(acc, plan->glyphs, plan->drop_hints);
Michiharu Arizaa11420b2018-08-29 12:14:30 -0700408 if (!flattener.flatten (flat_charstrings))
409 return false;
410
411 /* no global/local subroutines */
412 offsets.globalSubrsInfo.size = HBUINT16::static_size; /* count 0 only */
413 }
414 else
415 {
416 /* Subset global & local subrs */
417 SubrSubsetter<const OT::cff1::accelerator_subset_t, CFF1CSInterpEnv, CFF1CSOpSet_SubsetSubrs> subsetter(acc, plan->glyphs);
Michiharu Ariza633ce882018-08-15 12:00:19 -0700418 if (!subsetter.collect_refs (subrRefMaps))
419 return false;
420
421 offsets.globalSubrsInfo.size = acc.globalSubrs->calculate_serialized_size (offsets.globalSubrsInfo.offSize, subrRefMaps.global_map, 1);
422 if (!offsets.localSubrsInfos.resize (orig_fdcount))
423 return false;
424 for (unsigned int i = 0; i < orig_fdcount; i++)
425 offsets.localSubrsInfos[i].size = acc.privateDicts[i].localSubrs->calculate_serialized_size (offsets.localSubrsInfos[i].offSize, subrRefMaps.local_maps[i], 1);
426 }
Michiharu Ariza64c54122018-08-10 11:07:07 -0700427 /* global subrs */
Michiharu Ariza633ce882018-08-15 12:00:19 -0700428 offsets.globalSubrsInfo.offset = final_size;
429 final_size += offsets.globalSubrsInfo.size;
Michiharu Ariza64c54122018-08-10 11:07:07 -0700430
431 /* Encoding */
432 offsets.encodingOffset = final_size;
Michiharu Arizaaca73c92018-09-06 17:28:15 -0700433 if (subset_encoding)
434 final_size += plan_subset_encoding (acc, plan);
Michiharu Ariza64c54122018-08-10 11:07:07 -0700435
436 /* Charset */
437 offsets.charsetOffset = final_size;
Michiharu Arizaaca73c92018-09-06 17:28:15 -0700438 if (subset_charset)
439 final_size += plan_subset_charset (acc, plan);
Michiharu Ariza64c54122018-08-10 11:07:07 -0700440
441 /* FDSelect */
Michiharu Arizafdbfa182018-08-16 00:13:09 -0700442 if (acc.fdSelect != &Null(CFF1FDSelect))
Michiharu Ariza64c54122018-08-10 11:07:07 -0700443 {
444 offsets.FDSelectInfo.offset = final_size;
445 if (unlikely (!hb_plan_subset_cff_fdselect (plan->glyphs,
446 orig_fdcount,
447 *acc.fdSelect,
Michiharu Arizaaca73c92018-09-06 17:28:15 -0700448 subset_fdcount,
Michiharu Ariza64c54122018-08-10 11:07:07 -0700449 offsets.FDSelectInfo.size,
Michiharu Arizaaca73c92018-09-06 17:28:15 -0700450 subset_fdselect_format,
451 subset_fdselect_first_glyphs,
Michiharu Ariza64c54122018-08-10 11:07:07 -0700452 fdmap)))
453 return false;
454
455 if (!is_fds_subsetted ())
456 offsets.FDSelectInfo.size = acc.fdSelect->calculate_serialized_size (acc.num_glyphs);
457 final_size += offsets.FDSelectInfo.size;
458 }
459
460 /* FDArray (FDIndex) */
Michiharu Arizafdbfa182018-08-16 00:13:09 -0700461 if (acc.fdArray != &Null(CFF1FDArray)) {
Michiharu Ariza633ce882018-08-15 12:00:19 -0700462 offsets.FDArrayInfo.offset = final_size;
Michiharu Ariza9fd08cc2018-08-29 18:18:18 -0700463 CFFFontDict_OpSerializer fontSzr;
Michiharu Arizaaca73c92018-09-06 17:28:15 -0700464 final_size += CFF1FDArray::calculate_serialized_size(offsets.FDArrayInfo.offSize/*OUT*/, acc.fontDicts, subset_fdcount, fdmap, fontSzr);
Michiharu Ariza64c54122018-08-10 11:07:07 -0700465 }
466
467 /* CharStrings */
468 {
Michiharu Ariza633ce882018-08-15 12:00:19 -0700469 offsets.charStringsInfo.offset = final_size;
Michiharu Ariza64c54122018-08-10 11:07:07 -0700470 unsigned int dataSize = 0;
471 for (unsigned int i = 0; i < plan->glyphs.len; i++)
472 {
Michiharu Arizaa11420b2018-08-29 12:14:30 -0700473 if (flatten_subrs)
474 {
475 ByteStrBuff &flatstr = flat_charstrings[i];
476 ByteStr str (&flatstr[0], flatstr.len);
477 subset_charstrings.push (str);
478 dataSize += flatstr.len;
479 }
480 else
481 {
482 const ByteStr str = (*acc.charStrings)[plan->glyphs[i]];
483 subset_charstrings.push (str);
484 dataSize += str.len;
485 }
Michiharu Ariza64c54122018-08-10 11:07:07 -0700486 }
Michiharu Ariza633ce882018-08-15 12:00:19 -0700487 offsets.charStringsInfo.offSize = calcOffSize (dataSize + 1);
Michiharu Arizafdbfa182018-08-16 00:13:09 -0700488 final_size += CFF1CharStrings::calculate_serialized_size (offsets.charStringsInfo.offSize, plan->glyphs.len, dataSize);
Michiharu Ariza64c54122018-08-10 11:07:07 -0700489 }
490
491 /* private dicts & local subrs */
492 offsets.privateDictInfo.offset = final_size;
493 for (unsigned int i = 0; i < orig_fdcount; i++)
494 {
Michiharu Arizaa97ed342018-08-10 12:55:22 -0700495 if (!fdmap.excludes (i))
496 {
Michiharu Ariza5cde2f52018-08-17 16:50:13 -0700497 unsigned int priv_size;
Michiharu Ariza9fd08cc2018-08-29 18:18:18 -0700498 CFFPrivateDict_OpSerializer privSzr (plan->drop_hints, flatten_subrs);
Michiharu Arizaa11420b2018-08-29 12:14:30 -0700499 priv_size = PrivateDict::calculate_serialized_size (acc.privateDicts[i], privSzr);
Michiharu Ariza5cde2f52018-08-17 16:50:13 -0700500 TableInfo privInfo = { final_size, priv_size, 0 };
Michiharu Arizaa97ed342018-08-10 12:55:22 -0700501 privateDictInfos.push (privInfo);
Michiharu Arizaa11420b2018-08-29 12:14:30 -0700502 final_size += privInfo.size;
503 if (!flatten_subrs)
504 final_size += offsets.localSubrsInfos[i].size;
Michiharu Arizaa97ed342018-08-10 12:55:22 -0700505 }
Michiharu Ariza64c54122018-08-10 11:07:07 -0700506 }
507
508 if (!acc.is_CID ())
509 offsets.privateDictInfo = privateDictInfos[0];
510
Michiharu Arizaa11420b2018-08-29 12:14:30 -0700511 return ((subset_charstrings.len == plan->glyphs.len) &&
Michiharu Arizaaca73c92018-09-06 17:28:15 -0700512 (privateDictInfos.len == subset_fdcount));
Michiharu Ariza64c54122018-08-10 11:07:07 -0700513 }
514
515 inline unsigned int get_final_size (void) const { return final_size; }
516
Michiharu Arizaaca73c92018-09-06 17:28:15 -0700517 unsigned int final_size;
Michiharu Ariza64c54122018-08-10 11:07:07 -0700518 hb_vector_t<unsigned int> topdict_sizes;
Michiharu Arizaaca73c92018-09-06 17:28:15 -0700519 CFF1TopDictValuesMod topdict_mod;
520 CFF1SubTableOffsets offsets;
Michiharu Ariza64c54122018-08-10 11:07:07 -0700521
Michiharu Arizaaca73c92018-09-06 17:28:15 -0700522 unsigned int num_glyphs;
Michiharu Ariza64c54122018-08-10 11:07:07 -0700523 unsigned int orig_fdcount;
Michiharu Arizaaca73c92018-09-06 17:28:15 -0700524 unsigned int subset_fdcount;
525 inline bool is_fds_subsetted (void) const { return subset_fdcount < orig_fdcount; }
526 unsigned int subset_fdselect_format;
527 hb_vector_t<hb_codepoint_t> subset_fdselect_first_glyphs;
Michiharu Ariza64c54122018-08-10 11:07:07 -0700528
529 /* font dict index remap table from fullset FDArray to subset FDArray.
530 * set to HB_SET_VALUE_INVALID if excluded from subset */
Michiharu Arizaa97ed342018-08-10 12:55:22 -0700531 FDMap fdmap;
Michiharu Ariza64c54122018-08-10 11:07:07 -0700532
Michiharu Arizaa11420b2018-08-29 12:14:30 -0700533 hb_vector_t<ByteStr> subset_charstrings;
534 ByteStrBuffArray flat_charstrings;
535 hb_vector_t<TableInfo> privateDictInfos;
Michiharu Ariza633ce882018-08-15 12:00:19 -0700536
537 SubrRefMaps subrRefMaps;
Michiharu Ariza5cde2f52018-08-17 16:50:13 -0700538
Michiharu Arizaaca73c92018-09-06 17:28:15 -0700539 bool flatten_subrs;
540 bool drop_hints;
541
542 bool gid_renum;
543 bool subset_encoding;
544 uint8_t subset_enc_format;
545 unsigned int subset_enc_num_codes;
546 hb_vector_t<code_pair> subset_enc_code_ranges;
547 hb_vector_t<code_pair> subset_enc_supp_codes;
548
549 uint8_t subset_charset_format;
550 hb_vector_t<code_pair> subset_charset_ranges;
551 bool subset_charset;
Michiharu Ariza64c54122018-08-10 11:07:07 -0700552};
553
Michiharu Arizafdbfa182018-08-16 00:13:09 -0700554static inline bool _write_cff1 (const cff_subset_plan &plan,
Michiharu Arizae67bb3f2018-08-16 00:25:57 -0700555 const OT::cff1::accelerator_subset_t &acc,
Michiharu Ariza64c54122018-08-10 11:07:07 -0700556 const hb_vector_t<hb_codepoint_t>& glyphs,
557 unsigned int dest_sz,
558 void *dest)
559{
560 hb_serialize_context_t c (dest, dest_sz);
561
Michiharu Arizac2348392018-08-15 13:04:43 -0700562 char RETURN_OP[1] = { OpCode_return };
Michiharu Ariza270452a2018-08-15 13:15:08 -0700563 const ByteStr NULL_SUBR (RETURN_OP, 1);
Michiharu Arizac2348392018-08-15 13:04:43 -0700564
Michiharu Arizae67bb3f2018-08-16 00:25:57 -0700565 OT::cff1 *cff = c.start_serialize<OT::cff1> ();
Michiharu Ariza64c54122018-08-10 11:07:07 -0700566 if (unlikely (!c.extend_min (*cff)))
567 return false;
568
569 /* header */
570 cff->version.major.set (0x01);
571 cff->version.minor.set (0x00);
572 cff->nameIndex.set (cff->min_size);
573 cff->offSize.set (4); /* unused? */
574
575 /* name INDEX */
576 {
577 assert (cff->nameIndex == c.head - c.start);
Michiharu Arizafdbfa182018-08-16 00:13:09 -0700578 CFF1NameIndex *dest = c.start_embed<CFF1NameIndex> ();
Michiharu Ariza64c54122018-08-10 11:07:07 -0700579 if (unlikely (dest == nullptr)) return false;
580 if (unlikely (!dest->serialize (&c, *acc.nameIndex)))
581 {
582 DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF name INDEX");
583 return false;
584 }
585 }
586
587 /* top dict INDEX */
588 {
Michiharu Ariza633ce882018-08-15 12:00:19 -0700589 assert (plan.offsets.topDictInfo.offset == c.head - c.start);
Michiharu Arizafdbfa182018-08-16 00:13:09 -0700590 CFF1IndexOf<TopDict> *dest = c.start_embed< CFF1IndexOf<TopDict> > ();
Michiharu Ariza64c54122018-08-10 11:07:07 -0700591 if (dest == nullptr) return false;
Michiharu Arizafdbfa182018-08-16 00:13:09 -0700592 CFF1TopDict_OpSerializer topSzr;
Michiharu Arizaaca73c92018-09-06 17:28:15 -0700593 if (unlikely (!dest->serialize (&c, plan.offsets.topDictInfo.offSize,
594 &plan.topdict_mod, 1,
595 plan.topdict_sizes, topSzr, plan.offsets)))
Michiharu Ariza64c54122018-08-10 11:07:07 -0700596 {
597 DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF top dict");
598 return false;
599 }
600 }
601
602 /* String INDEX */
603 {
604 assert (plan.offsets.stringIndexOffset == c.head - c.start);
Michiharu Arizafdbfa182018-08-16 00:13:09 -0700605 CFF1StringIndex *dest = c.start_embed<CFF1StringIndex> ();
Michiharu Ariza64c54122018-08-10 11:07:07 -0700606 if (unlikely (dest == nullptr)) return false;
607 if (unlikely (!dest->serialize (&c, *acc.stringIndex)))
608 {
609 DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF string INDEX");
610 return false;
611 }
612 }
613
614 /* global subrs */
615 {
Michiharu Arizaa11420b2018-08-29 12:14:30 -0700616 assert (plan.offsets.globalSubrsInfo.offset != 0);
Michiharu Ariza633ce882018-08-15 12:00:19 -0700617 assert (plan.offsets.globalSubrsInfo.offset == c.head - c.start);
Michiharu Arizafdbfa182018-08-16 00:13:09 -0700618 CFF1Subrs *dest = c.start_embed<CFF1Subrs> ();
Michiharu Ariza64c54122018-08-10 11:07:07 -0700619 if (unlikely (dest == nullptr)) return false;
Michiharu Ariza633ce882018-08-15 12:00:19 -0700620 if (unlikely (!dest->serialize (&c, *acc.globalSubrs, plan.offsets.globalSubrsInfo.offSize, plan.subrRefMaps.global_map, NULL_SUBR)))
Michiharu Ariza64c54122018-08-10 11:07:07 -0700621 {
622 DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF global subrs");
623 return false;
624 }
625 }
626
627 /* Encoding */
Michiharu Arizaaca73c92018-09-06 17:28:15 -0700628 if (plan.subset_encoding)
629 {
Michiharu Ariza64c54122018-08-10 11:07:07 -0700630 assert (plan.offsets.encodingOffset == c.head - c.start);
631 Encoding *dest = c.start_embed<Encoding> ();
632 if (unlikely (dest == nullptr)) return false;
Michiharu Arizaaca73c92018-09-06 17:28:15 -0700633 if (unlikely (!dest->serialize (&c,
634 plan.subset_enc_format,
635 plan.subset_enc_num_codes,
636 plan.subset_enc_code_ranges,
637 plan.subset_enc_supp_codes)))
Michiharu Ariza64c54122018-08-10 11:07:07 -0700638 {
639 DEBUG_MSG (SUBSET, nullptr, "failed to serialize Encoding");
640 return false;
641 }
642 }
643
644 /* Charset */
Michiharu Arizaaca73c92018-09-06 17:28:15 -0700645 if (plan.subset_charset)
Michiharu Ariza64c54122018-08-10 11:07:07 -0700646 {
647 assert (plan.offsets.charsetOffset == c.head - c.start);
648 Charset *dest = c.start_embed<Charset> ();
649 if (unlikely (dest == nullptr)) return false;
Michiharu Arizaaca73c92018-09-06 17:28:15 -0700650 if (unlikely (!dest->serialize (&c,
651 plan.subset_charset_format,
652 plan.num_glyphs,
653 plan.subset_charset_ranges)))
Michiharu Ariza64c54122018-08-10 11:07:07 -0700654 {
655 DEBUG_MSG (SUBSET, nullptr, "failed to serialize Charset");
656 return false;
657 }
658 }
659
660 /* FDSelect */
Michiharu Arizafdbfa182018-08-16 00:13:09 -0700661 if (acc.fdSelect != &Null(CFF1FDSelect))
Michiharu Ariza64c54122018-08-10 11:07:07 -0700662 {
663 assert (plan.offsets.FDSelectInfo.offset == c.head - c.start);
664
665 if (plan.is_fds_subsetted ())
666 {
667 if (unlikely (!hb_serialize_cff_fdselect (&c, glyphs, *acc.fdSelect, acc.fdCount,
Michiharu Arizaaca73c92018-09-06 17:28:15 -0700668 plan.subset_fdselect_format, plan.offsets.FDSelectInfo.size,
669 plan.subset_fdselect_first_glyphs,
Michiharu Ariza64c54122018-08-10 11:07:07 -0700670 plan.fdmap)))
671 {
672 DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF subset FDSelect");
673 return false;
674 }
675 }
676 else
677 {
Michiharu Arizafdbfa182018-08-16 00:13:09 -0700678 CFF1FDSelect *dest = c.start_embed<CFF1FDSelect> ();
Michiharu Ariza64c54122018-08-10 11:07:07 -0700679 if (unlikely (!dest->serialize (&c, *acc.fdSelect, acc.num_glyphs)))
680 {
681 DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF FDSelect");
682 return false;
683 }
684 }
685 }
686
687 /* FDArray (FD Index) */
Michiharu Arizafdbfa182018-08-16 00:13:09 -0700688 if (acc.fdArray != &Null(CFF1FDArray))
Michiharu Ariza64c54122018-08-10 11:07:07 -0700689 {
Michiharu Ariza633ce882018-08-15 12:00:19 -0700690 assert (plan.offsets.FDArrayInfo.offset == c.head - c.start);
Michiharu Arizafdbfa182018-08-16 00:13:09 -0700691 CFF1FDArray *fda = c.start_embed<CFF1FDArray> ();
Michiharu Ariza64c54122018-08-10 11:07:07 -0700692 if (unlikely (fda == nullptr)) return false;
Michiharu Ariza9fd08cc2018-08-29 18:18:18 -0700693 CFFFontDict_OpSerializer fontSzr;
Michiharu Ariza633ce882018-08-15 12:00:19 -0700694 if (unlikely (!fda->serialize (&c, plan.offsets.FDArrayInfo.offSize,
Michiharu Arizaaca73c92018-09-06 17:28:15 -0700695 acc.fontDicts, plan.subset_fdcount, plan.fdmap,
Michiharu Ariza64c54122018-08-10 11:07:07 -0700696 fontSzr, plan.privateDictInfos)))
697 {
698 DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF FDArray");
699 return false;
700 }
701 }
702
703 /* CharStrings */
704 {
Michiharu Ariza633ce882018-08-15 12:00:19 -0700705 assert (plan.offsets.charStringsInfo.offset == c.head - c.start);
Michiharu Arizafdbfa182018-08-16 00:13:09 -0700706 CFF1CharStrings *cs = c.start_embed<CFF1CharStrings> ();
Michiharu Ariza64c54122018-08-10 11:07:07 -0700707 if (unlikely (cs == nullptr)) return false;
Michiharu Ariza633ce882018-08-15 12:00:19 -0700708 if (unlikely (!cs->serialize (&c, plan.offsets.charStringsInfo.offSize, plan.subset_charstrings)))
Michiharu Ariza64c54122018-08-10 11:07:07 -0700709 {
710 DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF CharStrings");
711 return false;
712 }
713 }
714
715 /* private dicts & local subrs */
716 assert (plan.offsets.privateDictInfo.offset == c.head - c.start);
717 for (unsigned int i = 0; i < acc.privateDicts.len; i++)
718 {
Michiharu Arizaa97ed342018-08-10 12:55:22 -0700719 if (!plan.fdmap.excludes (i))
Michiharu Ariza64c54122018-08-10 11:07:07 -0700720 {
Michiharu Arizaa97ed342018-08-10 12:55:22 -0700721 PrivateDict *pd = c.start_embed<PrivateDict> ();
722 if (unlikely (pd == nullptr)) return false;
Michiharu Arizaa11420b2018-08-29 12:14:30 -0700723 unsigned int priv_size = plan.flatten_subrs? 0: plan.privateDictInfos[plan.fdmap[i]].size;
Michiharu Ariza5cde2f52018-08-17 16:50:13 -0700724 bool result;
Michiharu Ariza9fd08cc2018-08-29 18:18:18 -0700725 CFFPrivateDict_OpSerializer privSzr (plan.drop_hints, plan.flatten_subrs);
Michiharu Arizaa97ed342018-08-10 12:55:22 -0700726 /* N.B. local subrs immediately follows its corresponding private dict. i.e., subr offset == private dict size */
Michiharu Arizaa11420b2018-08-29 12:14:30 -0700727 result = pd->serialize (&c, acc.privateDicts[i], privSzr, priv_size);
Michiharu Ariza5cde2f52018-08-17 16:50:13 -0700728 if (unlikely (!result))
Michiharu Ariza64c54122018-08-10 11:07:07 -0700729 {
Michiharu Arizaa97ed342018-08-10 12:55:22 -0700730 DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF Private Dict[%d]", i);
Michiharu Ariza64c54122018-08-10 11:07:07 -0700731 return false;
732 }
Michiharu Arizaa11420b2018-08-29 12:14:30 -0700733 if (!plan.flatten_subrs && (acc.privateDicts[i].subrsOffset != 0))
Michiharu Ariza64c54122018-08-10 11:07:07 -0700734 {
Michiharu Arizafdbfa182018-08-16 00:13:09 -0700735 CFF1Subrs *subrs = c.start_embed<CFF1Subrs> ();
736 if (unlikely (subrs == nullptr) || acc.privateDicts[i].localSubrs == &Null(CFF1Subrs))
Michiharu Arizaa97ed342018-08-10 12:55:22 -0700737 {
738 DEBUG_MSG (SUBSET, nullptr, "CFF subset: local subrs unexpectedly null [%d]", i);
739 return false;
740 }
Michiharu Ariza633ce882018-08-15 12:00:19 -0700741 if (unlikely (!subrs->serialize (&c, *acc.privateDicts[i].localSubrs, plan.offsets.localSubrsInfos[i].offSize, plan.subrRefMaps.local_maps[i], NULL_SUBR)))
Michiharu Arizaa97ed342018-08-10 12:55:22 -0700742 {
743 DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF local subrs [%d]", i);
744 return false;
745 }
Michiharu Ariza64c54122018-08-10 11:07:07 -0700746 }
747 }
748 }
749
Michiharu Arizacef75ea2018-08-17 13:13:18 -0700750 assert (c.head == c.end);
Michiharu Ariza64c54122018-08-10 11:07:07 -0700751 c.end_serialize ();
752
753 return true;
754}
755
756static bool
Michiharu Arizae67bb3f2018-08-16 00:25:57 -0700757_hb_subset_cff1 (const OT::cff1::accelerator_subset_t &acc,
Michiharu Ariza64c54122018-08-10 11:07:07 -0700758 const char *data,
759 hb_subset_plan_t *plan,
760 hb_blob_t **prime /* OUT */)
761{
762 cff_subset_plan cff_plan;
763
764 if (unlikely (!cff_plan.create (acc, plan)))
765 {
766 DEBUG_MSG(SUBSET, nullptr, "Failed to generate a cff subsetting plan.");
767 return false;
768 }
769
770 unsigned int cff_prime_size = cff_plan.get_final_size ();
771 char *cff_prime_data = (char *) calloc (1, cff_prime_size);
772
Michiharu Arizafdbfa182018-08-16 00:13:09 -0700773 if (unlikely (!_write_cff1 (cff_plan, acc, plan->glyphs,
Michiharu Ariza64c54122018-08-10 11:07:07 -0700774 cff_prime_size, cff_prime_data))) {
775 DEBUG_MSG(SUBSET, nullptr, "Failed to write a subset cff.");
776 free (cff_prime_data);
777 return false;
778 }
779
780 *prime = hb_blob_create (cff_prime_data,
781 cff_prime_size,
782 HB_MEMORY_MODE_READONLY,
783 cff_prime_data,
784 free);
785 return true;
786}
787
788/**
Michiharu Arizafdbfa182018-08-16 00:13:09 -0700789 * hb_subset_cff1:
Michiharu Ariza64c54122018-08-10 11:07:07 -0700790 * Subsets the CFF table according to a provided plan.
791 *
792 * Return value: subsetted cff table.
793 **/
794bool
Michiharu Arizafdbfa182018-08-16 00:13:09 -0700795hb_subset_cff1 (hb_subset_plan_t *plan,
Michiharu Ariza64c54122018-08-10 11:07:07 -0700796 hb_blob_t **prime /* OUT */)
797{
Michiharu Arizae67bb3f2018-08-16 00:25:57 -0700798 hb_blob_t *cff_blob = hb_sanitize_context_t().reference_table<CFF::cff1> (plan->source);
Michiharu Ariza64c54122018-08-10 11:07:07 -0700799 const char *data = hb_blob_get_data(cff_blob, nullptr);
800
Michiharu Arizae67bb3f2018-08-16 00:25:57 -0700801 OT::cff1::accelerator_subset_t acc;
Michiharu Ariza64c54122018-08-10 11:07:07 -0700802 acc.init(plan->source);
803 bool result = likely (acc.is_valid ()) &&
Michiharu Arizafdbfa182018-08-16 00:13:09 -0700804 _hb_subset_cff1 (acc, data, plan, prime);
Michiharu Ariza64c54122018-08-10 11:07:07 -0700805 hb_blob_destroy (cff_blob);
806 acc.fini ();
807
808 return result;
809}