Commit afe16b6d authored by Ryan VanderMeulen's avatar Ryan VanderMeulen
Browse files

Bug 1748352 - Update OTS to 8.2.1. r=jfkthame

parent ac8e284b
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -2,7 +2,7 @@ This is the Sanitiser for OpenType project, from http://code.google.com/p/ots/.

Our reference repository is https://github.com/khaledhosny/ots/.

Current revision: a6533c4f6a7cb777153c78b78295e42f185ccd3d (8.1.4)
Current revision: 2369c7c00de9e729c79d13e41e2c3601ed2f6c69 (8.2.1)

Upstream files included: LICENSE, src/, include/, tests/*.cc

+19 −3
Original line number Diff line number Diff line
@@ -404,13 +404,17 @@ bool ParsePrivateDictData(
  std::vector<Operand> operands;
  bool cff2 = (out_cff->major == 2);
  bool blend_seen = false;
  uint32_t vsindex = 0;
  int32_t vsindex = 0;

  // Since a Private DICT for FDArray might not have a Local Subr (e.g. Hiragino
  // Kaku Gothic Std W8), we create an empty Local Subr here to match the size
  // of FDArray the size of |local_subrs_per_font|.
  // For CFF2, |vsindex_per_font| gets a similar treatment.
  if (type == DICT_DATA_FDARRAY) {
    out_cff->local_subrs_per_font.push_back(new ots::CFFIndex);
    if (cff2) {
      out_cff->vsindex_per_font.push_back(vsindex);
    }
  }

  while (dict.offset() < dict.length()) {
@@ -527,9 +531,11 @@ bool ParsePrivateDictData(
          return OTS_FAILURE();
        }
        vsindex = operands.back().first;
        if (vsindex >= out_cff->region_index_count.size()) {
        if (vsindex < 0 ||
            vsindex >= (int32_t)out_cff->region_index_count.size()) {
          return OTS_FAILURE();
        }
        out_cff->vsindex_per_font.back() = vsindex;
        break;
      }

@@ -540,7 +546,7 @@ bool ParsePrivateDictData(
        if (operands.size() < 1) {
          return OTS_FAILURE();
        }
        if (vsindex >= out_cff->region_index_count.size()) {
        if (vsindex >= (int32_t)out_cff->region_index_count.size()) {
          return OTS_FAILURE();
        }
        uint16_t k = out_cff->region_index_count.at(vsindex);
@@ -625,6 +631,7 @@ bool ParseDictData(ots::Buffer& table, ots::Buffer& dict,
  bool have_charstrings = false;
  bool have_vstore = false;
  size_t charset_offset = 0;
  bool have_private = false;

  if (cff2) {
    // Parse VariationStore first, since it might be referenced in other places
@@ -640,6 +647,10 @@ bool ParseDictData(ots::Buffer& table, ots::Buffer& dict,
      const uint32_t op = operands.back().first;
      operands.pop_back();

      if (op == 18 && type == DICT_DATA_FDARRAY) {
        have_private = true;
      }

      if (op == 24) {  // vstore
        if (type != DICT_DATA_TOPLEVEL) {
          return OTS_FAILURE();
@@ -661,6 +672,11 @@ bool ParseDictData(ots::Buffer& table, ots::Buffer& dict,
    }
    operands.clear();
    dict.set_offset(dict_offset);

    if (type == DICT_DATA_FDARRAY && !have_private) {
      return OTS_FAILURE();  // CFF2 FD must have PrivateDICT entry (even if 0, 0)
    }

  }

  while (dict.offset() < dict.length()) {
+5 −0
Original line number Diff line number Diff line
@@ -64,6 +64,11 @@ class OpenTypeCFF : public Table {
  // CFF2 VariationStore regionIndexCount.
  std::vector<uint16_t> region_index_count;

  // CFF2 vsindex: per FontDICT->PrivateDICT
  // default of 0 is stored for each font if not
  // explicitly set in Font's PrivateDICT.
  std::vector<int32_t> vsindex_per_font;

 protected:
  bool ValidateFDSelect(uint16_t num_glyphs);

+90 −88
Original line number Diff line number Diff line
@@ -36,10 +36,7 @@ bool ExecuteCharString(ots::OpenTypeCFF& cff,
                       ots::Buffer *cff_table,
                       ots::Buffer *char_string,
                       std::stack<int32_t> *argument_stack,
                       bool *out_found_endchar,
                       bool *out_found_width,
                       size_t *in_out_num_stems,
                       bool cff2);
                       ots::CharStringContext& cs_ctx);

bool ArgumentStackOverflows(std::stack<int32_t> *argument_stack, bool cff2) {
  if ((cff2 && argument_stack->size() > ots::kMaxCFF2ArgumentStack) ||
@@ -266,8 +263,8 @@ bool ValidCFF2Operator(int32_t op) {

// Executes |op| and updates |argument_stack|. Returns true if the execution
// succeeds. If the |op| is kCallSubr or kCallGSubr, the function recursively
// calls ExecuteCharString() function. The arguments other than |op| and
// |argument_stack| are passed for that reason.
// calls ExecuteCharString() function. The |cs_ctx| argument holds values that
// need to persist through these calls (see CharStringContext for details)
bool ExecuteCharStringOperator(ots::OpenTypeCFF& cff,
                               int32_t op,
                               size_t call_depth,
@@ -276,17 +273,11 @@ bool ExecuteCharStringOperator(ots::OpenTypeCFF& cff,
                               ots::Buffer *cff_table,
                               ots::Buffer *char_string,
                               std::stack<int32_t> *argument_stack,
                               bool *out_found_endchar,
                               bool *in_out_found_width,
                               size_t *in_out_num_stems,
                               bool *in_out_have_blend,
                               bool *in_out_have_visindex,
                               int32_t *in_out_vsindex,
                               bool cff2) {
                               ots::CharStringContext& cs_ctx) {
  ots::Font* font = cff.GetFont();
  const size_t stack_size = argument_stack->size();

  if (cff2 && !ValidCFF2Operator(op)) {
  if (cs_ctx.cff2 && !ValidCFF2Operator(op)) {
    return OTS_FAILURE();
  }

@@ -349,62 +340,60 @@ bool ExecuteCharStringOperator(ots::OpenTypeCFF& cff,
                             cff_table,
                             &char_string_to_jump,
                             argument_stack,
                             out_found_endchar,
                             in_out_found_width,
                             in_out_num_stems,
                             cff2);
                             cs_ctx);
  }

  case ots::kReturn:
    return true;

  case ots::kEndChar:
    *out_found_endchar = true;
    *in_out_found_width = true;  // just in case.
    cs_ctx.endchar_seen = true;
    cs_ctx.width_seen = true;  // just in case.
    return true;

  case ots::kVSIndex: {
    if (!cff2) {
    if (!cs_ctx.cff2) {
      return OTS_FAILURE();
    }
    if (stack_size != 1) {
      return OTS_FAILURE();
    }
    if (*in_out_have_blend || *in_out_have_visindex) {
    if (cs_ctx.blend_seen || cs_ctx.vsindex_seen) {
      return OTS_FAILURE();
    }
    if (argument_stack->top() >= cff.region_index_count.size()) {
    if (argument_stack->top() < 0 ||
        argument_stack->top() >= (int32_t)cff.region_index_count.size()) {
      return OTS_FAILURE();
    }
    *in_out_have_visindex = true;
    *in_out_vsindex = argument_stack->top();
    cs_ctx.vsindex_seen = true;
    cs_ctx.vsindex = argument_stack->top();
    while (!argument_stack->empty())
      argument_stack->pop();
    return true;
  }

  case ots::kBlend: {
    if (!cff2) {
    if (!cs_ctx.cff2) {
      return OTS_FAILURE();
    }
    if (stack_size < 1) {
      return OTS_FAILURE();
    }
    if (*in_out_vsindex >= cff.region_index_count.size()) {
    if (cs_ctx.vsindex >= (int32_t)cff.region_index_count.size()) {
      return OTS_FAILURE();
    }
    uint16_t k = cff.region_index_count.at(*in_out_vsindex);
    uint16_t k = cff.region_index_count.at(cs_ctx.vsindex);
    uint16_t n = argument_stack->top();
    if (stack_size < n * (k + 1) + 1) {
      return OTS_FAILURE();
    }

    // Keep the 1st n operands on the stack for the next operator to use and
    // pop the rest. There can be multiple consecutive blend operator, so this
    // pop the rest. There can be multiple consecutive blend operators, so this
    // makes sure the operands of all of them are kept on the stack.
    while (argument_stack->size() > stack_size - ((n * k) + 1))
      argument_stack->pop();
    *in_out_have_blend = true;
    cs_ctx.blend_seen = true;
    return true;
  }

@@ -418,18 +407,18 @@ bool ExecuteCharStringOperator(ots::OpenTypeCFF& cff,
    }
    if ((stack_size % 2) == 0) {
      successful = true;
    } else if ((!(*in_out_found_width)) && (((stack_size - 1) % 2) == 0)) {
    } else if ((!(cs_ctx.width_seen)) && (((stack_size - 1) % 2) == 0)) {
      // The -1 is for "width" argument. For details, see Adobe Technical Note
      // #5177, page 16, note 4.
      successful = true;
    }
    (*in_out_num_stems) += (stack_size / 2);
    if ((*in_out_num_stems) > kMaxNumberOfStemHints) {
    cs_ctx.num_stems += (stack_size / 2);
    if ((cs_ctx.num_stems) > kMaxNumberOfStemHints) {
      return OTS_FAILURE();
    }
    while (!argument_stack->empty())
      argument_stack->pop();
    *in_out_found_width = true;  // always set true since "w" might be 0 byte.
    cs_ctx.width_seen = true;  // always set true since "w" might be 0 byte.
    return successful ? true : OTS_FAILURE();
  }

@@ -437,12 +426,12 @@ bool ExecuteCharStringOperator(ots::OpenTypeCFF& cff,
    bool successful = false;
    if (stack_size == 2) {
      successful = true;
    } else if ((!(*in_out_found_width)) && (stack_size - 1 == 2)) {
    } else if ((!(cs_ctx.width_seen)) && (stack_size - 1 == 2)) {
      successful = true;
    }
    while (!argument_stack->empty())
      argument_stack->pop();
    *in_out_found_width = true;
    cs_ctx.width_seen = true;
    return successful ? true : OTS_FAILURE();
  }

@@ -451,12 +440,12 @@ bool ExecuteCharStringOperator(ots::OpenTypeCFF& cff,
    bool successful = false;
    if (stack_size == 1) {
      successful = true;
    } else if ((!(*in_out_found_width)) && (stack_size - 1 == 1)) {
    } else if ((!(cs_ctx.width_seen)) && (stack_size - 1 == 1)) {
      successful = true;
    }
    while (!argument_stack->empty())
      argument_stack->pop();
    *in_out_found_width = true;
    cs_ctx.width_seen = true;
    return successful ? true : OTS_FAILURE();
  }

@@ -465,15 +454,15 @@ bool ExecuteCharStringOperator(ots::OpenTypeCFF& cff,
    bool successful = false;
    if (stack_size == 0) {
      successful = true;
    } else if ((!(*in_out_found_width)) && (stack_size == 1)) {
    } else if ((!(cs_ctx.width_seen)) && (stack_size == 1)) {
      // A number for "width" is found.
      successful = true;
    } else if ((!(*in_out_found_width)) ||  // in this case, any sizes are ok.
    } else if ((!(cs_ctx.width_seen)) ||  // in this case, any sizes are ok.
               ((stack_size % 2) == 0)) {
      // The numbers are vstem definition.
      // See Adobe Technical Note #5177, page 24, hintmask.
      (*in_out_num_stems) += (stack_size / 2);
      if ((*in_out_num_stems) > kMaxNumberOfStemHints) {
      cs_ctx.num_stems += (stack_size / 2);
      if ((cs_ctx.num_stems) > kMaxNumberOfStemHints) {
        return OTS_FAILURE();
      }
      successful = true;
@@ -482,21 +471,21 @@ bool ExecuteCharStringOperator(ots::OpenTypeCFF& cff,
       return OTS_FAILURE();
    }

    if ((*in_out_num_stems) == 0) {
    if ((cs_ctx.num_stems) == 0) {
      return OTS_FAILURE();
    }
    const size_t mask_bytes = (*in_out_num_stems + 7) / 8;
    const size_t mask_bytes = (cs_ctx.num_stems + 7) / 8;
    if (!char_string->Skip(mask_bytes)) {
      return OTS_FAILURE();
    }
    while (!argument_stack->empty())
      argument_stack->pop();
    *in_out_found_width = true;
    cs_ctx.width_seen = true;
    return true;
  }

  case ots::kRLineTo:
    if (!(*in_out_found_width)) {
    if (!(cs_ctx.width_seen)) {
      // The first stack-clearing operator should be one of hstem, hstemhm,
      // vstem, vstemhm, cntrmask, hintmask, hmoveto, vmoveto, rmoveto, or
      // endchar. For details, see Adobe Technical Note #5177, page 16, note 4.
@@ -514,7 +503,7 @@ bool ExecuteCharStringOperator(ots::OpenTypeCFF& cff,

  case ots::kHLineTo:
  case ots::kVLineTo:
    if (!(*in_out_found_width)) {
    if (!(cs_ctx.width_seen)) {
      return OTS_FAILURE();
    }
    if (stack_size < 1) {
@@ -525,7 +514,7 @@ bool ExecuteCharStringOperator(ots::OpenTypeCFF& cff,
    return true;

  case ots::kRRCurveTo:
    if (!(*in_out_found_width)) {
    if (!(cs_ctx.width_seen)) {
      return OTS_FAILURE();
    }
    if (stack_size < 6) {
@@ -539,7 +528,7 @@ bool ExecuteCharStringOperator(ots::OpenTypeCFF& cff,
    return true;

  case ots::kRCurveLine:
    if (!(*in_out_found_width)) {
    if (!(cs_ctx.width_seen)) {
      return OTS_FAILURE();
    }
    if (stack_size < 8) {
@@ -553,7 +542,7 @@ bool ExecuteCharStringOperator(ots::OpenTypeCFF& cff,
    return true;

  case ots::kRLineCurve:
    if (!(*in_out_found_width)) {
    if (!(cs_ctx.width_seen)) {
      return OTS_FAILURE();
    }
    if (stack_size < 8) {
@@ -567,7 +556,7 @@ bool ExecuteCharStringOperator(ots::OpenTypeCFF& cff,
    return true;

  case ots::kVVCurveTo:
    if (!(*in_out_found_width)) {
    if (!(cs_ctx.width_seen)) {
      return OTS_FAILURE();
    }
    if (stack_size < 4) {
@@ -583,7 +572,7 @@ bool ExecuteCharStringOperator(ots::OpenTypeCFF& cff,

  case ots::kHHCurveTo: {
    bool successful = false;
    if (!(*in_out_found_width)) {
    if (!(cs_ctx.width_seen)) {
      return OTS_FAILURE();
    }
    if (stack_size < 4) {
@@ -604,7 +593,7 @@ bool ExecuteCharStringOperator(ots::OpenTypeCFF& cff,
  case ots::kVHCurveTo:
  case ots::kHVCurveTo: {
    bool successful = false;
    if (!(*in_out_found_width)) {
    if (!(cs_ctx.width_seen)) {
      return OTS_FAILURE();
    }
    if (stack_size < 4) {
@@ -747,7 +736,7 @@ bool ExecuteCharStringOperator(ots::OpenTypeCFF& cff,
    argument_stack->pop();
    argument_stack->push(dummy_result);
    argument_stack->push(dummy_result);
    if (ArgumentStackOverflows(argument_stack, cff2)) {
    if (ArgumentStackOverflows(argument_stack, cs_ctx.cff2)) {
      return OTS_FAILURE();
    }
    // TODO(yusukes): Implement this. We should push a real value for all
@@ -767,7 +756,7 @@ bool ExecuteCharStringOperator(ots::OpenTypeCFF& cff,
    return true;

  case ots::kHFlex:
    if (!(*in_out_found_width)) {
    if (!(cs_ctx.width_seen)) {
      return OTS_FAILURE();
    }
    if (stack_size != 7) {
@@ -778,7 +767,7 @@ bool ExecuteCharStringOperator(ots::OpenTypeCFF& cff,
    return true;

  case ots::kFlex:
    if (!(*in_out_found_width)) {
    if (!(cs_ctx.width_seen)) {
      return OTS_FAILURE();
    }
    if (stack_size != 13) {
@@ -789,7 +778,7 @@ bool ExecuteCharStringOperator(ots::OpenTypeCFF& cff,
    return true;

  case ots::kHFlex1:
    if (!(*in_out_found_width)) {
    if (!(cs_ctx.width_seen)) {
      return OTS_FAILURE();
    }
    if (stack_size != 9) {
@@ -800,7 +789,7 @@ bool ExecuteCharStringOperator(ots::OpenTypeCFF& cff,
    return true;

  case ots::kFlex1:
    if (!(*in_out_found_width)) {
    if (!(cs_ctx.width_seen)) {
      return OTS_FAILURE();
    }
    if (stack_size != 11) {
@@ -816,6 +805,7 @@ bool ExecuteCharStringOperator(ots::OpenTypeCFF& cff,

// Executes |char_string| and updates |argument_stack|.
//
// cff: parent OpenTypeCFF reference
// call_depth: The current call depth. Initial value is zero.
// global_subrs_index: Global subroutines.
// local_subrs_index: Local subroutines for the current glyph.
@@ -823,10 +813,16 @@ bool ExecuteCharStringOperator(ots::OpenTypeCFF& cff,
// char_string: A charstring we'll execute. |char_string| can be a main routine
//              in CharString INDEX, or a subroutine in GlobalSubr/LocalSubr.
// argument_stack: The stack which an operator in |char_string| operates.
// out_found_endchar: true is set if |char_string| contains 'endchar'.
// in_out_found_width: true is set if |char_string| contains 'width' byte (which
//                     is 0 or 1 byte.)
// in_out_num_stems: total number of hstems and vstems processed so far.
// cs_ctx: a CharStringContext holding values to persist across subrs, etc.
//   endchar_seen: true is set if |char_string| contains 'endchar'.
//   width_seen: true is set if |char_string| contains 'width' byte (which
//               is 0 or 1 byte) or if cff2
//   num_stems: total number of hstems and vstems processed so far.
//   cff2: true if this is a CFF2 table
//   blend_seen: initially false; set to true if 'blend' operator encountered.
//   vsindex_seen: initially false; set to true if 'vsindex' encountered.
//   vsindex: initially = PrivateDICT's vsindex; may be changed by 'vsindex'
//            operator in CharString
bool ExecuteCharString(ots::OpenTypeCFF& cff,
                       size_t call_depth,
                       const ots::CFFIndex& global_subrs_index,
@@ -834,17 +830,12 @@ bool ExecuteCharString(ots::OpenTypeCFF& cff,
                       ots::Buffer *cff_table,
                       ots::Buffer *char_string,
                       std::stack<int32_t> *argument_stack,
                       bool *out_found_endchar,
                       bool *in_out_found_width,
                       size_t *in_out_num_stems,
                       bool cff2) {
                       ots::CharStringContext& cs_ctx) {
  if (call_depth > kMaxSubrNesting) {
    return OTS_FAILURE();
  }
  *out_found_endchar = false;
  cs_ctx.endchar_seen = false;

  bool in_out_have_blend = false, in_out_have_visindex = false;
  int32_t in_out_vsindex = 0;
  const size_t length = char_string->length();
  while (char_string->offset() < length) {
    int32_t operator_or_operand = 0;
@@ -873,7 +864,7 @@ bool ExecuteCharString(ots::OpenTypeCFF& cff,

    if (!is_operator) {
      argument_stack->push(operator_or_operand);
      if (ArgumentStackOverflows(argument_stack, cff2)) {
      if (ArgumentStackOverflows(argument_stack, cs_ctx.cff2)) {
        return OTS_FAILURE();
      }
      continue;
@@ -888,16 +879,10 @@ bool ExecuteCharString(ots::OpenTypeCFF& cff,
                                   cff_table,
                                   char_string,
                                   argument_stack,
                                   out_found_endchar,
                                   in_out_found_width,
                                   in_out_num_stems,
                                   &in_out_have_blend,
                                   &in_out_have_visindex,
                                   &in_out_vsindex,
                                   cff2)) {
                                   cs_ctx)) {
      return OTS_FAILURE();
    }
    if (*out_found_endchar) {
    if (cs_ctx.endchar_seen) {
      return true;
    }
    if (operator_or_operand == ots::kReturn) {
@@ -905,13 +890,13 @@ bool ExecuteCharString(ots::OpenTypeCFF& cff,
    }
  }

  // No endchar operator is found.
  if (cff2)
  // No endchar operator is found (CFF1 only)
  if (cs_ctx.cff2)
    return true;
  return OTS_FAILURE();
}

// Selects a set of subroutings for |glyph_index| from |cff| and sets it on
// Selects a set of subroutines for |glyph_index| from |cff| and sets it on
// |out_local_subrs_to_use|. Returns true on success.
bool SelectLocalSubr(const ots::OpenTypeCFF& cff,
                     uint16_t glyph_index,  // 0-origin
@@ -960,7 +945,6 @@ bool ValidateCFFCharStrings(
    return OTS_FAILURE();  // no charstring.
  }

  bool cff2 = (cff.major == 2);
  // For each glyph, validate the corresponding charstring.
  for (unsigned i = 1; i < char_strings_index.offsets.size(); ++i) {
    // Prepare a Buffer object, |char_string|, which contains the charstring
@@ -993,20 +977,38 @@ bool ValidateCFFCharStrings(

    // Check a charstring for the |i|-th glyph.
    std::stack<int32_t> argument_stack;
    bool found_endchar = false;
    // Context to store values that must persist across subrs, etc.
    CharStringContext cs_ctx;
    cs_ctx.cff2 = (cff.major == 2);
    // CFF2 CharString has no value for width, so we start with true here to
    // error out if width is found.
    bool found_width = cff2;
    size_t num_stems = 0;
    cs_ctx.width_seen = cs_ctx.cff2;
    // CFF2 CharStrings' default vsindex comes from the associated PrivateDICT
    if (cs_ctx.cff2) {
      const auto& iter = cff.fd_select.find(glyph_index);
      auto fd_index = 0;
      if (iter != cff.fd_select.end()) {
        fd_index = iter->second;
      }
      if (fd_index >= (int32_t)cff.vsindex_per_font.size()) {
        // shouldn't get this far with a font in this condition, but just in case
        return OTS_FAILURE();  // fd_index out-of-range
      }
      cs_ctx.vsindex = cff.vsindex_per_font.at(fd_index);
    }

#ifdef DUMP_T2CHARSTRING
    fprintf(stderr, "\n---- CharString %*d ----\n", 5, glyph_index);
#endif

    if (!ExecuteCharString(cff,
                           0 /* initial call_depth is zero */,
                           global_subrs_index, *local_subrs_to_use,
                           cff_table, &char_string, &argument_stack,
                           &found_endchar, &found_width, &num_stems,
                           cff2)) {
                           cs_ctx)) {
      return OTS_FAILURE();
    }
    if (!cff2 && !found_endchar) {
    if (!cs_ctx.cff2 && !cs_ctx.endchar_seen) {
      return OTS_FAILURE();
    }
  }
+13 −6
Original line number Diff line number Diff line
@@ -21,7 +21,7 @@ const size_t kMaxCFF2ArgumentStack = 513;
// http://www.adobe.com/devnet/font/pdfs/5177.Type2.pdf
//
// The validation will fail if one of the following conditions is met:
//  1. The code uses more than 48 values of argument stack.
//  1. The code uses more than the max argument stack size (48 for CFF1; 513 for CFF2)
//  2. The code uses deeply nested subroutine calls (more than 10 levels.)
//  3. The code passes invalid number of operands to an operator.
//  4. The code calls an undefined global or local subroutine.
@@ -29,12 +29,9 @@ const size_t kMaxCFF2ArgumentStack = 513;
//     an ordinary fonts, and could be dangerous: random, put, get, index, roll.
//
// Arguments:
//  cff: parent OpenTypeCFF reference
//  global_subrs_index: Global subroutines which could be called by a charstring
//                      in |char_strings_index|.
//  fd_select: A map from glyph # to font #.
//  local_subrs_per_font: A list of Local Subrs associated with FDArrays. Can be
//                        empty.
//  local_subrs: A Local Subrs associated with Top DICT. Can be NULL.
//  cff_table: A buffer which contains actual byte code of charstring, global
//             subroutines and local subroutines.
bool ValidateCFFCharStrings(
@@ -95,7 +92,17 @@ enum CharStringOperator {
  kFlex = (12 << 8) + 35,
  kHFlex1 = (12 << 8) + 36,
  kFlex1 = (12 << 8) + 37,
  // Operators that are undocumented, such as 'blend', will be rejected.
  // Operators that are undocumented will be rejected.
};

struct CharStringContext {
  bool endchar_seen = false;
  bool width_seen = false;
  size_t num_stems = 0;
  bool cff2 = false;
  bool blend_seen = false;
  bool vsindex_seen = false;
  int32_t vsindex = 0;
};

}  // namespace ots
Loading