hb-ot-cff-common.hh 19.5 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
/*
 * 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
 */
M
Michiharu Ariza 已提交
26 27
#ifndef HB_OT_CFF_COMMON_HH
#define HB_OT_CFF_COMMON_HH
M
Michiharu Ariza 已提交
28

29 30 31
#include "hb-open-type.hh"
#include "hb-ot-layout-common.hh"
#include "hb-cff-interp-dict-common.hh"
M
Michiharu Ariza 已提交
32
#include "hb-subset-plan.hh"
M
Michiharu Ariza 已提交
33 34 35 36 37

namespace CFF {

using namespace OT;

M
Michiharu Ariza 已提交
38 39 40 41 42
/* utility macro */
template<typename Type>
static inline const Type& StructAtOffsetOrNull(const void *P, unsigned int offset)
{ return offset? (* reinterpret_cast<const Type*> ((const char *) P + offset)): Null(Type); }

M
Michiharu Ariza 已提交
43 44 45 46 47 48 49 50 51 52 53
inline unsigned int calcOffSize(unsigned int offset)
{
  unsigned int size = 1;
  while ((offset & ~0xFF) != 0)
  {
    size++;
    offset >>= 8;
  }
  assert (size <= 4);
  return size;
}
M
Michiharu Ariza 已提交
54 55

/* CFF INDEX */
M
Michiharu Ariza 已提交
56
template <typename COUNT>
57
struct CFFIndex
M
Michiharu Ariza 已提交
58 59 60 61
{
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
    TRACE_SANITIZE (this);
62 63 64 65
    return_trace (likely ((count.sanitize (c) && count == 0) || /* empty INDEX */
                          (c->check_struct (this) && offSize >= 1 && offSize <= 4 &&
                           c->check_array (offsets, offSize, count + 1) &&
                           c->check_array (data_base (), 1, max_offset () - 1))));
M
Michiharu Ariza 已提交
66 67
  }

M
Michiharu Ariza 已提交
68
  inline static unsigned int calculate_offset_array_size (unsigned int offSize, unsigned int count)
M
Michiharu Ariza 已提交
69 70
  { return offSize * (count + 1); }

M
Michiharu Ariza 已提交
71 72 73 74 75 76
  inline unsigned int offset_array_size (void) const
  { return calculate_offset_array_size (offSize, count); }

  inline static unsigned int calculate_serialized_size (unsigned int offSize, unsigned int count, unsigned int dataSize)
  { return min_size + calculate_offset_array_size (offSize, count) + dataSize; }

77
  inline bool serialize (hb_serialize_context_t *c, const CFFIndex &src)
M
Michiharu Ariza 已提交
78
  {
M
Michiharu Ariza 已提交
79
    TRACE_SERIALIZE (this);
M
Michiharu Ariza 已提交
80
    unsigned int size = src.get_size ();
81
    CFFIndex *dest = c->allocate_size<CFFIndex> (size);
M
Michiharu Ariza 已提交
82 83 84 85 86 87
    if (unlikely (dest == nullptr)) return_trace (false);
    memcpy (dest, &src, size);
    return_trace (true);
  }

  inline bool serialize (hb_serialize_context_t *c,
M
Michiharu Ariza 已提交
88 89
                         unsigned int offSize_,
                         const hb_vector_t<ByteStr> &byteArray)
M
Michiharu Ariza 已提交
90 91
  {
    TRACE_SERIALIZE (this);
92
    /* serialize CFFIndex header */
M
Michiharu Ariza 已提交
93
    if (unlikely (!c->extend_min (*this))) return_trace (false);
M
Michiharu Ariza 已提交
94 95 96
    this->count.set (byteArray.len);
    this->offSize.set (offSize_);
    if (!unlikely (c->allocate_size<HBUINT8> (offSize_ * (byteArray.len + 1))))
M
Michiharu Ariza 已提交
97 98 99 100
      return_trace (false);
  
    /* serialize indices */
    unsigned int  offset = 1;
M
Michiharu Ariza 已提交
101
    unsigned int  i = 0;
M
Michiharu Ariza 已提交
102
    for (; i < byteArray.len; i++)
M
Michiharu Ariza 已提交
103 104
    {
      set_offset_at (i, offset);
M
Michiharu Ariza 已提交
105
      offset += byteArray[i].get_size ();
M
Michiharu Ariza 已提交
106
    }
M
Michiharu Ariza 已提交
107
    set_offset_at (i, offset);
M
Michiharu Ariza 已提交
108 109

    /* serialize data */
M
Michiharu Ariza 已提交
110
    for (unsigned int i = 0; i < byteArray.len; i++)
M
Michiharu Ariza 已提交
111
    {
M
Michiharu Ariza 已提交
112 113 114
      ByteStr  *dest = c->start_embed<ByteStr> ();
      if (unlikely (dest == nullptr ||
                    !dest->serialize (c, byteArray[i])))
M
Michiharu Ariza 已提交
115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131
        return_trace (false);
    }
    return_trace (true);
  }

  inline void set_offset_at (unsigned int index, unsigned int offset)
  {
    HBUINT8 *p = offsets + offSize * index + offSize;
    unsigned int size = offSize;
    for (; size; size--)
    {
      --p;
      p->set (offset & 0xFF);
      offset >>= 8;
    }
  }

M
Michiharu Ariza 已提交
132 133
  inline const unsigned int offset_at (unsigned int index) const
  {
134
    assert (index <= count);
M
Michiharu Ariza 已提交
135 136 137 138 139 140 141 142 143 144 145 146
    const HBUINT8 *p = offsets + offSize * index;
    unsigned int size = offSize;
    unsigned int offset = 0;
    for (; size; size--)
      offset = (offset << 8) + *p++;
    return offset;
  }

  inline const unsigned int length_at (unsigned int index) const
  { return offset_at (index + 1) - offset_at (index); }

  inline const char *data_base (void) const
M
Michiharu Ariza 已提交
147
  { return (const char *)this + min_size + offset_array_size (); }
M
Michiharu Ariza 已提交
148 149 150 151

  inline unsigned int data_size (void) const
  { return HBINT8::static_size; };

M
Michiharu Ariza 已提交
152
  ByteStr operator [] (unsigned int index) const
M
Michiharu Ariza 已提交
153 154
  {
    if (likely (index < count))
M
Michiharu Ariza 已提交
155 156 157
      return ByteStr (data_base () + offset_at (index) - 1, offset_at (index + 1) - offset_at (index));
    else
      return Null(ByteStr);
M
Michiharu Ariza 已提交
158 159 160
  }

  inline unsigned int get_size (void) const
M
Michiharu Ariza 已提交
161
  {
162
    if (this != &Null(CFFIndex))
163 164 165 166
    {
      if (count > 0)
        return min_size + offset_array_size () + (offset_at (count) - 1);
      else
167
        return count.static_size;  /* empty CFFIndex contains count only */
168
    }
M
Michiharu Ariza 已提交
169 170 171
    else
      return 0;
  }
M
Michiharu Ariza 已提交
172

173 174 175 176 177 178 179 180 181 182 183 184 185
  protected:
  inline unsigned int max_offset (void) const
  {
    unsigned int max = 0;
    for (unsigned int i = 0; i <= count; i++)
    {
      unsigned int off = offset_at (i);
      if (off > max) max = off;
    }
    return max;
  }

  public:
M
Michiharu Ariza 已提交
186
  COUNT     count;        /* Number of object data. Note there are (count+1) offsets */
M
Michiharu Ariza 已提交
187 188 189 190
  HBUINT8   offSize;      /* The byte size of each offset in the offsets array. */
  HBUINT8   offsets[VAR]; /* The array of (count + 1) offsets into objects array (1-base). */
  /* HBUINT8 data[VAR];      Object data */
  public:
M
Michiharu Ariza 已提交
191
  DEFINE_SIZE_ARRAY (COUNT::static_size + HBUINT8::static_size, offsets);
M
Michiharu Ariza 已提交
192 193
};

M
Michiharu Ariza 已提交
194
template <typename COUNT, typename TYPE>
195
struct IndexOf : CFFIndex<COUNT>
M
Michiharu Ariza 已提交
196
{
M
Michiharu Ariza 已提交
197
  inline const ByteStr operator [] (unsigned int index) const
M
Michiharu Ariza 已提交
198
  {
199 200
    if (likely (index < CFFIndex<COUNT>::count))
      return ByteStr (CFFIndex<COUNT>::data_base () + CFFIndex<COUNT>::offset_at (index) - 1, CFFIndex<COUNT>::length_at (index));
M
Michiharu Ariza 已提交
201
    return Null(ByteStr);
M
Michiharu Ariza 已提交
202
  }
M
Michiharu Ariza 已提交
203 204 205 206 207 208 209 210 211 212

  template <typename DATA, typename PARAM1, typename PARAM2>
  inline bool serialize (hb_serialize_context_t *c,
                         unsigned int offSize_,
                         const hb_vector_t<DATA> &dataArray,
                         const hb_vector_t<unsigned int> &dataSizeArray,
                         const PARAM1 &param1,
                         const PARAM2 &param2)
  {
    TRACE_SERIALIZE (this);
213
    /* serialize CFFIndex header */
M
Michiharu Ariza 已提交
214 215 216 217 218 219 220 221 222 223 224
    if (unlikely (!c->extend_min (*this))) return_trace (false);
    this->count.set (dataArray.len);
    this->offSize.set (offSize_);
    if (!unlikely (c->allocate_size<HBUINT8> (offSize_ * (dataArray.len + 1))))
      return_trace (false);
  
    /* serialize indices */
    unsigned int  offset = 1;
    unsigned int  i = 0;
    for (; i < dataArray.len; i++)
    {
225
      CFFIndex<COUNT>::set_offset_at (i, offset);
M
Michiharu Ariza 已提交
226 227
      offset += dataSizeArray[i];
    }
228
    CFFIndex<COUNT>::set_offset_at (i, offset);
M
Michiharu Ariza 已提交
229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257

    /* serialize data */
    for (unsigned int i = 0; i < dataArray.len; i++)
    {
      TYPE  *dest = c->start_embed<TYPE> ();
      if (unlikely (dest == nullptr ||
                    !dest->serialize (c, dataArray[i], param1, param2)))
        return_trace (false);
    }
    return_trace (true);
  }

  /* in parallel to above */
  template <typename DATA, typename PARAM>
  inline static unsigned int calculate_serialized_size (unsigned int &offSize_ /* OUT */,
                                                        const hb_vector_t<DATA> &dataArray,
                                                        hb_vector_t<unsigned int> &dataSizeArray, /* OUT */
                                                        const PARAM &param)
  {
    /* determine offset size */
    unsigned int  totalDataSize = 0;
    for (unsigned int i = 0; i < dataArray.len; i++)
    {
      unsigned int dataSize = TYPE::calculate_serialized_size (dataArray[i], param);
      dataSizeArray[i] = dataSize;
      totalDataSize += dataSize;
    }
    offSize_ = calcOffSize (totalDataSize);

258
    return CFFIndex<COUNT>::calculate_serialized_size (offSize_, dataArray.len, totalDataSize);
M
Michiharu Ariza 已提交
259 260 261
  }
};

M
Michiharu Ariza 已提交
262
/* Top Dict, Font Dict, Private Dict */
M
Michiharu Ariza 已提交
263 264
struct Dict : UnsizedByteStr
{
265
  template <typename DICTVAL, typename OP_SERIALIZER, typename PARAM>
M
Michiharu Ariza 已提交
266
  inline bool serialize (hb_serialize_context_t *c,
267
                        const DICTVAL &dictval,
M
Michiharu Ariza 已提交
268 269 270 271
                        OP_SERIALIZER& opszr,
                        PARAM& param)
  {
    TRACE_SERIALIZE (this);
272
    for (unsigned int i = 0; i < dictval.values.len; i++)
M
Michiharu Ariza 已提交
273
    {
274
      if (unlikely (!opszr.serialize (c, dictval.values[i], param)))
M
Michiharu Ariza 已提交
275 276 277 278
        return_trace (false);
    }
    return_trace (true);
  }
M
Michiharu Ariza 已提交
279

M
Michiharu Ariza 已提交
280
  /* in parallel to above */
281 282
  template <typename DICTVAL, typename OP_SERIALIZER>
  inline static unsigned int calculate_serialized_size (const DICTVAL &dictval,
M
Michiharu Ariza 已提交
283 284 285
                                                        OP_SERIALIZER& opszr)
  {
    unsigned int size = 0;
286 287
    for (unsigned int i = 0; i < dictval.values.len; i++)
      size += opszr.calculate_serialized_size (dictval.values[i]);
M
Michiharu Ariza 已提交
288 289 290 291 292 293 294 295 296 297 298 299 300 301
    return size;
  }

  template <typename INTTYPE, int minVal, int maxVal>
  inline static bool serialize_offset_op (hb_serialize_context_t *c, OpCode op, int value, OpCode intOp)
  {
    if (value == 0)
      return true;
    // XXX: not sure why but LLVM fails to compile the following 'unlikely' macro invocation
    if (/*unlikely*/ (!serialize_int<INTTYPE, minVal, maxVal> (c, intOp, value)))
      return false;

    TRACE_SERIALIZE (this);
    /* serialize the opcode */
M
Michiharu Ariza 已提交
302
    HBUINT8 *p = c->allocate_size<HBUINT8> (OpCode_Size (op));
M
Michiharu Ariza 已提交
303
    if (unlikely (p == nullptr)) return_trace (false);
M
Michiharu Ariza 已提交
304
    if (Is_OpCode_ESC (op))
M
Michiharu Ariza 已提交
305 306
    {
      p->set (OpCode_escape);
M
Michiharu Ariza 已提交
307
      op = Unmake_OpCode_ESC (op);
M
Michiharu Ariza 已提交
308 309 310 311 312 313 314
      p++;
    }
    p->set (op);
    return_trace (true);
  }

  inline static bool serialize_offset4_op (hb_serialize_context_t *c, OpCode op, int value)
M
Michiharu Ariza 已提交
315
  { return serialize_offset_op<HBUINT32, 0, 0x7FFFFFFF> (c, op, value, OpCode_longintdict); }
M
Michiharu Ariza 已提交
316 317 318 319 320 321 322 323 324

  inline static bool serialize_offset2_op (hb_serialize_context_t *c, OpCode op, int value)
  { return serialize_offset_op<HBUINT16, 0, 0x7FFF> (c, op, value, OpCode_shortint); }
};

struct TopDict : Dict {};
struct FontDict : Dict {};
struct PrivateDict : Dict {};

M
Michiharu Ariza 已提交
325 326
struct TableInfo
{
M
Michiharu Ariza 已提交
327
  void init (void) { offSize = offset = size = 0; }
M
Michiharu Ariza 已提交
328 329 330

  unsigned int    offset;
  unsigned int    size;
M
Michiharu Ariza 已提交
331
  unsigned int    offSize;
M
Michiharu Ariza 已提交
332 333
};

334 335 336 337 338 339 340 341 342 343 344 345 346
/* font dict index remap table from fullset FDArray to subset FDArray.
 * set to HB_SET_VALUE_INVALID if excluded from subset */
struct FDMap : hb_vector_t<hb_codepoint_t>
{
  inline void init (void)
  { hb_vector_t<hb_codepoint_t>::init (); }

  inline void fini (void)
  { hb_vector_t<hb_codepoint_t>::fini (); }

  inline bool fullset (void) const
  {
    for (unsigned int i = 0; i < len; i++)
M
Michiharu Ariza 已提交
347
      if (hb_vector_t<hb_codepoint_t>::operator[] (i) == HB_SET_VALUE_INVALID)
348 349 350 351 352 353
        return false;
    return true;
  }

  inline bool excludes (hb_codepoint_t fd) const
  { return (fd < len) && ((*this)[fd] == HB_SET_VALUE_INVALID); }
354 355 356 357 358 359 360 361 362 363 364 365 366 367

  inline hb_codepoint_t operator[] (hb_codepoint_t i) const
  {
    if (fullset ())
      return i;
    else
      return hb_vector_t<hb_codepoint_t>::operator[] (i);
  }

  inline hb_codepoint_t &operator[] (hb_codepoint_t i)
  {
    assert (i < len);
    return hb_vector_t<hb_codepoint_t>::operator[] (i);
  }
368 369
};

M
Michiharu Ariza 已提交
370 371
template <typename COUNT>
struct FDArray : IndexOf<COUNT, FontDict>
M
Michiharu Ariza 已提交
372 373 374
{
  template <typename DICTVAL, typename OP_SERIALIZER>
  inline bool serialize (hb_serialize_context_t *c,
M
Michiharu Ariza 已提交
375
                        unsigned int offSize_,
M
Michiharu Ariza 已提交
376
                        const hb_vector_t<DICTVAL> &fontDicts,
M
Michiharu Ariza 已提交
377
                        unsigned int fdCount,
378
                        const FDMap &fdmap,
M
Michiharu Ariza 已提交
379
                        OP_SERIALIZER& opszr,
M
Michiharu Ariza 已提交
380
                        const hb_vector_t<TableInfo> &privateInfos)
M
Michiharu Ariza 已提交
381 382 383
  {
    TRACE_SERIALIZE (this);
    if (unlikely (!c->extend_min (*this))) return_trace (false);
M
Michiharu Ariza 已提交
384
    this->count.set (fdCount);
M
Michiharu Ariza 已提交
385 386
    this->offSize.set (offSize_);
    if (!unlikely (c->allocate_size<HBUINT8> (offSize_ * (fdCount + 1))))
M
Michiharu Ariza 已提交
387 388 389 390
      return_trace (false);
    
    /* serialize font dict offsets */
    unsigned int  offset = 1;
M
Michiharu Ariza 已提交
391 392
    unsigned int  fid = 0;
    for (unsigned i = 0; i < fontDicts.len; i++)
393
      if (!fdmap.excludes (i))
M
Michiharu Ariza 已提交
394
      {
M
Michiharu Ariza 已提交
395
        IndexOf<COUNT, FontDict>::set_offset_at (fid++, offset);
M
Michiharu Ariza 已提交
396 397
        offset += FontDict::calculate_serialized_size (fontDicts[i], opszr);
      }
M
Michiharu Ariza 已提交
398
    IndexOf<COUNT, FontDict>::set_offset_at (fid, offset);
M
Michiharu Ariza 已提交
399 400 401

    /* serialize font dicts */
    for (unsigned int i = 0; i < fontDicts.len; i++)
402
      if (!fdmap.excludes (i))
M
Michiharu Ariza 已提交
403 404
      {
        FontDict *dict = c->start_embed<FontDict> ();
405
        if (unlikely (!dict->serialize (c, fontDicts[i], opszr, privateInfos[fdmap[i]])))
M
Michiharu Ariza 已提交
406 407
          return_trace (false);
      }
M
Michiharu Ariza 已提交
408 409 410 411 412
    return_trace (true);
  }
  
  /* in parallel to above */
  template <typename OP_SERIALIZER, typename DICTVAL>
M
Michiharu Ariza 已提交
413
  inline static unsigned int calculate_serialized_size (unsigned int &offSize_ /* OUT */,
M
Michiharu Ariza 已提交
414
                                                        const hb_vector_t<DICTVAL> &fontDicts,
M
Michiharu Ariza 已提交
415
                                                        unsigned int fdCount,
416
                                                        const FDMap &fdmap,
M
Michiharu Ariza 已提交
417 418 419 420
                                                        OP_SERIALIZER& opszr)
  {
    unsigned int dictsSize = 0;
    for (unsigned int i = 0; i < fontDicts.len; i++)
421
      if (!fdmap.excludes (i))
M
Michiharu Ariza 已提交
422
        dictsSize += FontDict::calculate_serialized_size (fontDicts[i], opszr);
M
Michiharu Ariza 已提交
423

M
Michiharu Ariza 已提交
424
    offSize_ = calcOffSize (dictsSize + 1);
425
    return CFFIndex<COUNT>::calculate_serialized_size (offSize_, fdCount, dictsSize);
M
Michiharu Ariza 已提交
426 427
  }
};
M
Michiharu Ariza 已提交
428 429 430

/* FDSelect */
struct FDSelect0 {
M
Michiharu Ariza 已提交
431
  inline bool sanitize (hb_sanitize_context_t *c, unsigned int fdcount) const
432 433
  {
    TRACE_SANITIZE (this);
M
Michiharu Ariza 已提交
434 435 436 437 438 439 440 441 442 443 444 445
    if (unlikely (!(c->check_struct (this))))
      return_trace (false);
    for (unsigned int i = 0; i < c->get_num_glyphs (); i++)
      if (unlikely (!fds[i].sanitize (c)))
        return_trace (false);

    return_trace (true);
  }

  inline hb_codepoint_t get_fd (hb_codepoint_t glyph) const
  {
    return (hb_codepoint_t)fds[glyph];
446 447
  }

M
Michiharu Ariza 已提交
448 449 450
  inline unsigned int get_size (unsigned int num_glyphs) const
  { return HBUINT8::static_size * num_glyphs; }

M
Michiharu Ariza 已提交
451
  HBUINT8     fds[VAR];
452 453

  DEFINE_SIZE_MIN (1);
M
Michiharu Ariza 已提交
454 455
};

M
Michiharu Ariza 已提交
456 457 458
template <typename GID_TYPE, typename FD_TYPE>
struct FDSelect3_4_Range {
  inline bool sanitize (hb_sanitize_context_t *c, unsigned int fdcount) const
459 460
  {
    TRACE_SANITIZE (this);
M
Michiharu Ariza 已提交
461
    return_trace (likely (c->check_struct (this) && (first < c->get_num_glyphs ()) && (fd < fdcount)));
462 463
  }

M
Michiharu Ariza 已提交
464 465
  GID_TYPE    first;
  FD_TYPE     fd;
466

M
Michiharu Ariza 已提交
467
  DEFINE_SIZE_STATIC (GID_TYPE::static_size + FD_TYPE::static_size);
M
Michiharu Ariza 已提交
468 469
};

M
Michiharu Ariza 已提交
470 471
template <typename GID_TYPE, typename FD_TYPE>
struct FDSelect3_4 {
M
Michiharu Ariza 已提交
472
  inline unsigned int get_size (void) const
M
Michiharu Ariza 已提交
473
  { return GID_TYPE::static_size * 2 + FDSelect3_4_Range<GID_TYPE, FD_TYPE>::static_size * nRanges; }
M
Michiharu Ariza 已提交
474

M
Michiharu Ariza 已提交
475
  inline bool sanitize (hb_sanitize_context_t *c, unsigned int fdcount) const
476 477
  {
    TRACE_SANITIZE (this);
M
Michiharu Ariza 已提交
478 479 480 481 482 483 484 485 486 487 488 489 490 491
    if (unlikely (!(c->check_struct (this) && (nRanges > 0) && (ranges[0].first == 0))))
      return_trace (false);

    for (unsigned int i = 0; i < nRanges; i++)
    {
      if (unlikely (!ranges[i].sanitize (c, fdcount)))
        return_trace (false);
      if ((0 < i) && unlikely (ranges[i - 1].first >= ranges[i].first))
        return_trace (false);
    }
    if (unlikely (!sentinel().sanitize (c) || (sentinel() != c->get_num_glyphs ())))
      return_trace (false);

    return_trace (true);
492 493
  }

M
Michiharu Ariza 已提交
494 495
  inline hb_codepoint_t get_fd (hb_codepoint_t glyph) const
  {
M
Michiharu Ariza 已提交
496 497 498
    for (unsigned int i = 1; i < nRanges; i++)
      if (glyph < ranges[i].first)
        return (hb_codepoint_t)ranges[i - 1].fd;
M
Michiharu Ariza 已提交
499 500 501

    assert (false);
  }
502

M
Michiharu Ariza 已提交
503 504 505 506 507 508 509 510
  inline GID_TYPE &sentinel (void)  { return StructAfter<GID_TYPE> (ranges[nRanges - 1]); }
  inline const GID_TYPE &sentinel (void) const  { return StructAfter<GID_TYPE> (ranges[nRanges - 1]); }

  GID_TYPE         nRanges;
  FDSelect3_4_Range<GID_TYPE, FD_TYPE>  ranges[VAR];
  /* GID_TYPE sentinel */

  DEFINE_SIZE_ARRAY (GID_TYPE::static_size * 2, ranges);
M
Michiharu Ariza 已提交
511 512
};

M
Michiharu Ariza 已提交
513 514 515
typedef FDSelect3_4<HBUINT16, HBUINT8> FDSelect3;
typedef FDSelect3_4_Range<HBUINT16, HBUINT8> FDSelect3_Range;

M
Michiharu Ariza 已提交
516
struct FDSelect {
M
Michiharu Ariza 已提交
517
  inline bool sanitize (hb_sanitize_context_t *c, unsigned int fdcount) const
518 519
  {
    TRACE_SANITIZE (this);
M
Michiharu Ariza 已提交
520

521
    return_trace (likely (c->check_struct (this) && (format == 0 || format == 3) &&
M
Michiharu Ariza 已提交
522 523 524
                          (format == 0)?
                          u.format0.sanitize (c, fdcount):
                          u.format3.sanitize (c, fdcount)));
525 526
  }

M
Michiharu Ariza 已提交
527 528
  inline bool serialize (hb_serialize_context_t *c, const FDSelect &src, unsigned int num_glyphs)
  {
M
Michiharu Ariza 已提交
529
    TRACE_SERIALIZE (this);
M
Michiharu Ariza 已提交
530 531 532 533 534 535 536 537 538 539 540 541 542 543 544
    unsigned int size = src.get_size (num_glyphs);
    FDSelect *dest = c->allocate_size<FDSelect> (size);
    if (unlikely (dest == nullptr)) return_trace (false);
    memcpy (dest, &src, size);
    return_trace (true);
  }

  inline unsigned int calculate_serialized_size (unsigned int num_glyphs) const
  { return get_size (num_glyphs); }

  inline unsigned int get_size (unsigned int num_glyphs) const
  {
    unsigned int size = format.static_size;
    if (format == 0)
      size += u.format0.get_size (num_glyphs);
M
Michiharu Ariza 已提交
545
    else
M
Michiharu Ariza 已提交
546 547 548 549
      size += u.format3.get_size ();
    return size;
  }

M
Michiharu Ariza 已提交
550 551
  inline hb_codepoint_t get_fd (hb_codepoint_t glyph) const
  {
M
Michiharu Ariza 已提交
552 553
    if (this == &Null(FDSelect))
      return 0;
M
Michiharu Ariza 已提交
554 555 556 557 558 559
    if (format == 0)
      return u.format0.get_fd (glyph);
    else
      return u.format3.get_fd (glyph);
  }

M
Michiharu Ariza 已提交
560 561 562 563 564
  HBUINT8       format;
  union {
    FDSelect0   format0;
    FDSelect3   format3;
  } u;
565

M
Michiharu Ariza 已提交
566
  DEFINE_SIZE_MIN (1);
M
Michiharu Ariza 已提交
567 568
};

M
Michiharu Ariza 已提交
569
template <typename COUNT>
570
struct Subrs : CFFIndex<COUNT>
M
Michiharu Ariza 已提交
571
{
M
Michiharu Ariza 已提交
572
  inline bool serialize (hb_serialize_context_t *c, const Subrs<COUNT> &subrs, unsigned int offSize, const hb_set_t *set, const ByteStr& nullStr = ByteStr())
M
Michiharu Ariza 已提交
573
  {
M
Michiharu Ariza 已提交
574
    TRACE_SERIALIZE (this);
M
Michiharu Ariza 已提交
575 576
    if (&subrs == &Null(Subrs<COUNT>))
      return_trace (true);
M
Michiharu Ariza 已提交
577
    if ((subrs.count == 0) || (set == nullptr) || (hb_set_is_empty (set)))
M
Michiharu Ariza 已提交
578
    {
M
Michiharu Ariza 已提交
579 580
      if (!unlikely (c->allocate_size<COUNT> (COUNT::static_size)))
        return_trace (false);
581
      CFFIndex<COUNT>::count.set (0);
M
Michiharu Ariza 已提交
582
      return_trace (true);
M
Michiharu Ariza 已提交
583 584
    }
    
M
Michiharu Ariza 已提交
585 586 587 588 589 590
    hb_vector_t<ByteStr> bytesArray;
    bytesArray.init ();
    if (!bytesArray.resize (subrs.count))
      return_trace (false);
    for (hb_codepoint_t i = 0; i < subrs.count; i++)
      bytesArray[i] = (hb_set_has (set, i))? subrs[i]: nullStr;
M
Michiharu Ariza 已提交
591

592
    bool result = CFFIndex<COUNT>::serialize (c, offSize, bytesArray);
M
Michiharu Ariza 已提交
593 594
    bytesArray.fini ();
    return_trace (result);
M
Michiharu Ariza 已提交
595 596
  }
  
M
Michiharu Ariza 已提交
597 598
  /* in parallel to above */
  inline unsigned int calculate_serialized_size (unsigned int &offSize /*OUT*/, const hb_set_t *set, unsigned int nullStrSize = 0) const
M
Michiharu Ariza 已提交
599
  {
M
Michiharu Ariza 已提交
600 601
    if (this == &Null(Subrs<COUNT>))
      return 0;
602
    unsigned int  count_ = CFFIndex<COUNT>::count;
M
Michiharu Ariza 已提交
603 604 605
    offSize = 0;
    if ((count_ == 0) || (hb_set_get_population (set) == 0))
      return COUNT::static_size;
M
Michiharu Ariza 已提交
606

M
Michiharu Ariza 已提交
607 608
    unsigned int dataSize = 0;
    for (hb_codepoint_t i = 0; i < count_; i++)
M
Michiharu Ariza 已提交
609
    {
M
Michiharu Ariza 已提交
610 611 612 613
      if (hb_set_has (set, i))
        dataSize += (*this)[i].len;
      else
        dataSize += nullStrSize;
M
Michiharu Ariza 已提交
614
    }
M
Michiharu Ariza 已提交
615
    offSize = calcOffSize(dataSize);
616
    return CFFIndex<COUNT>::calculate_serialized_size (offSize, count_, dataSize);
M
Michiharu Ariza 已提交
617 618 619 620 621
  }
};

} /* namespace CFF */

M
Michiharu Ariza 已提交
622
#endif /* HB_OT_CFF_COMMON_HH */
M
Michiharu Ariza 已提交
623