hb-subset-cff1.cc 20.0 KB
Newer Older
M
Michiharu Ariza 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
/*
 * Copyright © 2018 Adobe Systems Incorporated.
 *
 *  This is part of HarfBuzz, a text shaping library.
 *
 * Permission is hereby granted, without written agreement and without
 * license or royalty fees, to use, copy, modify, and distribute this
 * software and its documentation for any purpose, provided that the
 * above copyright notice and the following two paragraphs appear in
 * all copies of this software.
 *
 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
 * DAMAGE.
 *
 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
 * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 *
 * Adobe Author(s): Michiharu Ariza
 */

27
#include "hb-open-type.hh"
28
#include "hb-ot-cff1-table.hh"
M
Michiharu Ariza 已提交
29
#include "hb-set.h"
30
#include "hb-subset-cff1.hh"
M
Michiharu Ariza 已提交
31
#include "hb-subset-plan.hh"
32
#include "hb-subset-cff-common.hh"
33
#include "hb-cff1-interp-cs.hh"
M
Michiharu Ariza 已提交
34 35 36

using namespace CFF;

M
Michiharu Ariza 已提交
37 38
struct CFF1SubTableOffsets : CFFSubTableOffsets
{
39
  inline CFF1SubTableOffsets (void)
M
Michiharu Ariza 已提交
40 41 42 43 44
    : CFFSubTableOffsets (),
      nameIndexOffset (0),
      stringIndexOffset (0),
      encodingOffset (0),
      charsetOffset (0)
M
Michiharu Ariza 已提交
45
  {
M
Michiharu Ariza 已提交
46
    privateDictInfo.init ();
M
Michiharu Ariza 已提交
47 48 49 50 51 52 53 54 55
  }

  unsigned int  nameIndexOffset;
  unsigned int  stringIndexOffset;
  unsigned int  encodingOffset;
  unsigned int  charsetOffset;
  TableInfo     privateDictInfo;
};

M
Michiharu Ariza 已提交
56
struct CFF1TopDict_OpSerializer : CFFTopDict_OpSerializer
M
Michiharu Ariza 已提交
57 58 59
{
  inline bool serialize (hb_serialize_context_t *c,
                         const OpStr &opstr,
60
                         const CFF1SubTableOffsets &offsets) const
M
Michiharu Ariza 已提交
61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84
  {
    TRACE_SERIALIZE (this);

    switch (opstr.op)
    {
      case OpCode_charset:
        return_trace (FontDict::serialize_offset4_op(c, opstr.op, offsets.charsetOffset));

      case OpCode_Encoding:
        return_trace (FontDict::serialize_offset4_op(c, opstr.op, offsets.encodingOffset));

      case OpCode_Private:
        {
          if (unlikely (!UnsizedByteStr::serialize_int2 (c, offsets.privateDictInfo.size)))
            return_trace (false);
          if (unlikely (!UnsizedByteStr::serialize_int4 (c, offsets.privateDictInfo.offset)))
            return_trace (false);
          HBUINT8 *p = c->allocate_size<HBUINT8> (1);
          if (unlikely (p == nullptr)) return_trace (false);
          p->set (OpCode_Private);
        }
        break;

      default:
M
Michiharu Ariza 已提交
85
        return_trace (CFFTopDict_OpSerializer::serialize (c, opstr, offsets));
M
Michiharu Ariza 已提交
86 87 88 89 90 91 92 93 94 95
    }
    return_trace (true);
  }

  inline unsigned int calculate_serialized_size (const OpStr &opstr) const
  {
    switch (opstr.op)
    {
      case OpCode_charset:
      case OpCode_Encoding:
M
Michiharu Ariza 已提交
96
        return OpCode_Size (OpCode_longintdict) + 4 + OpCode_Size (opstr.op);
M
Michiharu Ariza 已提交
97 98
    
      case OpCode_Private:
M
Michiharu Ariza 已提交
99
        return OpCode_Size (OpCode_longintdict) + 4 + OpCode_Size (OpCode_shortint) + 2 + OpCode_Size (OpCode_Private);
M
Michiharu Ariza 已提交
100 101
    
      default:
M
Michiharu Ariza 已提交
102
        return CFFTopDict_OpSerializer::calculate_serialized_size (opstr);
M
Michiharu Ariza 已提交
103 104 105 106
    }
  }
};

M
Michiharu Ariza 已提交
107
struct CFF1CSOpSet_Flatten : CFF1CSOpSet<CFF1CSOpSet_Flatten, ByteStrBuff>
108
{
M
Michiharu Ariza 已提交
109
  static inline bool process_op (OpCode op, CFF1CSInterpEnv &env, ByteStrBuff& flatStr)
110
  {
M
Michiharu Ariza 已提交
111 112 113 114 115 116 117 118 119 120 121 122 123
    if (unlikely (!SUPER::process_op (op, env, flatStr)))
      return false;
    switch (op)
    {
      case OpCode_hintmask:
      case OpCode_cntrmask:
        if (unlikely (!flatStr.encode_op (op)))
          return false;
        for (int i = -env.hintmask_size; i < 0; i++)
          if (unlikely (!flatStr.encode_byte (env.substr[i])))
            return false;
        break;
      default:
M
Michiharu Ariza 已提交
124 125
        if (!CSOPSET::is_subr_op (op) &&
            !CSOPSET::is_arg_op (op))
M
Michiharu Ariza 已提交
126 127 128
          return flatStr.encode_op (op);
    }
    return true;
129 130
  }

M
Michiharu Ariza 已提交
131
  static inline void flush_stack (CFF1CSInterpEnv &env, ByteStrBuff& flatStr)
132
  {
M
Michiharu Ariza 已提交
133 134 135
    for (unsigned int i = 0; i < env.argStack.size; i++)
      flatStr.encode_num (env.argStack.elements[i]);
    SUPER::flush_stack (env, flatStr);
136
  }
M
Michiharu Ariza 已提交
137 138 139

  private:
  typedef CFF1CSOpSet<CFF1CSOpSet_Flatten, ByteStrBuff> SUPER;
M
Michiharu Ariza 已提交
140
  typedef CSOpSet<CFF1CSOpSet_Flatten, CFF1CSInterpEnv, ByteStrBuff> CSOPSET;
141 142
};

M
Michiharu Ariza 已提交
143
struct CFF1CSOpSet_SubsetSubrs : CFF1CSOpSet<CFF1CSOpSet_SubsetSubrs, SubrRefMapPair>
M
Michiharu Ariza 已提交
144
{
145
  static inline bool process_op (OpCode op, CFF1CSInterpEnv &env, SubrRefMapPair& refMapPair)
M
Michiharu Ariza 已提交
146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163
  {
    unsigned int  subr_num;
    switch (op) {
      case OpCode_callsubr:
        if (!unlikely (env.popSubrNum(env.localSubrs, subr_num)))
          return false;
        env.argStack.unpop ();
        refMapPair.local_map->add (subr_num);
        break;
      case OpCode_callgsubr:
        if (!unlikely (env.popSubrNum(env.globalSubrs, subr_num)))
          return false;
        env.argStack.unpop ();
        refMapPair.global_map->add (subr_num);
        break;
      default:
        break;
    }
M
Michiharu Ariza 已提交
164
    return CFF1CSOpSet<CFF1CSOpSet_SubsetSubrs, SubrRefMapPair>::process_op (op, env, refMapPair);
M
Michiharu Ariza 已提交
165 166 167
  }
};

M
Michiharu Ariza 已提交
168 169 170 171
struct cff_subset_plan {
  inline cff_subset_plan (void)
    : final_size (0),
      orig_fdcount (0),
M
Michiharu Ariza 已提交
172
      subst_fdcount (1),
M
Michiharu Ariza 已提交
173
      subst_fdselect_format (0),
M
Michiharu Ariza 已提交
174 175 176
      offsets (),
      flatten_subrs (true),
      drop_hints (false)
M
Michiharu Ariza 已提交
177 178 179 180 181 182
  {
    topdict_sizes.init ();
    topdict_sizes.resize (1);
    subst_fdselect_first_glyphs.init ();
    fdmap.init ();
    subset_charstrings.init ();
M
Michiharu Ariza 已提交
183
    flat_charstrings.init ();
M
Michiharu Ariza 已提交
184
    privateDictInfos.init ();
M
Michiharu Ariza 已提交
185
    subrRefMaps.init ();
M
Michiharu Ariza 已提交
186 187 188 189 190 191 192 193
  }

  inline ~cff_subset_plan (void)
  {
    topdict_sizes.fini ();
    subst_fdselect_first_glyphs.fini ();
    fdmap.fini ();
    subset_charstrings.fini ();
M
Michiharu Ariza 已提交
194
    flat_charstrings.fini ();
M
Michiharu Ariza 已提交
195
    privateDictInfos.fini ();
M
Michiharu Ariza 已提交
196
    subrRefMaps.fini ();
M
Michiharu Ariza 已提交
197 198
  }

199
  inline bool create (const OT::cff1::accelerator_subset_t &acc,
M
Michiharu Ariza 已提交
200 201 202 203
                      hb_subset_plan_t *plan)
  {
    final_size = 0;
    orig_fdcount = acc.fdCount;
204
    drop_hints = plan->drop_hints;
M
Michiharu Ariza 已提交
205 206

    /* CFF header */
207
    final_size += OT::cff1::static_size;
M
Michiharu Ariza 已提交
208 209 210 211 212 213 214
    
    /* Name INDEX */
    offsets.nameIndexOffset = final_size;
    final_size += acc.nameIndex->get_size ();
    
    /* top dict INDEX */
    {
M
Michiharu Ariza 已提交
215
      offsets.topDictInfo.offset = final_size;
216
      CFF1TopDict_OpSerializer topSzr;
M
Michiharu Ariza 已提交
217
      unsigned int topDictSize = TopDict::calculate_serialized_size (acc.topDicts[0], topSzr);
M
Michiharu Ariza 已提交
218
      offsets.topDictInfo.offSize = calcOffSize(topDictSize);
219
      final_size += CFF1IndexOf<TopDict>::calculate_serialized_size<CFF1TopDictValues> (offsets.topDictInfo.offSize, acc.topDicts, topdict_sizes, topSzr);
M
Michiharu Ariza 已提交
220 221 222 223 224 225
    }

    /* String INDEX */
    offsets.stringIndexOffset = final_size;
    final_size += acc.stringIndex->get_size ();
    
M
Michiharu Ariza 已提交
226 227 228 229 230 231 232 233 234 235 236
    if (flatten_subrs)
    {
      /* Flatten global & local subrs */
      SubrFlattener<const OT::cff1::accelerator_subset_t, CFF1CSInterpEnv, CFF1CSOpSet_Flatten> flattener(acc, plan->glyphs);
      if (!flattener.flatten (flat_charstrings))
        return false;
      
      /* no global/local subroutines */
      offsets.globalSubrsInfo.size = HBUINT16::static_size; /* count 0 only */
    }
    else
M
Michiharu Ariza 已提交
237
    {
M
Michiharu Ariza 已提交
238 239
      /* Subset global & local subrs */
      SubrSubsetter<const OT::cff1::accelerator_subset_t, CFF1CSInterpEnv, CFF1CSOpSet_SubsetSubrs> subsetter(acc, plan->glyphs);
M
Michiharu Ariza 已提交
240 241 242 243 244 245 246 247 248
      if (!subsetter.collect_refs (subrRefMaps))
        return false;
      
      offsets.globalSubrsInfo.size = acc.globalSubrs->calculate_serialized_size (offsets.globalSubrsInfo.offSize, subrRefMaps.global_map, 1);
      if (!offsets.localSubrsInfos.resize (orig_fdcount))
        return false;
      for (unsigned int i = 0; i < orig_fdcount; i++)
        offsets.localSubrsInfos[i].size = acc.privateDicts[i].localSubrs->calculate_serialized_size (offsets.localSubrsInfos[i].offSize, subrRefMaps.local_maps[i], 1);
    }
M
Michiharu Ariza 已提交
249
    /* global subrs */
M
Michiharu Ariza 已提交
250 251
    offsets.globalSubrsInfo.offset = final_size;
    final_size += offsets.globalSubrsInfo.size;
M
Michiharu Ariza 已提交
252 253 254 255 256 257 258 259 260 261 262 263

    /* Encoding */
    offsets.encodingOffset = final_size;
    if (acc.encoding != &Null(Encoding))
      final_size += acc.encoding->get_size ();

    /* Charset */
    offsets.charsetOffset = final_size;
    if (acc.charset != &Null(Charset))
      final_size += acc.charset->get_size (acc.num_glyphs);

    /* FDSelect */
264
    if (acc.fdSelect != &Null(CFF1FDSelect))
M
Michiharu Ariza 已提交
265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282
    {
      offsets.FDSelectInfo.offset = final_size;
      if (unlikely (!hb_plan_subset_cff_fdselect (plan->glyphs,
                                  orig_fdcount,
                                  *acc.fdSelect,
                                  subst_fdcount,
                                  offsets.FDSelectInfo.size,
                                  subst_fdselect_format,
                                  subst_fdselect_first_glyphs,
                                  fdmap)))
        return false;
      
      if (!is_fds_subsetted ())
        offsets.FDSelectInfo.size = acc.fdSelect->calculate_serialized_size (acc.num_glyphs);
      final_size += offsets.FDSelectInfo.size;
    }

    /* FDArray (FDIndex) */
283
    if (acc.fdArray != &Null(CFF1FDArray)) {
M
Michiharu Ariza 已提交
284
      offsets.FDArrayInfo.offset = final_size;
M
Michiharu Ariza 已提交
285
      CFFFontDict_OpSerializer fontSzr;
286
      final_size += CFF1FDArray::calculate_serialized_size(offsets.FDArrayInfo.offSize/*OUT*/, acc.fontDicts, subst_fdcount, fdmap, fontSzr);
M
Michiharu Ariza 已提交
287 288 289 290
    }

    /* CharStrings */
    {
M
Michiharu Ariza 已提交
291
      offsets.charStringsInfo.offset = final_size;
M
Michiharu Ariza 已提交
292 293 294
      unsigned int dataSize = 0;
      for (unsigned int i = 0; i < plan->glyphs.len; i++)
      {
M
Michiharu Ariza 已提交
295 296 297 298 299 300 301 302 303 304 305 306 307
        if (flatten_subrs)
        {
          ByteStrBuff &flatstr = flat_charstrings[i];
          ByteStr str (&flatstr[0], flatstr.len);
          subset_charstrings.push (str);
          dataSize += flatstr.len;
        }
        else
        {
          const ByteStr str = (*acc.charStrings)[plan->glyphs[i]];
          subset_charstrings.push (str);
          dataSize += str.len;
        }
M
Michiharu Ariza 已提交
308
      }
M
Michiharu Ariza 已提交
309
      offsets.charStringsInfo.offSize = calcOffSize (dataSize + 1);
310
      final_size += CFF1CharStrings::calculate_serialized_size (offsets.charStringsInfo.offSize, plan->glyphs.len, dataSize);
M
Michiharu Ariza 已提交
311 312 313 314 315 316
    }

    /* private dicts & local subrs */
    offsets.privateDictInfo.offset = final_size;
    for (unsigned int i = 0; i < orig_fdcount; i++)
    {
317 318
      if (!fdmap.excludes (i))
      {
319
        unsigned int  priv_size;
M
Michiharu Ariza 已提交
320
        CFFPrivateDict_OpSerializer privSzr (plan->drop_hints, flatten_subrs);
M
Michiharu Ariza 已提交
321
        priv_size = PrivateDict::calculate_serialized_size (acc.privateDicts[i], privSzr);
322
        TableInfo  privInfo = { final_size, priv_size, 0 };
323
        privateDictInfos.push (privInfo);
M
Michiharu Ariza 已提交
324 325 326
        final_size += privInfo.size;
        if (!flatten_subrs)
          final_size += offsets.localSubrsInfos[i].size;
327
      }
M
Michiharu Ariza 已提交
328 329 330 331 332
    }

    if (!acc.is_CID ())
      offsets.privateDictInfo = privateDictInfos[0];

M
Michiharu Ariza 已提交
333 334
    return ((subset_charstrings.len == plan->glyphs.len) &&
            (privateDictInfos.len == subst_fdcount));
M
Michiharu Ariza 已提交
335 336 337 338 339 340
  }

  inline unsigned int get_final_size (void) const  { return final_size; }

  unsigned int        final_size;
  hb_vector_t<unsigned int> topdict_sizes;
341
  CFF1SubTableOffsets  offsets;
M
Michiharu Ariza 已提交
342 343 344 345 346 347 348 349 350

  unsigned int    orig_fdcount;
  unsigned int    subst_fdcount;
  inline bool     is_fds_subsetted (void) const { return subst_fdcount < orig_fdcount; }
  unsigned int    subst_fdselect_format;
  hb_vector_t<hb_codepoint_t>   subst_fdselect_first_glyphs;

  /* font dict index remap table from fullset FDArray to subset FDArray.
   * set to HB_SET_VALUE_INVALID if excluded from subset */
351
  FDMap   fdmap;
M
Michiharu Ariza 已提交
352

M
Michiharu Ariza 已提交
353 354 355
  hb_vector_t<ByteStr>    subset_charstrings;
  ByteStrBuffArray        flat_charstrings;
  hb_vector_t<TableInfo>  privateDictInfos;
M
Michiharu Ariza 已提交
356 357

  SubrRefMaps             subrRefMaps;
358

M
Michiharu Ariza 已提交
359
  bool            flatten_subrs;
360
  bool            drop_hints;
M
Michiharu Ariza 已提交
361 362
};

363
static inline bool _write_cff1 (const cff_subset_plan &plan,
364
                                const OT::cff1::accelerator_subset_t  &acc,
M
Michiharu Ariza 已提交
365 366 367 368 369 370
                                const hb_vector_t<hb_codepoint_t>& glyphs,
                                unsigned int dest_sz,
                                void *dest)
{
  hb_serialize_context_t c (dest, dest_sz);

M
Michiharu Ariza 已提交
371
  char RETURN_OP[1] = { OpCode_return };
M
Michiharu Ariza 已提交
372
  const ByteStr NULL_SUBR (RETURN_OP, 1);
M
Michiharu Ariza 已提交
373

374
  OT::cff1 *cff = c.start_serialize<OT::cff1> ();
M
Michiharu Ariza 已提交
375 376 377 378 379 380 381 382 383 384 385 386
  if (unlikely (!c.extend_min (*cff)))
    return false;

  /* header */
  cff->version.major.set (0x01);
  cff->version.minor.set (0x00);
  cff->nameIndex.set (cff->min_size);
  cff->offSize.set (4); /* unused? */

  /* name INDEX */
  {
    assert (cff->nameIndex == c.head - c.start);
387
    CFF1NameIndex *dest = c.start_embed<CFF1NameIndex> ();
M
Michiharu Ariza 已提交
388 389 390 391 392 393 394 395 396 397
    if (unlikely (dest == nullptr)) return false;
    if (unlikely (!dest->serialize (&c, *acc.nameIndex)))
    {
      DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF name INDEX");
      return false;
    }
  }

  /* top dict INDEX */
  {
M
Michiharu Ariza 已提交
398
    assert (plan.offsets.topDictInfo.offset == c.head - c.start);
399
    CFF1IndexOf<TopDict> *dest = c.start_embed< CFF1IndexOf<TopDict> > ();
M
Michiharu Ariza 已提交
400
    if (dest == nullptr) return false;
401
    CFF1TopDict_OpSerializer topSzr;
M
Michiharu Ariza 已提交
402
    if (unlikely (!dest->serialize (&c, plan.offsets.topDictInfo.offSize, acc.topDicts, plan.topdict_sizes, topSzr, plan.offsets)))
M
Michiharu Ariza 已提交
403 404 405 406 407 408 409 410 411
    {
      DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF top dict");
      return false;
    }
  }

  /* String INDEX */
  {
    assert (plan.offsets.stringIndexOffset == c.head - c.start);
412
    CFF1StringIndex *dest = c.start_embed<CFF1StringIndex> ();
M
Michiharu Ariza 已提交
413 414 415 416 417 418 419 420 421 422
    if (unlikely (dest == nullptr)) return false;
    if (unlikely (!dest->serialize (&c, *acc.stringIndex)))
    {
      DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF string INDEX");
      return false;
    }
  }

  /* global subrs */
  {
M
Michiharu Ariza 已提交
423
    assert (plan.offsets.globalSubrsInfo.offset != 0);
M
Michiharu Ariza 已提交
424
    assert (plan.offsets.globalSubrsInfo.offset == c.head - c.start);
425
    CFF1Subrs *dest = c.start_embed<CFF1Subrs> ();
M
Michiharu Ariza 已提交
426
    if (unlikely (dest == nullptr)) return false;
M
Michiharu Ariza 已提交
427
    if (unlikely (!dest->serialize (&c, *acc.globalSubrs, plan.offsets.globalSubrsInfo.offSize, plan.subrRefMaps.global_map, NULL_SUBR)))
M
Michiharu Ariza 已提交
428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459
    {
      DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF global subrs");
      return false;
    }
  }

  /* Encoding */
  if (acc.encoding != &Null(Encoding)){
    assert (plan.offsets.encodingOffset == c.head - c.start);
    Encoding *dest = c.start_embed<Encoding> ();
    if (unlikely (dest == nullptr)) return false;
    if (unlikely (!dest->serialize (&c, *acc.encoding, acc.num_glyphs)))  // XXX: TODO
    {
      DEBUG_MSG (SUBSET, nullptr, "failed to serialize Encoding");
      return false;
    }
  }

  /* Charset */
  if (acc.charset != &Null(Charset))
  {
    assert (plan.offsets.charsetOffset == c.head - c.start);
    Charset *dest = c.start_embed<Charset> ();
    if (unlikely (dest == nullptr)) return false;
    if (unlikely (!dest->serialize (&c, *acc.charset, acc.num_glyphs)))  // XXX: TODO
    {
      DEBUG_MSG (SUBSET, nullptr, "failed to serialize Charset");
      return false;
    }
  }

  /* FDSelect */
460
  if (acc.fdSelect != &Null(CFF1FDSelect))
M
Michiharu Ariza 已提交
461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476
  {
    assert (plan.offsets.FDSelectInfo.offset == c.head - c.start);
    
    if (plan.is_fds_subsetted ())
    {
      if (unlikely (!hb_serialize_cff_fdselect (&c, glyphs, *acc.fdSelect, acc.fdCount,
                                                plan.subst_fdselect_format, plan.offsets.FDSelectInfo.size,
                                                plan.subst_fdselect_first_glyphs,
                                                plan.fdmap)))
      {
        DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF subset FDSelect");
        return false;
      }
    }
    else
    {
477
      CFF1FDSelect *dest = c.start_embed<CFF1FDSelect> ();
M
Michiharu Ariza 已提交
478 479 480 481 482 483 484 485 486
      if (unlikely (!dest->serialize (&c, *acc.fdSelect, acc.num_glyphs)))
      {
        DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF FDSelect");
        return false;
      }
    }
  }

  /* FDArray (FD Index) */
487
  if (acc.fdArray != &Null(CFF1FDArray))
M
Michiharu Ariza 已提交
488
  {
M
Michiharu Ariza 已提交
489
    assert (plan.offsets.FDArrayInfo.offset == c.head - c.start);
490
    CFF1FDArray  *fda = c.start_embed<CFF1FDArray> ();
M
Michiharu Ariza 已提交
491
    if (unlikely (fda == nullptr)) return false;
M
Michiharu Ariza 已提交
492
    CFFFontDict_OpSerializer  fontSzr;
M
Michiharu Ariza 已提交
493
    if (unlikely (!fda->serialize (&c, plan.offsets.FDArrayInfo.offSize,
M
Michiharu Ariza 已提交
494 495 496 497 498 499 500 501 502 503
                                   acc.fontDicts, plan.subst_fdcount, plan.fdmap,
                                   fontSzr, plan.privateDictInfos)))
    {
      DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF FDArray");
      return false;
    }
  }

  /* CharStrings */
  {
M
Michiharu Ariza 已提交
504
    assert (plan.offsets.charStringsInfo.offset == c.head - c.start);
505
    CFF1CharStrings  *cs = c.start_embed<CFF1CharStrings> ();
M
Michiharu Ariza 已提交
506
    if (unlikely (cs == nullptr)) return false;
M
Michiharu Ariza 已提交
507
    if (unlikely (!cs->serialize (&c, plan.offsets.charStringsInfo.offSize, plan.subset_charstrings)))
M
Michiharu Ariza 已提交
508 509 510 511 512 513 514 515 516 517
    {
      DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF CharStrings");
      return false;
    }
  }

  /* private dicts & local subrs */
  assert (plan.offsets.privateDictInfo.offset == c.head - c.start);
  for (unsigned int i = 0; i < acc.privateDicts.len; i++)
  {
518
    if (!plan.fdmap.excludes (i))
M
Michiharu Ariza 已提交
519
    {
520 521
      PrivateDict  *pd = c.start_embed<PrivateDict> ();
      if (unlikely (pd == nullptr)) return false;
M
Michiharu Ariza 已提交
522
      unsigned int priv_size = plan.flatten_subrs? 0: plan.privateDictInfos[plan.fdmap[i]].size;
523
      bool result;
M
Michiharu Ariza 已提交
524
      CFFPrivateDict_OpSerializer privSzr (plan.drop_hints, plan.flatten_subrs);
525
      /* N.B. local subrs immediately follows its corresponding private dict. i.e., subr offset == private dict size */
M
Michiharu Ariza 已提交
526
      result = pd->serialize (&c, acc.privateDicts[i], privSzr, priv_size);
527
      if (unlikely (!result))
M
Michiharu Ariza 已提交
528
      {
529
        DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF Private Dict[%d]", i);
M
Michiharu Ariza 已提交
530 531
        return false;
      }
M
Michiharu Ariza 已提交
532
      if (!plan.flatten_subrs && (acc.privateDicts[i].subrsOffset != 0))
M
Michiharu Ariza 已提交
533
      {
534 535
        CFF1Subrs *subrs = c.start_embed<CFF1Subrs> ();
        if (unlikely (subrs == nullptr) || acc.privateDicts[i].localSubrs == &Null(CFF1Subrs))
536 537 538 539
        {
          DEBUG_MSG (SUBSET, nullptr, "CFF subset: local subrs unexpectedly null [%d]", i);
          return false;
        }
M
Michiharu Ariza 已提交
540
        if (unlikely (!subrs->serialize (&c, *acc.privateDicts[i].localSubrs, plan.offsets.localSubrsInfos[i].offSize, plan.subrRefMaps.local_maps[i], NULL_SUBR)))
541 542 543 544
        {
          DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF local subrs [%d]", i);
          return false;
        }
M
Michiharu Ariza 已提交
545 546 547 548
      }
    }
  }

M
Michiharu Ariza 已提交
549
  assert (c.head == c.end);
M
Michiharu Ariza 已提交
550 551 552 553 554 555
  c.end_serialize ();

  return true;
}

static bool
556
_hb_subset_cff1 (const OT::cff1::accelerator_subset_t  &acc,
M
Michiharu Ariza 已提交
557 558 559 560 561 562 563 564 565 566 567 568 569 570 571
                const char                      *data,
                hb_subset_plan_t                *plan,
                hb_blob_t                       **prime /* OUT */)
{
  cff_subset_plan cff_plan;

  if (unlikely (!cff_plan.create (acc, plan)))
  {
    DEBUG_MSG(SUBSET, nullptr, "Failed to generate a cff subsetting plan.");
    return false;
  }

  unsigned int  cff_prime_size = cff_plan.get_final_size ();
  char *cff_prime_data = (char *) calloc (1, cff_prime_size);

572
  if (unlikely (!_write_cff1 (cff_plan, acc, plan->glyphs,
M
Michiharu Ariza 已提交
573 574 575 576 577 578 579 580 581 582 583 584 585 586 587
                              cff_prime_size, cff_prime_data))) {
    DEBUG_MSG(SUBSET, nullptr, "Failed to write a subset cff.");
    free (cff_prime_data);
    return false;
  }

  *prime = hb_blob_create (cff_prime_data,
                           cff_prime_size,
                           HB_MEMORY_MODE_READONLY,
                           cff_prime_data,
                           free);
  return true;
}

/**
588
 * hb_subset_cff1:
M
Michiharu Ariza 已提交
589 590 591 592 593
 * Subsets the CFF table according to a provided plan.
 *
 * Return value: subsetted cff table.
 **/
bool
594
hb_subset_cff1 (hb_subset_plan_t *plan,
M
Michiharu Ariza 已提交
595 596
                hb_blob_t       **prime /* OUT */)
{
597
  hb_blob_t *cff_blob = hb_sanitize_context_t().reference_table<CFF::cff1> (plan->source);
M
Michiharu Ariza 已提交
598 599
  const char *data = hb_blob_get_data(cff_blob, nullptr);

600
  OT::cff1::accelerator_subset_t acc;
M
Michiharu Ariza 已提交
601 602
  acc.init(plan->source);
  bool result = likely (acc.is_valid ()) &&
603
                        _hb_subset_cff1 (acc, data, plan, prime);
M
Michiharu Ariza 已提交
604 605 606 607 608
  hb_blob_destroy (cff_blob);
  acc.fini ();

  return result;
}