blob: 2ffbdc91cccfaad7c33649b16096fbbd76f16bf9 [file] [log] [blame]
Michiharu Ariza64c54122018-08-10 11:07:07 -07001/*
Michiharu Ariza0dfa5842018-11-12 08:47:07 -08002 * Copyright © 2018 Adobe Inc.
Michiharu Ariza64c54122018-08-10 11:07:07 -07003 *
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 Ariza1666b892018-09-10 16:00:20 -070037struct RemapSID : Remap
38{
39 inline unsigned int add (unsigned int sid)
40 {
41 if ((sid != CFF_UNDEF_SID) && !is_std_std (sid))
42 return offset_sid (Remap::add (unoffset_sid (sid)));
43 else
44 return sid;
45 }
46
47 inline unsigned int operator[] (unsigned int sid) const
48 {
Michiharu Ariza9d0231c2018-11-15 15:39:43 -080049 if (is_std_std (sid) || (sid == CFF_UNDEF_SID))
Michiharu Ariza1666b892018-09-10 16:00:20 -070050 return sid;
51 else
52 return offset_sid (Remap::operator [] (unoffset_sid (sid)));
53 }
54
55 static const unsigned int num_std_strings = 391;
56
57 static inline bool is_std_std (unsigned int sid) { return sid < num_std_strings; }
58 static inline unsigned int offset_sid (unsigned int sid) { return sid + num_std_strings; }
59 static inline unsigned int unoffset_sid (unsigned int sid) { return sid - num_std_strings; }
60};
61
Michiharu Ariza9fd08cc2018-08-29 18:18:18 -070062struct CFF1SubTableOffsets : CFFSubTableOffsets
63{
Michiharu Arizafdbfa182018-08-16 00:13:09 -070064 inline CFF1SubTableOffsets (void)
Michiharu Ariza9fd08cc2018-08-29 18:18:18 -070065 : CFFSubTableOffsets (),
66 nameIndexOffset (0),
Michiharu Ariza1666b892018-09-10 16:00:20 -070067 encodingOffset (0)
Michiharu Ariza64c54122018-08-10 11:07:07 -070068 {
Michiharu Ariza1666b892018-09-10 16:00:20 -070069 stringIndexInfo.init ();
70 charsetInfo.init ();
Michiharu Ariza9fd08cc2018-08-29 18:18:18 -070071 privateDictInfo.init ();
Michiharu Ariza64c54122018-08-10 11:07:07 -070072 }
73
74 unsigned int nameIndexOffset;
Michiharu Ariza1666b892018-09-10 16:00:20 -070075 TableInfo stringIndexInfo;
Michiharu Ariza64c54122018-08-10 11:07:07 -070076 unsigned int encodingOffset;
Michiharu Ariza1666b892018-09-10 16:00:20 -070077 TableInfo charsetInfo;
Michiharu Ariza64c54122018-08-10 11:07:07 -070078 TableInfo privateDictInfo;
79};
80
Michiharu Ariza1666b892018-09-10 16:00:20 -070081/* a copy of a parsed out CFF1TopDictValues augmented with additional operators */
82struct CFF1TopDictValuesMod : CFF1TopDictValues
83{
84 inline void init (const CFF1TopDictValues *base_= &Null(CFF1TopDictValues))
85 {
86 SUPER::init ();
87 base = base_;
88 }
89
90 inline void fini (void)
91 {
92 SUPER::fini ();
93 }
94
Michiharu Arizad56e3382018-10-31 22:30:34 -070095 inline unsigned get_count (void) const
Michiharu Ariza1666b892018-09-10 16:00:20 -070096 {
Michiharu Arizad56e3382018-10-31 22:30:34 -070097 return base->get_count () + SUPER::get_count ();
Michiharu Ariza1666b892018-09-10 16:00:20 -070098 }
Michiharu Arizad56e3382018-10-31 22:30:34 -070099 inline const CFF1TopDictVal &get_value (unsigned int i) const
Michiharu Ariza1666b892018-09-10 16:00:20 -0700100 {
Michiharu Arizad56e3382018-10-31 22:30:34 -0700101 if (i < base->get_count ())
Michiharu Ariza1666b892018-09-10 16:00:20 -0700102 return (*base)[i];
103 else
Michiharu Arizad56e3382018-10-31 22:30:34 -0700104 return SUPER::values[i - base->get_count ()];
Michiharu Ariza1666b892018-09-10 16:00:20 -0700105 }
Michiharu Arizad56e3382018-10-31 22:30:34 -0700106 inline const CFF1TopDictVal &operator [] (unsigned int i) const { return get_value (i); }
Michiharu Ariza1666b892018-09-10 16:00:20 -0700107
108 inline void reassignSIDs (const RemapSID& sidmap)
109 {
Michiharu Arizac6f75c32018-09-10 17:02:31 -0700110 for (unsigned int i = 0; i < NameDictValues::ValCount; i++)
Michiharu Ariza1666b892018-09-10 16:00:20 -0700111 nameSIDs[i] = sidmap[base->nameSIDs[i]];
112 }
113
114 protected:
115 typedef CFF1TopDictValues SUPER;
116 const CFF1TopDictValues *base;
117};
118
119struct TopDictModifiers
120{
121 inline TopDictModifiers (const CFF1SubTableOffsets &offsets_,
Michiharu Arizac6f75c32018-09-10 17:02:31 -0700122 const unsigned int (&nameSIDs_)[NameDictValues::ValCount])
Michiharu Ariza1666b892018-09-10 16:00:20 -0700123 : offsets (offsets_),
124 nameSIDs (nameSIDs_)
125 {}
126
127 const CFF1SubTableOffsets &offsets;
Michiharu Arizac6f75c32018-09-10 17:02:31 -0700128 const unsigned int (&nameSIDs)[NameDictValues::ValCount];
Michiharu Ariza1666b892018-09-10 16:00:20 -0700129};
130
131struct CFF1TopDict_OpSerializer : CFFTopDict_OpSerializer<CFF1TopDictVal>
Michiharu Ariza64c54122018-08-10 11:07:07 -0700132{
133 inline bool serialize (hb_serialize_context_t *c,
Michiharu Ariza1666b892018-09-10 16:00:20 -0700134 const CFF1TopDictVal &opstr,
135 const TopDictModifiers &mod) const
Michiharu Ariza64c54122018-08-10 11:07:07 -0700136 {
137 TRACE_SERIALIZE (this);
138
Michiharu Ariza1666b892018-09-10 16:00:20 -0700139 OpCode op = opstr.op;
140 switch (op)
Michiharu Ariza64c54122018-08-10 11:07:07 -0700141 {
142 case OpCode_charset:
Michiharu Ariza1666b892018-09-10 16:00:20 -0700143 return_trace (FontDict::serialize_offset4_op(c, op, mod.offsets.charsetInfo.offset));
Michiharu Ariza64c54122018-08-10 11:07:07 -0700144
145 case OpCode_Encoding:
Michiharu Ariza1666b892018-09-10 16:00:20 -0700146 return_trace (FontDict::serialize_offset4_op(c, op, mod.offsets.encodingOffset));
Michiharu Ariza64c54122018-08-10 11:07:07 -0700147
Michiharu Ariza64c54122018-08-10 11:07:07 -0700148 case OpCode_Private:
149 {
Michiharu Ariza1666b892018-09-10 16:00:20 -0700150 if (unlikely (!UnsizedByteStr::serialize_int2 (c, mod.offsets.privateDictInfo.size)))
Michiharu Ariza64c54122018-08-10 11:07:07 -0700151 return_trace (false);
Michiharu Ariza1666b892018-09-10 16:00:20 -0700152 if (unlikely (!UnsizedByteStr::serialize_int4 (c, mod.offsets.privateDictInfo.offset)))
Michiharu Ariza64c54122018-08-10 11:07:07 -0700153 return_trace (false);
154 HBUINT8 *p = c->allocate_size<HBUINT8> (1);
155 if (unlikely (p == nullptr)) return_trace (false);
156 p->set (OpCode_Private);
157 }
158 break;
159
Michiharu Ariza1666b892018-09-10 16:00:20 -0700160 case OpCode_version:
161 case OpCode_Notice:
162 case OpCode_Copyright:
163 case OpCode_FullName:
164 case OpCode_FamilyName:
165 case OpCode_Weight:
166 case OpCode_PostScript:
167 case OpCode_BaseFontName:
168 case OpCode_FontName:
169 return_trace (FontDict::serialize_offset2_op(c, op, mod.nameSIDs[NameDictValues::name_op_to_index (op)]));
170
171 case OpCode_ROS:
172 {
173 /* for registry & ordering, reassigned SIDs are serialized
174 * for supplement, the original byte string is copied along with the op code */
175 OpStr supp_op;
176 supp_op.op = op;
177 supp_op.str.str = opstr.str.str + opstr.last_arg_offset;
178 assert (opstr.str.len >= opstr.last_arg_offset + 3);
179 supp_op.str.len = opstr.str.len - opstr.last_arg_offset;
Michiharu Arizac6f75c32018-09-10 17:02:31 -0700180 return_trace (UnsizedByteStr::serialize_int2 (c, mod.nameSIDs[NameDictValues::registry]) &&
181 UnsizedByteStr::serialize_int2 (c, mod.nameSIDs[NameDictValues::ordering]) &&
Michiharu Ariza1666b892018-09-10 16:00:20 -0700182 copy_opstr (c, supp_op));
183 }
Michiharu Ariza64c54122018-08-10 11:07:07 -0700184 default:
Michiharu Ariza1666b892018-09-10 16:00:20 -0700185 return_trace (CFFTopDict_OpSerializer<CFF1TopDictVal>::serialize (c, opstr, mod.offsets));
Michiharu Ariza64c54122018-08-10 11:07:07 -0700186 }
187 return_trace (true);
188 }
189
Michiharu Ariza1666b892018-09-10 16:00:20 -0700190 inline unsigned int calculate_serialized_size (const CFF1TopDictVal &opstr) const
Michiharu Ariza64c54122018-08-10 11:07:07 -0700191 {
Michiharu Ariza1666b892018-09-10 16:00:20 -0700192 OpCode op = opstr.op;
193 switch (op)
Michiharu Ariza64c54122018-08-10 11:07:07 -0700194 {
195 case OpCode_charset:
196 case OpCode_Encoding:
Michiharu Ariza1666b892018-09-10 16:00:20 -0700197 return OpCode_Size (OpCode_longintdict) + 4 + OpCode_Size (op);
Michiharu Ariza64c54122018-08-10 11:07:07 -0700198
199 case OpCode_Private:
Michiharu Ariza633ce882018-08-15 12:00:19 -0700200 return OpCode_Size (OpCode_longintdict) + 4 + OpCode_Size (OpCode_shortint) + 2 + OpCode_Size (OpCode_Private);
Michiharu Ariza64c54122018-08-10 11:07:07 -0700201
Michiharu Ariza1666b892018-09-10 16:00:20 -0700202 case OpCode_version:
203 case OpCode_Notice:
204 case OpCode_Copyright:
205 case OpCode_FullName:
206 case OpCode_FamilyName:
207 case OpCode_Weight:
208 case OpCode_PostScript:
209 case OpCode_BaseFontName:
210 case OpCode_FontName:
211 return OpCode_Size (OpCode_shortint) + 2 + OpCode_Size (op);
212
213 case OpCode_ROS:
214 return ((OpCode_Size (OpCode_shortint) + 2) * 2) + (opstr.str.len - opstr.last_arg_offset)/* supplement + op */;
215
Michiharu Ariza64c54122018-08-10 11:07:07 -0700216 default:
Michiharu Ariza1666b892018-09-10 16:00:20 -0700217 return CFFTopDict_OpSerializer<CFF1TopDictVal>::calculate_serialized_size (opstr);
Michiharu Ariza64c54122018-08-10 11:07:07 -0700218 }
219 }
220};
221
Michiharu Ariza1666b892018-09-10 16:00:20 -0700222struct FontDictValuesMod
223{
224 inline void init (const CFF1FontDictValues *base_,
225 unsigned int fontName_,
226 const TableInfo &privateDictInfo_)
227 {
228 base = base_;
229 fontName = fontName_;
230 privateDictInfo = privateDictInfo_;
231 }
232
Michiharu Arizad56e3382018-10-31 22:30:34 -0700233 inline unsigned get_count (void) const
Michiharu Ariza1666b892018-09-10 16:00:20 -0700234 {
Michiharu Arizad56e3382018-10-31 22:30:34 -0700235 return base->get_count ();
Michiharu Ariza1666b892018-09-10 16:00:20 -0700236 }
237
238 inline const OpStr &operator [] (unsigned int i) const { return (*base)[i]; }
239
240 const CFF1FontDictValues *base;
241 TableInfo privateDictInfo;
242 unsigned int fontName;
243};
244
245struct CFF1FontDict_OpSerializer : CFFFontDict_OpSerializer
246{
247 inline bool serialize (hb_serialize_context_t *c,
248 const OpStr &opstr,
249 const FontDictValuesMod &mod) const
250 {
251 TRACE_SERIALIZE (this);
252
253 if (opstr.op == OpCode_FontName)
254 return_trace (FontDict::serialize_uint2_op (c, opstr.op, mod.fontName));
255 else
256 return_trace (SUPER::serialize (c, opstr, mod.privateDictInfo));
257 }
258
259 inline unsigned int calculate_serialized_size (const OpStr &opstr) const
260 {
261 if (opstr.op == OpCode_FontName)
262 return OpCode_Size (OpCode_shortint) + 2 + OpCode_Size (OpCode_FontName);
263 else
264 return SUPER::calculate_serialized_size (opstr);
265 }
266
267 private:
268 typedef CFFFontDict_OpSerializer SUPER;
269};
270
Michiharu Ariza8c5e03b2018-08-30 17:21:56 -0700271struct CFF1CSOpSet_Flatten : CFF1CSOpSet<CFF1CSOpSet_Flatten, FlattenParam>
Michiharu Ariza5cde2f52018-08-17 16:50:13 -0700272{
Michiharu Arizad56e3382018-10-31 22:30:34 -0700273 static inline void flush_args_and_op (OpCode op, CFF1CSInterpEnv &env, FlattenParam& param)
Michiharu Ariza5cde2f52018-08-17 16:50:13 -0700274 {
Michiharu Arizad56e3382018-10-31 22:30:34 -0700275 if (env.arg_start > 0)
Michiharu Arizaebeccf32018-09-18 17:24:30 -0700276 flush_width (env, param);
277
Michiharu Arizaa11420b2018-08-29 12:14:30 -0700278 switch (op)
279 {
Michiharu Ariza968168b2018-08-31 13:28:16 -0700280 case OpCode_hstem:
281 case OpCode_hstemhm:
282 case OpCode_vstem:
283 case OpCode_vstemhm:
Michiharu Arizaa11420b2018-08-29 12:14:30 -0700284 case OpCode_hintmask:
285 case OpCode_cntrmask:
Michiharu Arizab67a7c72018-11-16 12:28:24 -0800286 case OpCode_dotsection:
Michiharu Ariza8c5e03b2018-08-30 17:21:56 -0700287 if (param.drop_hints)
288 {
Michiharu Ariza968168b2018-08-31 13:28:16 -0700289 env.clear_args ();
290 return;
Michiharu Ariza8c5e03b2018-08-30 17:21:56 -0700291 }
Michiharu Ariza35b64df2018-10-02 14:13:36 -0700292 HB_FALLTHROUGH;
293
Michiharu Arizaa11420b2018-08-29 12:14:30 -0700294 default:
Michiharu Arizad56e3382018-10-31 22:30:34 -0700295 SUPER::flush_args_and_op (op, env, param);
Michiharu Ariza968168b2018-08-31 13:28:16 -0700296 break;
Michiharu Arizaa11420b2018-08-29 12:14:30 -0700297 }
Michiharu Ariza5cde2f52018-08-17 16:50:13 -0700298 }
Michiharu Arizad56e3382018-10-31 22:30:34 -0700299 static inline void flush_args (CFF1CSInterpEnv &env, FlattenParam& param)
Michiharu Ariza5cde2f52018-08-17 16:50:13 -0700300 {
Michiharu Arizad56e3382018-10-31 22:30:34 -0700301 StrEncoder encoder (param.flatStr);
302 for (unsigned int i = env.arg_start; i < env.argStack.get_count (); i++)
303 encoder.encode_num (env.eval_arg (i));
304 SUPER::flush_args (env, param);
Michiharu Ariza968168b2018-08-31 13:28:16 -0700305 }
306
307 static inline void flush_op (OpCode op, CFF1CSInterpEnv &env, FlattenParam& param)
308 {
Michiharu Arizad56e3382018-10-31 22:30:34 -0700309 StrEncoder encoder (param.flatStr);
310 encoder.encode_op (op);
Michiharu Ariza968168b2018-08-31 13:28:16 -0700311 }
312
Michiharu Arizaebeccf32018-09-18 17:24:30 -0700313 static inline void flush_width (CFF1CSInterpEnv &env, FlattenParam& param)
314 {
315 assert (env.has_width);
Michiharu Arizad56e3382018-10-31 22:30:34 -0700316 StrEncoder encoder (param.flatStr);
317 encoder.encode_num (env.width);
Michiharu Arizaebeccf32018-09-18 17:24:30 -0700318 }
319
Michiharu Ariza968168b2018-08-31 13:28:16 -0700320 static inline void flush_hintmask (OpCode op, CFF1CSInterpEnv &env, FlattenParam& param)
321 {
322 SUPER::flush_hintmask (op, env, param);
Michiharu Arizaf2d299b2018-09-04 10:25:21 -0700323 if (!param.drop_hints)
Michiharu Arizad56e3382018-10-31 22:30:34 -0700324 {
325 StrEncoder encoder (param.flatStr);
Michiharu Arizaf2d299b2018-09-04 10:25:21 -0700326 for (unsigned int i = 0; i < env.hintmask_size; i++)
Michiharu Arizad56e3382018-10-31 22:30:34 -0700327 encoder.encode_byte (env.substr[i]);
328 }
Michiharu Ariza5cde2f52018-08-17 16:50:13 -0700329 }
Michiharu Arizaa11420b2018-08-29 12:14:30 -0700330
331 private:
Michiharu Ariza8c5e03b2018-08-30 17:21:56 -0700332 typedef CFF1CSOpSet<CFF1CSOpSet_Flatten, FlattenParam> SUPER;
Michiharu Ariza5cde2f52018-08-17 16:50:13 -0700333};
334
Michiharu Ariza16084812018-09-12 13:22:19 -0700335struct RangeList : hb_vector_t<code_pair>
336{
337 /* replace the first glyph ID in the "glyph" field each range with a nLeft value */
Michiharu Arizaa6da9b92018-11-16 17:29:03 -0800338 inline bool finalize (unsigned int last_glyph)
Michiharu Ariza16084812018-09-12 13:22:19 -0700339 {
Michiharu Arizaa6da9b92018-11-16 17:29:03 -0800340 bool two_byte = false;
Michiharu Ariza16084812018-09-12 13:22:19 -0700341 for (unsigned int i = (*this).len; i > 0; i--)
342 {
343 code_pair &pair = (*this)[i - 1];
344 unsigned int nLeft = last_glyph - pair.glyph - 1;
Michiharu Arizaa6da9b92018-11-16 17:29:03 -0800345 if (nLeft >= 0x100)
346 two_byte = true;
Michiharu Ariza16084812018-09-12 13:22:19 -0700347 last_glyph = pair.glyph;
348 pair.glyph = nLeft;
349 }
Michiharu Arizaa6da9b92018-11-16 17:29:03 -0800350 return two_byte;
Michiharu Ariza16084812018-09-12 13:22:19 -0700351 }
352};
353
Michiharu Arizad56e3382018-10-31 22:30:34 -0700354struct CFF1CSOpSet_SubrSubset : CFF1CSOpSet<CFF1CSOpSet_SubrSubset, SubrSubsetParam>
355{
356 static inline void process_op (OpCode op, CFF1CSInterpEnv &env, SubrSubsetParam& param)
357 {
358 switch (op) {
359
360 case OpCode_return:
361 param.current_parsed_str->add_op (op, env.substr);
362 param.current_parsed_str->set_parsed ();
363 env.returnFromSubr ();
364 param.set_current_str (env);
365 break;
366
367 case OpCode_endchar:
368 param.current_parsed_str->add_op (op, env.substr);
369 param.current_parsed_str->set_parsed ();
370 SUPER::process_op (op, env, param);
371 break;
372
373 case OpCode_callsubr:
374 process_call_subr (op, CSType_LocalSubr, env, param, env.localSubrs, param.local_closure);
375 break;
376
377 case OpCode_callgsubr:
378 process_call_subr (op, CSType_GlobalSubr, env, param, env.globalSubrs, param.global_closure);
379 break;
380
381 default:
382 SUPER::process_op (op, env, param);
383 param.current_parsed_str->add_op (op, env.substr);
384 break;
385 }
386 }
387
Michiharu Arizad56e3382018-10-31 22:30:34 -0700388 protected:
389 static inline void process_call_subr (OpCode op, CSType type,
390 CFF1CSInterpEnv &env, SubrSubsetParam& param,
391 CFF1BiasedSubrs& subrs, hb_set_t *closure)
392 {
393 SubByteStr substr = env.substr;
394 env.callSubr (subrs, type);
Michiharu Ariza6186dbf2018-11-01 17:25:23 -0700395 param.current_parsed_str->add_call_op (op, substr, env.context.subr_num);
Michiharu Arizad56e3382018-10-31 22:30:34 -0700396 hb_set_add (closure, env.context.subr_num);
397 param.set_current_str (env);
398 }
399
400 private:
401 typedef CFF1CSOpSet<CFF1CSOpSet_SubrSubset, SubrSubsetParam> SUPER;
402};
403
404struct CFF1SubrSubsetter : SubrSubsetter<CFF1SubrSubsetter, CFF1Subrs, const OT::cff1::accelerator_subset_t, CFF1CSInterpEnv, CFF1CSOpSet_SubrSubset>
405{
Michiharu Ariza191ca0f2018-11-03 22:42:22 -0700406 static inline void finalize_parsed_str (CFF1CSInterpEnv &env, SubrSubsetParam& param, ParsedCStr &charstring)
Michiharu Arizad56e3382018-10-31 22:30:34 -0700407 {
Michiharu Ariza191ca0f2018-11-03 22:42:22 -0700408 /* insert width at the beginning of the charstring as necessary */
Michiharu Ariza1bc710a2018-11-02 15:28:01 -0700409 if (env.has_width)
Michiharu Arizad56e3382018-10-31 22:30:34 -0700410 charstring.set_prefix (env.width);
Michiharu Ariza191ca0f2018-11-03 22:42:22 -0700411
412 /* subroutines/charstring left on the call stack are legally left unmarked
413 * unmarked when a subroutine terminates with endchar. mark them.
414 */
415 param.current_parsed_str->set_parsed ();
416 for (unsigned int i = 0; i < env.callStack.get_count (); i++)
417 {
418 ParsedCStr *parsed_str = param.get_parsed_str_for_context (env.callStack[i]);
419 if (likely (parsed_str != nullptr))
420 parsed_str->set_parsed ();
421 else
422 env.set_error ();
423 }
Michiharu Arizad56e3382018-10-31 22:30:34 -0700424 }
425};
426
Michiharu Ariza64c54122018-08-10 11:07:07 -0700427struct cff_subset_plan {
428 inline cff_subset_plan (void)
429 : final_size (0),
Michiharu Arizaa11420b2018-08-29 12:14:30 -0700430 offsets (),
Michiharu Arizad7b384a2018-10-02 21:08:36 -0700431 orig_fdcount (0),
Michiharu Arizae9cc71a2018-10-02 20:44:30 -0700432 subset_fdcount (1),
Michiharu Ariza51d5bf42018-10-02 14:38:06 -0700433 subset_fdselect_format (0),
Michiharu Arizad56e3382018-10-31 22:30:34 -0700434 drop_hints (false),
435 desubroutinize(false)
Michiharu Ariza64c54122018-08-10 11:07:07 -0700436 {
437 topdict_sizes.init ();
438 topdict_sizes.resize (1);
Michiharu Arizaaca73c92018-09-06 17:28:15 -0700439 topdict_mod.init ();
Michiharu Ariza0f159a32018-09-12 16:08:54 -0700440 subset_fdselect_ranges.init ();
Michiharu Ariza64c54122018-08-10 11:07:07 -0700441 fdmap.init ();
442 subset_charstrings.init ();
Michiharu Arizad56e3382018-10-31 22:30:34 -0700443 subset_globalsubrs.init ();
444 subset_localsubrs.init ();
Michiharu Ariza1666b892018-09-10 16:00:20 -0700445 fontdicts_mod.init ();
Michiharu Arizaaca73c92018-09-06 17:28:15 -0700446 subset_enc_code_ranges.init ();
447 subset_enc_supp_codes.init ();
448 subset_charset_ranges.init ();
Michiharu Ariza1666b892018-09-10 16:00:20 -0700449 sidmap.init ();
Michiharu Arizac6f75c32018-09-10 17:02:31 -0700450 for (unsigned int i = 0; i < NameDictValues::ValCount; i++)
Michiharu Ariza1666b892018-09-10 16:00:20 -0700451 topDictModSIDs[i] = CFF_UNDEF_SID;
Michiharu Ariza64c54122018-08-10 11:07:07 -0700452 }
453
454 inline ~cff_subset_plan (void)
455 {
456 topdict_sizes.fini ();
Michiharu Arizaaca73c92018-09-06 17:28:15 -0700457 topdict_mod.fini ();
Michiharu Ariza0f159a32018-09-12 16:08:54 -0700458 subset_fdselect_ranges.fini ();
Michiharu Ariza64c54122018-08-10 11:07:07 -0700459 fdmap.fini ();
Michiharu Arizaa9c305c2018-11-01 10:31:21 -0700460 subset_charstrings.fini_deep ();
461 subset_globalsubrs.fini_deep ();
Michiharu Arizad56e3382018-10-31 22:30:34 -0700462 subset_localsubrs.fini_deep ();
Michiharu Ariza1666b892018-09-10 16:00:20 -0700463 fontdicts_mod.fini ();
Michiharu Arizaaca73c92018-09-06 17:28:15 -0700464 subset_enc_code_ranges.fini ();
465 subset_enc_supp_codes.init ();
466 subset_charset_ranges.fini ();
Michiharu Ariza1666b892018-09-10 16:00:20 -0700467 sidmap.fini ();
468 fontdicts_mod.fini ();
Michiharu Arizaaca73c92018-09-06 17:28:15 -0700469 }
470
471 inline unsigned int plan_subset_encoding (const OT::cff1::accelerator_subset_t &acc, hb_subset_plan_t *plan)
472 {
473 const Encoding *encoding = acc.encoding;
474 unsigned int size0, size1, supp_size;
475 hb_codepoint_t code, last_code = CFF_UNDEF_CODE;
476 hb_vector_t<hb_codepoint_t> supp_codes;
477
478 subset_enc_code_ranges.resize (0);
479 supp_size = 0;
480 supp_codes.init ();
481
482 subset_enc_num_codes = plan->glyphs.len - 1;
483 unsigned int glyph;
484 for (glyph = 1; glyph < plan->glyphs.len; glyph++)
485 {
486 hb_codepoint_t orig_glyph = plan->glyphs[glyph];
487 code = acc.glyph_to_code (orig_glyph);
488 if (code == CFF_UNDEF_CODE)
489 {
490 subset_enc_num_codes = glyph - 1;
491 break;
492 }
493
494 if (code != last_code + 1)
495 {
Michiharu Arizaaca73c92018-09-06 17:28:15 -0700496 code_pair pair = { code, glyph };
497 subset_enc_code_ranges.push (pair);
498 }
499 last_code = code;
500
501 if (encoding != &Null(Encoding))
502 {
503 hb_codepoint_t sid = acc.glyph_to_sid (orig_glyph);
504 encoding->get_supplement_codes (sid, supp_codes);
505 for (unsigned int i = 0; i < supp_codes.len; i++)
506 {
507 code_pair pair = { supp_codes[i], sid };
508 subset_enc_supp_codes.push (pair);
509 }
510 supp_size += SuppEncoding::static_size * supp_codes.len;
511 }
512 }
513 supp_codes.fini ();
Michiharu Ariza16084812018-09-12 13:22:19 -0700514
515 subset_enc_code_ranges.finalize (glyph);
Michiharu Arizaaca73c92018-09-06 17:28:15 -0700516
517 assert (subset_enc_num_codes <= 0xFF);
518 size0 = Encoding0::min_size + HBUINT8::static_size * subset_enc_num_codes;
519 size1 = Encoding1::min_size + Encoding1_Range::static_size * subset_enc_code_ranges.len;
520
521 if (size0 < size1)
522 subset_enc_format = 0;
523 else
524 subset_enc_format = 1;
525
526 return Encoding::calculate_serialized_size (
527 subset_enc_format,
528 subset_enc_format? subset_enc_code_ranges.len: subset_enc_num_codes,
529 subset_enc_supp_codes.len);
530 }
531
532 inline unsigned int plan_subset_charset (const OT::cff1::accelerator_subset_t &acc, hb_subset_plan_t *plan)
533 {
Michiharu Arizaaca73c92018-09-06 17:28:15 -0700534 unsigned int size0, size_ranges;
535 hb_codepoint_t sid, last_sid = CFF_UNDEF_CODE;
Michiharu Arizaaca73c92018-09-06 17:28:15 -0700536
537 subset_charset_ranges.resize (0);
538 unsigned int glyph;
539 for (glyph = 1; glyph < plan->glyphs.len; glyph++)
540 {
541 hb_codepoint_t orig_glyph = plan->glyphs[glyph];
542 sid = acc.glyph_to_sid (orig_glyph);
543
Michiharu Ariza1666b892018-09-10 16:00:20 -0700544 if (!acc.is_CID ())
545 sid = sidmap.add (sid);
546
Michiharu Arizaaca73c92018-09-06 17:28:15 -0700547 if (sid != last_sid + 1)
548 {
Michiharu Arizaaca73c92018-09-06 17:28:15 -0700549 code_pair pair = { sid, glyph };
550 subset_charset_ranges.push (pair);
551 }
552 last_sid = sid;
553 }
554
Michiharu Arizaa6da9b92018-11-16 17:29:03 -0800555 bool two_byte = subset_charset_ranges.finalize (glyph);
Michiharu Arizaaca73c92018-09-06 17:28:15 -0700556
557 size0 = Charset0::min_size + HBUINT16::static_size * (plan->glyphs.len - 1);
558 if (!two_byte)
559 size_ranges = Charset1::min_size + Charset1_Range::static_size * subset_charset_ranges.len;
560 else
561 size_ranges = Charset2::min_size + Charset2_Range::static_size * subset_charset_ranges.len;
562
563 if (size0 < size_ranges)
564 subset_charset_format = 0;
565 else if (!two_byte)
566 subset_charset_format = 1;
567 else
568 subset_charset_format = 2;
569
570 return Charset::calculate_serialized_size (
571 subset_charset_format,
572 subset_charset_format? subset_charset_ranges.len: plan->glyphs.len);
Michiharu Ariza64c54122018-08-10 11:07:07 -0700573 }
574
Michiharu Ariza1666b892018-09-10 16:00:20 -0700575 inline bool collect_sids_in_dicts (const OT::cff1::accelerator_subset_t &acc)
576 {
577 if (unlikely (!sidmap.reset (acc.stringIndex->count)))
578 return false;
579
Michiharu Arizac6f75c32018-09-10 17:02:31 -0700580 for (unsigned int i = 0; i < NameDictValues::ValCount; i++)
Michiharu Ariza1666b892018-09-10 16:00:20 -0700581 {
582 unsigned int sid = acc.topDict.nameSIDs[i];
583 if (sid != CFF_UNDEF_SID)
584 {
585 (void)sidmap.add (sid);
586 topDictModSIDs[i] = sidmap[sid];
587 }
588 }
589
590 if (acc.fdArray != &Null(CFF1FDArray))
Michiharu Arizad56e3382018-10-31 22:30:34 -0700591 for (unsigned int i = 0; i < orig_fdcount; i++)
592 if (fdmap.includes (i))
593 (void)sidmap.add (acc.fontDicts[i].fontName);
Michiharu Ariza1666b892018-09-10 16:00:20 -0700594
595 return true;
596 }
597
Michiharu Arizae67bb3f2018-08-16 00:25:57 -0700598 inline bool create (const OT::cff1::accelerator_subset_t &acc,
Michiharu Ariza64c54122018-08-10 11:07:07 -0700599 hb_subset_plan_t *plan)
600 {
Michiharu Arizaaca73c92018-09-06 17:28:15 -0700601 /* make sure notdef is first */
Michiharu Arizad8c69132018-11-30 18:58:14 -0800602 if ((plan->glyphs.len == 0) || (plan->glyphs[0] != 0)) return false;
Michiharu Arizaaca73c92018-09-06 17:28:15 -0700603
Michiharu Ariza64c54122018-08-10 11:07:07 -0700604 final_size = 0;
Michiharu Arizaaca73c92018-09-06 17:28:15 -0700605 num_glyphs = plan->glyphs.len;
Michiharu Ariza64c54122018-08-10 11:07:07 -0700606 orig_fdcount = acc.fdCount;
Michiharu Ariza5cde2f52018-08-17 16:50:13 -0700607 drop_hints = plan->drop_hints;
Michiharu Ariza6186dbf2018-11-01 17:25:23 -0700608 desubroutinize = plan->desubroutinize;
Michiharu Ariza64c54122018-08-10 11:07:07 -0700609
Michiharu Arizaaca73c92018-09-06 17:28:15 -0700610 /* check whether the subset renumbers any glyph IDs */
611 gid_renum = false;
612 for (unsigned int glyph = 0; glyph < plan->glyphs.len; glyph++)
613 {
614 if (plan->glyphs[glyph] != glyph) {
615 gid_renum = true;
616 break;
617 }
618 }
619
620 subset_charset = gid_renum || !acc.is_predef_charset ();
Michiharu Arizaebeccf32018-09-18 17:24:30 -0700621 subset_encoding = !acc.is_CID() && !acc.is_predef_encoding ();
Michiharu Arizaaca73c92018-09-06 17:28:15 -0700622
Michiharu Ariza64c54122018-08-10 11:07:07 -0700623 /* CFF header */
Michiharu Arizae67bb3f2018-08-16 00:25:57 -0700624 final_size += OT::cff1::static_size;
Michiharu Ariza64c54122018-08-10 11:07:07 -0700625
626 /* Name INDEX */
627 offsets.nameIndexOffset = final_size;
628 final_size += acc.nameIndex->get_size ();
Michiharu Arizaaca73c92018-09-06 17:28:15 -0700629
Michiharu Ariza64c54122018-08-10 11:07:07 -0700630 /* top dict INDEX */
631 {
Michiharu Arizaaca73c92018-09-06 17:28:15 -0700632 /* Add encoding/charset to a (copy of) top dict as necessary */
Michiharu Ariza1666b892018-09-10 16:00:20 -0700633 topdict_mod.init (&acc.topDict);
Michiharu Arizad56e3382018-10-31 22:30:34 -0700634 bool need_to_add_enc = (subset_encoding && !acc.topDict.has_op (OpCode_Encoding));
635 bool need_to_add_set = (subset_charset && !acc.topDict.has_op (OpCode_charset));
Michiharu Arizaaca73c92018-09-06 17:28:15 -0700636 if (need_to_add_enc || need_to_add_set)
637 {
638 if (need_to_add_enc)
Michiharu Arizad56e3382018-10-31 22:30:34 -0700639 topdict_mod.add_op (OpCode_Encoding);
Michiharu Arizaaca73c92018-09-06 17:28:15 -0700640 if (need_to_add_set)
Michiharu Arizad56e3382018-10-31 22:30:34 -0700641 topdict_mod.add_op (OpCode_charset);
Michiharu Arizaaca73c92018-09-06 17:28:15 -0700642 }
Michiharu Ariza633ce882018-08-15 12:00:19 -0700643 offsets.topDictInfo.offset = final_size;
Michiharu Arizafdbfa182018-08-16 00:13:09 -0700644 CFF1TopDict_OpSerializer topSzr;
Michiharu Arizaaca73c92018-09-06 17:28:15 -0700645 unsigned int topDictSize = TopDict::calculate_serialized_size (topdict_mod, topSzr);
Michiharu Ariza633ce882018-08-15 12:00:19 -0700646 offsets.topDictInfo.offSize = calcOffSize(topDictSize);
Michiharu Arizaaca73c92018-09-06 17:28:15 -0700647 final_size += CFF1IndexOf<TopDict>::calculate_serialized_size<CFF1TopDictValuesMod>
648 (offsets.topDictInfo.offSize,
649 &topdict_mod, 1, topdict_sizes, topSzr);
Michiharu Ariza64c54122018-08-10 11:07:07 -0700650 }
651
Michiharu Ariza1666b892018-09-10 16:00:20 -0700652 /* Determine re-mapping of font index as fdmap among other info */
Michiharu Arizab6903bd2018-11-16 13:46:58 -0800653 if (acc.fdSelect != &Null(CFF1FDSelect))
654 {
655 if (unlikely (!hb_plan_subset_cff_fdselect (plan->glyphs,
Michiharu Ariza1666b892018-09-10 16:00:20 -0700656 orig_fdcount,
657 *acc.fdSelect,
658 subset_fdcount,
659 offsets.FDSelectInfo.size,
660 subset_fdselect_format,
Michiharu Ariza0f159a32018-09-12 16:08:54 -0700661 subset_fdselect_ranges,
Michiharu Ariza1666b892018-09-10 16:00:20 -0700662 fdmap)))
663 return false;
Michiharu Arizab6903bd2018-11-16 13:46:58 -0800664 }
665 else
666 fdmap.identity (1);
Michiharu Ariza1666b892018-09-10 16:00:20 -0700667
668 /* remove unused SIDs & reassign SIDs */
669 {
670 /* SIDs for name strings in dicts are added before glyph names so they fit in 16-bit int range */
671 if (unlikely (!collect_sids_in_dicts (acc)))
672 return false;
673 assert (sidmap.get_count () <= 0x8000);
674 if (subset_charset)
675 offsets.charsetInfo.size = plan_subset_charset (acc, plan);
676
677 topdict_mod.reassignSIDs (sidmap);
678 }
679
Michiharu Ariza64c54122018-08-10 11:07:07 -0700680 /* String INDEX */
Michiharu Ariza1666b892018-09-10 16:00:20 -0700681 {
682 offsets.stringIndexInfo.offset = final_size;
683 offsets.stringIndexInfo.size = acc.stringIndex->calculate_serialized_size (offsets.stringIndexInfo.offSize, sidmap);
684 final_size += offsets.stringIndexInfo.size;
685 }
Michiharu Ariza64c54122018-08-10 11:07:07 -0700686
Michiharu Arizad56e3382018-10-31 22:30:34 -0700687 if (desubroutinize)
Michiharu Ariza633ce882018-08-15 12:00:19 -0700688 {
Michiharu Arizaa11420b2018-08-29 12:14:30 -0700689 /* Flatten global & local subrs */
Michiharu Ariza8c5e03b2018-08-30 17:21:56 -0700690 SubrFlattener<const OT::cff1::accelerator_subset_t, CFF1CSInterpEnv, CFF1CSOpSet_Flatten>
691 flattener(acc, plan->glyphs, plan->drop_hints);
Michiharu Arizad56e3382018-10-31 22:30:34 -0700692 if (!flattener.flatten (subset_charstrings))
Michiharu Arizaa11420b2018-08-29 12:14:30 -0700693 return false;
694
695 /* no global/local subroutines */
Michiharu Ariza1bc710a2018-11-02 15:28:01 -0700696 offsets.globalSubrsInfo.size = CFF1Subrs::calculate_serialized_size (1, 0, 0);
Michiharu Arizaa11420b2018-08-29 12:14:30 -0700697 }
Michiharu Arizad56e3382018-10-31 22:30:34 -0700698 else
699 {
700 /* Subset subrs: collect used subroutines, leaving all unused ones behind */
701 if (!subr_subsetter.subset (acc, plan->glyphs, plan->drop_hints))
702 return false;
703
704 /* encode charstrings, global subrs, local subrs with new subroutine numbers */
705 if (!subr_subsetter.encode_charstrings (acc, plan->glyphs, subset_charstrings))
706 return false;
707
708 if (!subr_subsetter.encode_globalsubrs (subset_globalsubrs))
709 return false;
710
711 /* global subrs */
712 unsigned int dataSize = subset_globalsubrs.total_size ();
713 offsets.globalSubrsInfo.offSize = calcOffSize (dataSize);
714 offsets.globalSubrsInfo.size = CFF1Subrs::calculate_serialized_size (offsets.globalSubrsInfo.offSize, subset_globalsubrs.len, dataSize);
715
716 /* local subrs */
717 if (!offsets.localSubrsInfos.resize (orig_fdcount))
718 return false;
719 if (!subset_localsubrs.resize (orig_fdcount))
720 return false;
721 for (unsigned int fd = 0; fd < orig_fdcount; fd++)
722 {
723 subset_localsubrs[fd].init ();
Michiharu Ariza1bc710a2018-11-02 15:28:01 -0700724 offsets.localSubrsInfos[fd].init ();
Michiharu Arizad56e3382018-10-31 22:30:34 -0700725 if (fdmap.includes (fd))
726 {
727 if (!subr_subsetter.encode_localsubrs (fd, subset_localsubrs[fd]))
728 return false;
729
730 unsigned int dataSize = subset_localsubrs[fd].total_size ();
Michiharu Ariza1bc710a2018-11-02 15:28:01 -0700731 if (dataSize > 0)
732 {
733 offsets.localSubrsInfos[fd].offset = final_size;
734 offsets.localSubrsInfos[fd].offSize = calcOffSize (dataSize);
735 offsets.localSubrsInfos[fd].size = CFF1Subrs::calculate_serialized_size (offsets.localSubrsInfos[fd].offSize, subset_localsubrs[fd].len, dataSize);
736 }
Michiharu Arizad56e3382018-10-31 22:30:34 -0700737 }
738 }
739 }
Michiharu Arizacc52e532018-09-10 16:27:49 -0700740
Michiharu Ariza64c54122018-08-10 11:07:07 -0700741 /* global subrs */
Michiharu Ariza633ce882018-08-15 12:00:19 -0700742 offsets.globalSubrsInfo.offset = final_size;
743 final_size += offsets.globalSubrsInfo.size;
Michiharu Ariza64c54122018-08-10 11:07:07 -0700744
745 /* Encoding */
Michiharu Arizaecdb77f2018-11-15 10:54:15 -0800746 if (!subset_encoding)
Michiharu Ariza9228db02018-10-13 17:25:09 -0700747 offsets.encodingOffset = acc.topDict.EncodingOffset;
748 else
Michiharu Arizaecdb77f2018-11-15 10:54:15 -0800749 {
Michiharu Ariza9228db02018-10-13 17:25:09 -0700750 offsets.encodingOffset = final_size;
Michiharu Arizaaca73c92018-09-06 17:28:15 -0700751 final_size += plan_subset_encoding (acc, plan);
Michiharu Arizaecdb77f2018-11-15 10:54:15 -0800752 }
Michiharu Ariza64c54122018-08-10 11:07:07 -0700753
754 /* Charset */
Michiharu Ariza9228db02018-10-13 17:25:09 -0700755 if (!subset_charset && acc.is_predef_charset ())
756 offsets.charsetInfo.offset = acc.topDict.CharsetOffset;
757 else
758 offsets.charsetInfo.offset = final_size;
Michiharu Ariza1666b892018-09-10 16:00:20 -0700759 final_size += offsets.charsetInfo.size;
Michiharu Ariza64c54122018-08-10 11:07:07 -0700760
761 /* FDSelect */
Michiharu Arizafdbfa182018-08-16 00:13:09 -0700762 if (acc.fdSelect != &Null(CFF1FDSelect))
Michiharu Ariza64c54122018-08-10 11:07:07 -0700763 {
764 offsets.FDSelectInfo.offset = final_size;
Michiharu Ariza64c54122018-08-10 11:07:07 -0700765 final_size += offsets.FDSelectInfo.size;
766 }
767
768 /* FDArray (FDIndex) */
Michiharu Arizafdbfa182018-08-16 00:13:09 -0700769 if (acc.fdArray != &Null(CFF1FDArray)) {
Michiharu Ariza633ce882018-08-15 12:00:19 -0700770 offsets.FDArrayInfo.offset = final_size;
Michiharu Ariza1666b892018-09-10 16:00:20 -0700771 CFF1FontDict_OpSerializer fontSzr;
772 unsigned int dictsSize = 0;
773 for (unsigned int i = 0; i < acc.fontDicts.len; i++)
Michiharu Arizad56e3382018-10-31 22:30:34 -0700774 if (fdmap.includes (i))
Michiharu Ariza1666b892018-09-10 16:00:20 -0700775 dictsSize += FontDict::calculate_serialized_size (acc.fontDicts[i], fontSzr);
776
Michiharu Ariza5b453f72018-09-11 16:20:39 -0700777 offsets.FDArrayInfo.offSize = calcOffSize (dictsSize);
Michiharu Ariza1666b892018-09-10 16:00:20 -0700778 final_size += CFF1Index::calculate_serialized_size (offsets.FDArrayInfo.offSize, subset_fdcount, dictsSize);
Michiharu Ariza64c54122018-08-10 11:07:07 -0700779 }
780
781 /* CharStrings */
782 {
Michiharu Ariza633ce882018-08-15 12:00:19 -0700783 offsets.charStringsInfo.offset = final_size;
Michiharu Arizad56e3382018-10-31 22:30:34 -0700784 unsigned int dataSize = subset_charstrings.total_size ();
Michiharu Ariza5b453f72018-09-11 16:20:39 -0700785 offsets.charStringsInfo.offSize = calcOffSize (dataSize);
Michiharu Arizafdbfa182018-08-16 00:13:09 -0700786 final_size += CFF1CharStrings::calculate_serialized_size (offsets.charStringsInfo.offSize, plan->glyphs.len, dataSize);
Michiharu Ariza64c54122018-08-10 11:07:07 -0700787 }
788
789 /* private dicts & local subrs */
790 offsets.privateDictInfo.offset = final_size;
791 for (unsigned int i = 0; i < orig_fdcount; i++)
792 {
Michiharu Arizad56e3382018-10-31 22:30:34 -0700793 if (fdmap.includes (i))
Michiharu Arizaa97ed342018-08-10 12:55:22 -0700794 {
Michiharu Ariza191ca0f2018-11-03 22:42:22 -0700795 bool has_localsubrs = offsets.localSubrsInfos[i].size > 0;
Michiharu Arizad56e3382018-10-31 22:30:34 -0700796 CFFPrivateDict_OpSerializer privSzr (desubroutinize, plan->drop_hints);
Michiharu Ariza191ca0f2018-11-03 22:42:22 -0700797 unsigned int priv_size = PrivateDict::calculate_serialized_size (acc.privateDicts[i], privSzr, has_localsubrs);
Michiharu Ariza5cde2f52018-08-17 16:50:13 -0700798 TableInfo privInfo = { final_size, priv_size, 0 };
Michiharu Ariza1666b892018-09-10 16:00:20 -0700799 FontDictValuesMod fontdict_mod;
Michiharu Arizab6903bd2018-11-16 13:46:58 -0800800 if (!acc.is_CID ())
801 fontdict_mod.init ( &Null(CFF1FontDictValues), CFF_UNDEF_SID, privInfo );
802 else
803 fontdict_mod.init ( &acc.fontDicts[i], sidmap[acc.fontDicts[i].fontName], privInfo );
Michiharu Ariza1666b892018-09-10 16:00:20 -0700804 fontdicts_mod.push (fontdict_mod);
Michiharu Arizaa11420b2018-08-29 12:14:30 -0700805 final_size += privInfo.size;
Michiharu Arizad56e3382018-10-31 22:30:34 -0700806
Michiharu Ariza191ca0f2018-11-03 22:42:22 -0700807 if (!plan->desubroutinize && has_localsubrs)
Michiharu Ariza1bc710a2018-11-02 15:28:01 -0700808 {
809 offsets.localSubrsInfos[i].offset = final_size;
Michiharu Arizad56e3382018-10-31 22:30:34 -0700810 final_size += offsets.localSubrsInfos[i].size;
Michiharu Ariza1bc710a2018-11-02 15:28:01 -0700811 }
Michiharu Arizaa97ed342018-08-10 12:55:22 -0700812 }
Michiharu Ariza64c54122018-08-10 11:07:07 -0700813 }
814
815 if (!acc.is_CID ())
Michiharu Arizad8c69132018-11-30 18:58:14 -0800816 offsets.privateDictInfo = fontdicts_mod[0].privateDictInfo;
Michiharu Ariza64c54122018-08-10 11:07:07 -0700817
Michiharu Arizad56e3382018-10-31 22:30:34 -0700818 return ((subset_charstrings.len == plan->glyphs.len)
819 && (fontdicts_mod.len == subset_fdcount));
Michiharu Ariza64c54122018-08-10 11:07:07 -0700820 }
821
822 inline unsigned int get_final_size (void) const { return final_size; }
823
Michiharu Arizaaca73c92018-09-06 17:28:15 -0700824 unsigned int final_size;
Michiharu Ariza64c54122018-08-10 11:07:07 -0700825 hb_vector_t<unsigned int> topdict_sizes;
Michiharu Arizaaca73c92018-09-06 17:28:15 -0700826 CFF1TopDictValuesMod topdict_mod;
827 CFF1SubTableOffsets offsets;
Michiharu Ariza64c54122018-08-10 11:07:07 -0700828
Michiharu Arizaaca73c92018-09-06 17:28:15 -0700829 unsigned int num_glyphs;
Michiharu Ariza64c54122018-08-10 11:07:07 -0700830 unsigned int orig_fdcount;
Michiharu Arizaaca73c92018-09-06 17:28:15 -0700831 unsigned int subset_fdcount;
Michiharu Arizaaca73c92018-09-06 17:28:15 -0700832 unsigned int subset_fdselect_format;
Michiharu Ariza0f159a32018-09-12 16:08:54 -0700833 hb_vector_t<code_pair> subset_fdselect_ranges;
Michiharu Ariza64c54122018-08-10 11:07:07 -0700834
835 /* font dict index remap table from fullset FDArray to subset FDArray.
Michiharu Ariza1666b892018-09-10 16:00:20 -0700836 * set to CFF_UNDEF_CODE if excluded from subset */
837 Remap fdmap;
Michiharu Ariza64c54122018-08-10 11:07:07 -0700838
Michiharu Arizad56e3382018-10-31 22:30:34 -0700839 StrBuffArray subset_charstrings;
840 StrBuffArray subset_globalsubrs;
841 hb_vector_t<StrBuffArray> subset_localsubrs;
Michiharu Ariza1666b892018-09-10 16:00:20 -0700842 hb_vector_t<FontDictValuesMod> fontdicts_mod;
Michiharu Ariza633ce882018-08-15 12:00:19 -0700843
Michiharu Arizaaca73c92018-09-06 17:28:15 -0700844 bool drop_hints;
845
846 bool gid_renum;
847 bool subset_encoding;
848 uint8_t subset_enc_format;
849 unsigned int subset_enc_num_codes;
Michiharu Ariza16084812018-09-12 13:22:19 -0700850 RangeList subset_enc_code_ranges;
Michiharu Arizaaca73c92018-09-06 17:28:15 -0700851 hb_vector_t<code_pair> subset_enc_supp_codes;
852
853 uint8_t subset_charset_format;
Michiharu Ariza16084812018-09-12 13:22:19 -0700854 RangeList subset_charset_ranges;
Michiharu Arizaaca73c92018-09-06 17:28:15 -0700855 bool subset_charset;
Michiharu Ariza1666b892018-09-10 16:00:20 -0700856
857 RemapSID sidmap;
Michiharu Arizac6f75c32018-09-10 17:02:31 -0700858 unsigned int topDictModSIDs[NameDictValues::ValCount];
Michiharu Arizad56e3382018-10-31 22:30:34 -0700859
860 bool desubroutinize;
861 CFF1SubrSubsetter subr_subsetter;
Michiharu Ariza64c54122018-08-10 11:07:07 -0700862};
863
Michiharu Arizafdbfa182018-08-16 00:13:09 -0700864static inline bool _write_cff1 (const cff_subset_plan &plan,
Michiharu Arizae67bb3f2018-08-16 00:25:57 -0700865 const OT::cff1::accelerator_subset_t &acc,
Michiharu Ariza64c54122018-08-10 11:07:07 -0700866 const hb_vector_t<hb_codepoint_t>& glyphs,
867 unsigned int dest_sz,
868 void *dest)
869{
870 hb_serialize_context_t c (dest, dest_sz);
871
Michiharu Arizac2348392018-08-15 13:04:43 -0700872 char RETURN_OP[1] = { OpCode_return };
Michiharu Ariza270452a2018-08-15 13:15:08 -0700873 const ByteStr NULL_SUBR (RETURN_OP, 1);
Michiharu Arizac2348392018-08-15 13:04:43 -0700874
Michiharu Arizae67bb3f2018-08-16 00:25:57 -0700875 OT::cff1 *cff = c.start_serialize<OT::cff1> ();
Michiharu Ariza64c54122018-08-10 11:07:07 -0700876 if (unlikely (!c.extend_min (*cff)))
877 return false;
878
879 /* header */
880 cff->version.major.set (0x01);
881 cff->version.minor.set (0x00);
882 cff->nameIndex.set (cff->min_size);
883 cff->offSize.set (4); /* unused? */
884
885 /* name INDEX */
886 {
887 assert (cff->nameIndex == c.head - c.start);
Michiharu Arizafdbfa182018-08-16 00:13:09 -0700888 CFF1NameIndex *dest = c.start_embed<CFF1NameIndex> ();
Michiharu Ariza64c54122018-08-10 11:07:07 -0700889 if (unlikely (dest == nullptr)) return false;
890 if (unlikely (!dest->serialize (&c, *acc.nameIndex)))
891 {
892 DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF name INDEX");
893 return false;
894 }
895 }
896
897 /* top dict INDEX */
898 {
Michiharu Ariza633ce882018-08-15 12:00:19 -0700899 assert (plan.offsets.topDictInfo.offset == c.head - c.start);
Michiharu Arizafdbfa182018-08-16 00:13:09 -0700900 CFF1IndexOf<TopDict> *dest = c.start_embed< CFF1IndexOf<TopDict> > ();
Michiharu Ariza64c54122018-08-10 11:07:07 -0700901 if (dest == nullptr) return false;
Michiharu Arizafdbfa182018-08-16 00:13:09 -0700902 CFF1TopDict_OpSerializer topSzr;
Michiharu Ariza1666b892018-09-10 16:00:20 -0700903 TopDictModifiers modifier (plan.offsets, plan.topDictModSIDs);
Michiharu Arizaaca73c92018-09-06 17:28:15 -0700904 if (unlikely (!dest->serialize (&c, plan.offsets.topDictInfo.offSize,
905 &plan.topdict_mod, 1,
Michiharu Ariza1666b892018-09-10 16:00:20 -0700906 plan.topdict_sizes, topSzr, modifier)))
Michiharu Ariza64c54122018-08-10 11:07:07 -0700907 {
908 DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF top dict");
909 return false;
910 }
911 }
912
913 /* String INDEX */
914 {
Michiharu Ariza1666b892018-09-10 16:00:20 -0700915 assert (plan.offsets.stringIndexInfo.offset == c.head - c.start);
Michiharu Arizafdbfa182018-08-16 00:13:09 -0700916 CFF1StringIndex *dest = c.start_embed<CFF1StringIndex> ();
Michiharu Ariza64c54122018-08-10 11:07:07 -0700917 if (unlikely (dest == nullptr)) return false;
Michiharu Ariza1666b892018-09-10 16:00:20 -0700918 if (unlikely (!dest->serialize (&c, *acc.stringIndex, plan.offsets.stringIndexInfo.offSize, plan.sidmap)))
Michiharu Ariza64c54122018-08-10 11:07:07 -0700919 {
920 DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF string INDEX");
921 return false;
922 }
923 }
924
925 /* global subrs */
926 {
Michiharu Arizaa11420b2018-08-29 12:14:30 -0700927 assert (plan.offsets.globalSubrsInfo.offset != 0);
Michiharu Ariza633ce882018-08-15 12:00:19 -0700928 assert (plan.offsets.globalSubrsInfo.offset == c.head - c.start);
Michiharu Arizad56e3382018-10-31 22:30:34 -0700929
Michiharu Ariza1bc710a2018-11-02 15:28:01 -0700930 CFF1Subrs *dest = c.start_embed <CFF1Subrs> ();
931 if (unlikely (dest == nullptr)) return false;
932 if (unlikely (!dest->serialize (&c, plan.offsets.globalSubrsInfo.offSize, plan.subset_globalsubrs)))
Michiharu Arizad56e3382018-10-31 22:30:34 -0700933 {
Michiharu Ariza1bc710a2018-11-02 15:28:01 -0700934 DEBUG_MSG (SUBSET, nullptr, "failed to serialize global subroutines");
935 return false;
Michiharu Arizad56e3382018-10-31 22:30:34 -0700936 }
Michiharu Ariza64c54122018-08-10 11:07:07 -0700937 }
938
939 /* Encoding */
Michiharu Arizaaca73c92018-09-06 17:28:15 -0700940 if (plan.subset_encoding)
941 {
Michiharu Ariza64c54122018-08-10 11:07:07 -0700942 assert (plan.offsets.encodingOffset == c.head - c.start);
943 Encoding *dest = c.start_embed<Encoding> ();
944 if (unlikely (dest == nullptr)) return false;
Michiharu Arizaaca73c92018-09-06 17:28:15 -0700945 if (unlikely (!dest->serialize (&c,
946 plan.subset_enc_format,
947 plan.subset_enc_num_codes,
948 plan.subset_enc_code_ranges,
949 plan.subset_enc_supp_codes)))
Michiharu Ariza64c54122018-08-10 11:07:07 -0700950 {
951 DEBUG_MSG (SUBSET, nullptr, "failed to serialize Encoding");
952 return false;
953 }
954 }
955
956 /* Charset */
Michiharu Arizaaca73c92018-09-06 17:28:15 -0700957 if (plan.subset_charset)
Michiharu Ariza64c54122018-08-10 11:07:07 -0700958 {
Michiharu Ariza1666b892018-09-10 16:00:20 -0700959 assert (plan.offsets.charsetInfo.offset == c.head - c.start);
Michiharu Ariza64c54122018-08-10 11:07:07 -0700960 Charset *dest = c.start_embed<Charset> ();
961 if (unlikely (dest == nullptr)) return false;
Michiharu Arizaaca73c92018-09-06 17:28:15 -0700962 if (unlikely (!dest->serialize (&c,
963 plan.subset_charset_format,
964 plan.num_glyphs,
965 plan.subset_charset_ranges)))
Michiharu Ariza64c54122018-08-10 11:07:07 -0700966 {
967 DEBUG_MSG (SUBSET, nullptr, "failed to serialize Charset");
968 return false;
969 }
970 }
971
972 /* FDSelect */
Michiharu Arizafdbfa182018-08-16 00:13:09 -0700973 if (acc.fdSelect != &Null(CFF1FDSelect))
Michiharu Ariza64c54122018-08-10 11:07:07 -0700974 {
975 assert (plan.offsets.FDSelectInfo.offset == c.head - c.start);
976
Michiharu Ariza9d0231c2018-11-15 15:39:43 -0800977 if (unlikely (!hb_serialize_cff_fdselect (&c, glyphs.len, *acc.fdSelect, acc.fdCount,
978 plan.subset_fdselect_format, plan.offsets.FDSelectInfo.size,
979 plan.subset_fdselect_ranges)))
Michiharu Ariza64c54122018-08-10 11:07:07 -0700980 {
Michiharu Ariza9d0231c2018-11-15 15:39:43 -0800981 DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF subset FDSelect");
982 return false;
Michiharu Ariza64c54122018-08-10 11:07:07 -0700983 }
984 }
985
986 /* FDArray (FD Index) */
Michiharu Arizafdbfa182018-08-16 00:13:09 -0700987 if (acc.fdArray != &Null(CFF1FDArray))
Michiharu Ariza64c54122018-08-10 11:07:07 -0700988 {
Michiharu Ariza633ce882018-08-15 12:00:19 -0700989 assert (plan.offsets.FDArrayInfo.offset == c.head - c.start);
Michiharu Arizafdbfa182018-08-16 00:13:09 -0700990 CFF1FDArray *fda = c.start_embed<CFF1FDArray> ();
Michiharu Ariza64c54122018-08-10 11:07:07 -0700991 if (unlikely (fda == nullptr)) return false;
Michiharu Ariza1666b892018-09-10 16:00:20 -0700992 CFF1FontDict_OpSerializer fontSzr;
Michiharu Ariza633ce882018-08-15 12:00:19 -0700993 if (unlikely (!fda->serialize (&c, plan.offsets.FDArrayInfo.offSize,
Michiharu Ariza1666b892018-09-10 16:00:20 -0700994 plan.fontdicts_mod,
995 fontSzr)))
Michiharu Ariza64c54122018-08-10 11:07:07 -0700996 {
997 DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF FDArray");
998 return false;
999 }
1000 }
1001
1002 /* CharStrings */
1003 {
Michiharu Ariza633ce882018-08-15 12:00:19 -07001004 assert (plan.offsets.charStringsInfo.offset == c.head - c.start);
Michiharu Arizafdbfa182018-08-16 00:13:09 -07001005 CFF1CharStrings *cs = c.start_embed<CFF1CharStrings> ();
Michiharu Ariza64c54122018-08-10 11:07:07 -07001006 if (unlikely (cs == nullptr)) return false;
Michiharu Ariza633ce882018-08-15 12:00:19 -07001007 if (unlikely (!cs->serialize (&c, plan.offsets.charStringsInfo.offSize, plan.subset_charstrings)))
Michiharu Ariza64c54122018-08-10 11:07:07 -07001008 {
1009 DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF CharStrings");
1010 return false;
1011 }
1012 }
1013
1014 /* private dicts & local subrs */
1015 assert (plan.offsets.privateDictInfo.offset == c.head - c.start);
1016 for (unsigned int i = 0; i < acc.privateDicts.len; i++)
1017 {
Michiharu Ariza1bc710a2018-11-02 15:28:01 -07001018 if (plan.fdmap.includes (i))
Michiharu Ariza64c54122018-08-10 11:07:07 -07001019 {
Michiharu Arizaa97ed342018-08-10 12:55:22 -07001020 PrivateDict *pd = c.start_embed<PrivateDict> ();
1021 if (unlikely (pd == nullptr)) return false;
Michiharu Arizacc52e532018-09-10 16:27:49 -07001022 unsigned int priv_size = plan.fontdicts_mod[plan.fdmap[i]].privateDictInfo.size;
Michiharu Ariza5cde2f52018-08-17 16:50:13 -07001023 bool result;
Michiharu Arizad56e3382018-10-31 22:30:34 -07001024 CFFPrivateDict_OpSerializer privSzr (plan.desubroutinize, plan.drop_hints);
Michiharu Arizaa97ed342018-08-10 12:55:22 -07001025 /* N.B. local subrs immediately follows its corresponding private dict. i.e., subr offset == private dict size */
Michiharu Ariza191ca0f2018-11-03 22:42:22 -07001026 unsigned int subroffset = (plan.offsets.localSubrsInfos[i].size > 0)? priv_size: 0;
1027 result = pd->serialize (&c, acc.privateDicts[i], privSzr, subroffset);
Michiharu Ariza5cde2f52018-08-17 16:50:13 -07001028 if (unlikely (!result))
Michiharu Ariza64c54122018-08-10 11:07:07 -07001029 {
Michiharu Arizaa97ed342018-08-10 12:55:22 -07001030 DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF Private Dict[%d]", i);
Michiharu Ariza64c54122018-08-10 11:07:07 -07001031 return false;
1032 }
Michiharu Ariza1bc710a2018-11-02 15:28:01 -07001033 if (plan.offsets.localSubrsInfos[i].size > 0)
Michiharu Arizad56e3382018-10-31 22:30:34 -07001034 {
1035 CFF1Subrs *dest = c.start_embed <CFF1Subrs> ();
1036 if (unlikely (dest == nullptr)) return false;
1037 if (unlikely (!dest->serialize (&c, plan.offsets.localSubrsInfos[i].offSize, plan.subset_localsubrs[i])))
1038 {
1039 DEBUG_MSG (SUBSET, nullptr, "failed to serialize local subroutines");
1040 return false;
1041 }
1042 }
1043 }
1044 }
1045
Michiharu Arizacef75ea2018-08-17 13:13:18 -07001046 assert (c.head == c.end);
Michiharu Ariza64c54122018-08-10 11:07:07 -07001047 c.end_serialize ();
1048
1049 return true;
1050}
1051
1052static bool
Michiharu Arizae67bb3f2018-08-16 00:25:57 -07001053_hb_subset_cff1 (const OT::cff1::accelerator_subset_t &acc,
Michiharu Ariza64c54122018-08-10 11:07:07 -07001054 const char *data,
1055 hb_subset_plan_t *plan,
1056 hb_blob_t **prime /* OUT */)
1057{
1058 cff_subset_plan cff_plan;
1059
1060 if (unlikely (!cff_plan.create (acc, plan)))
1061 {
1062 DEBUG_MSG(SUBSET, nullptr, "Failed to generate a cff subsetting plan.");
1063 return false;
1064 }
1065
1066 unsigned int cff_prime_size = cff_plan.get_final_size ();
1067 char *cff_prime_data = (char *) calloc (1, cff_prime_size);
1068
Michiharu Arizafdbfa182018-08-16 00:13:09 -07001069 if (unlikely (!_write_cff1 (cff_plan, acc, plan->glyphs,
Michiharu Ariza64c54122018-08-10 11:07:07 -07001070 cff_prime_size, cff_prime_data))) {
1071 DEBUG_MSG(SUBSET, nullptr, "Failed to write a subset cff.");
1072 free (cff_prime_data);
1073 return false;
1074 }
1075
1076 *prime = hb_blob_create (cff_prime_data,
1077 cff_prime_size,
1078 HB_MEMORY_MODE_READONLY,
1079 cff_prime_data,
1080 free);
1081 return true;
1082}
1083
1084/**
Michiharu Arizafdbfa182018-08-16 00:13:09 -07001085 * hb_subset_cff1:
Michiharu Ariza64c54122018-08-10 11:07:07 -07001086 * Subsets the CFF table according to a provided plan.
1087 *
1088 * Return value: subsetted cff table.
1089 **/
1090bool
Michiharu Arizafdbfa182018-08-16 00:13:09 -07001091hb_subset_cff1 (hb_subset_plan_t *plan,
Michiharu Ariza64c54122018-08-10 11:07:07 -07001092 hb_blob_t **prime /* OUT */)
1093{
Michiharu Arizae67bb3f2018-08-16 00:25:57 -07001094 hb_blob_t *cff_blob = hb_sanitize_context_t().reference_table<CFF::cff1> (plan->source);
Michiharu Ariza64c54122018-08-10 11:07:07 -07001095 const char *data = hb_blob_get_data(cff_blob, nullptr);
1096
Michiharu Arizae67bb3f2018-08-16 00:25:57 -07001097 OT::cff1::accelerator_subset_t acc;
Michiharu Ariza64c54122018-08-10 11:07:07 -07001098 acc.init(plan->source);
1099 bool result = likely (acc.is_valid ()) &&
Michiharu Arizafdbfa182018-08-16 00:13:09 -07001100 _hb_subset_cff1 (acc, data, plan, prime);
Michiharu Ariza64c54122018-08-10 11:07:07 -07001101 hb_blob_destroy (cff_blob);
1102 acc.fini ();
1103
1104 return result;
1105}