16263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org// Copyright (c) 2010 The Chromium Authors. All rights reserved.
26263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org// Use of this source code is governed by a BSD-style license that can be
36263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org// found in the LICENSE file.
46263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org
56263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org// A parser for the Type 2 Charstring Format.
66263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org// http://www.adobe.com/devnet/font/pdfs/5177.Type2.pdf
76263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org
86263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org#include "cff_type2_charstring.h"
96263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org
10fbb12969b4421ce7a155b7b34a7d855580d0f669yusukes@chromium.org#include <climits>
116263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org#include <cstdio>
126263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org#include <cstring>
136263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org#include <stack>
146263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org#include <string>
156263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org#include <utility>
166263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org
176263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.orgnamespace {
186263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org
196263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org// Type 2 Charstring Implementation Limits. See Appendix. B in Adobe Technical
206263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org// Note #5177.
21fbb12969b4421ce7a155b7b34a7d855580d0f669yusukes@chromium.orgconst int32_t kMaxSubrsCount = 65536;
226263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.orgconst size_t kMaxCharStringLength = 65535;
236263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.orgconst size_t kMaxArgumentStack = 48;
246263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.orgconst size_t kMaxNumberOfStemHints = 96;
256263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.orgconst size_t kMaxSubrNesting = 10;
266263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org
27fbb12969b4421ce7a155b7b34a7d855580d0f669yusukes@chromium.org// |dummy_result| should be a huge positive integer so callsubr and callgsubr
28fbb12969b4421ce7a155b7b34a7d855580d0f669yusukes@chromium.org// will fail with the dummy value.
29fbb12969b4421ce7a155b7b34a7d855580d0f669yusukes@chromium.orgconst int32_t dummy_result = INT_MAX;
30fbb12969b4421ce7a155b7b34a7d855580d0f669yusukes@chromium.org
316263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.orgbool ExecuteType2CharString(size_t call_depth,
326263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org                            const ots::CFFIndex& global_subrs_index,
336263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org                            const ots::CFFIndex& local_subrs_index,
346263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org                            ots::Buffer *cff_table,
356263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org                            ots::Buffer *char_string,
366263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org                            std::stack<int32_t> *argument_stack,
376263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org                            bool *out_found_endchar,
386263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org                            bool *out_found_width,
396263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org                            size_t *in_out_num_stems);
406263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org
416263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org// Read one or more bytes from the |char_string| buffer and stores the number
426263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org// read on |out_number|. If the number read is an operator (ex 'vstem'), sets
436263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org// true on |out_is_operator|. Returns true if the function read a number.
446263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.orgbool ReadNextNumberFromType2CharString(ots::Buffer *char_string,
456263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org                                       int32_t *out_number,
466263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org                                       bool *out_is_operator) {
476263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org  uint8_t v = 0;
486263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org  if (!char_string->ReadU8(&v)) {
496263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    return OTS_FAILURE();
506263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org  }
516263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org  *out_is_operator = false;
526263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org
536263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org  // The conversion algorithm is described in Adobe Technical Note #5177, page
546263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org  // 13, Table 1.
556263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org  if (v <= 11) {
566263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    *out_number = v;
576263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    *out_is_operator = true;
586263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org  } else if (v == 12) {
596263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    uint16_t result = (v << 8);
606263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    if (!char_string->ReadU8(&v)) {
616263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org      return OTS_FAILURE();
626263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    }
636263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    result += v;
646263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    *out_number = result;
656263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    *out_is_operator = true;
666263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org  } else if (v <= 27) {
676263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    // Special handling for v==19 and v==20 are implemented in
686263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    // ExecuteType2CharStringOperator().
696263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    *out_number = v;
706263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    *out_is_operator = true;
716263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org  } else if (v == 28) {
726263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    if (!char_string->ReadU8(&v)) {
736263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org      return OTS_FAILURE();
746263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    }
756263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    uint16_t result = (v << 8);
766263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    if (!char_string->ReadU8(&v)) {
776263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org      return OTS_FAILURE();
786263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    }
796263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    result += v;
806263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    *out_number = result;
816263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org  } else if (v <= 31) {
826263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    *out_number = v;
836263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    *out_is_operator = true;
846263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org  } else if (v <= 246) {
856263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    *out_number = static_cast<int32_t>(v) - 139;
866263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org  } else if (v <= 250) {
876263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    uint8_t w = 0;
886263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    if (!char_string->ReadU8(&w)) {
896263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org      return OTS_FAILURE();
906263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    }
916263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    *out_number = ((static_cast<int32_t>(v) - 247) * 256) +
926263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org        static_cast<int32_t>(w) + 108;
936263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org  } else if (v <= 254) {
946263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    uint8_t w = 0;
956263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    if (!char_string->ReadU8(&w)) {
966263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org      return OTS_FAILURE();
976263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    }
986263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    *out_number = -((static_cast<int32_t>(v) - 251) * 256) -
996263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org        static_cast<int32_t>(w) - 108;
1006263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org  } else if (v == 255) {
101fbb12969b4421ce7a155b7b34a7d855580d0f669yusukes@chromium.org    // TODO(yusukes): We should not skip the 4 bytes. Note that when v is 255,
102fbb12969b4421ce7a155b7b34a7d855580d0f669yusukes@chromium.org    // we should treat the following 4-bytes as a 16.16 fixed-point number
1036263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    // rather than 32bit signed int.
104fbb12969b4421ce7a155b7b34a7d855580d0f669yusukes@chromium.org    if (!char_string->Skip(4)) {
105fbb12969b4421ce7a155b7b34a7d855580d0f669yusukes@chromium.org      return OTS_FAILURE();
106fbb12969b4421ce7a155b7b34a7d855580d0f669yusukes@chromium.org    }
107fbb12969b4421ce7a155b7b34a7d855580d0f669yusukes@chromium.org    *out_number = dummy_result;
1086263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org  } else {
1096263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    return OTS_FAILURE();
1106263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org  }
1116263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org
1126263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org  return true;
1136263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org}
1146263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org
1156263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org// Executes |op| and updates |argument_stack|. Returns true if the execution
1166263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org// succeeds. If the |op| is kCallSubr or kCallGSubr, the function recursively
1176263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org// calls ExecuteType2CharString() function. The arguments other than |op| and
1186263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org// |argument_stack| are passed for that reason.
1196263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.orgbool ExecuteType2CharStringOperator(int32_t op,
1206263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org                                    size_t call_depth,
1216263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org                                    const ots::CFFIndex& global_subrs_index,
1226263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org                                    const ots::CFFIndex& local_subrs_index,
1236263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org                                    ots::Buffer *cff_table,
1246263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org                                    ots::Buffer *char_string,
1256263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org                                    std::stack<int32_t> *argument_stack,
1266263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org                                    bool *out_found_endchar,
1276263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org                                    bool *in_out_found_width,
1286263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org                                    size_t *in_out_num_stems) {
1296263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org  const size_t stack_size = argument_stack->size();
1306263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org
1316263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org  switch (op) {
132fbb12969b4421ce7a155b7b34a7d855580d0f669yusukes@chromium.org  case ots::kCallSubr:
133fbb12969b4421ce7a155b7b34a7d855580d0f669yusukes@chromium.org  case ots::kCallGSubr: {
1346263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    const ots::CFFIndex& subrs_index =
135fbb12969b4421ce7a155b7b34a7d855580d0f669yusukes@chromium.org        (op == ots::kCallSubr ? local_subrs_index : global_subrs_index);
1366263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org
1376263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    if (stack_size < 1) {
1386263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org      return OTS_FAILURE();
1396263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    }
1406263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    int32_t subr_number = argument_stack->top();
1416263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    argument_stack->pop();
1426263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    if (subr_number == dummy_result) {
1436263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org      // For safety, we allow subr calls only with immediate subr numbers for
1446263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org      // now. For example, we allow "123 callgsubr", but does not allow "100 12
1456263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org      // add callgsubr". Please note that arithmetic and conditional operators
1466263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org      // always push the |dummy_result| in this implementation.
1476263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org      return OTS_FAILURE();
1486263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    }
1496263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org
1506263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    // See Adobe Technical Note #5176 (CFF), "16. Local/GlobalSubrs INDEXes."
1516263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    int32_t bias = 32768;
1526263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    if (subrs_index.count < 1240) {
1536263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org      bias = 107;
1546263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    } else if (subrs_index.count < 33900) {
1556263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org      bias = 1131;
1566263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    }
1576263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    subr_number += bias;
1586263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org
1596263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    // Sanity checks of |subr_number|.
1606263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    if (subr_number < 0) {
1616263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org      return OTS_FAILURE();
1626263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    }
163fbb12969b4421ce7a155b7b34a7d855580d0f669yusukes@chromium.org    if (subr_number >= kMaxSubrsCount) {
164fbb12969b4421ce7a155b7b34a7d855580d0f669yusukes@chromium.org      return OTS_FAILURE();
165fbb12969b4421ce7a155b7b34a7d855580d0f669yusukes@chromium.org    }
166fbb12969b4421ce7a155b7b34a7d855580d0f669yusukes@chromium.org    if (subrs_index.offsets.size() <= static_cast<size_t>(subr_number + 1)) {
1676263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org      return OTS_FAILURE();  // The number is out-of-bounds.
1686263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    }
1696263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org
1706263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    // Prepare ots::Buffer where we're going to jump.
1716263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    const size_t length =
1726263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org      subrs_index.offsets[subr_number + 1] - subrs_index.offsets[subr_number];
1736263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    if (length > kMaxCharStringLength) {
1746263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org      return OTS_FAILURE();
1756263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    }
1766263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    const size_t offset = subrs_index.offsets[subr_number];
1776263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    cff_table->set_offset(offset);
1786263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    if (!cff_table->Skip(length)) {
1796263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org      return OTS_FAILURE();
1806263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    }
1816263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    ots::Buffer char_string_to_jump(cff_table->buffer() + offset, length);
1826263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org
1836263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    return ExecuteType2CharString(call_depth + 1,
1846263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org                                  global_subrs_index,
1856263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org                                  local_subrs_index,
1866263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org                                  cff_table,
1876263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org                                  &char_string_to_jump,
1886263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org                                  argument_stack,
1896263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org                                  out_found_endchar,
1906263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org                                  in_out_found_width,
1916263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org                                  in_out_num_stems);
1926263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org  }
1936263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org
194fbb12969b4421ce7a155b7b34a7d855580d0f669yusukes@chromium.org  case ots::kReturn:
1956263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    return true;
1966263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org
197fbb12969b4421ce7a155b7b34a7d855580d0f669yusukes@chromium.org  case ots::kEndChar:
1986263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    *out_found_endchar = true;
1996263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    *in_out_found_width = true;  // just in case.
2006263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    return true;
2016263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org
202fbb12969b4421ce7a155b7b34a7d855580d0f669yusukes@chromium.org  case ots::kHStem:
203fbb12969b4421ce7a155b7b34a7d855580d0f669yusukes@chromium.org  case ots::kVStem:
204fbb12969b4421ce7a155b7b34a7d855580d0f669yusukes@chromium.org  case ots::kHStemHm:
205fbb12969b4421ce7a155b7b34a7d855580d0f669yusukes@chromium.org  case ots::kVStemHm: {
2066263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    bool successful = false;
2076263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    if (stack_size < 2) {
2086263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org      return OTS_FAILURE();
2096263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    }
2106263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    if ((stack_size % 2) == 0) {
2116263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org      successful = true;
2126263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    } else if ((!(*in_out_found_width)) && (((stack_size - 1) % 2) == 0)) {
2136263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org      // The -1 is for "width" argument. For details, see Adobe Technical Note
2146263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org      // #5177, page 16, note 4.
2156263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org      successful = true;
2166263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    }
2176263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    (*in_out_num_stems) += (stack_size / 2);
2186263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    if ((*in_out_num_stems) > kMaxNumberOfStemHints) {
2196263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org      return OTS_FAILURE();
2206263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    }
2216263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    while (!argument_stack->empty())
2226263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org      argument_stack->pop();
2236263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    *in_out_found_width = true;  // always set true since "w" might be 0 byte.
2246263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    return successful ? true : OTS_FAILURE();
2256263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org  }
2266263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org
227fbb12969b4421ce7a155b7b34a7d855580d0f669yusukes@chromium.org  case ots::kRMoveTo: {
2286263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    bool successful = false;
2296263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    if (stack_size == 2) {
2306263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org      successful = true;
2316263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    } else if ((!(*in_out_found_width)) && (stack_size - 1 == 2)) {
2326263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org      successful = true;
2336263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    }
2346263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    while (!argument_stack->empty())
2356263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org      argument_stack->pop();
2366263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    *in_out_found_width = true;
2376263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    return successful ? true : OTS_FAILURE();
2386263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org  }
2396263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org
240fbb12969b4421ce7a155b7b34a7d855580d0f669yusukes@chromium.org  case ots::kVMoveTo:
241fbb12969b4421ce7a155b7b34a7d855580d0f669yusukes@chromium.org  case ots::kHMoveTo: {
2426263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    bool successful = false;
2436263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    if (stack_size == 1) {
2446263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org      successful = true;
2456263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    } else if ((!(*in_out_found_width)) && (stack_size - 1 == 1)) {
2466263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org      successful = true;
2476263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    }
2486263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    while (!argument_stack->empty())
2496263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org      argument_stack->pop();
2506263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    *in_out_found_width = true;
2516263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    return successful ? true : OTS_FAILURE();
2526263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org  }
2536263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org
254fbb12969b4421ce7a155b7b34a7d855580d0f669yusukes@chromium.org  case ots::kHintMask:
255fbb12969b4421ce7a155b7b34a7d855580d0f669yusukes@chromium.org  case ots::kCntrMask: {
2566263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    bool successful = false;
2576263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    if (stack_size == 0) {
2586263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org      successful = true;
2596263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    } else if ((!(*in_out_found_width)) && (stack_size == 1)) {
2606263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org      // A number for "width" is found.
2616263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org      successful = true;
2626263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    } else if ((!(*in_out_found_width)) ||  // in this case, any sizes are ok.
2636263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org               ((stack_size % 2) == 0)) {
2646263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org      // The numbers are vstem definition.
2656263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org      // See Adobe Technical Note #5177, page 24, hintmask.
2666263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org      (*in_out_num_stems) += (stack_size / 2);
2676263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org      if ((*in_out_num_stems) > kMaxNumberOfStemHints) {
2686263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org        return OTS_FAILURE();
2696263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org      }
2706263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org      successful = true;
2716263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    }
2726263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    if (!successful) {
2736263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org       return OTS_FAILURE();
2746263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    }
2756263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org
2766263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    if ((*in_out_num_stems) == 0) {
2776263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org      return OTS_FAILURE();
2786263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    }
2796263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    const size_t mask_bytes = (*in_out_num_stems + 7) / 8;
2806263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    if (!char_string->Skip(mask_bytes)) {
2816263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org      return OTS_FAILURE();
2826263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    }
2836263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    while (!argument_stack->empty())
2846263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org      argument_stack->pop();
2856263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    *in_out_found_width = true;
2866263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    return true;
2876263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org  }
2886263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org
289fbb12969b4421ce7a155b7b34a7d855580d0f669yusukes@chromium.org  case ots::kRLineTo:
2906263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    if (!(*in_out_found_width)) {
2916263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org      // The first stack-clearing operator should be one of hstem, hstemhm,
2926263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org      // vstem, vstemhm, cntrmask, hintmask, hmoveto, vmoveto, rmoveto, or
2936263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org      // endchar. For details, see Adobe Technical Note #5177, page 16, note 4.
2946263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org      return OTS_FAILURE();
2956263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    }
2966263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    if (stack_size < 2) {
2976263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org      return OTS_FAILURE();
2986263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    }
2996263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    if ((stack_size % 2) != 0) {
3006263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org      return OTS_FAILURE();
3016263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    }
3026263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    while (!argument_stack->empty())
3036263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org      argument_stack->pop();
3046263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    return true;
3056263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org
306fbb12969b4421ce7a155b7b34a7d855580d0f669yusukes@chromium.org  case ots::kHLineTo:
307fbb12969b4421ce7a155b7b34a7d855580d0f669yusukes@chromium.org  case ots::kVLineTo:
3086263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    if (!(*in_out_found_width)) {
3096263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org      return OTS_FAILURE();
3106263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    }
3116263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    if (stack_size < 1) {
3126263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org      return OTS_FAILURE();
3136263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    }
3146263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    while (!argument_stack->empty())
3156263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org      argument_stack->pop();
3166263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    return true;
3176263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org
318fbb12969b4421ce7a155b7b34a7d855580d0f669yusukes@chromium.org  case ots::kRRCurveTo:
3196263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    if (!(*in_out_found_width)) {
3206263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org      return OTS_FAILURE();
3216263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    }
3226263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    if (stack_size < 6) {
3236263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org      return OTS_FAILURE();
3246263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    }
3256263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    if ((stack_size % 6) != 0) {
3266263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org      return OTS_FAILURE();
3276263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    }
3286263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    while (!argument_stack->empty())
3296263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org      argument_stack->pop();
3306263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    return true;
3316263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org
332fbb12969b4421ce7a155b7b34a7d855580d0f669yusukes@chromium.org  case ots::kRCurveLine:
3336263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    if (!(*in_out_found_width)) {
3346263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org      return OTS_FAILURE();
3356263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    }
3366263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    if (stack_size < 8) {
3376263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org      return OTS_FAILURE();
3386263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    }
3396263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    if (((stack_size - 2) % 6) != 0) {
3406263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org      return OTS_FAILURE();
3416263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    }
3426263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    while (!argument_stack->empty())
3436263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org      argument_stack->pop();
3446263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    return true;
3456263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org
346fbb12969b4421ce7a155b7b34a7d855580d0f669yusukes@chromium.org  case ots::kRLineCurve:
3476263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    if (!(*in_out_found_width)) {
3486263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org      return OTS_FAILURE();
3496263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    }
3506263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    if (stack_size < 8) {
3516263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org      return OTS_FAILURE();
3526263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    }
3536263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    if (((stack_size - 6) % 2) != 0) {
3546263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org      return OTS_FAILURE();
3556263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    }
3566263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    while (!argument_stack->empty())
3576263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org      argument_stack->pop();
3586263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    return true;
3596263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org
360fbb12969b4421ce7a155b7b34a7d855580d0f669yusukes@chromium.org  case ots::kVVCurveTo:
3616263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    if (!(*in_out_found_width)) {
3626263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org      return OTS_FAILURE();
3636263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    }
3646263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    if (stack_size < 4) {
3656263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org      return OTS_FAILURE();
3666263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    }
3676263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    if (((stack_size % 4) != 0) &&
3686263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org        (((stack_size - 1) % 4) != 0)) {
3696263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org      return OTS_FAILURE();
3706263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    }
3716263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    while (!argument_stack->empty())
3726263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org      argument_stack->pop();
3736263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    return true;
3746263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org
375fbb12969b4421ce7a155b7b34a7d855580d0f669yusukes@chromium.org  case ots::kHHCurveTo: {
3766263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    bool successful = false;
3776263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    if (!(*in_out_found_width)) {
3786263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org      return OTS_FAILURE();
3796263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    }
3806263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    if (stack_size < 4) {
3816263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org      return OTS_FAILURE();
3826263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    }
3836263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    if ((stack_size % 4) == 0) {
3846263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org      // {dxa dxb dyb dxc}+
3856263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org      successful = true;
3866263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    } else if (((stack_size - 1) % 4) == 0) {
3876263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org      // dy1? {dxa dxb dyb dxc}+
3886263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org      successful = true;
3896263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    }
3906263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    while (!argument_stack->empty())
3916263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org      argument_stack->pop();
3926263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    return successful ? true : OTS_FAILURE();
3936263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org  }
3946263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org
395fbb12969b4421ce7a155b7b34a7d855580d0f669yusukes@chromium.org  case ots::kVHCurveTo:
396fbb12969b4421ce7a155b7b34a7d855580d0f669yusukes@chromium.org  case ots::kHVCurveTo: {
3976263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    bool successful = false;
3986263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    if (!(*in_out_found_width)) {
3996263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org      return OTS_FAILURE();
4006263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    }
4016263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    if (stack_size < 4) {
4026263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org      return OTS_FAILURE();
4036263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    }
4046263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    if (((stack_size - 4) % 8) == 0) {
4056263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org      // dx1 dx2 dy2 dy3 {dya dxb dyb dxc dxd dxe dye dyf}*
4066263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org      successful = true;
4076263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    } else if ((stack_size >= 5) &&
4086263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org               ((stack_size - 5) % 8) == 0) {
4096263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org      // dx1 dx2 dy2 dy3 {dya dxb dyb dxc dxd dxe dye dyf}* dxf
4106263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org      successful = true;
4116263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    } else if ((stack_size >= 8) &&
4126263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org               ((stack_size - 8) % 8) == 0) {
4136263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org      // {dxa dxb dyb dyc dyd dxe dye dxf}+
4146263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org      successful = true;
4156263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    } else if ((stack_size >= 9) &&
4166263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org               ((stack_size - 9) % 8) == 0) {
4176263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org      // {dxa dxb dyb dyc dyd dxe dye dxf}+ dyf?
4186263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org      successful = true;
4196263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    }
4206263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    while (!argument_stack->empty())
4216263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org      argument_stack->pop();
4226263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    return successful ? true : OTS_FAILURE();
4236263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org  }
4246263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org
425fbb12969b4421ce7a155b7b34a7d855580d0f669yusukes@chromium.org  case ots::kAnd:
426fbb12969b4421ce7a155b7b34a7d855580d0f669yusukes@chromium.org  case ots::kOr:
427fbb12969b4421ce7a155b7b34a7d855580d0f669yusukes@chromium.org  case ots::kEq:
428fbb12969b4421ce7a155b7b34a7d855580d0f669yusukes@chromium.org  case ots::kAdd:
429fbb12969b4421ce7a155b7b34a7d855580d0f669yusukes@chromium.org  case ots::kSub:
4306263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    if (stack_size < 2) {
4316263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org      return OTS_FAILURE();
4326263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    }
4336263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    argument_stack->pop();
4346263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    argument_stack->pop();
4356263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    argument_stack->push(dummy_result);
4366263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    // TODO(yusukes): Implement this. We should push a real value for all
4376263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    // arithmetic and conditional operations.
4386263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    return true;
4396263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org
440fbb12969b4421ce7a155b7b34a7d855580d0f669yusukes@chromium.org  case ots::kNot:
441fbb12969b4421ce7a155b7b34a7d855580d0f669yusukes@chromium.org  case ots::kAbs:
442fbb12969b4421ce7a155b7b34a7d855580d0f669yusukes@chromium.org  case ots::kNeg:
4436263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    if (stack_size < 1) {
4446263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org      return OTS_FAILURE();
4456263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    }
4466263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    argument_stack->pop();
4476263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    argument_stack->push(dummy_result);
4486263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    // TODO(yusukes): Implement this. We should push a real value for all
4496263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    // arithmetic and conditional operations.
4506263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    return true;
4516263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org
452fbb12969b4421ce7a155b7b34a7d855580d0f669yusukes@chromium.org  case ots::kDiv:
4536263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    // TODO(yusukes): Should detect div-by-zero errors.
454fbb12969b4421ce7a155b7b34a7d855580d0f669yusukes@chromium.org    if (stack_size < 2) {
4556263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org      return OTS_FAILURE();
4566263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    }
4576263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    argument_stack->pop();
458fbb12969b4421ce7a155b7b34a7d855580d0f669yusukes@chromium.org    argument_stack->pop();
4596263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    argument_stack->push(dummy_result);
4606263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    // TODO(yusukes): Implement this. We should push a real value for all
4616263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    // arithmetic and conditional operations.
4626263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    return true;
4636263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org
464fbb12969b4421ce7a155b7b34a7d855580d0f669yusukes@chromium.org  case ots::kDrop:
4656263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    if (stack_size < 1) {
4666263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org      return OTS_FAILURE();
4676263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    }
4686263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    argument_stack->pop();
4696263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    return true;
4706263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org
471fbb12969b4421ce7a155b7b34a7d855580d0f669yusukes@chromium.org  case ots::kPut:
472fbb12969b4421ce7a155b7b34a7d855580d0f669yusukes@chromium.org  case ots::kGet:
473fbb12969b4421ce7a155b7b34a7d855580d0f669yusukes@chromium.org  case ots::kIndex:
4746263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    // For now, just call OTS_FAILURE since there is no way to check whether the
4756263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    // index argument, |i|, is out-of-bounds or not. Fortunately, no OpenType
4766263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    // fonts I have (except malicious ones!) use the operators.
4776263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    // TODO(yusukes): Implement them in a secure way.
4786263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    return OTS_FAILURE();
4796263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org
480fbb12969b4421ce7a155b7b34a7d855580d0f669yusukes@chromium.org  case ots::kRoll:
4816263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    // Likewise, just call OTS_FAILURE for kRoll since there is no way to check
4826263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    // whether |N| is smaller than the current stack depth or not.
4836263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    // TODO(yusukes): Implement them in a secure way.
4846263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    return OTS_FAILURE();
4856263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org
486fbb12969b4421ce7a155b7b34a7d855580d0f669yusukes@chromium.org  case ots::kRandom:
4876263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    // For now, we don't handle the 'random' operator since the operator makes
4886263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    // it hard to analyze hinting code statically.
4896263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    return OTS_FAILURE();
4906263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org
491fbb12969b4421ce7a155b7b34a7d855580d0f669yusukes@chromium.org  case ots::kIfElse:
4926263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    if (stack_size < 4) {
4936263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org      return OTS_FAILURE();
4946263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    }
4956263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    argument_stack->pop();
4966263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    argument_stack->pop();
4976263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    argument_stack->pop();
4986263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    argument_stack->pop();
4996263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    argument_stack->push(dummy_result);
5006263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    // TODO(yusukes): Implement this. We should push a real value for all
5016263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    // arithmetic and conditional operations.
5026263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    return true;
5036263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org
504fbb12969b4421ce7a155b7b34a7d855580d0f669yusukes@chromium.org  case ots::kMul:
5056263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    // TODO(yusukes): Should detect overflows.
5066263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    if (stack_size < 2) {
5076263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org      return OTS_FAILURE();
5086263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    }
5096263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    argument_stack->pop();
5106263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    argument_stack->pop();
5116263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    argument_stack->push(dummy_result);
5126263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    // TODO(yusukes): Implement this. We should push a real value for all
5136263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    // arithmetic and conditional operations.
5146263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    return true;
5156263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org
516fbb12969b4421ce7a155b7b34a7d855580d0f669yusukes@chromium.org  case ots::kSqrt:
5176263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    // TODO(yusukes): Should check if the argument is negative.
5186263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    if (stack_size < 1) {
5196263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org      return OTS_FAILURE();
5206263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    }
5216263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    argument_stack->pop();
5226263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    argument_stack->push(dummy_result);
5236263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    // TODO(yusukes): Implement this. We should push a real value for all
5246263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    // arithmetic and conditional operations.
5256263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    return true;
5266263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org
527fbb12969b4421ce7a155b7b34a7d855580d0f669yusukes@chromium.org  case ots::kDup:
5286263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    if (stack_size < 1) {
5296263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org      return OTS_FAILURE();
5306263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    }
5316263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    argument_stack->pop();
5326263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    argument_stack->push(dummy_result);
5336263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    argument_stack->push(dummy_result);
5346263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    if (argument_stack->size() > kMaxArgumentStack) {
5356263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org      return OTS_FAILURE();
5366263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    }
5376263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    // TODO(yusukes): Implement this. We should push a real value for all
5386263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    // arithmetic and conditional operations.
5396263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    return true;
5406263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org
541fbb12969b4421ce7a155b7b34a7d855580d0f669yusukes@chromium.org  case ots::kExch:
5426263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    if (stack_size < 2) {
5436263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org      return OTS_FAILURE();
5446263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    }
5456263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    argument_stack->pop();
5466263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    argument_stack->pop();
5476263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    argument_stack->push(dummy_result);
5486263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    argument_stack->push(dummy_result);
5496263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    // TODO(yusukes): Implement this. We should push a real value for all
5506263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    // arithmetic and conditional operations.
5516263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    return true;
5526263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org
553fbb12969b4421ce7a155b7b34a7d855580d0f669yusukes@chromium.org  case ots::kHFlex:
5546263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    if (!(*in_out_found_width)) {
5556263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org      return OTS_FAILURE();
5566263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    }
5576263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    if (stack_size != 7) {
5586263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org      return OTS_FAILURE();
5596263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    }
5606263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    while (!argument_stack->empty())
5616263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org      argument_stack->pop();
5626263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    return true;
5636263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org
564fbb12969b4421ce7a155b7b34a7d855580d0f669yusukes@chromium.org  case ots::kFlex:
5656263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    if (!(*in_out_found_width)) {
5666263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org      return OTS_FAILURE();
5676263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    }
5686263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    if (stack_size != 13) {
5696263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org      return OTS_FAILURE();
5706263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    }
5716263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    while (!argument_stack->empty())
5726263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org      argument_stack->pop();
5736263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    return true;
5746263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org
575fbb12969b4421ce7a155b7b34a7d855580d0f669yusukes@chromium.org  case ots::kHFlex1:
5766263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    if (!(*in_out_found_width)) {
5776263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org      return OTS_FAILURE();
5786263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    }
5796263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    if (stack_size != 9) {
5806263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org      return OTS_FAILURE();
5816263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    }
5826263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    while (!argument_stack->empty())
5836263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org      argument_stack->pop();
5846263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    return true;
5856263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org
586fbb12969b4421ce7a155b7b34a7d855580d0f669yusukes@chromium.org  case ots::kFlex1:
5876263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    if (!(*in_out_found_width)) {
5886263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org      return OTS_FAILURE();
5896263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    }
5906263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    if (stack_size != 11) {
5916263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org      return OTS_FAILURE();
5926263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    }
5936263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    while (!argument_stack->empty())
5946263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org      argument_stack->pop();
5956263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    return true;
5966263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org  }
5976263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org
5986263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org  OTS_WARNING("Undefined operator: %d (0x%x)", op, op);
5996263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org  return OTS_FAILURE();
6006263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org}
6016263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org
6026263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org// Executes |char_string| and updates |argument_stack|.
6036263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org//
6046263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org// call_depth: The current call depth. Initial value is zero.
6056263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org// global_subrs_index: Global subroutines.
6066263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org// local_subrs_index: Local subroutines for the current glyph.
6076263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org// cff_table: A whole CFF table which contains all global and local subroutines.
6086263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org// char_string: A charstring we'll execute. |char_string| can be a main routine
6096263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org//              in CharString INDEX, or a subroutine in GlobalSubr/LocalSubr.
6106263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org// argument_stack: The stack which an operator in |char_string| operates.
6116263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org// out_found_endchar: true is set if |char_string| contains 'endchar'.
6126263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org// in_out_found_width: true is set if |char_string| contains 'width' byte (which
6136263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org//                     is 0 or 1 byte.)
6146263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org// in_out_num_stems: total number of hstems and vstems processed so far.
6156263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.orgbool ExecuteType2CharString(size_t call_depth,
6166263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org                            const ots::CFFIndex& global_subrs_index,
6176263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org                            const ots::CFFIndex& local_subrs_index,
6186263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org                            ots::Buffer *cff_table,
6196263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org                            ots::Buffer *char_string,
6206263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org                            std::stack<int32_t> *argument_stack,
6216263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org                            bool *out_found_endchar,
6226263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org                            bool *in_out_found_width,
6236263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org                            size_t *in_out_num_stems) {
6246263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org  if (call_depth > kMaxSubrNesting) {
6256263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    return OTS_FAILURE();
6266263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org  }
6276263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org  *out_found_endchar = false;
6286263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org
6296263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org  const size_t length = char_string->length();
6306263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org  while (char_string->offset() < length) {
6316263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    int32_t operator_or_operand = 0;
6326263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    bool is_operator = false;
6336263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    if (!ReadNextNumberFromType2CharString(char_string,
6346263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org                                           &operator_or_operand,
6356263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org                                           &is_operator)) {
6366263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org      return OTS_FAILURE();
6376263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    }
6386263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org
6396263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    /*
6406263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org      You can dump all operators and operands (except mask bytes for hintmask
6416263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org      and cntrmask) by the following code:
6426263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org
6436263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org      if (!is_operator) {
6446263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org        std::fprintf(stderr, "#%d# ", operator_or_operand);
6456263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org      } else {
6466263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org        std::fprintf(stderr, "#%s#\n",
6476263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org           Type2CharStringOperatorToString(
6486263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org               Type2CharStringOperator(operator_or_operand)),
6496263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org           operator_or_operand);
6506263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org      }
6516263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    */
6526263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org
6536263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    if (!is_operator) {
6546263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org      argument_stack->push(operator_or_operand);
6556263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org      if (argument_stack->size() > kMaxArgumentStack) {
6566263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org        return OTS_FAILURE();
6576263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org      }
6586263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org      continue;
6596263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    }
6606263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org
6616263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    // An operator is found. Execute it.
6626263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    if (!ExecuteType2CharStringOperator(operator_or_operand,
6636263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org                                        call_depth,
6646263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org                                        global_subrs_index,
6656263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org                                        local_subrs_index,
6666263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org                                        cff_table,
6676263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org                                        char_string,
6686263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org                                        argument_stack,
6696263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org                                        out_found_endchar,
6706263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org                                        in_out_found_width,
6716263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org                                        in_out_num_stems)) {
6726263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org      return OTS_FAILURE();
6736263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    }
6746263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    if (*out_found_endchar) {
6756263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org      return true;
6766263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    }
677fbb12969b4421ce7a155b7b34a7d855580d0f669yusukes@chromium.org    if (operator_or_operand == ots::kReturn) {
6786263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org      return true;
6796263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    }
6806263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org  }
6816263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org
6826263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org  // No endchar operator is found.
6836263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org  return OTS_FAILURE();
6846263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org}
6856263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org
6866263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org// Selects a set of subroutings for |glyph_index| from |cff| and sets it on
6876263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org// |out_local_subrs_to_use|. Returns true on success.
6886263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.orgbool SelectLocalSubr(const std::map<uint16_t, uint8_t> &fd_select,
6896263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org                     const std::vector<ots::CFFIndex *> &local_subrs_per_font,
6906263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org                     const ots::CFFIndex *local_subrs,
6916263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org                     uint16_t glyph_index,  // 0-origin
6926263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org                     const ots::CFFIndex **out_local_subrs_to_use) {
6936263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org  *out_local_subrs_to_use = NULL;
6946263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org
6956263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org  // First, find local subrs from |local_subrs_per_font|.
6966263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org  if ((fd_select.size() > 0) &&
6976263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org      (!local_subrs_per_font.empty())) {
6986263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    // Look up FDArray index for the glyph.
6996263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    std::map<uint16_t, uint8_t>::const_iterator iter =
7006263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org        fd_select.find(glyph_index);
7016263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    if (iter == fd_select.end()) {
7026263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org      return OTS_FAILURE();
7036263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    }
7046263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    const uint8_t fd_index = iter->second;
7056263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    if (fd_index >= local_subrs_per_font.size()) {
7066263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org      return OTS_FAILURE();
7076263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    }
7086263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    *out_local_subrs_to_use = local_subrs_per_font.at(fd_index);
7096263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org  } else if (local_subrs) {
7106263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    // Second, try to use |local_subrs|. Most Latin fonts don't have FDSelect
7116263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    // entries. If The font has a local subrs index associated with the Top
7126263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    // DICT (not FDArrays), use it.
7136263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    *out_local_subrs_to_use = local_subrs;
7146263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org  } else {
7156263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    // Just return NULL.
7166263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    *out_local_subrs_to_use = NULL;
7176263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org  }
7186263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org
7196263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org  return true;
7206263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org}
7216263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org
7226263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org}  // namespace
7236263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org
7246263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.orgnamespace ots {
7256263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org
7266263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.orgbool ValidateType2CharStringIndex(
7276263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    const CFFIndex& char_strings_index,
7286263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    const CFFIndex& global_subrs_index,
7296263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    const std::map<uint16_t, uint8_t> &fd_select,
7306263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    const std::vector<CFFIndex *> &local_subrs_per_font,
7316263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    const CFFIndex *local_subrs,
7326263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    Buffer* cff_table) {
7336263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org  if (char_strings_index.offsets.size() == 0) {
7346263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    return OTS_FAILURE();  // no charstring.
7356263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org  }
7366263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org
7376263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org  // For each glyph, validate the corresponding charstring.
7386263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org  for (unsigned i = 1; i < char_strings_index.offsets.size(); ++i) {
7396263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    // Prepare a Buffer object, |char_string|, which contains the charstring
7406263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    // for the |i|-th glyph.
7416263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    const size_t length =
7426263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org      char_strings_index.offsets[i] - char_strings_index.offsets[i - 1];
7436263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    if (length > kMaxCharStringLength) {
7446263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org      return OTS_FAILURE();
7456263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    }
7466263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    const size_t offset = char_strings_index.offsets[i - 1];
7476263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    cff_table->set_offset(offset);
7486263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    if (!cff_table->Skip(length)) {
7496263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org      return OTS_FAILURE();
7506263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    }
7516263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    Buffer char_string(cff_table->buffer() + offset, length);
7526263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org
7536263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    // Get a local subrs for the glyph.
7546263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    const unsigned glyph_index = i - 1;  // index in the map is 0-origin.
7556263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    const CFFIndex *local_subrs_to_use = NULL;
7566263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    if (!SelectLocalSubr(fd_select,
7576263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org                         local_subrs_per_font,
7586263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org                         local_subrs,
7596263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org                         glyph_index,
7606263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org                         &local_subrs_to_use)) {
7616263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org      return OTS_FAILURE();
7626263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    }
7636263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    // If |local_subrs_to_use| is still NULL, use an empty one.
7646263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    CFFIndex default_empty_subrs;
7656263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    if (!local_subrs_to_use){
7666263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org      local_subrs_to_use = &default_empty_subrs;
7676263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    }
7686263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org
7696263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    // Check a charstring for the |i|-th glyph.
7706263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    std::stack<int32_t> argument_stack;
7716263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    bool found_endchar = false;
7726263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    bool found_width = false;
7736263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    size_t num_stems = 0;
7746263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    if (!ExecuteType2CharString(0 /* initial call_depth is zero */,
7756263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org                                global_subrs_index, *local_subrs_to_use,
7766263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org                                cff_table, &char_string, &argument_stack,
7776263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org                                &found_endchar, &found_width, &num_stems)) {
7786263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org      return OTS_FAILURE();
7796263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org    }
780fbb12969b4421ce7a155b7b34a7d855580d0f669yusukes@chromium.org    if (!found_endchar) {
781fbb12969b4421ce7a155b7b34a7d855580d0f669yusukes@chromium.org      return OTS_FAILURE();
782fbb12969b4421ce7a155b7b34a7d855580d0f669yusukes@chromium.org    }
7836263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org  }
7846263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org  return true;
7856263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org}
7866263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org
7876263d06109011f6cff761aed14ded117c8fa1836yusukes@chromium.org}  // namespace ots
788