blob: 8a75b8a936bfa375cd9c3c0aa55713b02b1ffe1c [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 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 {
49 if (is_std_std (sid))
50 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
95 inline unsigned getNumValues (void) const
96 {
97 return base->getNumValues () + SUPER::getNumValues ();
98 }
99 inline const CFF1TopDictVal &getValue (unsigned int i) const
100 {
101 if (i < base->getNumValues ())
102 return (*base)[i];
103 else
104 return SUPER::values[i - base->getNumValues ()];
105 }
106 inline const CFF1TopDictVal &operator [] (unsigned int i) const { return getValue (i); }
107
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
233 inline unsigned getNumValues (void) const
234 {
235 return base->getNumValues ();
236 }
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 Arizaebeccf32018-09-18 17:24:30 -0700273 static inline void flush_args_and_op (OpCode op, CFF1CSInterpEnv &env, FlattenParam& param, unsigned int start_arg = 0)
Michiharu Ariza5cde2f52018-08-17 16:50:13 -0700274 {
Michiharu Arizaebeccf32018-09-18 17:24:30 -0700275 start_arg = env.check_width ();
276 if ((start_arg > 0) && likely (param.flatStr.len == 0))
277 flush_width (env, param);
278
Michiharu Arizaa11420b2018-08-29 12:14:30 -0700279 switch (op)
280 {
Michiharu Ariza968168b2018-08-31 13:28:16 -0700281 case OpCode_hstem:
282 case OpCode_hstemhm:
283 case OpCode_vstem:
284 case OpCode_vstemhm:
Michiharu Arizaa11420b2018-08-29 12:14:30 -0700285 case OpCode_hintmask:
286 case OpCode_cntrmask:
Michiharu Ariza968168b2018-08-31 13:28:16 -0700287 case OpCode_hflex:
288 case OpCode_flex:
289 case OpCode_hflex1:
290 case OpCode_flex1:
Michiharu Ariza8c5e03b2018-08-30 17:21:56 -0700291 if (param.drop_hints)
292 {
Michiharu Ariza968168b2018-08-31 13:28:16 -0700293 env.clear_args ();
294 return;
Michiharu Ariza8c5e03b2018-08-30 17:21:56 -0700295 }
Michiharu Ariza35b64df2018-10-02 14:13:36 -0700296 HB_FALLTHROUGH;
297
Michiharu Arizaa11420b2018-08-29 12:14:30 -0700298 default:
Michiharu Arizaebeccf32018-09-18 17:24:30 -0700299 SUPER::flush_args_and_op (op, env, param, start_arg);
Michiharu Ariza968168b2018-08-31 13:28:16 -0700300 break;
Michiharu Arizaa11420b2018-08-29 12:14:30 -0700301 }
Michiharu Ariza5cde2f52018-08-17 16:50:13 -0700302 }
303
Michiharu Arizaebeccf32018-09-18 17:24:30 -0700304 static inline void flush_args (CFF1CSInterpEnv &env, FlattenParam& param, unsigned int start_arg = 0)
Michiharu Ariza5cde2f52018-08-17 16:50:13 -0700305 {
Michiharu Arizaebeccf32018-09-18 17:24:30 -0700306 for (unsigned int i = start_arg; i < env.argStack.get_count (); i++)
Michiharu Arizac0c85b82018-09-17 11:14:56 -0700307 param.flatStr.encode_num (env.argStack[i]);
Michiharu Arizaebeccf32018-09-18 17:24:30 -0700308 SUPER::flush_args (env, param, start_arg);
Michiharu Ariza968168b2018-08-31 13:28:16 -0700309 }
310
311 static inline void flush_op (OpCode op, CFF1CSInterpEnv &env, FlattenParam& param)
312 {
313 param.flatStr.encode_op (op);
314 }
315
Michiharu Arizaebeccf32018-09-18 17:24:30 -0700316 static inline void flush_width (CFF1CSInterpEnv &env, FlattenParam& param)
317 {
318 assert (env.has_width);
319 param.flatStr.encode_num (env.width);
320 }
321
Michiharu Ariza968168b2018-08-31 13:28:16 -0700322 static inline void flush_hintmask (OpCode op, CFF1CSInterpEnv &env, FlattenParam& param)
323 {
324 SUPER::flush_hintmask (op, env, param);
Michiharu Arizaf2d299b2018-09-04 10:25:21 -0700325 if (!param.drop_hints)
326 for (unsigned int i = 0; i < env.hintmask_size; i++)
327 param.flatStr.encode_byte (env.substr[i]);
Michiharu Ariza5cde2f52018-08-17 16:50:13 -0700328 }
Michiharu Arizaa11420b2018-08-29 12:14:30 -0700329
330 private:
Michiharu Ariza8c5e03b2018-08-30 17:21:56 -0700331 typedef CFF1CSOpSet<CFF1CSOpSet_Flatten, FlattenParam> SUPER;
Michiharu Ariza5cde2f52018-08-17 16:50:13 -0700332};
333
Michiharu Ariza16084812018-09-12 13:22:19 -0700334struct RangeList : hb_vector_t<code_pair>
335{
336 /* replace the first glyph ID in the "glyph" field each range with a nLeft value */
337 inline void finalize (unsigned int last_glyph)
338 {
339 for (unsigned int i = (*this).len; i > 0; i--)
340 {
341 code_pair &pair = (*this)[i - 1];
342 unsigned int nLeft = last_glyph - pair.glyph - 1;
343 last_glyph = pair.glyph;
344 pair.glyph = nLeft;
345 }
346 }
347};
348
Michiharu Ariza64c54122018-08-10 11:07:07 -0700349struct cff_subset_plan {
350 inline cff_subset_plan (void)
351 : final_size (0),
352 orig_fdcount (0),
Michiharu Arizaaca73c92018-09-06 17:28:15 -0700353 subset_fdcount (1),
Michiharu Arizaa11420b2018-08-29 12:14:30 -0700354 offsets (),
Michiharu Ariza51d5bf42018-10-02 14:38:06 -0700355 subset_fdselect_format (0),
Michiharu Arizaa11420b2018-08-29 12:14:30 -0700356 drop_hints (false)
Michiharu Ariza64c54122018-08-10 11:07:07 -0700357 {
358 topdict_sizes.init ();
359 topdict_sizes.resize (1);
Michiharu Arizaaca73c92018-09-06 17:28:15 -0700360 topdict_mod.init ();
Michiharu Ariza0f159a32018-09-12 16:08:54 -0700361 subset_fdselect_ranges.init ();
Michiharu Ariza64c54122018-08-10 11:07:07 -0700362 fdmap.init ();
363 subset_charstrings.init ();
Michiharu Arizaa11420b2018-08-29 12:14:30 -0700364 flat_charstrings.init ();
Michiharu Ariza1666b892018-09-10 16:00:20 -0700365 fontdicts_mod.init ();
Michiharu Arizaaca73c92018-09-06 17:28:15 -0700366 subset_enc_code_ranges.init ();
367 subset_enc_supp_codes.init ();
368 subset_charset_ranges.init ();
Michiharu Ariza1666b892018-09-10 16:00:20 -0700369 sidmap.init ();
Michiharu Arizac6f75c32018-09-10 17:02:31 -0700370 for (unsigned int i = 0; i < NameDictValues::ValCount; i++)
Michiharu Ariza1666b892018-09-10 16:00:20 -0700371 topDictModSIDs[i] = CFF_UNDEF_SID;
Michiharu Ariza64c54122018-08-10 11:07:07 -0700372 }
373
374 inline ~cff_subset_plan (void)
375 {
376 topdict_sizes.fini ();
Michiharu Arizaaca73c92018-09-06 17:28:15 -0700377 topdict_mod.fini ();
Michiharu Ariza0f159a32018-09-12 16:08:54 -0700378 subset_fdselect_ranges.fini ();
Michiharu Ariza64c54122018-08-10 11:07:07 -0700379 fdmap.fini ();
380 subset_charstrings.fini ();
Michiharu Arizaa11420b2018-08-29 12:14:30 -0700381 flat_charstrings.fini ();
Michiharu Ariza1666b892018-09-10 16:00:20 -0700382 fontdicts_mod.fini ();
Michiharu Arizaaca73c92018-09-06 17:28:15 -0700383 subset_enc_code_ranges.fini ();
384 subset_enc_supp_codes.init ();
385 subset_charset_ranges.fini ();
Michiharu Ariza1666b892018-09-10 16:00:20 -0700386 sidmap.fini ();
387 fontdicts_mod.fini ();
Michiharu Arizaaca73c92018-09-06 17:28:15 -0700388 }
389
390 inline unsigned int plan_subset_encoding (const OT::cff1::accelerator_subset_t &acc, hb_subset_plan_t *plan)
391 {
392 const Encoding *encoding = acc.encoding;
393 unsigned int size0, size1, supp_size;
394 hb_codepoint_t code, last_code = CFF_UNDEF_CODE;
395 hb_vector_t<hb_codepoint_t> supp_codes;
396
397 subset_enc_code_ranges.resize (0);
398 supp_size = 0;
399 supp_codes.init ();
400
401 subset_enc_num_codes = plan->glyphs.len - 1;
402 unsigned int glyph;
403 for (glyph = 1; glyph < plan->glyphs.len; glyph++)
404 {
405 hb_codepoint_t orig_glyph = plan->glyphs[glyph];
406 code = acc.glyph_to_code (orig_glyph);
407 if (code == CFF_UNDEF_CODE)
408 {
409 subset_enc_num_codes = glyph - 1;
410 break;
411 }
412
413 if (code != last_code + 1)
414 {
Michiharu Arizaaca73c92018-09-06 17:28:15 -0700415 code_pair pair = { code, glyph };
416 subset_enc_code_ranges.push (pair);
417 }
418 last_code = code;
419
420 if (encoding != &Null(Encoding))
421 {
422 hb_codepoint_t sid = acc.glyph_to_sid (orig_glyph);
423 encoding->get_supplement_codes (sid, supp_codes);
424 for (unsigned int i = 0; i < supp_codes.len; i++)
425 {
426 code_pair pair = { supp_codes[i], sid };
427 subset_enc_supp_codes.push (pair);
428 }
429 supp_size += SuppEncoding::static_size * supp_codes.len;
430 }
431 }
432 supp_codes.fini ();
Michiharu Ariza16084812018-09-12 13:22:19 -0700433
434 subset_enc_code_ranges.finalize (glyph);
Michiharu Arizaaca73c92018-09-06 17:28:15 -0700435
436 assert (subset_enc_num_codes <= 0xFF);
437 size0 = Encoding0::min_size + HBUINT8::static_size * subset_enc_num_codes;
438 size1 = Encoding1::min_size + Encoding1_Range::static_size * subset_enc_code_ranges.len;
439
440 if (size0 < size1)
441 subset_enc_format = 0;
442 else
443 subset_enc_format = 1;
444
445 return Encoding::calculate_serialized_size (
446 subset_enc_format,
447 subset_enc_format? subset_enc_code_ranges.len: subset_enc_num_codes,
448 subset_enc_supp_codes.len);
449 }
450
451 inline unsigned int plan_subset_charset (const OT::cff1::accelerator_subset_t &acc, hb_subset_plan_t *plan)
452 {
Michiharu Arizaaca73c92018-09-06 17:28:15 -0700453 unsigned int size0, size_ranges;
454 hb_codepoint_t sid, last_sid = CFF_UNDEF_CODE;
455 bool two_byte = false;
456
457 subset_charset_ranges.resize (0);
458 unsigned int glyph;
459 for (glyph = 1; glyph < plan->glyphs.len; glyph++)
460 {
461 hb_codepoint_t orig_glyph = plan->glyphs[glyph];
462 sid = acc.glyph_to_sid (orig_glyph);
463
Michiharu Ariza1666b892018-09-10 16:00:20 -0700464 if (!acc.is_CID ())
465 sid = sidmap.add (sid);
466
Michiharu Arizaaca73c92018-09-06 17:28:15 -0700467 if (sid != last_sid + 1)
468 {
Michiharu Arizaaca73c92018-09-06 17:28:15 -0700469 code_pair pair = { sid, glyph };
470 subset_charset_ranges.push (pair);
471 }
472 last_sid = sid;
473 }
474
Michiharu Ariza16084812018-09-12 13:22:19 -0700475 subset_charset_ranges.finalize (glyph);
Michiharu Arizaaca73c92018-09-06 17:28:15 -0700476
477 size0 = Charset0::min_size + HBUINT16::static_size * (plan->glyphs.len - 1);
478 if (!two_byte)
479 size_ranges = Charset1::min_size + Charset1_Range::static_size * subset_charset_ranges.len;
480 else
481 size_ranges = Charset2::min_size + Charset2_Range::static_size * subset_charset_ranges.len;
482
483 if (size0 < size_ranges)
484 subset_charset_format = 0;
485 else if (!two_byte)
486 subset_charset_format = 1;
487 else
488 subset_charset_format = 2;
489
490 return Charset::calculate_serialized_size (
491 subset_charset_format,
492 subset_charset_format? subset_charset_ranges.len: plan->glyphs.len);
Michiharu Ariza64c54122018-08-10 11:07:07 -0700493 }
494
Michiharu Ariza1666b892018-09-10 16:00:20 -0700495 inline bool collect_sids_in_dicts (const OT::cff1::accelerator_subset_t &acc)
496 {
497 if (unlikely (!sidmap.reset (acc.stringIndex->count)))
498 return false;
499
Michiharu Arizac6f75c32018-09-10 17:02:31 -0700500 for (unsigned int i = 0; i < NameDictValues::ValCount; i++)
Michiharu Ariza1666b892018-09-10 16:00:20 -0700501 {
502 unsigned int sid = acc.topDict.nameSIDs[i];
503 if (sid != CFF_UNDEF_SID)
504 {
505 (void)sidmap.add (sid);
506 topDictModSIDs[i] = sidmap[sid];
507 }
508 }
509
510 if (acc.fdArray != &Null(CFF1FDArray))
511 for (unsigned int fd = 0; fd < orig_fdcount; fd++)
512 if (!fdmap.excludes (fd))
513 (void)sidmap.add (acc.fontDicts[fd].fontName);
514
515 return true;
516 }
517
Michiharu Arizae67bb3f2018-08-16 00:25:57 -0700518 inline bool create (const OT::cff1::accelerator_subset_t &acc,
Michiharu Ariza64c54122018-08-10 11:07:07 -0700519 hb_subset_plan_t *plan)
520 {
Michiharu Arizaaca73c92018-09-06 17:28:15 -0700521 /* make sure notdef is first */
522 if ((plan->glyphs.len == 0) || (plan->glyphs[0] != 0)) return false;
523
Michiharu Ariza64c54122018-08-10 11:07:07 -0700524 final_size = 0;
Michiharu Arizaaca73c92018-09-06 17:28:15 -0700525 num_glyphs = plan->glyphs.len;
Michiharu Ariza64c54122018-08-10 11:07:07 -0700526 orig_fdcount = acc.fdCount;
Michiharu Ariza5cde2f52018-08-17 16:50:13 -0700527 drop_hints = plan->drop_hints;
Michiharu Ariza64c54122018-08-10 11:07:07 -0700528
Michiharu Arizaaca73c92018-09-06 17:28:15 -0700529 /* check whether the subset renumbers any glyph IDs */
530 gid_renum = false;
531 for (unsigned int glyph = 0; glyph < plan->glyphs.len; glyph++)
532 {
533 if (plan->glyphs[glyph] != glyph) {
534 gid_renum = true;
535 break;
536 }
537 }
538
539 subset_charset = gid_renum || !acc.is_predef_charset ();
Michiharu Arizaebeccf32018-09-18 17:24:30 -0700540 subset_encoding = !acc.is_CID() && !acc.is_predef_encoding ();
Michiharu Arizaaca73c92018-09-06 17:28:15 -0700541
Michiharu Ariza64c54122018-08-10 11:07:07 -0700542 /* CFF header */
Michiharu Arizae67bb3f2018-08-16 00:25:57 -0700543 final_size += OT::cff1::static_size;
Michiharu Ariza64c54122018-08-10 11:07:07 -0700544
545 /* Name INDEX */
546 offsets.nameIndexOffset = final_size;
547 final_size += acc.nameIndex->get_size ();
Michiharu Arizaaca73c92018-09-06 17:28:15 -0700548
Michiharu Ariza64c54122018-08-10 11:07:07 -0700549 /* top dict INDEX */
550 {
Michiharu Arizaaca73c92018-09-06 17:28:15 -0700551 /* Add encoding/charset to a (copy of) top dict as necessary */
Michiharu Ariza1666b892018-09-10 16:00:20 -0700552 topdict_mod.init (&acc.topDict);
553 bool need_to_add_enc = (subset_encoding && !acc.topDict.hasOp (OpCode_Encoding));
554 bool need_to_add_set = (subset_charset && !acc.topDict.hasOp (OpCode_charset));
Michiharu Arizaaca73c92018-09-06 17:28:15 -0700555 if (need_to_add_enc || need_to_add_set)
556 {
557 if (need_to_add_enc)
558 topdict_mod.addOp (OpCode_Encoding);
559 if (need_to_add_set)
560 topdict_mod.addOp (OpCode_charset);
561 }
Michiharu Ariza633ce882018-08-15 12:00:19 -0700562 offsets.topDictInfo.offset = final_size;
Michiharu Arizafdbfa182018-08-16 00:13:09 -0700563 CFF1TopDict_OpSerializer topSzr;
Michiharu Arizaaca73c92018-09-06 17:28:15 -0700564 unsigned int topDictSize = TopDict::calculate_serialized_size (topdict_mod, topSzr);
Michiharu Ariza633ce882018-08-15 12:00:19 -0700565 offsets.topDictInfo.offSize = calcOffSize(topDictSize);
Michiharu Arizaaca73c92018-09-06 17:28:15 -0700566 final_size += CFF1IndexOf<TopDict>::calculate_serialized_size<CFF1TopDictValuesMod>
567 (offsets.topDictInfo.offSize,
568 &topdict_mod, 1, topdict_sizes, topSzr);
Michiharu Ariza64c54122018-08-10 11:07:07 -0700569 }
570
Michiharu Ariza1666b892018-09-10 16:00:20 -0700571 /* Determine re-mapping of font index as fdmap among other info */
572 if (acc.fdSelect != &Null(CFF1FDSelect)
573 && unlikely (!hb_plan_subset_cff_fdselect (plan->glyphs,
574 orig_fdcount,
575 *acc.fdSelect,
576 subset_fdcount,
577 offsets.FDSelectInfo.size,
578 subset_fdselect_format,
Michiharu Ariza0f159a32018-09-12 16:08:54 -0700579 subset_fdselect_ranges,
Michiharu Ariza1666b892018-09-10 16:00:20 -0700580 fdmap)))
581 return false;
582
583 /* remove unused SIDs & reassign SIDs */
584 {
585 /* SIDs for name strings in dicts are added before glyph names so they fit in 16-bit int range */
586 if (unlikely (!collect_sids_in_dicts (acc)))
587 return false;
588 assert (sidmap.get_count () <= 0x8000);
589 if (subset_charset)
590 offsets.charsetInfo.size = plan_subset_charset (acc, plan);
591
592 topdict_mod.reassignSIDs (sidmap);
593 }
594
Michiharu Ariza64c54122018-08-10 11:07:07 -0700595 /* String INDEX */
Michiharu Ariza1666b892018-09-10 16:00:20 -0700596 {
597 offsets.stringIndexInfo.offset = final_size;
598 offsets.stringIndexInfo.size = acc.stringIndex->calculate_serialized_size (offsets.stringIndexInfo.offSize, sidmap);
599 final_size += offsets.stringIndexInfo.size;
600 }
Michiharu Ariza64c54122018-08-10 11:07:07 -0700601
Michiharu Ariza633ce882018-08-15 12:00:19 -0700602 {
Michiharu Arizaa11420b2018-08-29 12:14:30 -0700603 /* Flatten global & local subrs */
Michiharu Ariza8c5e03b2018-08-30 17:21:56 -0700604 SubrFlattener<const OT::cff1::accelerator_subset_t, CFF1CSInterpEnv, CFF1CSOpSet_Flatten>
605 flattener(acc, plan->glyphs, plan->drop_hints);
Michiharu Arizaa11420b2018-08-29 12:14:30 -0700606 if (!flattener.flatten (flat_charstrings))
607 return false;
608
609 /* no global/local subroutines */
610 offsets.globalSubrsInfo.size = HBUINT16::static_size; /* count 0 only */
611 }
Michiharu Arizacc52e532018-09-10 16:27:49 -0700612
Michiharu Ariza64c54122018-08-10 11:07:07 -0700613 /* global subrs */
Michiharu Ariza633ce882018-08-15 12:00:19 -0700614 offsets.globalSubrsInfo.offset = final_size;
615 final_size += offsets.globalSubrsInfo.size;
Michiharu Ariza64c54122018-08-10 11:07:07 -0700616
617 /* Encoding */
618 offsets.encodingOffset = final_size;
Michiharu Arizaaca73c92018-09-06 17:28:15 -0700619 if (subset_encoding)
620 final_size += plan_subset_encoding (acc, plan);
Michiharu Ariza64c54122018-08-10 11:07:07 -0700621
622 /* Charset */
Michiharu Ariza1666b892018-09-10 16:00:20 -0700623 offsets.charsetInfo.offset = final_size;
624 final_size += offsets.charsetInfo.size;
Michiharu Ariza64c54122018-08-10 11:07:07 -0700625
626 /* FDSelect */
Michiharu Arizafdbfa182018-08-16 00:13:09 -0700627 if (acc.fdSelect != &Null(CFF1FDSelect))
Michiharu Ariza64c54122018-08-10 11:07:07 -0700628 {
629 offsets.FDSelectInfo.offset = final_size;
Michiharu Ariza64c54122018-08-10 11:07:07 -0700630 if (!is_fds_subsetted ())
631 offsets.FDSelectInfo.size = acc.fdSelect->calculate_serialized_size (acc.num_glyphs);
632 final_size += offsets.FDSelectInfo.size;
633 }
634
635 /* FDArray (FDIndex) */
Michiharu Arizafdbfa182018-08-16 00:13:09 -0700636 if (acc.fdArray != &Null(CFF1FDArray)) {
Michiharu Ariza633ce882018-08-15 12:00:19 -0700637 offsets.FDArrayInfo.offset = final_size;
Michiharu Ariza1666b892018-09-10 16:00:20 -0700638 CFF1FontDict_OpSerializer fontSzr;
639 unsigned int dictsSize = 0;
640 for (unsigned int i = 0; i < acc.fontDicts.len; i++)
641 if (!fdmap.excludes (i))
642 dictsSize += FontDict::calculate_serialized_size (acc.fontDicts[i], fontSzr);
643
Michiharu Ariza5b453f72018-09-11 16:20:39 -0700644 offsets.FDArrayInfo.offSize = calcOffSize (dictsSize);
Michiharu Ariza1666b892018-09-10 16:00:20 -0700645 final_size += CFF1Index::calculate_serialized_size (offsets.FDArrayInfo.offSize, subset_fdcount, dictsSize);
Michiharu Ariza64c54122018-08-10 11:07:07 -0700646 }
647
648 /* CharStrings */
649 {
Michiharu Ariza633ce882018-08-15 12:00:19 -0700650 offsets.charStringsInfo.offset = final_size;
Michiharu Ariza64c54122018-08-10 11:07:07 -0700651 unsigned int dataSize = 0;
652 for (unsigned int i = 0; i < plan->glyphs.len; i++)
653 {
Michiharu Arizacc52e532018-09-10 16:27:49 -0700654 ByteStrBuff &flatstr = flat_charstrings[i];
655 ByteStr str (&flatstr[0], flatstr.len);
656 subset_charstrings.push (str);
657 dataSize += flatstr.len;
Michiharu Ariza64c54122018-08-10 11:07:07 -0700658 }
Michiharu Ariza5b453f72018-09-11 16:20:39 -0700659 offsets.charStringsInfo.offSize = calcOffSize (dataSize);
Michiharu Arizafdbfa182018-08-16 00:13:09 -0700660 final_size += CFF1CharStrings::calculate_serialized_size (offsets.charStringsInfo.offSize, plan->glyphs.len, dataSize);
Michiharu Ariza64c54122018-08-10 11:07:07 -0700661 }
662
663 /* private dicts & local subrs */
664 offsets.privateDictInfo.offset = final_size;
665 for (unsigned int i = 0; i < orig_fdcount; i++)
666 {
Michiharu Arizaa97ed342018-08-10 12:55:22 -0700667 if (!fdmap.excludes (i))
668 {
Michiharu Arizacc52e532018-09-10 16:27:49 -0700669 CFFPrivateDict_OpSerializer privSzr (plan->drop_hints);
Michiharu Ariza1666b892018-09-10 16:00:20 -0700670 unsigned int priv_size = PrivateDict::calculate_serialized_size (acc.privateDicts[i], privSzr);
Michiharu Ariza5cde2f52018-08-17 16:50:13 -0700671 TableInfo privInfo = { final_size, priv_size, 0 };
Michiharu Ariza1666b892018-09-10 16:00:20 -0700672 FontDictValuesMod fontdict_mod;
673 fontdict_mod.init ( &acc.fontDicts[i], sidmap[acc.fontDicts[i].fontName], privInfo );
674 fontdicts_mod.push (fontdict_mod);
Michiharu Arizaa11420b2018-08-29 12:14:30 -0700675 final_size += privInfo.size;
Michiharu Arizaa97ed342018-08-10 12:55:22 -0700676 }
Michiharu Ariza64c54122018-08-10 11:07:07 -0700677 }
678
679 if (!acc.is_CID ())
Michiharu Ariza1666b892018-09-10 16:00:20 -0700680 offsets.privateDictInfo = fontdicts_mod[0].privateDictInfo;
Michiharu Ariza64c54122018-08-10 11:07:07 -0700681
Michiharu Arizaa11420b2018-08-29 12:14:30 -0700682 return ((subset_charstrings.len == plan->glyphs.len) &&
Michiharu Ariza1666b892018-09-10 16:00:20 -0700683 (fontdicts_mod.len == subset_fdcount));
Michiharu Ariza64c54122018-08-10 11:07:07 -0700684 }
685
686 inline unsigned int get_final_size (void) const { return final_size; }
687
Michiharu Arizaaca73c92018-09-06 17:28:15 -0700688 unsigned int final_size;
Michiharu Ariza64c54122018-08-10 11:07:07 -0700689 hb_vector_t<unsigned int> topdict_sizes;
Michiharu Arizaaca73c92018-09-06 17:28:15 -0700690 CFF1TopDictValuesMod topdict_mod;
691 CFF1SubTableOffsets offsets;
Michiharu Ariza64c54122018-08-10 11:07:07 -0700692
Michiharu Arizaaca73c92018-09-06 17:28:15 -0700693 unsigned int num_glyphs;
Michiharu Ariza64c54122018-08-10 11:07:07 -0700694 unsigned int orig_fdcount;
Michiharu Arizaaca73c92018-09-06 17:28:15 -0700695 unsigned int subset_fdcount;
696 inline bool is_fds_subsetted (void) const { return subset_fdcount < orig_fdcount; }
697 unsigned int subset_fdselect_format;
Michiharu Ariza0f159a32018-09-12 16:08:54 -0700698 hb_vector_t<code_pair> subset_fdselect_ranges;
Michiharu Ariza64c54122018-08-10 11:07:07 -0700699
700 /* font dict index remap table from fullset FDArray to subset FDArray.
Michiharu Ariza1666b892018-09-10 16:00:20 -0700701 * set to CFF_UNDEF_CODE if excluded from subset */
702 Remap fdmap;
Michiharu Ariza64c54122018-08-10 11:07:07 -0700703
Michiharu Arizaa11420b2018-08-29 12:14:30 -0700704 hb_vector_t<ByteStr> subset_charstrings;
705 ByteStrBuffArray flat_charstrings;
Michiharu Ariza1666b892018-09-10 16:00:20 -0700706 hb_vector_t<FontDictValuesMod> fontdicts_mod;
Michiharu Ariza633ce882018-08-15 12:00:19 -0700707
Michiharu Arizaaca73c92018-09-06 17:28:15 -0700708 bool flatten_subrs;
709 bool drop_hints;
710
711 bool gid_renum;
712 bool subset_encoding;
713 uint8_t subset_enc_format;
714 unsigned int subset_enc_num_codes;
Michiharu Ariza16084812018-09-12 13:22:19 -0700715 RangeList subset_enc_code_ranges;
Michiharu Arizaaca73c92018-09-06 17:28:15 -0700716 hb_vector_t<code_pair> subset_enc_supp_codes;
717
718 uint8_t subset_charset_format;
Michiharu Ariza16084812018-09-12 13:22:19 -0700719 RangeList subset_charset_ranges;
Michiharu Arizaaca73c92018-09-06 17:28:15 -0700720 bool subset_charset;
Michiharu Ariza1666b892018-09-10 16:00:20 -0700721
722 RemapSID sidmap;
Michiharu Arizac6f75c32018-09-10 17:02:31 -0700723 unsigned int topDictModSIDs[NameDictValues::ValCount];
Michiharu Ariza64c54122018-08-10 11:07:07 -0700724};
725
Michiharu Arizafdbfa182018-08-16 00:13:09 -0700726static inline bool _write_cff1 (const cff_subset_plan &plan,
Michiharu Arizae67bb3f2018-08-16 00:25:57 -0700727 const OT::cff1::accelerator_subset_t &acc,
Michiharu Ariza64c54122018-08-10 11:07:07 -0700728 const hb_vector_t<hb_codepoint_t>& glyphs,
729 unsigned int dest_sz,
730 void *dest)
731{
732 hb_serialize_context_t c (dest, dest_sz);
733
Michiharu Arizac2348392018-08-15 13:04:43 -0700734 char RETURN_OP[1] = { OpCode_return };
Michiharu Ariza270452a2018-08-15 13:15:08 -0700735 const ByteStr NULL_SUBR (RETURN_OP, 1);
Michiharu Arizac2348392018-08-15 13:04:43 -0700736
Michiharu Arizae67bb3f2018-08-16 00:25:57 -0700737 OT::cff1 *cff = c.start_serialize<OT::cff1> ();
Michiharu Ariza64c54122018-08-10 11:07:07 -0700738 if (unlikely (!c.extend_min (*cff)))
739 return false;
740
741 /* header */
742 cff->version.major.set (0x01);
743 cff->version.minor.set (0x00);
744 cff->nameIndex.set (cff->min_size);
745 cff->offSize.set (4); /* unused? */
746
747 /* name INDEX */
748 {
749 assert (cff->nameIndex == c.head - c.start);
Michiharu Arizafdbfa182018-08-16 00:13:09 -0700750 CFF1NameIndex *dest = c.start_embed<CFF1NameIndex> ();
Michiharu Ariza64c54122018-08-10 11:07:07 -0700751 if (unlikely (dest == nullptr)) return false;
752 if (unlikely (!dest->serialize (&c, *acc.nameIndex)))
753 {
754 DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF name INDEX");
755 return false;
756 }
757 }
758
759 /* top dict INDEX */
760 {
Michiharu Ariza633ce882018-08-15 12:00:19 -0700761 assert (plan.offsets.topDictInfo.offset == c.head - c.start);
Michiharu Arizafdbfa182018-08-16 00:13:09 -0700762 CFF1IndexOf<TopDict> *dest = c.start_embed< CFF1IndexOf<TopDict> > ();
Michiharu Ariza64c54122018-08-10 11:07:07 -0700763 if (dest == nullptr) return false;
Michiharu Arizafdbfa182018-08-16 00:13:09 -0700764 CFF1TopDict_OpSerializer topSzr;
Michiharu Ariza1666b892018-09-10 16:00:20 -0700765 TopDictModifiers modifier (plan.offsets, plan.topDictModSIDs);
Michiharu Arizaaca73c92018-09-06 17:28:15 -0700766 if (unlikely (!dest->serialize (&c, plan.offsets.topDictInfo.offSize,
767 &plan.topdict_mod, 1,
Michiharu Ariza1666b892018-09-10 16:00:20 -0700768 plan.topdict_sizes, topSzr, modifier)))
Michiharu Ariza64c54122018-08-10 11:07:07 -0700769 {
770 DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF top dict");
771 return false;
772 }
773 }
774
775 /* String INDEX */
776 {
Michiharu Ariza1666b892018-09-10 16:00:20 -0700777 assert (plan.offsets.stringIndexInfo.offset == c.head - c.start);
Michiharu Arizafdbfa182018-08-16 00:13:09 -0700778 CFF1StringIndex *dest = c.start_embed<CFF1StringIndex> ();
Michiharu Ariza64c54122018-08-10 11:07:07 -0700779 if (unlikely (dest == nullptr)) return false;
Michiharu Ariza1666b892018-09-10 16:00:20 -0700780 if (unlikely (!dest->serialize (&c, *acc.stringIndex, plan.offsets.stringIndexInfo.offSize, plan.sidmap)))
Michiharu Ariza64c54122018-08-10 11:07:07 -0700781 {
782 DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF string INDEX");
783 return false;
784 }
785 }
786
787 /* global subrs */
788 {
Michiharu Arizaa11420b2018-08-29 12:14:30 -0700789 assert (plan.offsets.globalSubrsInfo.offset != 0);
Michiharu Ariza633ce882018-08-15 12:00:19 -0700790 assert (plan.offsets.globalSubrsInfo.offset == c.head - c.start);
Michiharu Arizacc52e532018-09-10 16:27:49 -0700791 CFF1Subrs *dest = c.allocate_size <CFF1Subrs> (HBUINT16::static_size);
Michiharu Ariza64c54122018-08-10 11:07:07 -0700792 if (unlikely (dest == nullptr)) return false;
Michiharu Arizacc52e532018-09-10 16:27:49 -0700793 dest->count.set (0);
Michiharu Ariza64c54122018-08-10 11:07:07 -0700794 }
795
796 /* Encoding */
Michiharu Arizaaca73c92018-09-06 17:28:15 -0700797 if (plan.subset_encoding)
798 {
Michiharu Ariza64c54122018-08-10 11:07:07 -0700799 assert (plan.offsets.encodingOffset == c.head - c.start);
800 Encoding *dest = c.start_embed<Encoding> ();
801 if (unlikely (dest == nullptr)) return false;
Michiharu Arizaaca73c92018-09-06 17:28:15 -0700802 if (unlikely (!dest->serialize (&c,
803 plan.subset_enc_format,
804 plan.subset_enc_num_codes,
805 plan.subset_enc_code_ranges,
806 plan.subset_enc_supp_codes)))
Michiharu Ariza64c54122018-08-10 11:07:07 -0700807 {
808 DEBUG_MSG (SUBSET, nullptr, "failed to serialize Encoding");
809 return false;
810 }
811 }
812
813 /* Charset */
Michiharu Arizaaca73c92018-09-06 17:28:15 -0700814 if (plan.subset_charset)
Michiharu Ariza64c54122018-08-10 11:07:07 -0700815 {
Michiharu Ariza1666b892018-09-10 16:00:20 -0700816 assert (plan.offsets.charsetInfo.offset == c.head - c.start);
Michiharu Ariza64c54122018-08-10 11:07:07 -0700817 Charset *dest = c.start_embed<Charset> ();
818 if (unlikely (dest == nullptr)) return false;
Michiharu Arizaaca73c92018-09-06 17:28:15 -0700819 if (unlikely (!dest->serialize (&c,
820 plan.subset_charset_format,
821 plan.num_glyphs,
822 plan.subset_charset_ranges)))
Michiharu Ariza64c54122018-08-10 11:07:07 -0700823 {
824 DEBUG_MSG (SUBSET, nullptr, "failed to serialize Charset");
825 return false;
826 }
827 }
828
829 /* FDSelect */
Michiharu Arizafdbfa182018-08-16 00:13:09 -0700830 if (acc.fdSelect != &Null(CFF1FDSelect))
Michiharu Ariza64c54122018-08-10 11:07:07 -0700831 {
832 assert (plan.offsets.FDSelectInfo.offset == c.head - c.start);
833
834 if (plan.is_fds_subsetted ())
835 {
Michiharu Ariza0f159a32018-09-12 16:08:54 -0700836 if (unlikely (!hb_serialize_cff_fdselect (&c, glyphs.len, *acc.fdSelect, acc.fdCount,
Michiharu Arizaaca73c92018-09-06 17:28:15 -0700837 plan.subset_fdselect_format, plan.offsets.FDSelectInfo.size,
Michiharu Ariza0f159a32018-09-12 16:08:54 -0700838 plan.subset_fdselect_ranges,
Michiharu Ariza64c54122018-08-10 11:07:07 -0700839 plan.fdmap)))
840 {
841 DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF subset FDSelect");
842 return false;
843 }
844 }
845 else
846 {
Michiharu Arizafdbfa182018-08-16 00:13:09 -0700847 CFF1FDSelect *dest = c.start_embed<CFF1FDSelect> ();
Michiharu Ariza64c54122018-08-10 11:07:07 -0700848 if (unlikely (!dest->serialize (&c, *acc.fdSelect, acc.num_glyphs)))
849 {
850 DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF FDSelect");
851 return false;
852 }
853 }
854 }
855
856 /* FDArray (FD Index) */
Michiharu Arizafdbfa182018-08-16 00:13:09 -0700857 if (acc.fdArray != &Null(CFF1FDArray))
Michiharu Ariza64c54122018-08-10 11:07:07 -0700858 {
Michiharu Ariza633ce882018-08-15 12:00:19 -0700859 assert (plan.offsets.FDArrayInfo.offset == c.head - c.start);
Michiharu Arizafdbfa182018-08-16 00:13:09 -0700860 CFF1FDArray *fda = c.start_embed<CFF1FDArray> ();
Michiharu Ariza64c54122018-08-10 11:07:07 -0700861 if (unlikely (fda == nullptr)) return false;
Michiharu Ariza1666b892018-09-10 16:00:20 -0700862 CFF1FontDict_OpSerializer fontSzr;
Michiharu Ariza633ce882018-08-15 12:00:19 -0700863 if (unlikely (!fda->serialize (&c, plan.offsets.FDArrayInfo.offSize,
Michiharu Ariza1666b892018-09-10 16:00:20 -0700864 plan.fontdicts_mod,
865 fontSzr)))
Michiharu Ariza64c54122018-08-10 11:07:07 -0700866 {
867 DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF FDArray");
868 return false;
869 }
870 }
871
872 /* CharStrings */
873 {
Michiharu Ariza633ce882018-08-15 12:00:19 -0700874 assert (plan.offsets.charStringsInfo.offset == c.head - c.start);
Michiharu Arizafdbfa182018-08-16 00:13:09 -0700875 CFF1CharStrings *cs = c.start_embed<CFF1CharStrings> ();
Michiharu Ariza64c54122018-08-10 11:07:07 -0700876 if (unlikely (cs == nullptr)) return false;
Michiharu Ariza633ce882018-08-15 12:00:19 -0700877 if (unlikely (!cs->serialize (&c, plan.offsets.charStringsInfo.offSize, plan.subset_charstrings)))
Michiharu Ariza64c54122018-08-10 11:07:07 -0700878 {
879 DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF CharStrings");
880 return false;
881 }
882 }
883
884 /* private dicts & local subrs */
885 assert (plan.offsets.privateDictInfo.offset == c.head - c.start);
886 for (unsigned int i = 0; i < acc.privateDicts.len; i++)
887 {
Michiharu Arizaa97ed342018-08-10 12:55:22 -0700888 if (!plan.fdmap.excludes (i))
Michiharu Ariza64c54122018-08-10 11:07:07 -0700889 {
Michiharu Arizaa97ed342018-08-10 12:55:22 -0700890 PrivateDict *pd = c.start_embed<PrivateDict> ();
891 if (unlikely (pd == nullptr)) return false;
Michiharu Arizacc52e532018-09-10 16:27:49 -0700892 unsigned int priv_size = plan.fontdicts_mod[plan.fdmap[i]].privateDictInfo.size;
Michiharu Ariza5cde2f52018-08-17 16:50:13 -0700893 bool result;
Michiharu Arizacc52e532018-09-10 16:27:49 -0700894 CFFPrivateDict_OpSerializer privSzr (plan.drop_hints);
Michiharu Arizaa97ed342018-08-10 12:55:22 -0700895 /* N.B. local subrs immediately follows its corresponding private dict. i.e., subr offset == private dict size */
Michiharu Arizaa11420b2018-08-29 12:14:30 -0700896 result = pd->serialize (&c, acc.privateDicts[i], privSzr, priv_size);
Michiharu Ariza5cde2f52018-08-17 16:50:13 -0700897 if (unlikely (!result))
Michiharu Ariza64c54122018-08-10 11:07:07 -0700898 {
Michiharu Arizaa97ed342018-08-10 12:55:22 -0700899 DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF Private Dict[%d]", i);
Michiharu Ariza64c54122018-08-10 11:07:07 -0700900 return false;
901 }
Michiharu Ariza64c54122018-08-10 11:07:07 -0700902 }
903 }
904
Michiharu Arizacef75ea2018-08-17 13:13:18 -0700905 assert (c.head == c.end);
Michiharu Ariza64c54122018-08-10 11:07:07 -0700906 c.end_serialize ();
907
908 return true;
909}
910
911static bool
Michiharu Arizae67bb3f2018-08-16 00:25:57 -0700912_hb_subset_cff1 (const OT::cff1::accelerator_subset_t &acc,
Michiharu Ariza64c54122018-08-10 11:07:07 -0700913 const char *data,
914 hb_subset_plan_t *plan,
915 hb_blob_t **prime /* OUT */)
916{
917 cff_subset_plan cff_plan;
918
919 if (unlikely (!cff_plan.create (acc, plan)))
920 {
921 DEBUG_MSG(SUBSET, nullptr, "Failed to generate a cff subsetting plan.");
922 return false;
923 }
924
925 unsigned int cff_prime_size = cff_plan.get_final_size ();
926 char *cff_prime_data = (char *) calloc (1, cff_prime_size);
927
Michiharu Arizafdbfa182018-08-16 00:13:09 -0700928 if (unlikely (!_write_cff1 (cff_plan, acc, plan->glyphs,
Michiharu Ariza64c54122018-08-10 11:07:07 -0700929 cff_prime_size, cff_prime_data))) {
930 DEBUG_MSG(SUBSET, nullptr, "Failed to write a subset cff.");
931 free (cff_prime_data);
932 return false;
933 }
934
935 *prime = hb_blob_create (cff_prime_data,
936 cff_prime_size,
937 HB_MEMORY_MODE_READONLY,
938 cff_prime_data,
939 free);
940 return true;
941}
942
943/**
Michiharu Arizafdbfa182018-08-16 00:13:09 -0700944 * hb_subset_cff1:
Michiharu Ariza64c54122018-08-10 11:07:07 -0700945 * Subsets the CFF table according to a provided plan.
946 *
947 * Return value: subsetted cff table.
948 **/
949bool
Michiharu Arizafdbfa182018-08-16 00:13:09 -0700950hb_subset_cff1 (hb_subset_plan_t *plan,
Michiharu Ariza64c54122018-08-10 11:07:07 -0700951 hb_blob_t **prime /* OUT */)
952{
Michiharu Arizae67bb3f2018-08-16 00:25:57 -0700953 hb_blob_t *cff_blob = hb_sanitize_context_t().reference_table<CFF::cff1> (plan->source);
Michiharu Ariza64c54122018-08-10 11:07:07 -0700954 const char *data = hb_blob_get_data(cff_blob, nullptr);
955
Michiharu Arizae67bb3f2018-08-16 00:25:57 -0700956 OT::cff1::accelerator_subset_t acc;
Michiharu Ariza64c54122018-08-10 11:07:07 -0700957 acc.init(plan->source);
958 bool result = likely (acc.is_valid ()) &&
Michiharu Arizafdbfa182018-08-16 00:13:09 -0700959 _hb_subset_cff1 (acc, data, plan, prime);
Michiharu Ariza64c54122018-08-10 11:07:07 -0700960 hb_blob_destroy (cff_blob);
961 acc.fini ();
962
963 return result;
964}