mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-23 21:01:08 +00:00
Bug 1748352
- Update OTS to 8.2.1. r=jfkthame
Differential Revision: https://phabricator.services.mozilla.com/D134984
This commit is contained in:
parent
ac8e284b7b
commit
afe16b6d4e
@ -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
|
||||
|
||||
|
@ -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()) {
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -514,13 +514,16 @@ bool OpenTypeCMAP::Parse0514(const uint8_t *data, size_t length) {
|
||||
!subtable.ReadU16(&mappings[j].glyph_id)) {
|
||||
return Error("Can't read mapping %d in variation selector record %d", j, i);
|
||||
}
|
||||
if (mappings[j].glyph_id == 0 ||
|
||||
mappings[j].unicode_value == 0 ||
|
||||
mappings[j].unicode_value > kUnicodeUpperLimit ||
|
||||
(last_unicode_value &&
|
||||
mappings[j].unicode_value <= last_unicode_value)) {
|
||||
if (mappings[j].glyph_id == 0 || mappings[j].unicode_value == 0) {
|
||||
return Error("Bad mapping (%04X -> %d) in mapping %d of variation selector %d", mappings[j].unicode_value, mappings[j].glyph_id, j, i);
|
||||
}
|
||||
if (mappings[j].unicode_value > kUnicodeUpperLimit) {
|
||||
return Error("Invalid Unicode value (%04X > %04X) in mapping %d of variation selector %d", mappings[j].unicode_value, kUnicodeUpperLimit, j, i);
|
||||
}
|
||||
if (last_unicode_value &&
|
||||
mappings[j].unicode_value <= last_unicode_value) {
|
||||
return Error("Out of order Unicode value (%04X <= %04X) in mapping %d of variation selector %d", mappings[j].unicode_value, last_unicode_value, j, i);
|
||||
}
|
||||
last_unicode_value = mappings[j].unicode_value;
|
||||
}
|
||||
}
|
||||
|
@ -229,13 +229,13 @@ bool ProcessTTF(ots::FontFile *header,
|
||||
// Don't call ots_failure() here since ~25% of fonts (250+ fonts) in
|
||||
// http://www.princexml.com/fonts/ have unexpected search_range value.
|
||||
if (font->search_range != expected_search_range) {
|
||||
OTS_WARNING_MSG_HDR("bad search range");
|
||||
OTS_WARNING_MSG_HDR("bad table directory searchRange");
|
||||
font->search_range = expected_search_range; // Fix the value.
|
||||
}
|
||||
|
||||
// entry_selector is Log2(maximum power of 2 <= numTables)
|
||||
if (font->entry_selector != max_pow2) {
|
||||
OTS_WARNING_MSG_HDR("incorrect entrySelector for table directory");
|
||||
OTS_WARNING_MSG_HDR("bad table directory entrySelector");
|
||||
font->entry_selector = max_pow2; // Fix the value.
|
||||
}
|
||||
|
||||
@ -245,7 +245,7 @@ bool ProcessTTF(ots::FontFile *header,
|
||||
const uint16_t expected_range_shift =
|
||||
16 * font->num_tables - font->search_range;
|
||||
if (font->range_shift != expected_range_shift) {
|
||||
OTS_WARNING_MSG_HDR("bad range shift");
|
||||
OTS_WARNING_MSG_HDR("bad table directory rangeShift");
|
||||
font->range_shift = expected_range_shift; // the same as above.
|
||||
}
|
||||
|
||||
|
@ -206,7 +206,7 @@ bool ParseVariationData(const Font* font, const uint8_t* data, size_t length,
|
||||
return OTS_FAILURE_MSG("Failed to read tuple coordinate");
|
||||
}
|
||||
if (coordinate < -0x4000 || coordinate > 0x4000) {
|
||||
return OTS_FAILURE_MSG("Invalid tuple coordinate");
|
||||
return OTS_FAILURE_MSG("Tuple coordinate not in the range [-1.0, 1.0]: %g", coordinate / 16384.);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -219,7 +219,7 @@ bool ParseVariationData(const Font* font, const uint8_t* data, size_t length,
|
||||
return OTS_FAILURE_MSG("Failed to read tuple coordinate");
|
||||
}
|
||||
if (coordinate < -0x4000 || coordinate > 0x4000) {
|
||||
return OTS_FAILURE_MSG("Invalid tuple coordinate");
|
||||
return OTS_FAILURE_MSG("Tuple coordinate not in the range [-1.0, 1.0]: %g", coordinate / 16384.);
|
||||
}
|
||||
startTuple.push_back(coordinate);
|
||||
}
|
||||
@ -231,7 +231,7 @@ bool ParseVariationData(const Font* font, const uint8_t* data, size_t length,
|
||||
return OTS_FAILURE_MSG("Failed to read tuple coordinate");
|
||||
}
|
||||
if (coordinate < -0x4000 || coordinate > 0x4000) {
|
||||
return OTS_FAILURE_MSG("Invalid tuple coordinate");
|
||||
return OTS_FAILURE_MSG("Tuple coordinate not in the range [-1.0, 1.0]: %g", coordinate / 16384.);
|
||||
}
|
||||
endTuple.push_back(coordinate);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user